]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #96882 - jackh726:no-subst, r=oli-obk
authorYuki Okushi <jtitor@2k36.org>
Tue, 10 May 2022 15:09:36 +0000 (00:09 +0900)
committerGitHub <noreply@github.com>
Tue, 10 May 2022 15:09:36 +0000 (00:09 +0900)
Don't subst an AdtDef with its own substs

373 files changed:
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_const_eval/src/transform/promote_consts.rs
compiler/rustc_error_codes/src/error_codes/E0539.md
compiler/rustc_error_codes/src/error_codes/E0542.md
compiler/rustc_error_codes/src/error_codes/E0543.md
compiler/rustc_error_codes/src/error_codes/E0549.md
compiler/rustc_error_codes/src/error_codes/E0550.md
compiler/rustc_error_codes/src/error_codes/E0734.md
compiler/rustc_error_messages/locales/en-US/typeck.ftl
compiler/rustc_errors/src/lib.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/expect.rs
compiler/rustc_lint/src/late.rs
compiler/rustc_lint/src/levels.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_middle/src/lint.rs
compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
compiler/rustc_middle/src/middle/stability.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/switch_sources.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/impls_ty.rs
compiler/rustc_middle/src/ty/instance.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/subst.rs
compiler/rustc_mir_build/src/check_unsafety.rs
compiler/rustc_mir_dataflow/src/framework/direction.rs
compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
compiler/rustc_mir_transform/src/check_unsafety.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/reachable.rs
compiler/rustc_query_impl/src/keys.rs
compiler/rustc_symbol_mangling/src/lib.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/util.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/callee.rs
compiler/rustc_typeck/src/check/compare_method.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
compiler/rustc_typeck/src/check/method/confirm.rs
compiler/rustc_typeck/src/check/method/mod.rs
compiler/rustc_typeck/src/check/method/probe.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/errors.rs
library/alloc/src/collections/vec_deque/iter.rs
library/alloc/src/collections/vec_deque/iter_mut.rs
library/alloc/src/slice.rs
library/alloc/src/vec/into_iter.rs
library/core/src/alloc/layout.rs
library/core/src/alloc/mod.rs
library/core/src/array/iter.rs
library/core/src/convert/num.rs
library/core/src/fmt/mod.rs
library/core/src/hash/mod.rs
library/core/src/hash/sip.rs
library/core/src/intrinsics.rs
library/core/src/iter/adapters/cloned.rs
library/core/src/iter/adapters/copied.rs
library/core/src/iter/adapters/enumerate.rs
library/core/src/iter/adapters/fuse.rs
library/core/src/iter/adapters/map.rs
library/core/src/iter/adapters/zip.rs
library/core/src/iter/range.rs
library/core/src/macros/mod.rs
library/core/src/mem/mod.rs
library/core/src/num/f32.rs
library/core/src/num/f64.rs
library/core/src/num/int_macros.rs
library/core/src/num/shells/i128.rs
library/core/src/num/shells/i16.rs
library/core/src/num/shells/i32.rs
library/core/src/num/shells/i64.rs
library/core/src/num/shells/i8.rs
library/core/src/num/shells/int_macros.rs
library/core/src/num/shells/isize.rs
library/core/src/num/shells/u128.rs
library/core/src/num/shells/u16.rs
library/core/src/num/shells/u32.rs
library/core/src/num/shells/u64.rs
library/core/src/num/shells/u8.rs
library/core/src/num/shells/usize.rs
library/core/src/num/uint_macros.rs
library/core/src/primitive_docs.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/ptr/non_null.rs
library/core/src/slice/iter.rs
library/core/src/slice/iter/macros.rs
library/core/src/str/iter.rs
library/core/src/str/mod.rs
library/core/src/sync/atomic.rs
library/std/src/ascii.rs
library/std/src/collections/hash/map.rs
library/std/src/collections/hash/set.rs
library/std/src/collections/mod.rs
library/std/src/env.rs
library/std/src/error.rs
library/std/src/f32.rs
library/std/src/f64.rs
library/std/src/ffi/os_str.rs
library/std/src/ffi/os_str/tests.rs
library/std/src/fs.rs
library/std/src/io/cursor.rs
library/std/src/io/mod.rs
library/std/src/lib.rs
library/std/src/net/addr.rs
library/std/src/net/parser.rs
library/std/src/net/tcp.rs
library/std/src/os/android/fs.rs
library/std/src/os/android/raw.rs
library/std/src/os/dragonfly/fs.rs
library/std/src/os/dragonfly/raw.rs
library/std/src/os/emscripten/fs.rs
library/std/src/os/emscripten/raw.rs
library/std/src/os/espidf/fs.rs
library/std/src/os/espidf/raw.rs
library/std/src/os/freebsd/fs.rs
library/std/src/os/freebsd/raw.rs
library/std/src/os/fuchsia/raw.rs
library/std/src/os/haiku/fs.rs
library/std/src/os/haiku/raw.rs
library/std/src/os/illumos/fs.rs
library/std/src/os/illumos/raw.rs
library/std/src/os/ios/fs.rs
library/std/src/os/ios/raw.rs
library/std/src/os/l4re/fs.rs
library/std/src/os/l4re/raw.rs
library/std/src/os/linux/fs.rs
library/std/src/os/linux/raw.rs
library/std/src/os/macos/fs.rs
library/std/src/os/macos/raw.rs
library/std/src/os/netbsd/fs.rs
library/std/src/os/netbsd/raw.rs
library/std/src/os/openbsd/fs.rs
library/std/src/os/openbsd/raw.rs
library/std/src/os/redox/fs.rs
library/std/src/os/redox/raw.rs
library/std/src/os/solaris/fs.rs
library/std/src/os/solaris/raw.rs
library/std/src/os/unix/net/ancillary.rs
library/std/src/os/unix/net/tests.rs
library/std/src/os/unix/process.rs
library/std/src/os/unix/raw.rs
library/std/src/os/windows/io/handle.rs
library/std/src/os/windows/process.rs
library/std/src/path.rs
library/std/src/primitive_docs.rs
library/std/src/sync/condvar.rs
library/std/src/sync/mutex.rs
library/std/src/sync/once.rs
library/std/src/sync/rwlock.rs
library/std/src/sys/hermit/net.rs
library/std/src/sys/hermit/time.rs
library/std/src/sys/itron/spin.rs
library/std/src/sys/itron/thread.rs
library/std/src/sys/itron/time.rs
library/std/src/sys/sgx/abi/usercalls/mod.rs
library/std/src/sys/sgx/net.rs
library/std/src/sys/solid/time.rs
library/std/src/sys/unix/fs.rs
library/std/src/sys/unix/futex.rs
library/std/src/sys/unix/kernel_copy.rs
library/std/src/sys/unix/l4re.rs
library/std/src/sys/unix/process/process_fuchsia.rs
library/std/src/sys/unix/process/process_unix.rs
library/std/src/sys/unix/process/process_unsupported.rs
library/std/src/sys/unix/process/process_vxworks.rs
library/std/src/sys/unix/process/zircon.rs
library/std/src/sys/unix/thread_parker.rs
library/std/src/sys/unix/time.rs
library/std/src/sys/unsupported/net.rs
library/std/src/sys/wasi/net.rs
library/std/src/sys/wasm/atomics/futex.rs
library/std/src/sys/windows/fs.rs
library/std/src/sys/windows/os_str.rs
library/std/src/sys/windows/path/tests.rs
library/std/src/sys/windows/process.rs
library/std/src/sys/windows/process/tests.rs
library/std/src/sys/windows/thread.rs
library/std/src/sys/windows/thread_parker.rs
library/std/src/sys/windows/time.rs
library/std/src/sys_common/net.rs
library/std/src/sys_common/wtf8.rs
library/std/src/thread/mod.rs
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/defaults/config.codegen.toml
src/bootstrap/defaults/config.compiler.toml
src/bootstrap/defaults/config.tools.toml
src/bootstrap/lib.rs
src/bootstrap/mk/Makefile.in
src/bootstrap/sanity.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/ci/run.sh
src/doc/rustc/src/codegen-options/index.md
src/doc/rustc/src/command-line-arguments.md
src/doc/rustc/src/json.md
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/static/.eslintrc.js
src/librustdoc/html/static/js/main.js
src/librustdoc/html/static/js/scrape-examples.js
src/librustdoc/html/static/js/search.js
src/librustdoc/html/static/js/settings.js
src/librustdoc/html/static/js/storage.js
src/llvm-project
src/test/codegen/align-struct.rs
src/test/rustdoc-js-std/path-ordering.js [new file with mode: 0644]
src/test/rustdoc-js/path-ordering.js [new file with mode: 0644]
src/test/rustdoc-js/path-ordering.rs [new file with mode: 0644]
src/test/rustdoc-ui/expect-tool-lint-rfc-2383.rs [new file with mode: 0644]
src/test/rustdoc-ui/expect-tool-lint-rfc-2383.stderr [new file with mode: 0644]
src/test/rustdoc/deprecated-future-staged-api.rs [new file with mode: 0644]
src/test/rustdoc/inline_cross/auxiliary/macros.rs
src/test/rustdoc/inline_cross/macros.rs
src/test/rustdoc/issue-32374.rs
src/test/rustdoc/rustc_deprecated-future.rs [deleted file]
src/test/ui/argument-suggestions/basic.rs
src/test/ui/argument-suggestions/basic.stderr
src/test/ui/associated-types/associated-types-issue-20346.stderr
src/test/ui/associated-types/higher-ranked-projection.bad.stderr
src/test/ui/async-await/generator-desc.stderr
src/test/ui/async-await/suggest-missing-await.stderr
src/test/ui/borrowck/issue-28934.rs [new file with mode: 0644]
src/test/ui/borrowck/suggest-local-var-imm-and-mut.nll.stderr [deleted file]
src/test/ui/closures/closure_cap_coerce_many_fail.stderr
src/test/ui/closures/issue-6801.rs [new file with mode: 0644]
src/test/ui/closures/issue-6801.stderr [new file with mode: 0644]
src/test/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr
src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr
src/test/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr [deleted file]
src/test/ui/const-generics/const-argument-non-static-lifetime.rs
src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs [new file with mode: 0644]
src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-77357.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-77357.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-775377.rs [deleted file]
src/test/ui/const-generics/issues/issue-775377.stderr [deleted file]
src/test/ui/const-generics/issues/issue-86820.rs
src/test/ui/const-generics/issues/issue-86820.stderr
src/test/ui/const-generics/issues/issue-96654.rs [new file with mode: 0644]
src/test/ui/continue-after-missing-main.nll.stderr [deleted file]
src/test/ui/continue-after-missing-main.rs [deleted file]
src/test/ui/continue-after-missing-main.stderr [deleted file]
src/test/ui/deprecation/deprecation-in-future.rs
src/test/ui/deprecation/deprecation-in-future.stderr
src/test/ui/deprecation/deprecation-lint.rs
src/test/ui/deprecation/deprecation-sanity.rs
src/test/ui/deprecation/deprecation-sanity.stderr
src/test/ui/deprecation/rustc_deprecated.rs [new file with mode: 0644]
src/test/ui/deprecation/rustc_deprecated.stderr [new file with mode: 0644]
src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr
src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr
src/test/ui/error-codes/E0057.stderr
src/test/ui/error-codes/E0502.nll.stderr [deleted file]
src/test/ui/estr-subtyping.rs [deleted file]
src/test/ui/estr-subtyping.stderr [deleted file]
src/test/ui/fn/fn-item-type.rs
src/test/ui/fn/fn-item-type.stderr
src/test/ui/generator/type-mismatch-signature-deduction.stderr
src/test/ui/generic-associated-types/const_params_have_right_type.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/const_params_have_right_type.stderr [new file with mode: 0644]
src/test/ui/indexing-requires-a-uint.stderr
src/test/ui/issues/issue-13359.stderr
src/test/ui/issues/issue-14940.rs [deleted file]
src/test/ui/issues/issue-28934.rs [deleted file]
src/test/ui/issues/issue-38715.rs [deleted file]
src/test/ui/issues/issue-38715.stderr [deleted file]
src/test/ui/issues/issue-48803.rs [deleted file]
src/test/ui/issues/issue-48803.stderr [deleted file]
src/test/ui/issues/issue-52533-1.nll.stderr [deleted file]
src/test/ui/issues/issue-52533-1.rs [deleted file]
src/test/ui/issues/issue-52533-1.stderr [deleted file]
src/test/ui/issues/issue-6801.rs [deleted file]
src/test/ui/issues/issue-6801.stderr [deleted file]
src/test/ui/layout/debug.stderr
src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
src/test/ui/let-else/let-else-non-diverging.stderr
src/test/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs [new file with mode: 0644]
src/test/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr [new file with mode: 0644]
src/test/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs [new file with mode: 0644]
src/test/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout [new file with mode: 0644]
src/test/ui/lint/unused/unused-attr-doc-hidden.fixed [new file with mode: 0644]
src/test/ui/lint/unused/unused-attr-doc-hidden.rs [new file with mode: 0644]
src/test/ui/lint/unused/unused-attr-doc-hidden.stderr [new file with mode: 0644]
src/test/ui/macros/issue-38715.rs [new file with mode: 0644]
src/test/ui/macros/issue-38715.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/issue-26480.stderr
src/test/ui/nll/continue-after-missing-main.nll.stderr [new file with mode: 0644]
src/test/ui/nll/continue-after-missing-main.rs [new file with mode: 0644]
src/test/ui/nll/continue-after-missing-main.stderr [new file with mode: 0644]
src/test/ui/nll/issue-48803.rs [new file with mode: 0644]
src/test/ui/nll/issue-48803.stderr [new file with mode: 0644]
src/test/ui/nll/issue-52533-1.nll.stderr [new file with mode: 0644]
src/test/ui/nll/issue-52533-1.rs [new file with mode: 0644]
src/test/ui/nll/issue-52533-1.stderr [new file with mode: 0644]
src/test/ui/or-patterns/already-bound-name.stderr
src/test/ui/or-patterns/inconsistent-modes.stderr
src/test/ui/parser/recover-range-pats.stderr
src/test/ui/process/issue-14940.rs [new file with mode: 0644]
src/test/ui/reify-intrinsic.stderr
src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr
src/test/ui/rfc-2005-default-binding-mode/lit.stderr
src/test/ui/rust-2018/auxiliary/edition-lint-infer-outlives-macro.rs [new file with mode: 0644]
src/test/ui/rust-2018/edition-lint-infer-outlives-macro.rs [new file with mode: 0644]
src/test/ui/rust-2018/edition-lint-infer-outlives-macro.stderr [new file with mode: 0644]
src/test/ui/span/E0057.rs [deleted file]
src/test/ui/span/E0057.stderr [deleted file]
src/test/ui/stability-attribute/stability-attribute-sanity.rs
src/test/ui/stability-attribute/stability-attribute-sanity.stderr
src/test/ui/suggestions/issue-81839.stderr
src/test/ui/suggestions/issue-96555.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-96555.stderr [new file with mode: 0644]
src/test/ui/suggestions/match-prev-arm-needing-semi.rs
src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr
src/test/ui/suggestions/opaque-type-error.stderr
src/test/ui/traits/alias/only-maybe-bound.stderr
src/test/ui/traits/issue-52893.stderr
src/test/ui/traits/issue-65673.rs
src/test/ui/traits/issue-65673.stderr
src/test/ui/traits/issue-96664.rs [new file with mode: 0644]
src/test/ui/traits/issue-96665.rs [new file with mode: 0644]
src/test/ui/tuple/wrong_argument_ice-4.stderr
src/test/ui/type-alias-impl-trait/auxiliary/collect_hidden_types.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/collect_hidden_types.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/cross_inference.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/cross_inference_rpit.rs [new file with mode: 0644]
src/test/ui/typeck/issue-96738.rs
src/test/ui/typeck/issue-96738.stderr
src/test/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr
src/test/ui/unsized/box-instead-of-dyn-fn.stderr
src/test/ui/wf/wf-unsafe-trait-obj-match.stderr
src/tools/clippy/CHANGELOG.md
src/tools/clippy/clippy_lints/src/lib.register_lints.rs
src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/clippy/clippy_lints/src/significant_drop_in_scrutinee.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/trait_bounds.rs
src/tools/clippy/clippy_utils/src/attrs.rs
src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
src/tools/tidy/src/ui_tests.rs

index 5a95e5b084ad42b8ab9daf89c70527bde997dbae..cf97b270ed8f9779fb7d3c001b6ef3d5b0197abe 100644 (file)
@@ -11,6 +11,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::PredicateOrigin;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_session::utils::NtToTokenstream;
 use rustc_session::Session;
@@ -1346,7 +1347,13 @@ pub(super) fn lower_generics_mut(
         let mut predicates = SmallVec::new();
         predicates.extend(generics.params.iter().filter_map(|param| {
             let bounds = self.lower_param_bounds(&param.bounds, itctx.reborrow());
-            self.lower_generic_bound_predicate(param.ident, param.id, &param.kind, bounds)
+            self.lower_generic_bound_predicate(
+                param.ident,
+                param.id,
+                &param.kind,
+                bounds,
+                PredicateOrigin::GenericParam,
+            )
         }));
         predicates.extend(
             generics
@@ -1380,6 +1387,7 @@ pub(super) fn lower_generic_bound_predicate(
         id: NodeId,
         kind: &GenericParamKind,
         bounds: &'hir [hir::GenericBound<'hir>],
+        origin: PredicateOrigin,
     ) -> Option<hir::WherePredicate<'hir>> {
         // Do not create a clause if we do not have anything inside it.
         if bounds.is_empty() {
@@ -1419,7 +1427,7 @@ pub(super) fn lower_generic_bound_predicate(
                     bounds,
                     span,
                     bound_generic_params: &[],
-                    in_where_clause: false,
+                    origin,
                 }))
             }
             GenericParamKind::Lifetime => {
@@ -1458,7 +1466,7 @@ fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicat
                     )
                 })),
                 span: self.lower_span(span),
-                in_where_clause: true,
+                origin: PredicateOrigin::WhereClause,
             }),
             WherePredicate::RegionPredicate(WhereRegionPredicate {
                 ref lifetime,
index 54b081085cdd7b497d5868d8a471dc2990586f73..c143266f6c1de7921a52101ee312e2a243f041db 100644 (file)
@@ -1298,6 +1298,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                             def_node_id,
                             &GenericParamKind::Type { default: None },
                             hir_bounds,
+                            hir::PredicateOrigin::ImplTrait,
                         ) {
                             in_band_ty_bounds.push(preds)
                         }
index 8e748aaa58b598bf33f9c0329108406228bb55ec..5a79cf68f113e192d745abd3b630802bf11e9d90 100644 (file)
@@ -679,12 +679,12 @@ fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(Dep
             continue;
         }
 
-        if let Some((_, span)) = &depr {
-            struct_span_err!(diagnostic, attr.span, E0550, "multiple deprecated attributes")
-                .span_label(attr.span, "repeated deprecation attribute")
-                .span_label(*span, "first deprecation attribute")
+        // FIXME(jhpratt) remove this eventually
+        if attr.has_name(sym::rustc_deprecated) {
+            diagnostic
+                .struct_span_err(attr.span, "`#[rustc_deprecated]` has been removed")
+                .help("use `#[deprecated]` instead")
                 .emit();
-            break;
         }
 
         let Some(meta) = attr.meta() else {
@@ -742,12 +742,24 @@ fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(Dep
                                     continue 'outer;
                                 }
                             }
-                            // FIXME(jhpratt) remove this after a bootstrap occurs. Emitting an
-                            // error specific to the renaming would be a good idea as well.
+                            // FIXME(jhpratt) remove this eventually
                             sym::reason if attr.has_name(sym::rustc_deprecated) => {
                                 if !get(mi, &mut note) {
                                     continue 'outer;
                                 }
+
+                                let mut diag = diagnostic
+                                    .struct_span_err(mi.span, "`reason` has been renamed");
+                                match note {
+                                    Some(note) => diag.span_suggestion(
+                                        mi.span,
+                                        "use `note` instead",
+                                        format!("note = \"{note}\""),
+                                        Applicability::MachineApplicable,
+                                    ),
+                                    None => diag.span_help(mi.span, "use `note` instead"),
+                                };
+                                diag.emit();
                             }
                             sym::suggestion => {
                                 if !sess.features_untracked().deprecated_suggestion {
index 1052d588fadce960edcb7e895f9ab4d37ec439e6..f88538f61ec6eb43d6aaf4cb1b7aea98af3d6650 100644 (file)
@@ -60,9 +60,9 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 
         let mut rpo = traversal::reverse_postorder(body);
         let ccx = ConstCx::new(tcx, body);
-        let (temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
+        let (mut temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
 
-        let promotable_candidates = validate_candidates(&ccx, &temps, &all_candidates);
+        let promotable_candidates = validate_candidates(&ccx, &mut temps, &all_candidates);
 
         let promoted = promote_candidates(body, tcx, temps, promotable_candidates);
         self.promoted_fragments.set(promoted);
@@ -77,7 +77,7 @@ pub enum TempState {
     /// One direct assignment and any number of direct uses.
     /// A borrow of this temp is promotable if the assigned
     /// value is qualified as constant.
-    Defined { location: Location, uses: usize },
+    Defined { location: Location, uses: usize, valid: Result<(), ()> },
     /// Any other combination of assignments/uses.
     Unpromotable,
     /// This temp was part of an rvalue which got extracted
@@ -133,7 +133,7 @@ fn visit_local(&mut self, &index: &Local, context: PlaceContext, location: Locat
             match context {
                 PlaceContext::MutatingUse(MutatingUseContext::Store)
                 | PlaceContext::MutatingUse(MutatingUseContext::Call) => {
-                    *temp = TempState::Defined { location, uses: 0 };
+                    *temp = TempState::Defined { location, uses: 0, valid: Err(()) };
                     return;
                 }
                 _ => { /* mark as unpromotable below */ }
@@ -188,7 +188,7 @@ pub fn collect_temps_and_candidates<'tcx>(
 /// This wraps an `Item`, and has access to all fields of that `Item` via `Deref` coercion.
 struct Validator<'a, 'tcx> {
     ccx: &'a ConstCx<'a, 'tcx>,
-    temps: &'a IndexVec<Local, TempState>,
+    temps: &'a mut IndexVec<Local, TempState>,
 }
 
 impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> {
@@ -202,7 +202,7 @@ fn deref(&self) -> &Self::Target {
 struct Unpromotable;
 
 impl<'tcx> Validator<'_, 'tcx> {
-    fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
+    fn validate_candidate(&mut self, candidate: Candidate) -> Result<(), Unpromotable> {
         let loc = candidate.location;
         let statement = &self.body[loc.block].statements[loc.statement_index];
         match &statement.kind {
@@ -234,7 +234,7 @@ fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> {
     }
 
     // FIXME(eddyb) maybe cache this?
-    fn qualif_local<Q: qualifs::Qualif>(&self, local: Local) -> bool {
+    fn qualif_local<Q: qualifs::Qualif>(&mut self, local: Local) -> bool {
         if let TempState::Defined { location: loc, .. } = self.temps[local] {
             let num_stmts = self.body[loc.block].statements.len();
 
@@ -272,40 +272,50 @@ fn qualif_local<Q: qualifs::Qualif>(&self, local: Local) -> bool {
         }
     }
 
-    // FIXME(eddyb) maybe cache this?
-    fn validate_local(&self, local: Local) -> Result<(), Unpromotable> {
-        if let TempState::Defined { location: loc, .. } = self.temps[local] {
-            let block = &self.body[loc.block];
-            let num_stmts = block.statements.len();
-
-            if loc.statement_index < num_stmts {
-                let statement = &block.statements[loc.statement_index];
-                match &statement.kind {
-                    StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs),
-                    _ => {
-                        span_bug!(
-                            statement.source_info.span,
-                            "{:?} is not an assignment",
-                            statement
-                        );
-                    }
-                }
-            } else {
-                let terminator = block.terminator();
-                match &terminator.kind {
-                    TerminatorKind::Call { func, args, .. } => self.validate_call(func, args),
-                    TerminatorKind::Yield { .. } => Err(Unpromotable),
-                    kind => {
-                        span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
+    fn validate_local(&mut self, local: Local) -> Result<(), Unpromotable> {
+        if let TempState::Defined { location: loc, uses, valid } = self.temps[local] {
+            valid.or_else(|_| {
+                let ok = {
+                    let block = &self.body[loc.block];
+                    let num_stmts = block.statements.len();
+
+                    if loc.statement_index < num_stmts {
+                        let statement = &block.statements[loc.statement_index];
+                        match &statement.kind {
+                            StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs),
+                            _ => {
+                                span_bug!(
+                                    statement.source_info.span,
+                                    "{:?} is not an assignment",
+                                    statement
+                                );
+                            }
+                        }
+                    } else {
+                        let terminator = block.terminator();
+                        match &terminator.kind {
+                            TerminatorKind::Call { func, args, .. } => {
+                                self.validate_call(func, args)
+                            }
+                            TerminatorKind::Yield { .. } => Err(Unpromotable),
+                            kind => {
+                                span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
+                            }
+                        }
                     }
-                }
-            }
+                };
+                self.temps[local] = match ok {
+                    Ok(()) => TempState::Defined { location: loc, uses, valid: Ok(()) },
+                    Err(_) => TempState::Unpromotable,
+                };
+                ok
+            })
         } else {
             Err(Unpromotable)
         }
     }
 
-    fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
+    fn validate_place(&mut self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
         match place.last_projection() {
             None => self.validate_local(place.local),
             Some((place_base, elem)) => {
@@ -417,7 +427,7 @@ fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
         }
     }
 
-    fn validate_operand(&self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> {
+    fn validate_operand(&mut self, operand: &Operand<'tcx>) -> Result<(), Unpromotable> {
         match operand {
             Operand::Copy(place) | Operand::Move(place) => self.validate_place(place.as_ref()),
 
@@ -447,7 +457,7 @@ fn validate_operand(&self, operand: &Operand<'tcx>) -> Result<(), Unpromotable>
         }
     }
 
-    fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> {
+    fn validate_ref(&mut self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> {
         match kind {
             // Reject these borrow types just to be safe.
             // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
@@ -480,7 +490,7 @@ fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpr
         Ok(())
     }
 
-    fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
+    fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
         match rvalue {
             Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
                 self.validate_operand(operand)?;
@@ -623,7 +633,7 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
     }
 
     fn validate_call(
-        &self,
+        &mut self,
         callee: &Operand<'tcx>,
         args: &[Operand<'tcx>],
     ) -> Result<(), Unpromotable> {
@@ -665,10 +675,10 @@ fn validate_call(
 // FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
 pub fn validate_candidates(
     ccx: &ConstCx<'_, '_>,
-    temps: &IndexVec<Local, TempState>,
+    temps: &mut IndexVec<Local, TempState>,
     candidates: &[Candidate],
 ) -> Vec<Candidate> {
-    let validator = Validator { ccx, temps };
+    let mut validator = Validator { ccx, temps };
 
     candidates
         .iter()
@@ -720,7 +730,7 @@ fn is_temp_kind(&self, local: Local) -> bool {
     fn promote_temp(&mut self, temp: Local) -> Local {
         let old_keep_original = self.keep_original;
         let loc = match self.temps[temp] {
-            TempState::Defined { location, uses } if uses > 0 => {
+            TempState::Defined { location, uses, .. } if uses > 0 => {
                 if uses > 1 {
                     self.keep_original = true;
                 }
index df2d7d910bb360fc3e06b9bb87b98e85e3318b52..c53d60a5f4757b08a86b7e5e8e405cf611945548 100644 (file)
@@ -6,7 +6,7 @@ Erroneous code example:
 #![feature(staged_api)]
 #![stable(since = "1.0.0", feature = "test")]
 
-#[rustc_deprecated(reason)] // error!
+#[deprecated(note)] // error!
 #[unstable(feature = "deprecated_fn", issue = "123")]
 fn deprecated() {}
 
@@ -30,7 +30,7 @@ To fix these issues you need to give required key-value pairs.
 #![feature(staged_api)]
 #![stable(since = "1.0.0", feature = "test")]
 
-#[rustc_deprecated(since = "1.39.0", reason = "reason")] // ok!
+#[deprecated(since = "1.39.0", note = "reason")] // ok!
 #[unstable(feature = "deprecated_fn", issue = "123")]
 fn deprecated() {}
 
index 7fecfeaa57c283000e81c42e4f6dacb7200d824a..c69e574179b105691eee6e3083e62bdb99237472 100644 (file)
@@ -13,8 +13,8 @@ fn _stable_fn() {}
 const fn _stable_const_fn() {}
 
 #[stable(feature = "_deprecated_fn", since = "0.1.0")]
-#[rustc_deprecated(
-    reason = "explanation for deprecation"
+#[deprecated(
+    note = "explanation for deprecation"
 )] // invalid
 fn _deprecated_fn() {}
 ```
@@ -32,9 +32,9 @@ fn _stable_fn() {}
 const fn _stable_const_fn() {}
 
 #[stable(feature = "_deprecated_fn", since = "0.1.0")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.0.0",
-    reason = "explanation for deprecation"
+    note = "explanation for deprecation"
 )] // ok!
 fn _deprecated_fn() {}
 ```
index ba26f92e89f5e3f0b3204524c416a355a6f57251..d0b2e2f7a7d0fe3ad8ee0abefe5909c4c19e9ec8 100644 (file)
@@ -1,4 +1,4 @@
-The `reason` value is missing in a stability attribute.
+The `note` value is missing in a stability attribute.
 
 Erroneous code example:
 
@@ -7,22 +7,22 @@ Erroneous code example:
 #![stable(since = "1.0.0", feature = "test")]
 
 #[stable(since = "0.1.0", feature = "_deprecated_fn")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.0.0"
 )] // invalid
 fn _deprecated_fn() {}
 ```
 
-To fix this issue, you need to provide the `reason` field. Example:
+To fix this issue, you need to provide the `note` field. Example:
 
 ```
 #![feature(staged_api)]
 #![stable(since = "1.0.0", feature = "test")]
 
 #[stable(since = "0.1.0", feature = "_deprecated_fn")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.0.0",
-    reason = "explanation for deprecation"
+    note = "explanation for deprecation"
 )] // ok!
 fn _deprecated_fn() {}
 ```
index d4b78e7e0d668d706a6aa45c8a0ef4415a1fdc9f..70e458a98673ce8c1e5f7d403ec5ac6defb4c430 100644 (file)
@@ -1,5 +1,5 @@
-A `rustc_deprecated` attribute wasn't paired with a `stable`/`unstable`
-attribute.
+A `deprecated` attribute wasn't paired with a `stable`/`unstable` attribute with
+`#![feature(staged_api)]` enabled.
 
 Erroneous code example:
 
@@ -7,9 +7,9 @@ Erroneous code example:
 #![feature(staged_api)]
 #![stable(since = "1.0.0", feature = "test")]
 
-#[rustc_deprecated(
+#[deprecated(
     since = "1.0.1",
-    reason = "explanation for deprecation"
+    note = "explanation for deprecation"
 )] // invalid
 fn _deprecated_fn() {}
 ```
@@ -22,9 +22,9 @@ Example:
 #![stable(since = "1.0.0", feature = "test")]
 
 #[stable(since = "1.0.0", feature = "test")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.0.1",
-    reason = "explanation for deprecation"
+    note = "explanation for deprecation"
 )] // ok!
 fn _deprecated_fn() {}
 ```
index 1487d701847fcb653b6a2dbbcd22932fb5c59979..6aac5c969d23bf723fe47b203813ec6736dcad9e 100644 (file)
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler
+
 More than one `deprecated` attribute has been put on an item.
 
 Erroneous code example:
 
-```compile_fail,E0550
+```compile_fail
 #[deprecated(note = "because why not?")]
 #[deprecated(note = "right?")] // error!
 fn the_banished() {}
index 4b8e89a70604d0974f5630271e3632c709b3a066..b912061ec42ccbaf43a067f3b8adec0cb457556e 100644 (file)
@@ -3,7 +3,6 @@ A stability attribute has been used outside of the standard library.
 Erroneous code example:
 
 ```compile_fail,E0734
-#[rustc_deprecated(since = "b", reason = "text")] // invalid
 #[stable(feature = "a", since = "b")] // invalid
 #[unstable(feature = "b", issue = "none")] // invalid
 fn foo(){}
index aef18fcafaa05e5cb8267d432ffd27015abaaf14..9195d7a2b8f9248a1afd8e75be4bf67f7613d6eb 100644 (file)
@@ -45,6 +45,7 @@ typeck-copy-impl-on-non-adt =
 
 typeck-trait-object-declared-with-no-traits =
     at least one trait is required for an object type
+    .alias-span = this alias does not contain a trait
 
 typeck-ambiguous-lifetime-bound =
     ambiguous lifetime bound, explicit lifetime bound required
index f83fa68ced00daa6a0e17d615cac38f8a7e79af1..29643eaad992445fe4cac8c506002a4367daf797 100644 (file)
@@ -426,6 +426,13 @@ struct HandlerInner {
 
     future_breakage_diagnostics: Vec<Diagnostic>,
 
+    /// The [`Self::unstable_expect_diagnostics`] should be empty when this struct is
+    /// dropped. However, it can have values if the compilation is stopped early
+    /// or is only partially executed. To avoid ICEs, like in rust#94953 we only
+    /// check if [`Self::unstable_expect_diagnostics`] is empty, if the expectation ids
+    /// have been converted.
+    check_unstable_expect_diagnostics: bool,
+
     /// Expected [`Diagnostic`]s store a [`LintExpectationId`] as part of
     /// the lint level. [`LintExpectationId`]s created early during the compilation
     /// (before `HirId`s have been defined) are not stable and can therefore not be
@@ -497,10 +504,12 @@ fn drop(&mut self) {
             );
         }
 
-        assert!(
-            self.unstable_expect_diagnostics.is_empty(),
-            "all diagnostics with unstable expectations should have been converted",
-        );
+        if self.check_unstable_expect_diagnostics {
+            assert!(
+                self.unstable_expect_diagnostics.is_empty(),
+                "all diagnostics with unstable expectations should have been converted",
+            );
+        }
     }
 }
 
@@ -574,6 +583,7 @@ pub fn with_emitter_and_flags(
                 emitted_diagnostics: Default::default(),
                 stashed_diagnostics: Default::default(),
                 future_breakage_diagnostics: Vec::new(),
+                check_unstable_expect_diagnostics: false,
                 unstable_expect_diagnostics: Vec::new(),
                 fulfilled_expectations: Default::default(),
             }),
@@ -988,12 +998,13 @@ pub fn update_unstable_expectation_id(
         &self,
         unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
     ) {
-        let diags = std::mem::take(&mut self.inner.borrow_mut().unstable_expect_diagnostics);
+        let mut inner = self.inner.borrow_mut();
+        let diags = std::mem::take(&mut inner.unstable_expect_diagnostics);
+        inner.check_unstable_expect_diagnostics = true;
         if diags.is_empty() {
             return;
         }
 
-        let mut inner = self.inner.borrow_mut();
         for mut diag in diags.into_iter() {
             diag.update_unstable_expectation_id(unstable_to_stable);
 
index 5c07d9121cc54c015331a4b035930f747ca09098..520769d308e66f785c844f18bfe96e6946cacc35 100644 (file)
@@ -244,7 +244,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
 
     // Unstable `#[target_feature]` directives.
     (active, aarch64_ver_target_feature, "1.27.0", Some(44839), None),
-    (active, adx_target_feature, "1.32.0", Some(44839), None),
     (active, arm_target_feature, "1.27.0", Some(44839), None),
     (active, avx512_target_feature, "1.27.0", Some(44839), None),
     (active, bpf_target_feature, "1.54.0", Some(44839), None),
index 33d2e82b24a26c06d8f7586de88c3b14990fa183..c5f42aa7af72438e85ee45a71d60ed7e7814f0bb 100644 (file)
@@ -304,8 +304,7 @@ pub struct BuiltinAttribute {
             List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
             NameValueStr: "reason"
         ),
-        // This has special duplicate handling in E0550 to handle duplicates with rustc_deprecated
-        DuplicatesOk
+        ErrorFollowing
     ),
 
     // Crate properties:
@@ -469,10 +468,10 @@ pub struct BuiltinAttribute {
     // ==========================================================================
 
     ungated!(feature, CrateLevel, template!(List: "name1, name2, ..."), DuplicatesOk),
-    // DuplicatesOk since it has its own validation
+    // FIXME(jhpratt) remove this eventually
     ungated!(
         rustc_deprecated, Normal,
-        template!(List: r#"since = "version", note = "...""#), DuplicatesOk // See E0550
+        template!(List: r#"since = "version", note = "...""#), ErrorFollowing
     ),
     // DuplicatesOk since it has its own validation
     ungated!(
index db8807bad40b11985c88a37a87edd9831a5e88f7..a639df01a78d4acbe1fb4f70d4a5cabe0a8a5580 100644 (file)
@@ -229,6 +229,43 @@ pub fn is_fn_like(self) -> bool {
             _ => false,
         }
     }
+
+    /// Whether `query get_codegen_attrs` should be used with this definition.
+    pub fn has_codegen_attrs(self) -> bool {
+        match self {
+            DefKind::Fn
+            | DefKind::AssocFn
+            | DefKind::Ctor(..)
+            | DefKind::Closure
+            | DefKind::Generator
+            | DefKind::Static(_) => true,
+            DefKind::Mod
+            | DefKind::Struct
+            | DefKind::Union
+            | DefKind::Enum
+            | DefKind::Variant
+            | DefKind::Trait
+            | DefKind::TyAlias
+            | DefKind::ForeignTy
+            | DefKind::TraitAlias
+            | DefKind::AssocTy
+            | DefKind::Const
+            | DefKind::AssocConst
+            | DefKind::Macro(..)
+            | DefKind::Use
+            | DefKind::ForeignMod
+            | DefKind::OpaqueTy
+            | DefKind::Impl
+            | DefKind::Field
+            | DefKind::TyParam
+            | DefKind::ConstParam
+            | DefKind::LifetimeParam
+            | DefKind::AnonConst
+            | DefKind::InlineConst
+            | DefKind::GlobalAsm
+            | DefKind::ExternCrate => false,
+        }
+    }
 }
 
 /// The resolution of a path or export.
index 2f379b85b92c7bbb1d6043d9f878b49808e1c94f..4d4d4a28499af439e1a881202a6b305a2a1f4993 100644 (file)
@@ -706,7 +706,7 @@ pub fn span(&self) -> Span {
 
     pub fn in_where_clause(&self) -> bool {
         match self {
-            WherePredicate::BoundPredicate(p) => p.in_where_clause,
+            WherePredicate::BoundPredicate(p) => p.origin == PredicateOrigin::WhereClause,
             WherePredicate::RegionPredicate(p) => p.in_where_clause,
             WherePredicate::EqPredicate(_) => false,
         }
@@ -721,11 +721,19 @@ pub fn bounds(&self) -> GenericBounds<'hir> {
     }
 }
 
+#[derive(Debug, HashStable_Generic, PartialEq, Eq)]
+pub enum PredicateOrigin {
+    WhereClause,
+    GenericParam,
+    ImplTrait,
+}
+
 /// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
 #[derive(Debug, HashStable_Generic)]
 pub struct WhereBoundPredicate<'hir> {
     pub span: Span,
-    pub in_where_clause: bool,
+    /// Origin of the predicate.
+    pub origin: PredicateOrigin,
     /// Any generics from a `for` binding.
     pub bound_generic_params: &'hir [GenericParam<'hir>],
     /// The type being bounded.
index ccd860ce2428aa33f3b214ec7abce7aaa01aed73..af81f5cde2c41778bbdcdb14f94006ab65b140b3 100644 (file)
@@ -1584,9 +1584,10 @@ enum Mismatch<'a> {
             Variable(ty::error::ExpectedFound<Ty<'a>>),
             Fixed(&'static str),
         }
-        let (expected_found, exp_found, is_simple_error) = match values {
-            None => (None, Mismatch::Fixed("type"), false),
+        let (expected_found, exp_found, is_simple_error, values) = match values {
+            None => (None, Mismatch::Fixed("type"), false, None),
             Some(values) => {
+                let values = self.resolve_vars_if_possible(values);
                 let (is_simple_error, exp_found) = match values {
                     ValuePairs::Terms(infer::ExpectedFound {
                         expected: ty::Term::Ty(expected),
@@ -1614,7 +1615,7 @@ enum Mismatch<'a> {
                         return;
                     }
                 };
-                (vals, exp_found, is_simple_error)
+                (vals, exp_found, is_simple_error, Some(values))
             }
         };
 
index 08987dff660a4d78391280df384aa6a6430375f7..00119267e8561be4985be7d122ce95ab43793e0b 100644 (file)
@@ -1009,6 +1009,10 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
                 });
             }
         );
+
+        // This check has to be run after all lints are done processing. We don't
+        // define a lint filter, as all lint checks should have finished at this point.
+        sess.time("check_lint_expectations", || tcx.check_expectations(None));
     });
 
     Ok(())
index 24ccc730781f251aa619245b1b9cc4767afb1610..4141d952683efd62f25d35dcc73beddf70b02321 100644 (file)
@@ -36,9 +36,9 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
-use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind};
+use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind, PredicateOrigin};
 use rustc_index::vec::Idx;
-use rustc_middle::lint::LintDiagnosticBuilder;
+use rustc_middle::lint::{in_external_macro, LintDiagnosticBuilder};
 use rustc_middle::ty::layout::{LayoutError, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::GenericArgKind;
@@ -2115,6 +2115,7 @@ fn collect_outlives_bound_spans<'tcx>(
                     None
                 }
             })
+            .filter(|(_, span)| !in_external_macro(tcx.sess, *span))
             .collect()
     }
 
@@ -2226,7 +2227,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                                     Self::lifetimes_outliving_type(inferred_outlives, index),
                                     &predicate.bounds,
                                     predicate.span,
-                                    predicate.in_where_clause,
+                                    predicate.origin == PredicateOrigin::WhereClause,
                                 )
                             }
                             _ => {
index 67f5aa0540fbe19c42eb9a331189d3c3e47ec09b..dc48ac0a618e7b1574adc13346ab3bd252f4618a 100644 (file)
@@ -1,10 +1,16 @@
 use crate::builtin;
 use rustc_hir::HirId;
+use rustc_middle::ty::query::Providers;
 use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
 use rustc_session::lint::LintExpectationId;
 use rustc_span::symbol::sym;
+use rustc_span::Symbol;
 
-pub fn check_expectations(tcx: TyCtxt<'_>) {
+pub(crate) fn provide(providers: &mut Providers) {
+    *providers = Providers { check_expectations, ..*providers };
+}
+
+fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
     if !tcx.sess.features_untracked().enabled(sym::lint_reasons) {
         return;
     }
@@ -13,7 +19,9 @@ pub fn check_expectations(tcx: TyCtxt<'_>) {
     let lint_expectations = &tcx.lint_levels(()).lint_expectations;
 
     for (id, expectation) in lint_expectations {
-        if !fulfilled_expectations.contains(id) {
+        if !fulfilled_expectations.contains(id)
+            && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
+        {
             // This check will always be true, since `lint_expectations` only
             // holds stable ids
             if let LintExpectationId::Stable { hir_id, .. } = id {
index 0ac636b878e0d0bb1ad90568f4b11ae8e4cac54b..0ce760b64d9ca0e889f01d8877421d0852fc4521 100644 (file)
@@ -503,7 +503,4 @@ pub fn check_crate<'tcx, T: LateLintPass<'tcx>>(
             });
         },
     );
-
-    // This check has to be run after all lints are done processing for this crate
-    tcx.sess.time("check_lint_expectations", || crate::expect::check_expectations(tcx));
 }
index 01f1d1e79ac6c17d113cb14678a2996ee09dda32..257549bf1a1a47900bea026cf168fd709c2fbdc8 100644 (file)
@@ -371,7 +371,12 @@ pub(crate) fn push(
                             };
                             self.lint_expectations.push((
                                 expect_id,
-                                LintExpectation::new(reason, sp, is_unfulfilled_lint_expectations),
+                                LintExpectation::new(
+                                    reason,
+                                    sp,
+                                    is_unfulfilled_lint_expectations,
+                                    tool_name,
+                                ),
                             ));
                         }
                         let src = LintLevelSource::Node(
@@ -400,8 +405,10 @@ pub(crate) fn push(
                                     self.insert_spec(*id, (level, src));
                                 }
                                 if let Level::Expect(expect_id) = level {
-                                    self.lint_expectations
-                                        .push((expect_id, LintExpectation::new(reason, sp, false)));
+                                    self.lint_expectations.push((
+                                        expect_id,
+                                        LintExpectation::new(reason, sp, false, tool_name),
+                                    ));
                                 }
                             }
                             Err((Some(ids), ref new_lint_name)) => {
@@ -444,8 +451,10 @@ pub(crate) fn push(
                                     self.insert_spec(*id, (level, src));
                                 }
                                 if let Level::Expect(expect_id) = level {
-                                    self.lint_expectations
-                                        .push((expect_id, LintExpectation::new(reason, sp, false)));
+                                    self.lint_expectations.push((
+                                        expect_id,
+                                        LintExpectation::new(reason, sp, false, tool_name),
+                                    ));
                                 }
                             }
                             Err((None, _)) => {
@@ -550,8 +559,10 @@ pub(crate) fn push(
                             }
                         }
                         if let Level::Expect(expect_id) = level {
-                            self.lint_expectations
-                                .push((expect_id, LintExpectation::new(reason, sp, false)));
+                            self.lint_expectations.push((
+                                expect_id,
+                                LintExpectation::new(reason, sp, false, tool_name),
+                            ));
                         }
                     } else {
                         panic!("renamed lint does not exist: {}", new_name);
index 028c14366c6adefa7d5abc482403fe475617643d..a965587afb71527b30a0d1376c4e93f7e9a74886 100644 (file)
 
 pub fn provide(providers: &mut Providers) {
     levels::provide(providers);
+    expect::provide(providers);
     *providers = Providers { lint_mod, ..*providers };
 }
 
index b8ba65adaa8eeed360772cb30d28bcef8fbcb0c1..565ec4e5ab9b97c4679ff98026d2e5f224c3b961 100644 (file)
     /// used by user code.
     ///
     /// This lint is only enabled in the standard library. It works with the
-    /// use of `#[rustc_deprecated]` with a `since` field of a version in the
-    /// future. This allows something to be marked as deprecated in a future
-    /// version, and then this lint will ensure that the item is no longer
-    /// used in the standard library. See the [stability documentation] for
-    /// more details.
+    /// use of `#[deprecated]` with a `since` field of a version in the future.
+    /// This allows something to be marked as deprecated in a future version,
+    /// and then this lint will ensure that the item is no longer used in the
+    /// standard library. See the [stability documentation] for more details.
     ///
-    /// [stability documentation]: https://rustc-dev-guide.rust-lang.org/stability.html#rustc_deprecated
+    /// [stability documentation]: https://rustc-dev-guide.rust-lang.org/stability.html#deprecated
     pub DEPRECATED_IN_FUTURE,
     Allow,
     "detects use of items that will be deprecated in a future version",
index c00c6ce2f71dca7eb75a00fabbb0e81d55276126..9f7ef3981c75b6ff5a922a5164bb2b1abde43b21 100644 (file)
@@ -129,6 +129,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
     type_of => { table }
     variances_of => { table }
     fn_sig => { table }
+    codegen_fn_attrs => { table }
     impl_trait_ref => { table }
     const_param_default => { table }
     thir_abstract_const => { table }
index 77d6ce1e766ebb9bb4ff9a93fc0bbbbfdd9376a9..81388a0bf585ddac473097ad7c799a4524dc2a2c 100644 (file)
@@ -1007,6 +1007,9 @@ fn encode_def_ids(&mut self) {
             record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
             self.encode_attrs(def_id);
             record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
+            if def_kind.has_codegen_attrs() {
+                record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id));
+            }
             if should_encode_visibility(def_kind) {
                 record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
             }
index a0fd9ef4f87d95ea0df4e285b900558e3497bb63..356dad4b56be1b404a19836fbd20c266bae3d734 100644 (file)
@@ -14,6 +14,7 @@
 use rustc_hir::lang_items;
 use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
 use rustc_middle::metadata::ModChild;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use rustc_middle::mir;
 use rustc_middle::thir;
@@ -329,6 +330,7 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
     type_of: Table<DefIndex, Lazy!(Ty<'tcx>)>,
     variances_of: Table<DefIndex, Lazy<[ty::Variance]>>,
     fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
+    codegen_fn_attrs: Table<DefIndex, Lazy!(CodegenFnAttrs)>,
     impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>,
     const_param_default: Table<DefIndex, Lazy<rustc_middle::ty::Const<'tcx>>>,
     optimized_mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
index e55b0454eefc7c4d3309e3ee6b6f0c1fa6d6091f..c7c5f56867a5d461c07bb109b13f95a7fc120052 100644 (file)
@@ -210,6 +210,10 @@ pub struct LintExpectation {
     /// adjusted to include an additional note. Therefore, we have to track if
     /// the expectation is for the lint.
     pub is_unfulfilled_lint_expectations: bool,
+    /// This will hold the name of the tool that this lint belongs to. For
+    /// the lint `clippy::some_lint` the tool would be `clippy`, the same
+    /// goes for `rustdoc`. This will be `None` for rustc lints
+    pub lint_tool: Option<Symbol>,
 }
 
 impl LintExpectation {
@@ -217,8 +221,9 @@ pub fn new(
         reason: Option<Symbol>,
         emission_span: Span,
         is_unfulfilled_lint_expectations: bool,
+        lint_tool: Option<Symbol>,
     ) -> Self {
-        Self { reason, emission_span, is_unfulfilled_lint_expectations }
+        Self { reason, emission_span, is_unfulfilled_lint_expectations, lint_tool }
     }
 }
 
index 54eb2dc9e2890647b5f4652627c27e32e05a55b9..321fcd43797cc18f5feb7e0739264548dd9e29ee 100644 (file)
@@ -95,7 +95,9 @@ pub struct CodegenFnAttrFlags: u32 {
 }
 
 impl CodegenFnAttrs {
-    pub fn new() -> CodegenFnAttrs {
+    pub const EMPTY: &'static Self = &Self::new();
+
+    pub const fn new() -> CodegenFnAttrs {
         CodegenFnAttrs {
             flags: CodegenFnAttrFlags::empty(),
             inline: InlineAttr::None,
index 32041143240aa4022af8be480f30f016f0a61a5a..6918046390e6f9dc3b347e329d9baf615e41ff53 100644 (file)
@@ -118,8 +118,7 @@ fn parse_version(ver: &str) -> Vec<u32> {
     }
 
     if !is_since_rustc_version {
-        // The `since` field doesn't have semantic purpose in the stable `deprecated`
-        // attribute, only in `rustc_deprecated`.
+        // The `since` field doesn't have semantic purpose without `#![staged_api]`.
         return true;
     }
 
@@ -336,7 +335,7 @@ pub fn eval_stability(
                 // topmost deprecation. For example, if a struct is deprecated,
                 // the use of a field won't be linted.
                 //
-                // #[rustc_deprecated] however wants to emit down the whole
+                // With #![staged_api], we want to emit down the whole
                 // hierarchy.
                 let depr_attr = &depr_entry.attr;
                 if !skip || depr_attr.is_since_rustc_version {
index 682f3734d309eb3330267e01b1c8bffd232a356c..2c97c7704e77dbc5d7452218b899a1d23c8adb40 100644 (file)
@@ -580,6 +580,8 @@ pub fn predecessors(&self) -> &Predecessors {
         self.predecessor_cache.compute(&self.basic_blocks)
     }
 
+    /// `body.switch_sources()[&(target, switch)]` returns a list of switch
+    /// values that lead to a `target` block from a `switch` block.
     #[inline]
     pub fn switch_sources(&self) -> &SwitchSources {
         self.switch_source_cache.compute(&self.basic_blocks)
index 7f62b4d0dbab947efe98704f35f870ba18f96feb..adeeec70d1c0bb80b6af435db5519818b2d57eae 100644 (file)
@@ -2,6 +2,7 @@
 //! `Predecessors`/`PredecessorCache`.
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_map::FxHashMap;
 use rustc_data_structures::sync::OnceCell;
 use rustc_index::vec::IndexVec;
 use rustc_serialize as serialize;
@@ -9,7 +10,7 @@
 
 use crate::mir::{BasicBlock, BasicBlockData, Terminator, TerminatorKind};
 
-pub type SwitchSources = IndexVec<BasicBlock, IndexVec<BasicBlock, SmallVec<[Option<u128>; 1]>>>;
+pub type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option<u128>; 1]>>;
 
 #[derive(Clone, Debug)]
 pub(super) struct SwitchSourceCache {
@@ -35,19 +36,16 @@ pub(super) fn compute(
         basic_blocks: &IndexVec<BasicBlock, BasicBlockData<'_>>,
     ) -> &SwitchSources {
         self.cache.get_or_init(|| {
-            let mut switch_sources = IndexVec::from_elem(
-                IndexVec::from_elem(SmallVec::new(), basic_blocks),
-                basic_blocks,
-            );
+            let mut switch_sources: SwitchSources = FxHashMap::default();
             for (bb, data) in basic_blocks.iter_enumerated() {
                 if let Some(Terminator {
                     kind: TerminatorKind::SwitchInt { targets, .. }, ..
                 }) = &data.terminator
                 {
                     for (value, target) in targets.iter() {
-                        switch_sources[target][bb].push(Some(value));
+                        switch_sources.entry((target, bb)).or_default().push(Some(value));
                     }
-                    switch_sources[targets.otherwise()][bb].push(None);
+                    switch_sources.entry((targets.otherwise(), bb)).or_default().push(None);
                 }
             }
 
index e439d128dbc7773358b8058af5e4d447d6c0080e..629a550b77596cbcf887cc9712e1097d387d3280 100644 (file)
         desc { "running analysis passes on this crate" }
     }
 
+    /// This query checks the fulfillment of collected lint expectations.
+    /// All lint emitting queries have to be done before this is executed
+    /// to ensure that all expectations can be fulfilled.
+    ///
+    /// This is an extra query to enable other drivers (like rustdoc) to
+    /// only execute a small subset of the `analysis` query, while allowing
+    /// lints to be expected. In rustc, this query will be executed as part of
+    /// the `analysis` query and doesn't have to be called a second time.
+    ///
+    /// Tools can additionally pass in a tool filter. That will restrict the
+    /// expectations to only trigger for lints starting with the listed tool
+    /// name. This is useful for cases were not all linting code from rustc
+    /// was called. With the default `None` all registered lints will also
+    /// be checked for expectation fulfillment.
+    query check_expectations(key: Option<Symbol>) -> () {
+        eval_always
+        desc { "checking lint expectations (RFC 2383)" }
+    }
+
     /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
     /// associated generics.
     query generics_of(key: DefId) -> ty::Generics {
     query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
         desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) }
         storage(ArenaCacheSelector<'tcx>)
-        cache_on_disk_if { true }
+        cache_on_disk_if { def_id.is_local() }
+        separate_provide_extern
     }
 
     query asm_target_features(def_id: DefId) -> &'tcx FxHashSet<Symbol> {
index 4d06c95915b3998197f940ea26f11843dd31a6a5..9d3d509eb216beca26e858efd1b759f209f67966 100644 (file)
@@ -5,6 +5,7 @@
 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::codegen_fn_attrs::CodegenFnAttrs;
 use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
 use crate::middle::stability;
 use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
@@ -1066,6 +1067,28 @@ pub struct GlobalCtxt<'tcx> {
 }
 
 impl<'tcx> TyCtxt<'tcx> {
+    /// Expects a body and returns its codegen attributes.
+    ///
+    /// Unlike `codegen_fn_attrs`, this returns `CodegenFnAttrs::EMPTY` for
+    /// constants.
+    pub fn body_codegen_attrs(self, def_id: DefId) -> &'tcx CodegenFnAttrs {
+        let def_kind = self.def_kind(def_id);
+        if def_kind.has_codegen_attrs() {
+            self.codegen_fn_attrs(def_id)
+        } else if matches!(
+            def_kind,
+            DefKind::AnonConst | DefKind::AssocConst | DefKind::Const | DefKind::InlineConst
+        ) {
+            CodegenFnAttrs::EMPTY
+        } else {
+            bug!(
+                "body_codegen_fn_attrs called on unexpected definition: {:?} {:?}",
+                def_id,
+                def_kind
+            )
+        }
+    }
+
     pub fn typeck_opt_const_arg(
         self,
         def: ty::WithOptConstParam<LocalDefId>,
index 2009364b24e608cc32b9dccb87c5c53857bc5813..65c9b1aed050e63d9c247c7a85df23996a47f0ec 100644 (file)
@@ -86,18 +86,16 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
             //
             // In order to make it very unlikely for the sequence of bytes being hashed for
             // a `GenericArgKind::Type` to be the same as the sequence of bytes being
-            // hashed for one of the other variants, we hash a `0xFF` byte before hashing
-            // their discriminant (since the discriminant of `TyKind` is unlikely to ever start
-            // with 0xFF).
+            // hashed for one of the other variants, we hash some very high number instead
+            // of their actual discriminant since `TyKind` should never start with anything
+            // that high.
             ty::subst::GenericArgKind::Type(ty) => ty.hash_stable(hcx, hasher),
             ty::subst::GenericArgKind::Const(ct) => {
-                0xFFu8.hash_stable(hcx, hasher);
-                mem::discriminant(self).hash_stable(hcx, hasher);
+                0xF3u8.hash_stable(hcx, hasher);
                 ct.hash_stable(hcx, hasher);
             }
             ty::subst::GenericArgKind::Lifetime(lt) => {
-                0xFFu8.hash_stable(hcx, hasher);
-                mem::discriminant(self).hash_stable(hcx, hasher);
+                0xF5u8.hash_stable(hcx, hasher);
                 lt.hash_stable(hcx, hasher);
             }
         }
index 03d3a4a8c5f3c4263ef5d7286c2c5714be3ec35c..7cf7f8973475d26a766e9577848442e6cb2dab4c 100644 (file)
@@ -246,7 +246,7 @@ pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
         match *self {
             InstanceDef::Item(ty::WithOptConstParam { did: def_id, .. })
             | InstanceDef::Virtual(def_id, _) => {
-                tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
+                tcx.body_codegen_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
             }
             InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller,
             _ => false,
index cd4b23fca393282a40126213a1b24c35be53a042..c8055100d30968a5c1c9f0df09fa9d5400b72f38 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
@@ -220,6 +221,111 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+/// Enforce some basic invariants on layouts.
+fn sanity_check_layout<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    layout: &TyAndLayout<'tcx>,
+) {
+    // Type-level uninhabitedness should always imply ABI uninhabitedness.
+    if tcx.conservative_is_privately_uninhabited(param_env.and(layout.ty)) {
+        assert!(layout.abi.is_uninhabited());
+    }
+
+    if cfg!(debug_assertions) {
+        fn check_layout_abi<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) {
+            match layout.abi() {
+                Abi::Scalar(_scalar) => {
+                    // No padding in scalars.
+                    /* FIXME(#96185):
+                    assert_eq!(
+                        layout.align().abi,
+                        scalar.align(&tcx).abi,
+                        "alignment mismatch between ABI and layout in {layout:#?}"
+                    );
+                    assert_eq!(
+                        layout.size(),
+                        scalar.size(&tcx),
+                        "size mismatch between ABI and layout in {layout:#?}"
+                    );*/
+                }
+                Abi::Vector { count, element } => {
+                    // No padding in vectors. Alignment can be strengthened, though.
+                    assert!(
+                        layout.align().abi >= element.align(&tcx).abi,
+                        "alignment mismatch between ABI and layout in {layout:#?}"
+                    );
+                    let size = element.size(&tcx) * count;
+                    assert_eq!(
+                        layout.size(),
+                        size.align_to(tcx.data_layout().vector_align(size).abi),
+                        "size mismatch between ABI and layout in {layout:#?}"
+                    );
+                }
+                Abi::ScalarPair(scalar1, scalar2) => {
+                    // Sanity-check scalar pairs. These are a bit more flexible and support
+                    // padding, but we can at least ensure both fields actually fit into the layout
+                    // and the alignment requirement has not been weakened.
+                    let align1 = scalar1.align(&tcx).abi;
+                    let align2 = scalar2.align(&tcx).abi;
+                    assert!(
+                        layout.align().abi >= cmp::max(align1, align2),
+                        "alignment mismatch between ABI and layout in {layout:#?}",
+                    );
+                    let field2_offset = scalar1.size(&tcx).align_to(align2);
+                    assert!(
+                        layout.size() >= field2_offset + scalar2.size(&tcx),
+                        "size mismatch between ABI and layout in {layout:#?}"
+                    );
+                }
+                Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check.
+            }
+        }
+
+        check_layout_abi(tcx, layout.layout);
+
+        if let Variants::Multiple { variants, .. } = &layout.variants {
+            for variant in variants {
+                check_layout_abi(tcx, *variant);
+                // No nested "multiple".
+                assert!(matches!(variant.variants(), Variants::Single { .. }));
+                // Skip empty variants.
+                if variant.size() == Size::ZERO
+                    || variant.fields().count() == 0
+                    || variant.abi().is_uninhabited()
+                {
+                    // These are never actually accessed anyway, so we can skip them. (Note that
+                    // sometimes, variants with fields have size 0, and sometimes, variants without
+                    // fields have non-0 size.)
+                    continue;
+                }
+                // Variants should have the same or a smaller size as the full thing.
+                if variant.size() > layout.size {
+                    bug!(
+                        "Type with size {} bytes has variant with size {} bytes: {layout:#?}",
+                        layout.size.bytes(),
+                        variant.size().bytes(),
+                    )
+                }
+                // The top-level ABI and the ABI of the variants should be coherent.
+                let abi_coherent = match (layout.abi, variant.abi()) {
+                    (Abi::Scalar(..), Abi::Scalar(..)) => true,
+                    (Abi::ScalarPair(..), Abi::ScalarPair(..)) => true,
+                    (Abi::Uninhabited, _) => true,
+                    (Abi::Aggregate { .. }, _) => true,
+                    _ => false,
+                };
+                if !abi_coherent {
+                    bug!(
+                        "Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}",
+                        variant
+                    );
+                }
+            }
+        }
+    }
+}
+
 #[instrument(skip(tcx, query), level = "debug")]
 fn layout_of<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -263,10 +369,7 @@ fn layout_of<'tcx>(
 
             cx.record_layout_for_printing(layout);
 
-            // Type-level uninhabitedness should always imply ABI uninhabitedness.
-            if tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
-                assert!(layout.abi.is_uninhabited());
-            }
+            sanity_check_layout(tcx, param_env, &layout);
 
             Ok(layout)
         })
@@ -1313,9 +1416,11 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'
                 };
                 let mut abi = Abi::Aggregate { sized: true };
 
-                // Without latter check aligned enums with custom discriminant values
-                // Would result in ICE see the issue #92464 for more info
-                if tag.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) {
+                if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
+                    abi = Abi::Uninhabited;
+                } else if tag.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) {
+                    // Without latter check aligned enums with custom discriminant values
+                    // Would result in ICE see the issue #92464 for more info
                     abi = Abi::Scalar(tag);
                 } else {
                     // Try to use a ScalarPair for all tagged enums.
@@ -1389,8 +1494,22 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'
                     }
                 }
 
-                if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
-                    abi = Abi::Uninhabited;
+                // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the
+                // variants to ensure they are consistent. This is because a downcast is
+                // semantically a NOP, and thus should not affect layout.
+                if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
+                    for variant in &mut layout_variants {
+                        // We only do this for variants with fields; the others are not accessed anyway.
+                        // Also do not overwrite any already existing "clever" ABIs.
+                        if variant.fields.count() > 0
+                            && matches!(variant.abi, Abi::Aggregate { .. })
+                        {
+                            variant.abi = abi;
+                            // Also need to bump up the size and alignment, so that the entire value fits in here.
+                            variant.size = cmp::max(variant.size, size);
+                            variant.align.abi = cmp::max(variant.align.abi, align.abi);
+                        }
+                    }
                 }
 
                 let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
@@ -2762,14 +2881,22 @@ fn fn_sig_for_fn_abi(
 /// with `-Cpanic=abort` will look like they can't unwind when in fact they
 /// might (from a foreign exception or similar).
 #[inline]
-pub fn fn_can_unwind<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    codegen_fn_attr_flags: CodegenFnAttrFlags,
-    abi: SpecAbi,
-) -> bool {
-    // Special attribute for functions which can't unwind.
-    if codegen_fn_attr_flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
-        return false;
+pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool {
+    if let Some(did) = fn_def_id {
+        // Special attribute for functions which can't unwind.
+        if tcx.codegen_fn_attrs(did).flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
+            return false;
+        }
+
+        // With -Z panic-in-drop=abort, drop_in_place never unwinds.
+        //
+        // This is not part of `codegen_fn_attrs` as it can differ between crates
+        // and therefore cannot be computed in core.
+        if tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Abort {
+            if Some(did) == tcx.lang_items().drop_in_place_fn() {
+                return false;
+            }
+        }
     }
 
     // Otherwise if this isn't special then unwinding is generally determined by
@@ -2991,13 +3118,7 @@ fn fn_abi_of_fn_ptr<'tcx>(
 ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
     let (param_env, (sig, extra_args)) = query.into_parts();
 
-    LayoutCx { tcx, param_env }.fn_abi_new_uncached(
-        sig,
-        extra_args,
-        None,
-        CodegenFnAttrFlags::empty(),
-        false,
-    )
+    LayoutCx { tcx, param_env }.fn_abi_new_uncached(sig, extra_args, None, None, false)
 }
 
 fn fn_abi_of_instance<'tcx>(
@@ -3014,13 +3135,11 @@ fn fn_abi_of_instance<'tcx>(
         None
     };
 
-    let attrs = tcx.codegen_fn_attrs(instance.def_id()).flags;
-
     LayoutCx { tcx, param_env }.fn_abi_new_uncached(
         sig,
         extra_args,
         caller_location,
-        attrs,
+        Some(instance.def_id()),
         matches!(instance.def, ty::InstanceDef::Virtual(..)),
     )
 }
@@ -3033,7 +3152,7 @@ fn fn_abi_new_uncached(
         sig: ty::PolyFnSig<'tcx>,
         extra_args: &[Ty<'tcx>],
         caller_location: Option<Ty<'tcx>>,
-        codegen_fn_attr_flags: CodegenFnAttrFlags,
+        fn_def_id: Option<DefId>,
         // FIXME(eddyb) replace this with something typed, like an `enum`.
         force_thin_self_ptr: bool,
     ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
@@ -3205,7 +3324,7 @@ fn fn_abi_new_uncached(
             c_variadic: sig.c_variadic,
             fixed_count: inputs.len(),
             conv,
-            can_unwind: fn_can_unwind(self.tcx(), codegen_fn_attr_flags, sig.abi),
+            can_unwind: fn_can_unwind(self.tcx(), fn_def_id, sig.abi),
         };
         self.fn_abi_adjust_for_abi(&mut fn_abi, sig.abi)?;
         debug!("fn_abi_new_uncached = {:?}", fn_abi);
index 5063420e975d14663721f6adc9c0229e732130ea..5b1fb70872988c0787dc2bfe4d49ab0167c65969 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
 use rustc_serialize::{self, Decodable, Encodable};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::DUMMY_SP;
 use smallvec::SmallVec;
 
 use core::intrinsics;
@@ -498,34 +498,14 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow
     }
 }
 
-///////////////////////////////////////////////////////////////////////////
-// Public trait `Subst`
-//
-// Just call `foo.subst(tcx, substs)` to perform a substitution across
-// `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when
-// there is more information available (for better errors).
-
+// Just call `foo.subst(tcx, substs)` to perform a substitution across `foo`.
 pub trait Subst<'tcx>: Sized {
-    fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self {
-        self.subst_spanned(tcx, substs, None)
-    }
-
-    fn subst_spanned(
-        self,
-        tcx: TyCtxt<'tcx>,
-        substs: &[GenericArg<'tcx>],
-        span: Option<Span>,
-    ) -> Self;
+    fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self;
 }
 
 impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T {
-    fn subst_spanned(
-        self,
-        tcx: TyCtxt<'tcx>,
-        substs: &[GenericArg<'tcx>],
-        span: Option<Span>,
-    ) -> T {
-        let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 };
+    fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T {
+        let mut folder = SubstFolder { tcx, substs, binders_passed: 0 };
         self.fold_with(&mut folder)
     }
 }
@@ -537,9 +517,6 @@ struct SubstFolder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     substs: &'a [GenericArg<'tcx>],
 
-    /// The location for which the substitution is performed, if available.
-    span: Option<Span>,
-
     /// Number of region binders we have passed through while doing the substitution
     binders_passed: u32,
 }
@@ -571,13 +548,12 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
                 match rk {
                     Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
                     _ => {
-                        let span = self.span.unwrap_or(DUMMY_SP);
                         let msg = format!(
                             "Region parameter out of range \
                              when substituting in region {} (index={})",
                             data.name, data.index
                         );
-                        span_bug!(span, "{}", msg);
+                        span_bug!(DUMMY_SP, "{}", msg);
                     }
                 }
             }
@@ -617,9 +593,8 @@ fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
         let ty = match opt_ty {
             Some(GenericArgKind::Type(ty)) => ty,
             Some(kind) => {
-                let span = self.span.unwrap_or(DUMMY_SP);
                 span_bug!(
-                    span,
+                    DUMMY_SP,
                     "expected type for `{:?}` ({:?}/{}) but found {:?} \
                      when substituting, substs={:?}",
                     p,
@@ -630,9 +605,8 @@ fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
                 );
             }
             None => {
-                let span = self.span.unwrap_or(DUMMY_SP);
                 span_bug!(
-                    span,
+                    DUMMY_SP,
                     "type parameter `{:?}` ({:?}/{}) out of range \
                      when substituting, substs={:?}",
                     p,
@@ -652,9 +626,8 @@ fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'tcx>) -> ty::Cons
         let ct = match opt_ct {
             Some(GenericArgKind::Const(ct)) => ct,
             Some(kind) => {
-                let span = self.span.unwrap_or(DUMMY_SP);
                 span_bug!(
-                    span,
+                    DUMMY_SP,
                     "expected const for `{:?}` ({:?}/{}) but found {:?} \
                      when substituting substs={:?}",
                     p,
@@ -665,9 +638,8 @@ fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'tcx>) -> ty::Cons
                 );
             }
             None => {
-                let span = self.span.unwrap_or(DUMMY_SP);
                 span_bug!(
-                    span,
+                    DUMMY_SP,
                     "const parameter `{:?}` ({:?}/{}) out of range \
                      when substituting substs={:?}",
                     p,
index a841cce23dee994af0a520b202c6f34c98903888..6c14f207a7d14d7747f6dd1b2630f2ce29feb7a0 100644 (file)
@@ -27,7 +27,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
     body_unsafety: BodyUnsafety,
     /// The `#[target_feature]` attributes of the body. Used for checking
     /// calls to functions with `#[target_feature]` (RFC 2396).
-    body_target_features: &'tcx Vec<Symbol>,
+    body_target_features: &'tcx [Symbol],
     /// When inside the LHS of an assignment to a field, this is the type
     /// of the LHS and the span of the assignment expression.
     assignment_info: Option<(Ty<'tcx>, Span)>,
@@ -643,9 +643,8 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
         return;
     }
 
-    let (thir, expr) = match tcx.thir_body(def) {
-        Ok(body) => body,
-        Err(_) => return,
+    let Ok((thir, expr)) = tcx.thir_body(def) else {
+        return
     };
     let thir = &thir.borrow();
     // If `thir` is empty, a type error occurred, skip this body.
@@ -661,7 +660,7 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
             BodyUnsafety::Safe
         }
     });
-    let body_target_features = &tcx.codegen_fn_attrs(def.did).target_features;
+    let body_target_features = &tcx.body_codegen_attrs(def.did.to_def_id()).target_features;
     let safety_context =
         if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
     let mut visitor = UnsafetyVisitor {
index 93118dfeb7737f1623009f9b2549591303e2cff1..18795128b8571ca0f56d3a70f0d9a93ec0a72936 100644 (file)
@@ -269,9 +269,9 @@ fn join_state_into_successors_of<'tcx, A>(
 
                 mir::TerminatorKind::SwitchInt { targets: _, ref discr, switch_ty: _ } => {
                     let mut applier = BackwardSwitchIntEdgeEffectsApplier {
+                        body,
                         pred,
                         exit_state,
-                        values: &body.switch_sources()[bb][pred],
                         bb,
                         propagate: &mut propagate,
                         effects_applied: false,
@@ -305,9 +305,9 @@ fn join_state_into_successors_of<'tcx, A>(
 }
 
 struct BackwardSwitchIntEdgeEffectsApplier<'a, D, F> {
+    body: &'a mir::Body<'a>,
     pred: BasicBlock,
     exit_state: &'a mut D,
-    values: &'a [Option<u128>],
     bb: BasicBlock,
     propagate: &'a mut F,
 
@@ -322,7 +322,8 @@ impl<D, F> super::SwitchIntEdgeEffects<D> for BackwardSwitchIntEdgeEffectsApplie
     fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
         assert!(!self.effects_applied);
 
-        let targets = self.values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
+        let values = &self.body.switch_sources()[&(self.bb, self.pred)];
+        let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
 
         let mut tmp = None;
         for target in targets {
index 757dc093755847e89ffadf68b641efb43d39f2b8..ade6555f4d2c1c7c6a31791164340c77755e3cef 100644 (file)
@@ -1,6 +1,5 @@
 use crate::MirPass;
 use rustc_hir::def::DefKind;
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout;
 use rustc_middle::ty::{self, TyCtxt};
@@ -46,7 +45,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         //
         // Here we test for this function itself whether its ABI allows
         // unwinding or not.
-        let body_flags = tcx.codegen_fn_attrs(def_id).flags;
         let body_ty = tcx.type_of(def_id);
         let body_abi = match body_ty.kind() {
             ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
@@ -54,7 +52,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             ty::Generator(..) => Abi::Rust,
             _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty),
         };
-        let body_can_unwind = layout::fn_can_unwind(tcx, body_flags, body_abi);
+        let body_can_unwind = layout::fn_can_unwind(tcx, Some(def_id), body_abi);
 
         // Look in this function body for any basic blocks which are terminated
         // with a function call, and whose function we're calling may unwind.
@@ -73,19 +71,19 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                 TerminatorKind::Call { func, .. } => {
                     let ty = func.ty(body, tcx);
                     let sig = ty.fn_sig(tcx);
-                    let flags = match ty.kind() {
-                        ty::FnPtr(_) => CodegenFnAttrFlags::empty(),
-                        ty::FnDef(def_id, _) => tcx.codegen_fn_attrs(*def_id).flags,
+                    let fn_def_id = match ty.kind() {
+                        ty::FnPtr(_) => None,
+                        &ty::FnDef(def_id, _) => Some(def_id),
                         _ => span_bug!(span, "invalid callee of type {:?}", ty),
                     };
-                    layout::fn_can_unwind(tcx, flags, sig.abi())
+                    layout::fn_can_unwind(tcx, fn_def_id, sig.abi())
                 }
                 TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => {
                     tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Unwind
-                        && layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust)
+                        && layout::fn_can_unwind(tcx, None, Abi::Rust)
                 }
                 TerminatorKind::Assert { .. } | TerminatorKind::FalseUnwind { .. } => {
-                    layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust)
+                    layout::fn_can_unwind(tcx, None, Abi::Rust)
                 }
                 _ => continue,
             };
index dde79214b16470e16b942d08992448172c2e1874..1f73b7da815c505e1b9a7c6f98f2987eca4e36f3 100644 (file)
@@ -375,7 +375,8 @@ fn check_target_features(&mut self, func_did: DefId) {
         }
 
         let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
-        let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features;
+        // The body might be a constant, so it doesn't have codegen attributes.
+        let self_features = &self.tcx.body_codegen_attrs(self.body_did.to_def_id()).target_features;
 
         // Is `callee_features` a subset of `calling_features`?
         if !callee_features.iter().all(|feature| self_features.contains(feature)) {
index b297012f19f2f17475a6e2807ef82cd825cce38e..8d207e4e1a92489b1857b1bf0fb8a7f7610259ba 100644 (file)
@@ -4,7 +4,8 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
+use rustc_ast::tokenstream::DelimSpan;
+use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MacArgs, MetaItemKind, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@@ -104,6 +105,9 @@ fn check_attributes(
                 sym::rustc_allow_const_fn_unstable => {
                     self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
                 }
+                sym::rustc_std_internal_symbol => {
+                    self.check_rustc_std_internal_symbol(&attr, span, target)
+                }
                 sym::naked => self.check_naked(hir_id, attr, span, target),
                 sym::rustc_legacy_const_generics => {
                     self.check_rustc_legacy_const_generics(&attr, span, target, item)
@@ -193,6 +197,7 @@ fn check_attributes(
             return;
         }
 
+        // FIXME(@lcnr): this doesn't belong here.
         if matches!(target, Target::Closure | Target::Fn | Target::Method(_) | Target::ForeignFn) {
             self.tcx.ensure().codegen_fn_attrs(self.tcx.hir().local_def_id(hir_id));
         }
@@ -810,6 +815,68 @@ fn check_doc_inline(
         }
     }
 
+    /// Checks `#[doc(hidden)]` attributes. Returns `true` if valid.
+    fn check_doc_hidden(
+        &self,
+        attr: &Attribute,
+        meta_index: usize,
+        meta: &NestedMetaItem,
+        hir_id: HirId,
+        target: Target,
+    ) -> bool {
+        if let Target::AssocConst
+        | Target::AssocTy
+        | Target::Method(MethodKind::Trait { body: true }) = target
+        {
+            let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
+            let containing_item = self.tcx.hir().expect_item(parent_hir_id);
+
+            if Target::from_item(containing_item) == Target::Impl {
+                let meta_items = attr.meta_item_list().unwrap();
+
+                let (span, replacement_span) = if meta_items.len() == 1 {
+                    (attr.span, attr.span)
+                } else {
+                    let meta_span = meta.span();
+                    (
+                        meta_span,
+                        meta_span.until(match meta_items.get(meta_index + 1) {
+                            Some(next_item) => next_item.span(),
+                            None => match attr.get_normal_item().args {
+                                MacArgs::Delimited(DelimSpan { close, .. }, ..) => close,
+                                _ => unreachable!(),
+                            },
+                        }),
+                    )
+                };
+
+                // FIXME: #[doc(hidden)] was previously erroneously allowed on trait impl items,
+                // so for backward compatibility only emit a warning and do not mark it as invalid.
+                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| {
+                    lint.build("`#[doc(hidden)]` is ignored on trait impl items")
+                        .warn(
+                            "this was previously accepted by the compiler but is \
+                             being phased out; it will become a hard error in \
+                             a future release!",
+                        )
+                        .note(
+                            "whether the impl item is `doc(hidden)` or not \
+                             entirely depends on the corresponding trait item",
+                        )
+                        .span_suggestion(
+                            replacement_span,
+                            "remove this attribute",
+                            String::new(),
+                            Applicability::MachineApplicable,
+                        )
+                        .emit();
+                });
+            }
+        }
+
+        true
+    }
+
     /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
     fn check_attr_not_crate_level(
         &self,
@@ -928,7 +995,7 @@ fn check_doc_attrs(
         let mut is_valid = true;
 
         if let Some(mi) = attr.meta() && let Some(list) = mi.meta_item_list() {
-            for meta in list {
+            for (meta_index, meta) in list.into_iter().enumerate() {
                 if let Some(i_meta) = meta.meta_item() {
                     match i_meta.name_or_empty() {
                         sym::alias
@@ -969,6 +1036,15 @@ fn check_doc_attrs(
                             is_valid = false;
                         }
 
+                        sym::hidden if !self.check_doc_hidden(attr,
+                            meta_index,
+                            meta,
+                            hir_id,
+                            target,
+                            ) => {
+                            is_valid = false;
+                        }
+
                         // no_default_passes: deprecated
                         // passes: deprecated
                         // plugins: removed, but rustdoc warns about it itself
@@ -1659,7 +1735,7 @@ fn check_repr(
                     }
                 }
                 sym::align => {
-                    if let (Target::Fn, true) = (target, !self.tcx.features().fn_align) {
+                    if let (Target::Fn, false) = (target, self.tcx.features().fn_align) {
                         feature_err(
                             &self.tcx.sess.parse_sess,
                             sym::fn_align,
@@ -1980,6 +2056,25 @@ fn check_rustc_allow_const_fn_unstable(
         }
     }
 
+    fn check_rustc_std_internal_symbol(
+        &self,
+        attr: &Attribute,
+        span: Span,
+        target: Target,
+    ) -> bool {
+        match target {
+            Target::Fn | Target::Static => true,
+            _ => {
+                self.tcx
+                    .sess
+                    .struct_span_err(attr.span, "attribute should be applied functions or statics")
+                    .span_label(span, "not a function or static")
+                    .emit();
+                false
+            }
+        }
+    }
+
     /// default_method_body_is_const should only be applied to trait methods with default bodies.
     fn check_default_method_body_is_const(
         &self,
index 991d0d45546285601cb3caf45a10598ad2b618ba..df28ea4d444baafe6327d90277ef7cd8963182d9 100644 (file)
@@ -452,15 +452,17 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
     }
 
     let def_id = tcx.hir().local_def_id(id);
-    let cg_attrs = tcx.codegen_fn_attrs(def_id);
-
-    // #[used], #[no_mangle], #[export_name], etc also keeps the item alive
-    // forcefully, e.g., for placing it in a specific section.
-    if cg_attrs.contains_extern_indicator()
-        || cg_attrs.flags.contains(CodegenFnAttrFlags::USED)
-        || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
-    {
-        return true;
+    if tcx.def_kind(def_id).has_codegen_attrs() {
+        let cg_attrs = tcx.codegen_fn_attrs(def_id);
+
+        // #[used], #[no_mangle], #[export_name], etc also keeps the item alive
+        // forcefully, e.g., for placing it in a specific section.
+        if cg_attrs.contains_extern_indicator()
+            || cg_attrs.flags.contains(CodegenFnAttrFlags::USED)
+            || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
+        {
+            return true;
+        }
     }
 
     tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
index b603352a9beba57ecdbe3ea4d8aeade7f8ccb50e..a5133bfd9459cf10d7f92fb0285f85bdf05f4579 100644 (file)
@@ -208,7 +208,11 @@ fn propagate_node(&mut self, node: &Node<'tcx>, search_item: LocalDefId) {
                 } else {
                     false
                 };
-            let codegen_attrs = self.tcx.codegen_fn_attrs(search_item);
+            let codegen_attrs = if self.tcx.def_kind(search_item).has_codegen_attrs() {
+                self.tcx.codegen_fn_attrs(search_item)
+            } else {
+                CodegenFnAttrs::EMPTY
+            };
             let is_extern = codegen_attrs.contains_extern_indicator();
             let std_internal =
                 codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
@@ -329,16 +333,18 @@ fn push_to_worklist_if_has_custom_linkage(&mut self, def_id: LocalDefId) {
         // Anything which has custom linkage gets thrown on the worklist no
         // matter where it is in the crate, along with "special std symbols"
         // which are currently akin to allocator symbols.
-        let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
-        if codegen_attrs.contains_extern_indicator()
-            || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
-            // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
-            // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
-            // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
-            || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
-            || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
-        {
-            self.worklist.push(def_id);
+        if self.tcx.def_kind(def_id).has_codegen_attrs() {
+            let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
+            if codegen_attrs.contains_extern_indicator()
+                || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
+                // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
+                // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
+                // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
+                || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
+                || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
+            {
+                self.worklist.push(def_id);
+            }
         }
     }
 }
index 3f0f856b5dd7c16f2dca8f2075625ce49c13a5ba..6fbafeb1d32b3c40c51ce563d534e2a1488b29b9 100644 (file)
@@ -435,6 +435,16 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
     }
 }
 
+impl Key for Option<Symbol> {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+    fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 /// Canonical query goals correspond to abstract trait operations that
 /// are not tied to any crate in particular.
 impl<'tcx, T> Key for Canonical<'tcx, T> {
index 0ff0267d0ce768ad03807b72fd32b79922790f58..ee0994c9ad6ccf431d9168f04b39f98e4c1eeff0 100644 (file)
 #[macro_use]
 extern crate rustc_middle;
 
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::SubstsRef;
@@ -175,7 +177,11 @@ fn compute_symbol_name<'tcx>(
     }
 
     // FIXME(eddyb) Precompute a custom symbol name based on attributes.
-    let attrs = tcx.codegen_fn_attrs(def_id);
+    let attrs = if tcx.def_kind(def_id).has_codegen_attrs() {
+        tcx.codegen_fn_attrs(def_id)
+    } else {
+        CodegenFnAttrs::EMPTY
+    };
 
     // Foreign items by default use no mangling for their symbol name. There's a
     // few exceptions to this rule though:
@@ -213,20 +219,25 @@ fn compute_symbol_name<'tcx>(
         return tcx.item_name(def_id).to_string();
     }
 
-    let avoid_cross_crate_conflicts =
-        // If this is an instance of a generic function, we also hash in
-        // the ID of the instantiating crate. This avoids symbol conflicts
-        // in case the same instances is emitted in two crates of the same
-        // project.
-        is_generic(substs) ||
+    // If we're dealing with an instance of a function that's inlined from
+    // another crate but we're marking it as globally shared to our
+    // compilation (aka we're not making an internal copy in each of our
+    // codegen units) then this symbol may become an exported (but hidden
+    // visibility) symbol. This means that multiple crates may do the same
+    // and we want to be sure to avoid any symbol conflicts here.
+    let is_globally_shared_function = matches!(
+        tcx.def_kind(instance.def_id()),
+        DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator | DefKind::Ctor(..)
+    ) && matches!(
+        MonoItem::Fn(instance).instantiation_mode(tcx),
+        InstantiationMode::GloballyShared { may_conflict: true }
+    );
 
-        // If we're dealing with an instance of a function that's inlined from
-        // another crate but we're marking it as globally shared to our
-        // compilation (aka we're not making an internal copy in each of our
-        // codegen units) then this symbol may become an exported (but hidden
-        // visibility) symbol. This means that multiple crates may do the same
-        // and we want to be sure to avoid any symbol conflicts here.
-        matches!(MonoItem::Fn(instance).instantiation_mode(tcx), InstantiationMode::GloballyShared { may_conflict: true });
+    // If this is an instance of a generic function, we also hash in
+    // the ID of the instantiating crate. This avoids symbol conflicts
+    // in case the same instances is emitted in two crates of the same
+    // project.
+    let avoid_cross_crate_conflicts = is_generic(substs) || is_globally_shared_function;
 
     let instantiating_crate =
         if avoid_cross_crate_conflicts { Some(compute_instantiating_crate()) } else { None };
index bfb8ce6f1051c03b3573fbf39e2c5591c36da235..d20ba99ebc9b5b2434bd7f07fc24891823adf550 100644 (file)
@@ -1085,18 +1085,28 @@ fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut
                             self.in_progress_typeck_results.map(|t| t.borrow())
                             && let ty = typeck_results.expr_ty_adjusted(base)
                             && let ty::FnDef(def_id, _substs) = ty.kind()
-                            && let Some(hir::Node::Item(hir::Item { span, ident, .. })) =
+                            && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
                                 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,
+                            let msg = format!(
+                                "alternatively, consider making `fn {}` asynchronous",
+                                ident
                             );
+                            if vis_span.is_empty() {
+                                err.span_suggestion_verbose(
+                                    span.shrink_to_lo(),
+                                    &msg,
+                                    "async ".to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else {
+                                err.span_suggestion_verbose(
+                                    vis_span.shrink_to_hi(),
+                                    &msg,
+                                    " async".to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
                         }
                     }
                 }
index 8240f5c542a617fb1f325679d01140de108e746d..81819534e8b3bea0b3dd39f12416b34d4e1f4d64 100644 (file)
@@ -432,6 +432,9 @@ pub fn impossible_predicates<'tcx>(
     debug!("impossible_predicates(predicates={:?})", predicates);
 
     let result = tcx.infer_ctxt().enter(|infcx| {
+        // HACK: Set tainted by errors to gracefully exit in case of overflow.
+        infcx.set_tainted_by_errors();
+
         let param_env = ty::ParamEnv::reveal_all();
         let mut selcx = SelectionContext::new(&infcx);
         let mut fulfill_cx = FulfillmentContext::new();
@@ -448,6 +451,9 @@ pub fn impossible_predicates<'tcx>(
 
         let errors = fulfill_cx.select_all_or_error(&infcx);
 
+        // Clean up after ourselves
+        let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+
         !errors.is_empty()
     });
     debug!("impossible_predicates = {:?}", result);
@@ -461,6 +467,14 @@ fn subst_and_check_impossible_predicates<'tcx>(
     debug!("subst_and_check_impossible_predicates(key={:?})", key);
 
     let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
+
+    // Specifically check trait fulfillment to avoid an error when trying to resolve
+    // associated items.
+    if let Some(trait_def_id) = tcx.trait_of_item(key.0) {
+        let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, key.1);
+        predicates.push(ty::Binder::dummy(trait_ref).to_poly_trait_predicate().to_predicate(tcx));
+    }
+
     predicates.retain(|predicate| !predicate.needs_subst());
     let result = impossible_predicates(tcx, predicates);
 
index 7543d1f9a7b5532693d13bb990ce17d14618570a..d101f69096fe8e013572d2c605c99dc54a1d938b 100644 (file)
@@ -118,13 +118,14 @@ fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
 
         // Get components of trait alias.
         let predicates = tcx.super_predicates_of(trait_ref.def_id());
+        debug!(?predicates);
 
         let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
             pred.subst_supertrait(tcx, &trait_ref)
                 .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());
+        debug!("expand_trait_aliases: items={:?}", items.clone().collect::<Vec<_>>());
 
         self.stack.extend(items);
 
index 93f6b4a6b5aa88c3d37df5bf13ef7ca466147ee2..e940d065a999400e1819149f2a3893144f852f16 100644 (file)
@@ -523,11 +523,7 @@ fn inferred_kind(
                                 self.astconv
                                     .normalize_ty(
                                         self.span,
-                                        tcx.at(self.span).type_of(param.def_id).subst_spanned(
-                                            tcx,
-                                            substs,
-                                            Some(self.span),
-                                        ),
+                                        tcx.at(self.span).type_of(param.def_id).subst(tcx, substs),
                                     )
                                     .into()
                             }
@@ -547,9 +543,7 @@ fn inferred_kind(
                     GenericParamDefKind::Const { has_default } => {
                         let ty = tcx.at(self.span).type_of(param.def_id);
                         if !infer_args && has_default {
-                            tcx.const_param_default(param.def_id)
-                                .subst_spanned(tcx, substs.unwrap(), Some(self.span))
-                                .into()
+                            tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
                         } else {
                             if infer_args {
                                 self.astconv.ct_infer(ty, Some(param), self.span).into()
@@ -1070,6 +1064,7 @@ fn compute_bounds_inner(
         let mut bounds = Bounds::default();
 
         self.add_bounds(param_ty, ast_bounds.iter(), &mut bounds, ty::List::empty());
+        debug!(?bounds);
 
         bounds
     }
@@ -1333,8 +1328,9 @@ fn conv_object_ty_poly_trait_ref(
         // is used and no 'maybe' bounds are used.
         let expanded_traits =
             traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b)));
-        let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
-            expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
+        let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
+            .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
+            .partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
         if regular_traits.len() > 1 {
             let first_trait = &regular_traits[0];
             let additional_trait = &regular_traits[1];
@@ -1368,7 +1364,13 @@ trait here instead: `trait NewTrait: {} {{}}`",
         }
 
         if regular_traits.is_empty() && auto_traits.is_empty() {
-            tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span });
+            let trait_alias_span = bounds
+                .trait_bounds
+                .iter()
+                .map(|&(trait_ref, _, _)| trait_ref.def_id())
+                .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
+                .map(|trait_ref| tcx.def_span(trait_ref));
+            tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
             return tcx.ty_error();
         }
 
index 580fb7c3e0f063b289179fd5668d50bbda393d74..90b59df472cadf0f32d8fa2893c28b2174e7b915 100644 (file)
@@ -59,7 +59,7 @@ pub fn check_legal_trait_for_method_call(
 
 enum CallStep<'tcx> {
     Builtin(Ty<'tcx>),
-    DeferredClosure(ty::FnSig<'tcx>),
+    DeferredClosure(DefId, ty::FnSig<'tcx>),
     /// E.g., enum variant constructors.
     Overloaded(MethodCallee<'tcx>),
 }
@@ -107,8 +107,8 @@ pub fn check_call(
                 self.confirm_builtin_call(call_expr, callee_expr, callee_ty, arg_exprs, expected)
             }
 
-            Some(CallStep::DeferredClosure(fn_sig)) => {
-                self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig)
+            Some(CallStep::DeferredClosure(def_id, fn_sig)) => {
+                self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, def_id, fn_sig)
             }
 
             Some(CallStep::Overloaded(method_callee)) => {
@@ -171,7 +171,7 @@ fn try_overloaded_call_step(
                             closure_substs: substs,
                         },
                     );
-                    return Some(CallStep::DeferredClosure(closure_sig));
+                    return Some(CallStep::DeferredClosure(def_id, closure_sig));
                 }
             }
 
@@ -533,6 +533,7 @@ fn confirm_deferred_closure_call(
         call_expr: &'tcx hir::Expr<'tcx>,
         arg_exprs: &'tcx [hir::Expr<'tcx>],
         expected: Expectation<'tcx>,
+        closure_def_id: DefId,
         fn_sig: ty::FnSig<'tcx>,
     ) -> Ty<'tcx> {
         // `fn_sig` is the *signature* of the closure being called. We
@@ -555,7 +556,7 @@ fn confirm_deferred_closure_call(
             arg_exprs,
             fn_sig.c_variadic,
             TupleArgumentsFlag::TupleArguments,
-            None,
+            Some(closure_def_id),
         );
 
         fn_sig.output()
index 6d78a863d54cf97bdf0911899899684441f1e1d7..a83924d4636c59f4f57791c2eb4107591a0dccf4 100644 (file)
@@ -7,10 +7,10 @@
 use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
 use rustc_infer::traits::util;
-use rustc_middle::ty;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::util::ExplicitSelf;
+use rustc_middle::ty::{self, DefIdTree};
 use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
 use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
         return;
     }
 
+    if let Err(_) = compare_generic_param_kinds(tcx, impl_m, trait_m) {
+        return;
+    }
+
     if let Err(_) =
         compare_number_of_method_arguments(tcx, impl_m, impl_m_span, trait_m, trait_item_span)
     {
     {
         return;
     }
-
-    if let Err(_) = compare_const_param_types(tcx, impl_m, trait_m, trait_item_span) {
-        return;
-    }
 }
 
 fn compare_predicate_entailment<'tcx>(
@@ -579,6 +579,27 @@ fn compare_self_type<'tcx>(
     Ok(())
 }
 
+/// Checks that the number of generics on a given assoc item in a trait impl is the same
+/// as the number of generics on the respective assoc item in the trait definition.
+///
+/// For example this code emits the errors in the following code:
+/// ```
+/// trait Trait {
+///     fn foo();
+///     type Assoc<T>;
+/// }
+///
+/// impl Trait for () {
+///     fn foo<T>() {}
+///     //~^ error
+///     type Assoc = u32;
+///     //~^ error
+/// }
+/// ```
+///
+/// Notably this does not error on `foo<T>` implemented as `foo<const N: u8>` or
+/// `foo<const N: u8>` implemented as `foo<const N: u32>`. This is handled in
+/// [`compare_generic_param_kinds`]. This function also does not handle lifetime parameters
 fn compare_number_of_generics<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_: &ty::AssocItem,
@@ -589,6 +610,15 @@ fn compare_number_of_generics<'tcx>(
     let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
     let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();
 
+    // This avoids us erroring on `foo<T>` implemented as `foo<const N: u8>` as this is implemented
+    // in `compare_generic_param_kinds` which will give a nicer error message than something like:
+    // "expected 1 type parameter, found 0 type parameters"
+    if (trait_own_counts.types + trait_own_counts.consts)
+        == (impl_own_counts.types + impl_own_counts.consts)
+    {
+        return Ok(());
+    }
+
     let matchings = [
         ("type", trait_own_counts.types, impl_own_counts.types),
         ("const", trait_own_counts.consts, impl_own_counts.consts),
@@ -914,60 +944,93 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
     if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
 }
 
-fn compare_const_param_types<'tcx>(
+/// Checks that all parameters in the generics of a given assoc item in a trait impl have
+/// the same kind as the respective generic parameter in the trait def.
+///
+/// For example all 4 errors in the following code are emitted here:
+/// ```
+/// trait Foo {
+///     fn foo<const N: u8>();
+///     type bar<const N: u8>;
+///     fn baz<const N: u32>();
+///     type blah<T>;
+/// }
+///
+/// impl Foo for () {
+///     fn foo<const N: u64>() {}
+///     //~^ error
+///     type bar<const N: u64> {}
+///     //~^ error
+///     fn baz<T>() {}
+///     //~^ error
+///     type blah<const N: i64> = u32;
+///     //~^ error
+/// }
+/// ```
+///
+/// This function does not handle lifetime parameters
+fn compare_generic_param_kinds<'tcx>(
     tcx: TyCtxt<'tcx>,
-    impl_m: &ty::AssocItem,
-    trait_m: &ty::AssocItem,
-    trait_item_span: Option<Span>,
+    impl_item: &ty::AssocItem,
+    trait_item: &ty::AssocItem,
 ) -> Result<(), ErrorGuaranteed> {
-    let const_params_of = |def_id| {
-        tcx.generics_of(def_id).params.iter().filter_map(|param| match param.kind {
-            GenericParamDefKind::Const { .. } => Some(param.def_id),
-            _ => None,
+    assert_eq!(impl_item.kind, trait_item.kind);
+
+    let ty_const_params_of = |def_id| {
+        tcx.generics_of(def_id).params.iter().filter(|param| {
+            matches!(
+                param.kind,
+                GenericParamDefKind::Const { .. } | GenericParamDefKind::Type { .. }
+            )
         })
     };
-    let const_params_impl = const_params_of(impl_m.def_id);
-    let const_params_trait = const_params_of(trait_m.def_id);
-
-    for (const_param_impl, const_param_trait) in iter::zip(const_params_impl, const_params_trait) {
-        let impl_ty = tcx.type_of(const_param_impl);
-        let trait_ty = tcx.type_of(const_param_trait);
-        if impl_ty != trait_ty {
-            let (impl_span, impl_ident) = match tcx.hir().get_if_local(const_param_impl) {
-                Some(hir::Node::GenericParam(hir::GenericParam { span, name, .. })) => (
-                    span,
-                    match name {
-                        hir::ParamName::Plain(ident) => Some(ident),
-                        _ => None,
-                    },
-                ),
-                other => bug!(
-                    "expected GenericParam, found {:?}",
-                    other.map_or_else(|| "nothing".to_string(), |n| format!("{:?}", n))
-                ),
-            };
-            let trait_span = match tcx.hir().get_if_local(const_param_trait) {
-                Some(hir::Node::GenericParam(hir::GenericParam { span, .. })) => Some(span),
-                _ => None,
-            };
+
+    for (param_impl, param_trait) in
+        iter::zip(ty_const_params_of(impl_item.def_id), ty_const_params_of(trait_item.def_id))
+    {
+        use GenericParamDefKind::*;
+        if match (&param_impl.kind, &param_trait.kind) {
+            (Const { .. }, Const { .. })
+                if tcx.type_of(param_impl.def_id) != tcx.type_of(param_trait.def_id) =>
+            {
+                true
+            }
+            (Const { .. }, Type { .. }) | (Type { .. }, Const { .. }) => true,
+            // this is exhaustive so that anyone adding new generic param kinds knows
+            // to make sure this error is reported for them.
+            (Const { .. }, Const { .. }) | (Type { .. }, Type { .. }) => false,
+            (Lifetime { .. }, _) | (_, Lifetime { .. }) => unreachable!(),
+        } {
+            let param_impl_span = tcx.def_span(param_impl.def_id);
+            let param_trait_span = tcx.def_span(param_trait.def_id);
+
             let mut err = struct_span_err!(
                 tcx.sess,
-                *impl_span,
+                param_impl_span,
                 E0053,
-                "method `{}` has an incompatible const parameter type for trait",
-                trait_m.name
-            );
-            err.span_note(
-                trait_span.map_or_else(|| trait_item_span.unwrap_or(*impl_span), |span| *span),
-                &format!(
-                    "the const parameter{} has type `{}`, but the declaration \
-                              in trait `{}` has type `{}`",
-                    &impl_ident.map_or_else(|| "".to_string(), |ident| format!(" `{ident}`")),
-                    impl_ty,
-                    tcx.def_path_str(trait_m.def_id),
-                    trait_ty
-                ),
+                "{} `{}` has an incompatible generic parameter for trait `{}`",
+                assoc_item_kind_str(&impl_item),
+                trait_item.name,
+                &tcx.def_path_str(tcx.parent(trait_item.def_id))
             );
+
+            let make_param_message = |prefix: &str, param: &ty::GenericParamDef| match param.kind {
+                Const { .. } => {
+                    format!("{} const parameter of type `{}`", prefix, tcx.type_of(param.def_id))
+                }
+                Type { .. } => format!("{} type parameter", prefix),
+                Lifetime { .. } => unreachable!(),
+            };
+
+            let trait_header_span = tcx.def_ident_span(tcx.parent(trait_item.def_id)).unwrap();
+            err.span_label(trait_header_span, "");
+            err.span_label(param_trait_span, make_param_message("expected", param_trait));
+
+            let impl_header_span =
+                tcx.sess.source_map().guess_head_span(tcx.def_span(tcx.parent(impl_item.def_id)));
+            err.span_label(impl_header_span, "");
+            err.span_label(param_impl_span, make_param_message("found", param_impl));
+
             let reported = err.emit();
             return Err(reported);
         }
@@ -1095,6 +1158,8 @@ fn compare_const_param_types<'tcx>(
     let _: Result<(), ErrorGuaranteed> = (|| {
         compare_number_of_generics(tcx, impl_ty, impl_ty_span, trait_ty, trait_item_span)?;
 
+        compare_generic_param_kinds(tcx, impl_ty, trait_ty)?;
+
         let sp = tcx.def_span(impl_ty.def_id);
         compare_type_predicate_entailment(tcx, impl_ty, sp, trait_ty, impl_trait_ref)?;
 
index a1e8d2040dd80d82429fa9b4984a656fb3145ef6..f3a5b9f13dd1bac3c123a487f1b366e178bfa2bf 100644 (file)
@@ -44,7 +44,7 @@
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
+use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeFoldable};
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -2034,17 +2034,26 @@ fn check_call_constructor<G: EmissionGuarantee>(
         base: &'tcx hir::Expr<'tcx>,
         def_id: DefId,
     ) {
-        let local_id = def_id.expect_local();
-        let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id);
-        let node = self.tcx.hir().get(hir_id);
-
-        if let Some(fields) = node.tuple_fields() {
-            let kind = match self.tcx.opt_def_kind(local_id) {
-                Some(DefKind::Ctor(of, _)) => of,
-                _ => return,
-            };
+        if let Some(local_id) = def_id.as_local() {
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id);
+            let node = self.tcx.hir().get(hir_id);
+
+            if let Some(fields) = node.tuple_fields() {
+                let kind = match self.tcx.opt_def_kind(local_id) {
+                    Some(DefKind::Ctor(of, _)) => of,
+                    _ => return,
+                };
 
-            suggest_call_constructor(base.span, kind, fields.len(), err);
+                suggest_call_constructor(base.span, kind, fields.len(), err);
+            }
+        } else {
+            // The logic here isn't smart but `associated_item_def_ids`
+            // doesn't work nicely on local.
+            if let DefKind::Ctor(of, _) = self.tcx.def_kind(def_id) {
+                let parent_def_id = self.tcx.parent(def_id);
+                let fields = self.tcx.associated_item_def_ids(parent_def_id);
+                suggest_call_constructor(base.span, of, fields.len(), err);
+            }
         }
     }
 
index 93b0edb84c0547860b7b3e589e24315d3935b1c7..d824c1d7cf252a6b2da48ff43a9165876817b89d 100644 (file)
@@ -1403,10 +1403,7 @@ fn inferred_kind(
                             // is missing.
                             let default = tcx.type_of(param.def_id);
                             self.fcx
-                                .normalize_ty(
-                                    self.span,
-                                    default.subst_spanned(tcx, substs.unwrap(), Some(self.span)),
-                                )
+                                .normalize_ty(self.span, default.subst(tcx, substs.unwrap()))
                                 .into()
                         } else {
                             // If no type arguments were provided, we have to infer them.
@@ -1418,9 +1415,7 @@ fn inferred_kind(
                     }
                     GenericParamDefKind::Const { has_default } => {
                         if !infer_args && has_default {
-                            tcx.const_param_default(param.def_id)
-                                .subst_spanned(tcx, substs.unwrap(), Some(self.span))
-                                .into()
+                            tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
                         } else {
                             self.fcx.var_for_def(self.span, param)
                         }
index 48a66e8026beedd0b129434fef0853b641a6f490..b7ba9d978784627a3752e6c374b067dc05d26538 100644 (file)
@@ -3,6 +3,7 @@
 use rustc_middle::ty::error::TypeError;
 
 // An issue that might be found in the compatibility matrix
+#[derive(Debug)]
 enum Issue {
     /// The given argument is the invalid type for the input
     Invalid(usize),
@@ -23,9 +24,10 @@ pub(crate) enum Compatibility<'tcx> {
 }
 
 /// Similar to `Issue`, but contains some extra information
+#[derive(Debug)]
 pub(crate) enum Error<'tcx> {
-    /// The given argument is the invalid type for the input
-    Invalid(usize, Compatibility<'tcx>),
+    /// The provided argument is the invalid type for the expected input
+    Invalid(usize, usize, Compatibility<'tcx>), // provided, expected
     /// There is a missing input
     Missing(usize),
     /// There's a superfluous argument
@@ -37,8 +39,15 @@ pub(crate) enum Error<'tcx> {
 }
 
 pub(crate) struct ArgMatrix<'tcx> {
+    /// Maps the indices in the `compatibility_matrix` rows to the indices of
+    /// the *user provided* inputs
     input_indexes: Vec<usize>,
+    /// Maps the indices in the `compatibility_matrix` columns to the indices
+    /// of the *expected* args
     arg_indexes: Vec<usize>,
+    /// The first dimension (rows) are the remaining user provided inputs to
+    /// match and the second dimension (cols) are the remaining expected args
+    /// to match
     compatibility_matrix: Vec<Vec<Compatibility<'tcx>>>,
 }
 
@@ -52,8 +61,8 @@ pub(crate) fn new<F: FnMut(usize, usize) -> Compatibility<'tcx>>(
             .map(|i| (0..minimum_input_count).map(|j| is_compatible(i, j)).collect())
             .collect();
         ArgMatrix {
-            input_indexes: (0..minimum_input_count).collect(),
-            arg_indexes: (0..provided_arg_count).collect(),
+            input_indexes: (0..provided_arg_count).collect(),
+            arg_indexes: (0..minimum_input_count).collect(),
             compatibility_matrix,
         }
     }
@@ -61,15 +70,15 @@ pub(crate) fn new<F: FnMut(usize, usize) -> Compatibility<'tcx>>(
     /// Remove a given input from consideration
     fn eliminate_input(&mut self, idx: usize) {
         self.input_indexes.remove(idx);
-        for row in &mut self.compatibility_matrix {
-            row.remove(idx);
-        }
+        self.compatibility_matrix.remove(idx);
     }
 
     /// Remove a given argument from consideration
     fn eliminate_arg(&mut self, idx: usize) {
         self.arg_indexes.remove(idx);
-        self.compatibility_matrix.remove(idx);
+        for row in &mut self.compatibility_matrix {
+            row.remove(idx);
+        }
     }
 
     /// "satisfy" an input with a given arg, removing both from consideration
@@ -78,13 +87,15 @@ fn satisfy_input(&mut self, input_idx: usize, arg_idx: usize) {
         self.eliminate_arg(arg_idx);
     }
 
+    // Returns a `Vec` of (user input, expected arg) of matched arguments. These
+    // are inputs on the remaining diagonal that match.
     fn eliminate_satisfied(&mut self) -> Vec<(usize, usize)> {
         let mut i = cmp::min(self.input_indexes.len(), self.arg_indexes.len());
         let mut eliminated = vec![];
         while i > 0 {
             let idx = i - 1;
             if matches!(self.compatibility_matrix[idx][idx], Compatibility::Compatible) {
-                eliminated.push((self.arg_indexes[idx], self.input_indexes[idx]));
+                eliminated.push((self.input_indexes[idx], self.arg_indexes[idx]));
                 self.satisfy_input(idx, idx);
             }
             i -= 1;
@@ -92,7 +103,7 @@ fn eliminate_satisfied(&mut self) -> Vec<(usize, usize)> {
         return eliminated;
     }
 
-    // Check for the above mismatch cases
+    // Find some issue in the compatibility matrix
     fn find_issue(&self) -> Option<Issue> {
         let mat = &self.compatibility_matrix;
         let ai = &self.arg_indexes;
@@ -121,9 +132,9 @@ fn find_issue(&self) -> Option<Issue> {
             if is_arg {
                 for j in 0..ii.len() {
                     // If we find at least one input this argument could satisfy
-                    // this argument isn't completely useless
-                    if matches!(mat[i][j], Compatibility::Compatible) {
-                        useless = false;
+                    // this argument isn't unsatisfiable
+                    if matches!(mat[j][i], Compatibility::Compatible) {
+                        unsatisfiable = false;
                         break;
                     }
                 }
@@ -131,16 +142,16 @@ fn find_issue(&self) -> Option<Issue> {
             if is_input {
                 for j in 0..ai.len() {
                     // If we find at least one argument that could satisfy this input
-                    // this argument isn't unsatisfiable
-                    if matches!(mat[j][i], Compatibility::Compatible) {
-                        unsatisfiable = false;
+                    // this argument isn't useless
+                    if matches!(mat[i][j], Compatibility::Compatible) {
+                        useless = false;
                         break;
                     }
                 }
             }
 
-            match (is_arg, is_input, useless, unsatisfiable) {
-                // If an input is unsatisfied, and the argument in its position is useless
+            match (is_input, is_arg, useless, unsatisfiable) {
+                // If an argument is unsatisfied, and the input in its position is useless
                 // then the most likely explanation is that we just got the types wrong
                 (true, true, true, true) => return Some(Issue::Invalid(i)),
                 // Otherwise, if an input is useless, then indicate that this is an extra argument
@@ -167,7 +178,7 @@ fn find_issue(&self) -> Option<Issue> {
                 _ => {
                     continue;
                 }
-            };
+            }
         }
 
         // We didn't find any of the individual issues above, but
@@ -254,11 +265,11 @@ fn find_issue(&self) -> Option<Issue> {
     // We'll want to know which arguments and inputs these rows and columns correspond to
     // even after we delete them.
     pub(crate) fn find_errors(mut self) -> (Vec<Error<'tcx>>, Vec<Option<usize>>) {
-        let provided_arg_count = self.arg_indexes.len();
+        let provided_arg_count = self.input_indexes.len();
 
         let mut errors: Vec<Error<'tcx>> = vec![];
         // For each expected argument, the matched *actual* input
-        let mut matched_inputs: Vec<Option<usize>> = vec![None; self.input_indexes.len()];
+        let mut matched_inputs: Vec<Option<usize>> = vec![None; self.arg_indexes.len()];
 
         // Before we start looking for issues, eliminate any arguments that are already satisfied,
         // so that an argument which is already spoken for by the input it's in doesn't
@@ -269,28 +280,28 @@ pub(crate) fn find_errors(mut self) -> (Vec<Error<'tcx>>, Vec<Option<usize>>) {
         // Without this elimination, the first argument causes the second argument
         // to show up as both a missing input and extra argument, rather than
         // just an invalid type.
-        for (arg, inp) in self.eliminate_satisfied() {
-            matched_inputs[inp] = Some(arg);
+        for (inp, arg) in self.eliminate_satisfied() {
+            matched_inputs[arg] = Some(inp);
         }
 
         while self.input_indexes.len() > 0 || self.arg_indexes.len() > 0 {
-            // Check for the first relevant issue
             match self.find_issue() {
                 Some(Issue::Invalid(idx)) => {
                     let compatibility = self.compatibility_matrix[idx][idx].clone();
                     let input_idx = self.input_indexes[idx];
+                    let arg_idx = self.arg_indexes[idx];
                     self.satisfy_input(idx, idx);
-                    errors.push(Error::Invalid(input_idx, compatibility));
+                    errors.push(Error::Invalid(input_idx, arg_idx, compatibility));
                 }
                 Some(Issue::Extra(idx)) => {
-                    let arg_idx = self.arg_indexes[idx];
-                    self.eliminate_arg(idx);
-                    errors.push(Error::Extra(arg_idx));
-                }
-                Some(Issue::Missing(idx)) => {
                     let input_idx = self.input_indexes[idx];
                     self.eliminate_input(idx);
-                    errors.push(Error::Missing(input_idx));
+                    errors.push(Error::Extra(input_idx));
+                }
+                Some(Issue::Missing(idx)) => {
+                    let arg_idx = self.arg_indexes[idx];
+                    self.eliminate_arg(idx);
+                    errors.push(Error::Missing(arg_idx));
                 }
                 Some(Issue::Swap(idx, other)) => {
                     let input_idx = self.input_indexes[idx];
@@ -302,24 +313,21 @@ pub(crate) fn find_errors(mut self) -> (Vec<Error<'tcx>>, Vec<Option<usize>>) {
                     // Subtract 1 because we already removed the "min" row
                     self.satisfy_input(max - 1, min);
                     errors.push(Error::Swap(input_idx, other_input_idx, arg_idx, other_arg_idx));
-                    matched_inputs[input_idx] = Some(other_arg_idx);
-                    matched_inputs[other_input_idx] = Some(arg_idx);
+                    matched_inputs[other_arg_idx] = Some(input_idx);
+                    matched_inputs[arg_idx] = Some(other_input_idx);
                 }
                 Some(Issue::Permutation(args)) => {
-                    // FIXME: If satisfy_input ever did anything non-trivial (emit obligations to help type checking, for example)
-                    // we'd want to call this function with the correct arg/input pairs, but for now, we just throw them in a bucket.
-                    // This works because they force a cycle, so each row is guaranteed to also be a column
                     let mut idxs: Vec<usize> = args.iter().filter_map(|&a| a).collect();
 
                     let mut real_idxs = vec![None; provided_arg_count];
                     for (src, dst) in
                         args.iter().enumerate().filter_map(|(src, dst)| dst.map(|dst| (src, dst)))
                     {
-                        let src_arg = self.arg_indexes[src];
-                        let dst_arg = self.arg_indexes[dst];
-                        let dest_input = self.input_indexes[dst];
-                        real_idxs[src_arg] = Some((dst_arg, dest_input));
-                        matched_inputs[dest_input] = Some(src_arg);
+                        let src_input_idx = self.input_indexes[src];
+                        let dst_input_idx = self.input_indexes[dst];
+                        let dest_arg_idx = self.arg_indexes[dst];
+                        real_idxs[src_input_idx] = Some((dest_arg_idx, dst_input_idx));
+                        matched_inputs[dest_arg_idx] = Some(src_input_idx);
                     }
                     idxs.sort();
                     idxs.reverse();
@@ -331,8 +339,8 @@ pub(crate) fn find_errors(mut self) -> (Vec<Error<'tcx>>, Vec<Option<usize>>) {
                 None => {
                     // We didn't find any issues, so we need to push the algorithm forward
                     // First, eliminate any arguments that currently satisfy their inputs
-                    for (arg, inp) in self.eliminate_satisfied() {
-                        matched_inputs[inp] = Some(arg);
+                    for (inp, arg) in self.eliminate_satisfied() {
+                        matched_inputs[arg] = Some(inp);
                     }
                 }
             };
index 97d256cab685d4a4cfc8c378fa349a9b2965e2b8..847c2c32dba293f6487091932015837559d34954 100644 (file)
@@ -24,7 +24,7 @@
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
 use rustc_span::{self, Span};
@@ -274,9 +274,9 @@ pub(in super::super) fn check_argument_types(
         // A "softer" version of the helper above, which checks types without persisting them,
         // and treats error types differently
         // This will allow us to "probe" for other argument orders that would likely have been correct
-        let check_compatible = |arg_idx, input_idx| {
-            let formal_input_ty: Ty<'tcx> = formal_input_tys[input_idx];
-            let expected_input_ty: Ty<'tcx> = expected_input_tys[input_idx];
+        let check_compatible = |input_idx, arg_idx| {
+            let formal_input_ty: Ty<'tcx> = formal_input_tys[arg_idx];
+            let expected_input_ty: Ty<'tcx> = expected_input_tys[arg_idx];
 
             // If either is an error type, we defy the usual convention and consider them to *not* be
             // coercible.  This prevents our error message heuristic from trying to pass errors into
@@ -285,7 +285,7 @@ pub(in super::super) fn check_argument_types(
                 return Compatibility::Incompatible(None);
             }
 
-            let provided_arg: &hir::Expr<'tcx> = &provided_args[arg_idx];
+            let provided_arg: &hir::Expr<'tcx> = &provided_args[input_idx];
             let expectation = Expectation::rvalue_hint(self, expected_input_ty);
             // FIXME: check that this is safe; I don't believe this commits any of the obligations, but I can't be sure.
             //
@@ -394,6 +394,8 @@ pub(in super::super) fn check_argument_types(
                 break 'errors;
             }
 
+            self.set_tainted_by_errors();
+
             // The algorithm here is inspired by levenshtein distance and longest common subsequence.
             // We'll try to detect 4 different types of mistakes:
             // - An extra parameter has been provided that doesn't satisfy *any* of the other inputs
@@ -427,11 +429,11 @@ pub(in super::super) fn check_argument_types(
             let found_errors = !errors.is_empty();
 
             errors.drain_filter(|error| {
-                let Error::Invalid(input_idx, Compatibility::Incompatible(error)) = error else { return false };
-                let expected_ty = expected_input_tys[*input_idx];
-                let Some(Some((provided_ty, _))) = final_arg_types.get(*input_idx) else { return false };
+                let Error::Invalid(input_idx, arg_idx, Compatibility::Incompatible(error)) = error else { return false };
+                let expected_ty = expected_input_tys[*arg_idx];
+                let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap();
                 let cause = &self.misc(provided_args[*input_idx].span);
-                let trace = TypeTrace::types(cause, true, expected_ty, *provided_ty);
+                let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
                 if let Some(e) = error {
                     if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) {
                         self.report_and_explain_type_error(trace, e).emit();
@@ -502,6 +504,8 @@ pub(in super::super) fn check_argument_types(
                 TupleMatchFound::Single => {
                     let expected_ty = expected_input_tys[0];
                     let provided_ty = final_arg_types[0].map(|ty| ty.0).unwrap();
+                    let expected_ty = self.resolve_vars_if_possible(expected_ty);
+                    let provided_ty = self.resolve_vars_if_possible(provided_ty);
                     let cause = &self.misc(provided_args[0].span);
                     let compatibility = demand_compatible(0, &mut final_arg_types);
                     let type_error = match compatibility {
@@ -523,24 +527,7 @@ pub(in super::super) fn check_argument_types(
                         format!("arguments to this {} are incorrect", call_name),
                     );
                     // Call out where the function is defined
-                    if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
-                        let mut spans: MultiSpan = def_span.into();
-
-                        let params = tcx
-                            .hir()
-                            .get_if_local(def_id)
-                            .and_then(|node| node.body_id())
-                            .into_iter()
-                            .map(|id| tcx.hir().body(id).params)
-                            .flatten();
-
-                        for param in params {
-                            spans.push_span_label(param.span, String::new());
-                        }
-
-                        let def_kind = tcx.def_kind(def_id);
-                        err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
-                    }
+                    label_fn_like(tcx, &mut err, fn_def_id);
                     err.emit();
                     break 'errors;
                 }
@@ -558,24 +545,7 @@ pub(in super::super) fn check_argument_types(
                         DiagnosticId::Error(err_code.to_owned()),
                     );
                     // Call out where the function is defined
-                    if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
-                        let mut spans: MultiSpan = def_span.into();
-
-                        let params = tcx
-                            .hir()
-                            .get_if_local(def_id)
-                            .and_then(|node| node.body_id())
-                            .into_iter()
-                            .map(|id| tcx.hir().body(id).params)
-                            .flatten();
-
-                        for param in params {
-                            spans.push_span_label(param.span, String::new());
-                        }
-
-                        let def_kind = tcx.def_kind(def_id);
-                        err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
-                    }
+                    label_fn_like(tcx, &mut err, fn_def_id);
                     err.multipart_suggestion(
                         "use parentheses to construct a tuple",
                         vec![(start, '('.to_string()), (end, ')'.to_string())],
@@ -592,18 +562,23 @@ pub(in super::super) fn check_argument_types(
 
             // Next special case: if there is only one "Incompatible" error, just emit that
             if errors.len() == 1 {
-                if let Some(Error::Invalid(input_idx, Compatibility::Incompatible(Some(error)))) =
-                    errors.iter().next()
+                if let Some(Error::Invalid(
+                    input_idx,
+                    arg_idx,
+                    Compatibility::Incompatible(Some(error)),
+                )) = errors.iter().next()
                 {
-                    let expected_ty = expected_input_tys[*input_idx];
-                    let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap();
+                    let expected_ty = expected_input_tys[*arg_idx];
+                    let provided_ty = final_arg_types[*arg_idx].map(|ty| ty.0).unwrap();
+                    let expected_ty = self.resolve_vars_if_possible(expected_ty);
+                    let provided_ty = self.resolve_vars_if_possible(provided_ty);
                     let cause = &self.misc(provided_args[*input_idx].span);
                     let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
                     let mut err = self.report_and_explain_type_error(trace, error);
                     self.emit_coerce_suggestions(
                         &mut err,
                         &provided_args[*input_idx],
-                        final_arg_types[*input_idx].map(|ty| ty.0).unwrap(),
+                        provided_ty,
                         final_arg_types[*input_idx].map(|ty| ty.1).unwrap(),
                         None,
                         None,
@@ -613,24 +588,7 @@ pub(in super::super) fn check_argument_types(
                         format!("arguments to this {} are incorrect", call_name),
                     );
                     // Call out where the function is defined
-                    if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
-                        let mut spans: MultiSpan = def_span.into();
-
-                        let params = tcx
-                            .hir()
-                            .get_if_local(def_id)
-                            .and_then(|node| node.body_id())
-                            .into_iter()
-                            .map(|id| tcx.hir().body(id).params)
-                            .flatten();
-
-                        for param in params {
-                            spans.push_span_label(param.span, String::new());
-                        }
-
-                        let def_kind = tcx.def_kind(def_id);
-                        err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
-                    }
+                    label_fn_like(tcx, &mut err, fn_def_id);
                     err.emit();
                     break 'errors;
                 }
@@ -676,17 +634,13 @@ enum SuggestionText {
             let mut errors = errors.into_iter().peekable();
             while let Some(error) = errors.next() {
                 match error {
-                    Error::Invalid(input_idx, compatibility) => {
-                        let expected_ty = expected_input_tys[input_idx];
+                    Error::Invalid(input_idx, arg_idx, compatibility) => {
+                        let expected_ty = expected_input_tys[arg_idx];
+                        let provided_ty = final_arg_types[input_idx].map(|ty| ty.0).unwrap();
+                        let expected_ty = self.resolve_vars_if_possible(expected_ty);
+                        let provided_ty = self.resolve_vars_if_possible(provided_ty);
                         if let Compatibility::Incompatible(error) = &compatibility {
-                            let provided_ty = final_arg_types
-                                .get(input_idx)
-                                .and_then(|x| x.as_ref())
-                                .map(|ty| ty.0)
-                                .unwrap_or(tcx.ty_error());
-                            let cause = &self.misc(
-                                provided_args.get(input_idx).map(|i| i.span).unwrap_or(call_span),
-                            );
+                            let cause = &self.misc(provided_args[input_idx].span);
                             let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
                             if let Some(e) = error {
                                 self.note_type_err(
@@ -701,16 +655,14 @@ enum SuggestionText {
                             }
                         }
 
-                        if let Some(expr) = provided_args.get(input_idx) {
-                            self.emit_coerce_suggestions(
-                                &mut err,
-                                &expr,
-                                final_arg_types[input_idx].map(|ty| ty.0).unwrap(),
-                                final_arg_types[input_idx].map(|ty| ty.1).unwrap(),
-                                None,
-                                None,
-                            );
-                        }
+                        self.emit_coerce_suggestions(
+                            &mut err,
+                            &provided_args[input_idx],
+                            final_arg_types[input_idx].map(|ty| ty.0).unwrap(),
+                            final_arg_types[input_idx].map(|ty| ty.1).unwrap(),
+                            None,
+                            None,
+                        );
                     }
                     Error::Extra(arg_idx) => {
                         let arg_type = if let Some((_, ty)) = final_arg_types[arg_idx] {
@@ -886,12 +838,12 @@ enum SuggestionText {
                         }
                     }
                     Error::Swap(input_idx, other_input_idx, arg_idx, other_arg_idx) => {
-                        let first_span = provided_args[arg_idx].span;
-                        let second_span = provided_args[other_arg_idx].span;
+                        let first_span = provided_args[input_idx].span;
+                        let second_span = provided_args[other_input_idx].span;
 
                         let first_expected_ty =
-                            self.resolve_vars_if_possible(expected_input_tys[input_idx]);
-                        let first_provided_ty = if let Some((ty, _)) = final_arg_types[arg_idx] {
+                            self.resolve_vars_if_possible(expected_input_tys[arg_idx]);
+                        let first_provided_ty = if let Some((ty, _)) = final_arg_types[input_idx] {
                             format!(",found `{}`", ty)
                         } else {
                             "".into()
@@ -901,9 +853,9 @@ enum SuggestionText {
                             format!("expected `{}`{}", first_expected_ty, first_provided_ty),
                         ));
                         let other_expected_ty =
-                            self.resolve_vars_if_possible(expected_input_tys[other_input_idx]);
+                            self.resolve_vars_if_possible(expected_input_tys[other_arg_idx]);
                         let other_provided_ty =
-                            if let Some((ty, _)) = final_arg_types[other_arg_idx] {
+                            if let Some((ty, _)) = final_arg_types[other_input_idx] {
                                 format!(",found `{}`", ty)
                             } else {
                                 "".into()
@@ -948,24 +900,7 @@ enum SuggestionText {
             }
 
             // Call out where the function is defined
-            if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) {
-                let mut spans: MultiSpan = def_span.into();
-
-                let params = tcx
-                    .hir()
-                    .get_if_local(def_id)
-                    .and_then(|node| node.body_id())
-                    .into_iter()
-                    .flat_map(|id| tcx.hir().body(id).params)
-                    ;
-
-                for param in params {
-                    spans.push_span_label(param.span, String::new());
-                }
-
-                let def_kind = tcx.def_kind(def_id);
-                err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
-            }
+            label_fn_like(tcx, &mut err, fn_def_id);
 
             // And add a suggestion block for all of the parameters
             let suggestion_text = match suggestion_text {
@@ -986,14 +921,14 @@ enum SuggestionText {
                     "{}(",
                     source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| String::new())
                 );
-                for (idx, arg) in matched_inputs.iter().enumerate() {
-                    let suggestion_text = if let Some(arg) = arg {
-                        let arg_span = provided_args[*arg].span.source_callsite();
+                for (arg_index, input_idx) in matched_inputs.iter().enumerate() {
+                    let suggestion_text = if let Some(input_idx) = input_idx {
+                        let arg_span = provided_args[*input_idx].span.source_callsite();
                         let arg_text = source_map.span_to_snippet(arg_span).unwrap();
                         arg_text
                     } else {
                         // Propose a placeholder of the correct type
-                        let expected_ty = expected_input_tys[idx];
+                        let expected_ty = expected_input_tys[arg_index];
                         let input_ty = self.resolve_vars_if_possible(expected_ty);
                         if input_ty.is_unit() {
                             "()".to_string()
@@ -1002,7 +937,7 @@ enum SuggestionText {
                         }
                     };
                     suggestion += &suggestion_text;
-                    if idx < minimum_input_count - 1 {
+                    if arg_index < minimum_input_count - 1 {
                         suggestion += ", ";
                     }
                 }
@@ -1790,3 +1725,47 @@ fn point_at_type_arg_instead_of_call_if_possible(
         }
     }
 }
+
+fn label_fn_like<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>,
+    def_id: Option<DefId>,
+) {
+    let Some(def_id) = def_id else {
+        return;
+    };
+
+    if let Some(def_span) = tcx.def_ident_span(def_id) {
+        let mut spans: MultiSpan = def_span.into();
+
+        let params = tcx
+            .hir()
+            .get_if_local(def_id)
+            .and_then(|node| node.body_id())
+            .into_iter()
+            .map(|id| tcx.hir().body(id).params)
+            .flatten();
+
+        for param in params {
+            spans.push_span_label(param.span, String::new());
+        }
+
+        let def_kind = tcx.def_kind(def_id);
+        err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
+    } else {
+        match tcx.hir().get_if_local(def_id) {
+            Some(hir::Node::Expr(hir::Expr {
+                kind: hir::ExprKind::Closure(_, _, _, span, ..),
+                ..
+            })) => {
+                let spans: MultiSpan = (*span).into();
+
+                // Note: We don't point to param spans here because they overlap
+                // with the closure span itself
+
+                err.span_note(spans, "closure defined here");
+            }
+            _ => {}
+        }
+    }
+}
index bc0fa9165561da32e12488fae8967c8eb25e2216..1b619776b857c3f4e0208d776d322c0d7d02b8b4 100644 (file)
@@ -462,19 +462,13 @@ fn instantiate_method_sig(
 
         let sig = self.tcx.fn_sig(def_id);
 
-        // Instantiate late-bound regions and substitute the trait
-        // parameters into the method type to get the actual method type.
-        //
-        // N.B., instantiate late-bound regions first so that
-        // `instantiate_type_scheme` can normalize associated types that
-        // may reference those regions.
-        let method_sig = self.replace_bound_vars_with_fresh_vars(sig);
-        debug!("late-bound lifetimes from method instantiated, method_sig={:?}", method_sig);
+        let sig = sig.subst(self.tcx, all_substs);
+        debug!("type scheme substituted, sig={:?}", sig);
 
-        let method_sig = method_sig.subst(self.tcx, all_substs);
-        debug!("type scheme substituted, method_sig={:?}", method_sig);
+        let sig = self.replace_bound_vars_with_fresh_vars(sig);
+        debug!("late-bound lifetimes from method instantiated, sig={:?}", sig);
 
-        (method_sig, method_predicates)
+        (sig, method_predicates)
     }
 
     fn add_obligations(
index 8137d7029218296500edc721d5101f0b9eabe51c..1dd5e45fdc174026066730f9671bb4246dc4f00a 100644 (file)
@@ -461,8 +461,8 @@ fn construct_obligation_for_trait(
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
         let fn_sig = tcx.fn_sig(def_id);
-        let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0;
         let fn_sig = fn_sig.subst(self.tcx, substs);
+        let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0;
 
         let InferOk { value, obligations: o } = if is_op {
             self.normalize_op_associated_types_in_as_infer_ok(span, fn_sig, opt_input_expr)
index c7d0f61c601a80f41f5c1a1591cb36bab574eef0..c28ab9fa1ee40cfae6c0292a68fcf5661dd67bd2 100644 (file)
@@ -1784,12 +1784,8 @@ fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<
         let generics = self.tcx.generics_of(method);
         assert_eq!(substs.len(), generics.parent_count as usize);
 
-        // Erase any late-bound regions from the method and substitute
-        // in the values from the substitution.
-        let xform_fn_sig = self.erase_late_bound_regions(fn_sig);
-
-        if generics.params.is_empty() {
-            xform_fn_sig.subst(self.tcx, substs)
+        let xform_fn_sig = if generics.params.is_empty() {
+            fn_sig.subst(self.tcx, substs)
         } else {
             let substs = InternalSubsts::for_item(self.tcx, method, |param, _| {
                 let i = param.index as usize;
@@ -1807,8 +1803,10 @@ fn xform_method_sig(&self, method: DefId, substs: SubstsRef<'tcx>) -> ty::FnSig<
                     }
                 }
             });
-            xform_fn_sig.subst(self.tcx, substs)
-        }
+            fn_sig.subst(self.tcx, substs)
+        };
+
+        self.erase_late_bound_regions(xform_fn_sig)
     }
 
     /// Gets the type of an impl and generate substitutions with placeholders.
index c1c63c460664cc16eed32f5d518b3e5cbd372517..2e0e026631b5191bd3d5514e32f509d437ccdef9 100644 (file)
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-use rustc_target::spec::{abi, PanicStrategy, SanitizerSet};
+use rustc_target::spec::{abi, SanitizerSet};
 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
 use std::iter;
 
 mod item_bounds;
 mod type_of;
 
+#[derive(Debug)]
 struct OnlySelfBounds(bool);
 
 ///////////////////////////////////////////////////////////////////////////
@@ -650,6 +651,7 @@ impl<'tcx> ItemCtxt<'tcx> {
     /// AST. We do this to avoid having to convert *all* the bounds, which
     /// would create artificial cycles. Instead, we can only convert the
     /// bounds for a type parameter `X` if `X::Foo` is used.
+    #[instrument(level = "trace", skip(self, ast_generics))]
     fn type_parameter_bounds_in_generics(
         &self,
         ast_generics: &'tcx hir::Generics<'tcx>,
@@ -659,6 +661,7 @@ fn type_parameter_bounds_in_generics(
         assoc_name: Option<Ident>,
     ) -> Vec<(ty::Predicate<'tcx>, Span)> {
         let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
+        debug!(?param_def_id);
         ast_generics
             .predicates
             .iter()
@@ -676,13 +679,12 @@ fn type_parameter_bounds_in_generics(
                 };
                 let bvars = self.tcx.late_bound_vars(bp.bounded_ty.hir_id);
 
-                bp.bounds
-                    .iter()
-                    .filter(|b| match assoc_name {
+                bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).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, bvars)))
+                    },
+                )
             })
             .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
             .collect()
@@ -1140,6 +1142,7 @@ fn super_predicates_that_define_assoc_type(
 
         // Combine the two lists to form the complete set of superbounds:
         let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
+        debug!(?superbounds);
 
         // Now require that immediate supertraits are converted,
         // which will, in turn, reach indirect supertraits.
@@ -2610,7 +2613,6 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind>
 
 fn from_target_feature(
     tcx: TyCtxt<'_>,
-    id: DefId,
     attr: &ast::Attribute,
     supported_target_features: &FxHashMap<String, Option<Symbol>>,
     target_features: &mut Vec<Symbol>,
@@ -2679,7 +2681,7 @@ fn from_target_feature(
                 Some(name) => bug!("unknown target feature gate {}", name),
                 None => true,
             };
-            if !allowed && id.is_local() {
+            if !allowed {
                 feature_err(
                     &tcx.sess.parse_sess,
                     feature_gate.unwrap(),
@@ -2693,7 +2695,7 @@ fn from_target_feature(
     }
 }
 
-fn linkage_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Linkage {
+fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
     use rustc_middle::mir::mono::Linkage::*;
 
     // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
@@ -2716,36 +2718,30 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Linkage {
         "private" => Private,
         "weak" => WeakAny,
         "weak_odr" => WeakODR,
-        _ => {
-            let span = tcx.hir().span_if_local(def_id);
-            if let Some(span) = span {
-                tcx.sess.span_fatal(span, "invalid linkage specified")
-            } else {
-                tcx.sess.fatal(&format!("invalid linkage specified: {}", name))
-            }
-        }
+        _ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
     }
 }
 
-fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
-    let attrs = tcx.get_attrs(id);
+fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
+    if cfg!(debug_assertions) {
+        let def_kind = tcx.def_kind(did);
+        assert!(
+            def_kind.has_codegen_attrs(),
+            "unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
+        );
+    }
 
+    let did = did.expect_local();
+    let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did));
     let mut codegen_fn_attrs = CodegenFnAttrs::new();
-    if tcx.should_inherit_track_caller(id) {
+    if tcx.should_inherit_track_caller(did) {
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
     }
 
-    // With -Z panic-in-drop=abort, drop_in_place never unwinds.
-    if tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Abort {
-        if Some(id) == tcx.lang_items().drop_in_place_fn() {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
-        }
-    }
-
     // The panic_no_unwind function called by TerminatorKind::Abort will never
     // unwind. If the panic handler that it invokes unwind then it will simply
     // call the panic handler again.
-    if Some(id) == tcx.lang_items().panic_no_unwind() {
+    if Some(did.to_def_id()) == tcx.lang_items().panic_no_unwind() {
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
     }
 
@@ -2760,7 +2756,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         } else if attr.has_name(sym::rustc_allocator) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
         } else if attr.has_name(sym::ffi_returns_twice) {
-            if tcx.is_foreign_item(id) {
+            if tcx.is_foreign_item(did) {
                 codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
             } else {
                 // `#[ffi_returns_twice]` is only allowed `extern fn`s.
@@ -2773,7 +2769,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 .emit();
             }
         } else if attr.has_name(sym::ffi_pure) {
-            if tcx.is_foreign_item(id) {
+            if tcx.is_foreign_item(did) {
                 if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
                     // `#[ffi_const]` functions cannot be `#[ffi_pure]`
                     struct_span_err!(
@@ -2797,7 +2793,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 .emit();
             }
         } else if attr.has_name(sym::ffi_const) {
-            if tcx.is_foreign_item(id) {
+            if tcx.is_foreign_item(did) {
                 codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
             } else {
                 // `#[ffi_const]` is only allowed on foreign functions
@@ -2857,7 +2853,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 None => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED,
             }
         } else if attr.has_name(sym::cmse_nonsecure_entry) {
-            if !matches!(tcx.fn_sig(id).abi(), abi::Abi::C { .. }) {
+            if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) {
                 struct_span_err!(
                     tcx.sess,
                     attr.span,
@@ -2874,11 +2870,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         } else if attr.has_name(sym::thread_local) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
         } else if attr.has_name(sym::track_caller) {
-            if !tcx.is_closure(id) && tcx.fn_sig(id).abi() != abi::Abi::Rust {
+            if !tcx.is_closure(did.to_def_id()) && tcx.fn_sig(did).abi() != abi::Abi::Rust {
                 struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
                     .emit();
             }
-            if tcx.is_closure(id) && !tcx.features().closure_track_caller {
+            if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
                 feature_err(
                     &tcx.sess.parse_sess,
                     sym::closure_track_caller,
@@ -2904,7 +2900,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 codegen_fn_attrs.export_name = Some(s);
             }
         } else if attr.has_name(sym::target_feature) {
-            if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
+            if !tcx.is_closure(did.to_def_id())
+                && tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal
+            {
                 if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
                     // The `#[target_feature]` attribute is allowed on
                     // WebAssembly targets on all functions, including safe
@@ -2930,22 +2928,21 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                         attr.span,
                         "`#[target_feature(..)]` can only be applied to `unsafe` functions",
                     );
-                    err.span_label(tcx.def_span(id), "not an `unsafe` function");
+                    err.span_label(tcx.def_span(did), "not an `unsafe` function");
                     err.emit();
-                } else if let Some(local_id) = id.as_local() {
-                    check_target_feature_trait_unsafe(tcx, local_id, attr.span);
+                } else {
+                    check_target_feature_trait_unsafe(tcx, did, attr.span);
                 }
             }
             from_target_feature(
                 tcx,
-                id,
                 attr,
                 supported_target_features,
                 &mut codegen_fn_attrs.target_features,
             );
         } else if attr.has_name(sym::linkage) {
             if let Some(val) = attr.value_str() {
-                codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, val.as_str()));
+                codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, did, val.as_str()));
             }
         } else if attr.has_name(sym::link_section) {
             if let Some(val) = attr.value_str() {
@@ -3161,8 +3158,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
     });
 
     // #73631: closures inherit `#[target_feature]` annotations
-    if tcx.features().target_feature_11 && tcx.is_closure(id) {
-        let owner_id = tcx.parent(id);
+    if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
+        let owner_id = tcx.parent(did.to_def_id());
         codegen_fn_attrs
             .target_features
             .extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied())
@@ -3187,7 +3184,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
     if !codegen_fn_attrs.no_sanitize.is_empty() {
         if codegen_fn_attrs.inline == InlineAttr::Always {
             if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
-                let hir_id = tcx.hir().local_def_id_to_hir_id(id.expect_local());
+                let hir_id = tcx.hir().local_def_id_to_hir_id(did);
                 tcx.struct_span_lint_hir(
                     lint::builtin::INLINE_NO_SANITIZE,
                     hir_id,
@@ -3207,7 +3204,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
     // strippable by the linker.
     //
     // Additionally weak lang items have predetermined symbol names.
-    if tcx.is_weak_lang_item(id) {
+    if tcx.is_weak_lang_item(did.to_def_id()) {
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
     }
     if let Some(name) = weak_lang_items::link_name(attrs) {
@@ -3237,19 +3234,22 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
 
 /// Computes the set of target features used in a function for the purposes of
 /// inline assembly.
-fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, id: DefId) -> &'tcx FxHashSet<Symbol> {
+fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
     let mut target_features = tcx.sess.target_features.clone();
-    let attrs = tcx.codegen_fn_attrs(id);
-    target_features.extend(&attrs.target_features);
-    match attrs.instruction_set {
-        None => {}
-        Some(InstructionSetAttr::ArmA32) => {
-            target_features.remove(&sym::thumb_mode);
-        }
-        Some(InstructionSetAttr::ArmT32) => {
-            target_features.insert(sym::thumb_mode);
+    if tcx.def_kind(did).has_codegen_attrs() {
+        let attrs = tcx.codegen_fn_attrs(did);
+        target_features.extend(&attrs.target_features);
+        match attrs.instruction_set {
+            None => {}
+            Some(InstructionSetAttr::ArmA32) => {
+                target_features.remove(&sym::thumb_mode);
+            }
+            Some(InstructionSetAttr::ArmT32) => {
+                target_features.insert(sym::thumb_mode);
+            }
         }
     }
+
     tcx.arena.alloc(target_features)
 }
 
index a3e7108caae00778eaae5f6b00ea552af5e62d11..81d4c9135ef243695b6b515a277805ec46579919 100644 (file)
@@ -103,6 +103,8 @@ pub struct CopyImplOnNonAdt {
 pub struct TraitObjectDeclaredWithNoTraits {
     #[primary_span]
     pub span: Span,
+    #[label = "alias-span"]
+    pub trait_alias_span: Option<Span>,
 }
 
 #[derive(SessionDiagnostic)]
index e8290809276fbf031ad414615f4e1814edbff0f5..19198ab3aa1b53f562628ea16a2ffbcd3062667d 100644 (file)
@@ -122,7 +122,6 @@ fn last(mut self) -> Option<&'a T> {
     }
 
     #[inline]
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         // Safety: The TrustedRandomAccess contract requires that callers only pass an index
         // that is in bounds.
index ee2df0d5160127a26676b89f5ea04c39ff736136..b78c0d5e1b3cfdbeb68dfd134e8c3aa02c144b66 100644 (file)
@@ -100,7 +100,6 @@ fn last(mut self) -> Option<&'a mut T> {
     }
 
     #[inline]
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         // Safety: The TrustedRandomAccess contract requires that callers only pass an index
         // that is in bounds.
index 02a47c57b8ae3bcec2a7c27e8018b1d922d53543..5bdf36a63a22506122a2c5bf6a0ebbba99bc5ffe 100644 (file)
@@ -657,7 +657,7 @@ pub fn join<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Outp
     /// ```
     #[rustc_allow_incoherent_impl]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.3.0", reason = "renamed to join")]
+    #[deprecated(since = "1.3.0", note = "renamed to join")]
     pub fn connect<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
     where
         Self: Join<Separator>,
index 8134eea570ad722e347379b41973f4880e1b7abf..a7df6f59b59894270fffd5fd005c5e06024365eb 100644 (file)
@@ -202,7 +202,6 @@ fn count(self) -> usize {
         self.len()
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
     where
         Self: TrustedRandomAccessNoCoerce,
index 6ec178b7bd5eaea6b455bdffcc60a0e0a7931a93..cf864039a23bad947491e70efc956af49c63807e 100644 (file)
@@ -419,9 +419,9 @@ pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
 }
 
 #[stable(feature = "alloc_layout", since = "1.28.0")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.52.0",
-    reason = "Name does not follow std convention, use LayoutError",
+    note = "Name does not follow std convention, use LayoutError",
     suggestion = "LayoutError"
 )]
 pub type LayoutErr = LayoutError;
index 242725b96bd9090330f07746d800c48a8d1747ce..a034562d13ab7ad968f5e535e8251d097a53ebdb 100644 (file)
@@ -10,9 +10,9 @@
 #[stable(feature = "alloc_layout", since = "1.28.0")]
 pub use self::layout::Layout;
 #[stable(feature = "alloc_layout", since = "1.28.0")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.52.0",
-    reason = "Name does not follow std convention, use LayoutError",
+    note = "Name does not follow std convention, use LayoutError",
     suggestion = "LayoutError"
 )]
 #[allow(deprecated, deprecated_in_future)]
index e5024c215be9c77829704be7b4675b05254a7b05..5cecc4086d8f3ac6e538fbcfff0e5add75059614 100644 (file)
@@ -79,7 +79,7 @@ fn into_iter(self) -> Self::IntoIter {
 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")]
+    #[deprecated(since = "1.59.0", note = "use `IntoIterator::into_iter` instead")]
     pub fn new(array: [T; N]) -> Self {
         IntoIterator::into_iter(array)
     }
index 2b6ea90bf043019dd9f177fcb313716e8ab42d88..4fa5d129bc6af6ccfa6853c8cc16cf76ea1839dc 100644 (file)
@@ -25,7 +25,6 @@ impl private::Sealed for $Float {}
         $(
             #[unstable(feature = "convert_float_to_int", issue = "67057")]
             impl FloatToInt<$Int> for $Float {
-                #[doc(hidden)]
                 #[inline]
                 unsafe fn to_int_unchecked(self) -> $Int {
                     // SAFETY: the safety contract must be upheld by the caller.
index feedc6456b8b62ec446cbb26b258ecc8f53998f8..700a78cac5ab8abf28a5b088fe517646a3611314 100644 (file)
@@ -19,6 +19,7 @@
 mod num;
 
 #[stable(feature = "fmt_flags_align", since = "1.28.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Alignment")]
 /// Possible alignments returned by `Formatter::align`
 #[derive(Debug)]
 pub enum Alignment {
@@ -462,6 +463,7 @@ pub fn estimated_capacity(&self) -> usize {
 ///
 /// [`format()`]: ../../std/fmt/fn.format.html
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Arguments")]
 #[derive(Copy, Clone)]
 pub struct Arguments<'a> {
     // Format string pieces to print.
@@ -1651,10 +1653,10 @@ pub fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result {
     /// Flags for formatting
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.24.0",
-        reason = "use the `sign_plus`, `sign_minus`, `alternate`, \
-                  or `sign_aware_zero_pad` methods instead"
+        note = "use the `sign_plus`, `sign_minus`, `alternate`, \
+                or `sign_aware_zero_pad` methods instead"
     )]
     pub fn flags(&self) -> u32 {
         self.flags
index 9d64c786d67b5111167a92e3b92d81c4733690fc..3d168f62a09f5ff7e2b5e9e566c598343b0f64e6 100644 (file)
@@ -268,10 +268,29 @@ pub(crate) mod macros {
 /// instance (with [`write`] and [`write_u8`] etc.). Most of the time, `Hasher`
 /// instances are used in conjunction with the [`Hash`] trait.
 ///
-/// This trait makes no assumptions about how the various `write_*` methods are
+/// This trait provides no guarantees about how the various `write_*` methods are
 /// defined and implementations of [`Hash`] should not assume that they work one
 /// way or another. You cannot assume, for example, that a [`write_u32`] call is
-/// equivalent to four calls of [`write_u8`].
+/// equivalent to four calls of [`write_u8`].  Nor can you assume that adjacent
+/// `write` calls are merged, so it's possible, for example, that
+/// ```
+/// # fn foo(hasher: &mut impl std::hash::Hasher) {
+/// hasher.write(&[1, 2]);
+/// hasher.write(&[3, 4, 5, 6]);
+/// # }
+/// ```
+/// and
+/// ```
+/// # fn foo(hasher: &mut impl std::hash::Hasher) {
+/// hasher.write(&[1, 2, 3, 4]);
+/// hasher.write(&[5, 6]);
+/// # }
+/// ```
+/// end up producing different hashes.
+///
+/// Thus to produce the same hash value, [`Hash`] implementations must ensure
+/// for equivalent items that exactly the same sequence of calls is made -- the
+/// same methods with the same parameters in the same order.
 ///
 /// # Examples
 ///
index 9d7daf1f1a075f9cb9a390eafc8fabcb2d44487f..c2ade8c7e54edd246e5b8608e65b50cb77f5e644 100644 (file)
 ///
 /// See: <https://131002.net/siphash>
 #[unstable(feature = "hashmap_internals", issue = "none")]
-#[rustc_deprecated(
-    since = "1.13.0",
-    reason = "use `std::collections::hash_map::DefaultHasher` instead"
-)]
+#[deprecated(since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead")]
 #[derive(Debug, Clone, Default)]
 #[doc(hidden)]
 pub struct SipHasher13 {
@@ -28,10 +25,7 @@ pub struct SipHasher13 {
 ///
 /// See: <https://131002.net/siphash/>
 #[unstable(feature = "hashmap_internals", issue = "none")]
-#[rustc_deprecated(
-    since = "1.13.0",
-    reason = "use `std::collections::hash_map::DefaultHasher` instead"
-)]
+#[deprecated(since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead")]
 #[derive(Debug, Clone, Default)]
 struct SipHasher24 {
     hasher: Hasher<Sip24Rounds>,
@@ -50,10 +44,7 @@ struct SipHasher24 {
 /// it is not intended for cryptographic purposes. As such, all
 /// cryptographic uses of this implementation are _strongly discouraged_.
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "1.13.0",
-    reason = "use `std::collections::hash_map::DefaultHasher` instead"
-)]
+#[deprecated(since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead")]
 #[derive(Debug, Clone, Default)]
 pub struct SipHasher(SipHasher24);
 
@@ -153,9 +144,9 @@ impl SipHasher {
     /// Creates a new `SipHasher` with the two initial keys set to 0.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.13.0",
-        reason = "use `std::collections::hash_map::DefaultHasher` instead"
+        note = "use `std::collections::hash_map::DefaultHasher` instead"
     )]
     #[must_use]
     pub fn new() -> SipHasher {
@@ -165,9 +156,9 @@ pub fn new() -> SipHasher {
     /// Creates a `SipHasher` that is keyed off the provided keys.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.13.0",
-        reason = "use `std::collections::hash_map::DefaultHasher` instead"
+        note = "use `std::collections::hash_map::DefaultHasher` instead"
     )]
     #[must_use]
     pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
@@ -179,9 +170,9 @@ impl SipHasher13 {
     /// Creates a new `SipHasher13` with the two initial keys set to 0.
     #[inline]
     #[unstable(feature = "hashmap_internals", issue = "none")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.13.0",
-        reason = "use `std::collections::hash_map::DefaultHasher` instead"
+        note = "use `std::collections::hash_map::DefaultHasher` instead"
     )]
     pub fn new() -> SipHasher13 {
         SipHasher13::new_with_keys(0, 0)
@@ -190,9 +181,9 @@ pub fn new() -> SipHasher13 {
     /// Creates a `SipHasher13` that is keyed off the provided keys.
     #[inline]
     #[unstable(feature = "hashmap_internals", issue = "none")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.13.0",
-        reason = "use `std::collections::hash_map::DefaultHasher` instead"
+        note = "use `std::collections::hash_map::DefaultHasher` instead"
     )]
     pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
         SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) }
index 4e32c514d5f68fbadbbe12732b48ac5f5658eeab..d1647c388594c83f13606217a943cb9b2a017384 100644 (file)
 use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering};
 
 #[stable(feature = "drop_in_place", since = "1.8.0")]
-#[rustc_deprecated(
-    reason = "no longer an intrinsic - use `ptr::drop_in_place` directly",
-    since = "1.52.0"
-)]
+#[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")]
 #[inline]
 pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     // SAFETY: see `ptr::drop_in_place`
index 71a5a4ea831ffe6a12914a4eee5eebf34a33f3a4..aba24a79dcf7920595ed1f1a70a73f4540011853 100644 (file)
@@ -60,7 +60,6 @@ fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
         self.it.map(T::clone).fold(init, f)
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
     where
         Self: TrustedRandomAccessNoCoerce,
index e5f2886dcafadad5712125962ca5f9418fce1fa2..f9bfd77d7fbbff40bd337cc9e97eb199dc215207 100644 (file)
@@ -81,7 +81,6 @@ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
         self.it.advance_by(n)
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
     where
         Self: TrustedRandomAccessNoCoerce,
index 10b4db84b3904e1a115e50dcb261d86259e17504..14a126951115cd156891c48407431d74beb20af8 100644 (file)
@@ -128,7 +128,6 @@ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
     }
 
     #[rustc_inherit_overflow_checks]
-    #[doc(hidden)]
     #[inline]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
     where
index fbf752c6f2024ac54e959f0ab5815eb6d375e653..8adb53c6714284c1d6376c3114c6f15c92e1d243 100644 (file)
@@ -129,7 +129,6 @@ fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
     }
 
     #[inline]
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
     where
         Self: TrustedRandomAccessNoCoerce,
index 6cbb35dc7c6292ff586bbd36d3b73f64a13c202d..9e25dbe462c91eb3648dd7fd09af0ba99de3b248 100644 (file)
@@ -124,7 +124,6 @@ fn fold<Acc, G>(self, init: Acc, g: G) -> Acc
         self.iter.fold(init, map_fold(self.f, g))
     }
 
-    #[doc(hidden)]
     #[inline]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B
     where
index de44bd66501e20bb3445fdffdb700062d65c00f4..8153c8cfef133aa0c2d246d4b4169335dbeaf965 100644 (file)
@@ -95,7 +95,6 @@ fn nth(&mut self, n: usize) -> Option<Self::Item> {
     }
 
     #[inline]
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
     where
         Self: TrustedRandomAccessNoCoerce,
index 0ae94c05da6583c11d3df41058fa9eee57050202..f7aeee8c9adc6f36ec1f989441ae897b94b4763c 100644 (file)
@@ -752,7 +752,6 @@ fn advance_by(&mut self, n: usize) -> Result<(), usize> {
     }
 
     #[inline]
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
     where
         Self: TrustedRandomAccessNoCoerce,
index d00056f0c32e827945f36f127e6e588821013168..a231f533d190b0660927e7fdcc106830cb5d3ade 100644 (file)
@@ -410,7 +410,7 @@ macro_rules! matches {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "1.39.0", reason = "use the `?` operator instead")]
+#[deprecated(since = "1.39.0", note = "use the `?` operator instead")]
 #[doc(alias = "?")]
 macro_rules! r#try {
     ($expr:expr $(,)?) => {
@@ -1536,10 +1536,7 @@ macro_rules! trace_macros {
     #[rustc_builtin_macro]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[allow_internal_unstable(core_intrinsics, libstd_sys_internals)]
-    #[rustc_deprecated(
-        since = "1.52.0",
-        reason = "rustc-serialize is deprecated and no longer supported"
-    )]
+    #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")]
     #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
     pub macro RustcDecodable($item:item) {
         /* compiler built-in */
@@ -1549,10 +1546,7 @@ macro_rules! trace_macros {
     #[rustc_builtin_macro]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[allow_internal_unstable(core_intrinsics)]
-    #[rustc_deprecated(
-        since = "1.52.0",
-        reason = "rustc-serialize is deprecated and no longer supported"
-    )]
+    #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")]
     #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
     pub macro RustcEncodable($item:item) {
         /* compiler built-in */
index 712d06f217034967d47d8c2d532af643d6e87215..4ce7c8c2b607b1a629739d8b004348abcca07bd0 100644 (file)
@@ -408,7 +408,7 @@ pub const fn size_of_val<T: ?Sized>(val: &T) -> usize {
 #[inline]
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
+#[deprecated(note = "use `align_of` instead", since = "1.2.0")]
 pub fn min_align_of<T>() -> usize {
     intrinsics::min_align_of::<T>()
 }
@@ -431,7 +431,7 @@ pub fn min_align_of<T>() -> usize {
 #[inline]
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(reason = "use `align_of_val` instead", since = "1.2.0")]
+#[deprecated(note = "use `align_of_val` instead", since = "1.2.0")]
 pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
     // SAFETY: val is a reference, so it's a valid raw pointer
     unsafe { intrinsics::min_align_of_val(val) }
@@ -673,7 +673,7 @@ pub unsafe fn zeroed<T>() -> T {
 /// [inv]: MaybeUninit#initialization-invariant
 #[inline(always)]
 #[must_use]
-#[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")]
+#[deprecated(since = "1.39.0", note = "use `mem::MaybeUninit` instead")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated_in_future)]
 #[allow(deprecated)]
index e1a46086af060407134011f5bacce82997acd4d4..6548ad2e514fbacd9d2f25825c8c5726c7c3a0ff 100644 (file)
@@ -31,7 +31,7 @@
 /// let r = f32::RADIX;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `RADIX` associated constant on `f32`")]
+#[deprecated(since = "TBD", note = "replaced by the `RADIX` associated constant on `f32`")]
 pub const RADIX: u32 = f32::RADIX;
 
 /// Number of significant digits in base 2.
@@ -48,9 +48,9 @@
 /// let d = f32::MANTISSA_DIGITS;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
+#[deprecated(
     since = "TBD",
-    reason = "replaced by the `MANTISSA_DIGITS` associated constant on `f32`"
+    note = "replaced by the `MANTISSA_DIGITS` associated constant on `f32`"
 )]
 pub const MANTISSA_DIGITS: u32 = f32::MANTISSA_DIGITS;
 
@@ -68,7 +68,7 @@
 /// let d = f32::DIGITS;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `DIGITS` associated constant on `f32`")]
+#[deprecated(since = "TBD", note = "replaced by the `DIGITS` associated constant on `f32`")]
 pub const DIGITS: u32 = f32::DIGITS;
 
 /// [Machine epsilon] value for `f32`.
 /// let e = f32::EPSILON;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `EPSILON` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `EPSILON` associated constant on `f32`")]
 pub const EPSILON: f32 = f32::EPSILON;
 
 /// Smallest finite `f32` value.
 /// let min = f32::MIN;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on `f32`")]
+#[deprecated(since = "TBD", note = "replaced by the `MIN` associated constant on `f32`")]
 pub const MIN: f32 = f32::MIN;
 
 /// Smallest positive normal `f32` value.
 /// let min = f32::MIN_POSITIVE;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MIN_POSITIVE` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MIN_POSITIVE` associated constant on `f32`")]
 pub const MIN_POSITIVE: f32 = f32::MIN_POSITIVE;
 
 /// Largest finite `f32` value.
 /// let max = f32::MAX;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on `f32`")]
+#[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on `f32`")]
 pub const MAX: f32 = f32::MAX;
 
 /// One greater than the minimum possible normal power of 2 exponent.
 /// let min = f32::MIN_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MIN_EXP` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MIN_EXP` associated constant on `f32`")]
 pub const MIN_EXP: i32 = f32::MIN_EXP;
 
 /// Maximum possible power of 2 exponent.
 /// let max = f32::MAX_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MAX_EXP` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MAX_EXP` associated constant on `f32`")]
 pub const MAX_EXP: i32 = f32::MAX_EXP;
 
 /// Minimum possible normal power of 10 exponent.
 /// let min = f32::MIN_10_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MIN_10_EXP` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MIN_10_EXP` associated constant on `f32`")]
 pub const MIN_10_EXP: i32 = f32::MIN_10_EXP;
 
 /// Maximum possible power of 10 exponent.
 /// let max = f32::MAX_10_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MAX_10_EXP` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MAX_10_EXP` associated constant on `f32`")]
 pub const MAX_10_EXP: i32 = f32::MAX_10_EXP;
 
 /// Not a Number (NaN).
 /// let nan = f32::NAN;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `NAN` associated constant on `f32`")]
+#[deprecated(since = "TBD", note = "replaced by the `NAN` associated constant on `f32`")]
 pub const NAN: f32 = f32::NAN;
 
 /// Infinity (∞).
 /// let inf = f32::INFINITY;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `INFINITY` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `INFINITY` associated constant on `f32`")]
 pub const INFINITY: f32 = f32::INFINITY;
 
 /// Negative infinity (−∞).
 /// let ninf = f32::NEG_INFINITY;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `NEG_INFINITY` associated constant on `f32`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `NEG_INFINITY` associated constant on `f32`")]
 pub const NEG_INFINITY: f32 = f32::NEG_INFINITY;
 
 /// Basic mathematical constants.
@@ -417,6 +393,15 @@ impl f32 {
     pub const MAX_10_EXP: i32 = 38;
 
     /// Not a Number (NaN).
+    ///
+    /// Note that IEEE-745 doesn't define just a single NaN value;
+    /// a plethora of bit patterns are considered to be NaN.
+    /// Furthermore, the standard makes a difference
+    /// between a "signaling" and a "quiet" NaN,
+    /// and allows inspecting its "payload" (the unspecified bits in the bit pattern).
+    /// This constant isn't guaranteed to equal to any specific NaN bitpattern,
+    /// and the stability of its representation over Rust versions
+    /// and target platforms isn't guaranteed.
     #[stable(feature = "assoc_int_consts", since = "1.43.0")]
     pub const NAN: f32 = 0.0_f32 / 0.0_f32;
     /// Infinity (∞).
@@ -426,7 +411,7 @@ impl f32 {
     #[stable(feature = "assoc_int_consts", since = "1.43.0")]
     pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32;
 
-    /// Returns `true` if this value is `NaN`.
+    /// Returns `true` if this value is NaN.
     ///
     /// ```
     /// let nan = f32::NAN;
@@ -479,7 +464,7 @@ pub const fn is_infinite(self) -> bool {
         (self == f32::INFINITY) | (self == f32::NEG_INFINITY)
     }
 
-    /// Returns `true` if this number is neither infinite nor `NaN`.
+    /// Returns `true` if this number is neither infinite nor NaN.
     ///
     /// ```
     /// let f = 7.0f32;
@@ -530,7 +515,7 @@ pub const fn is_subnormal(self) -> bool {
     }
 
     /// Returns `true` if the number is neither zero, infinite,
-    /// [subnormal], or `NaN`.
+    /// [subnormal], or NaN.
     ///
     /// ```
     /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32
@@ -646,8 +631,12 @@ const fn classify_bits(b: u32) -> FpCategory {
         }
     }
 
-    /// Returns `true` if `self` has a positive sign, including `+0.0`, `NaN`s with
-    /// positive sign bit and positive infinity.
+    /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
+    /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any
+    /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
+    /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
+    /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
+    /// See [explanation of NaN as a special value](f32) for more info.
     ///
     /// ```
     /// let f = 7.0_f32;
@@ -664,8 +653,12 @@ pub const fn is_sign_positive(self) -> bool {
         !self.is_sign_negative()
     }
 
-    /// Returns `true` if `self` has a negative sign, including `-0.0`, `NaN`s with
-    /// negative sign bit and negative infinity.
+    /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
+    /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any
+    /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
+    /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
+    /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
+    /// See [explanation of NaN as a special value](f32) for more info.
     ///
     /// ```
     /// let f = 7.0f32;
@@ -737,10 +730,12 @@ pub fn to_radians(self) -> f32 {
         self * (value / 180.0f32)
     }
 
-    /// Returns the maximum of the two numbers.
+    /// Returns the maximum of the two numbers, ignoring NaN.
     ///
-    /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
-    /// This matches the behavior of libm’s fmax.
+    /// If one of the arguments is NaN, then the other argument is returned.
+    /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs;
+    /// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
+    /// This also matches the behavior of libm’s fmax.
     ///
     /// ```
     /// let x = 1.0f32;
@@ -748,8 +743,6 @@ pub fn to_radians(self) -> f32 {
     ///
     /// assert_eq!(x.max(y), y);
     /// ```
-    ///
-    /// If one of the arguments is NaN, then the other argument is returned.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -757,10 +750,12 @@ pub fn max(self, other: f32) -> f32 {
         intrinsics::maxnumf32(self, other)
     }
 
-    /// Returns the minimum of the two numbers.
+    /// Returns the minimum of the two numbers, ignoring NaN.
     ///
-    /// Follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs.
-    /// This matches the behavior of libm’s fmin.
+    /// If one of the arguments is NaN, then the other argument is returned.
+    /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs;
+    /// this function handles all NaNs the same way and avoids minNum's problems with associativity.
+    /// This also matches the behavior of libm’s fmin.
     ///
     /// ```
     /// let x = 1.0f32;
@@ -768,8 +763,6 @@ pub fn max(self, other: f32) -> f32 {
     ///
     /// assert_eq!(x.min(y), x);
     /// ```
-    ///
-    /// If one of the arguments is NaN, then the other argument is returned.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -777,7 +770,7 @@ pub fn min(self, other: f32) -> f32 {
         intrinsics::minnumf32(self, other)
     }
 
-    /// Returns the maximum of the two numbers, propagating NaNs.
+    /// Returns the maximum of the two numbers, propagating NaN.
     ///
     /// This returns NaN when *either* argument is NaN, as opposed to
     /// [`f32::max`] which only returns NaN when *both* arguments are NaN.
@@ -794,6 +787,9 @@ pub fn min(self, other: f32) -> f32 {
     /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
     /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
     /// Note that this follows the semantics specified in IEEE 754-2019.
+    ///
+    /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
+    /// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
@@ -809,7 +805,7 @@ pub fn maximum(self, other: f32) -> f32 {
         }
     }
 
-    /// Returns the minimum of the two numbers, propagating NaNs.
+    /// Returns the minimum of the two numbers, propagating NaN.
     ///
     /// This returns NaN when *either* argument is NaN, as opposed to
     /// [`f32::min`] which only returns NaN when *both* arguments are NaN.
@@ -826,6 +822,9 @@ pub fn maximum(self, other: f32) -> f32 {
     /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
     /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
     /// Note that this follows the semantics specified in IEEE 754-2019.
+    ///
+    /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
+    /// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
@@ -1033,6 +1032,9 @@ const fn ct_u32_to_f32(ct: u32) -> f32 {
     /// Return the memory representation of this floating point number as a byte array in
     /// big-endian (network) byte order.
     ///
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
     /// # Examples
     ///
     /// ```
@@ -1051,6 +1053,9 @@ const fn ct_u32_to_f32(ct: u32) -> f32 {
     /// Return the memory representation of this floating point number as a byte array in
     /// little-endian byte order.
     ///
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
     /// # Examples
     ///
     /// ```
@@ -1075,6 +1080,9 @@ const fn ct_u32_to_f32(ct: u32) -> f32 {
     /// [`to_be_bytes`]: f32::to_be_bytes
     /// [`to_le_bytes`]: f32::to_le_bytes
     ///
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
     /// # Examples
     ///
     /// ```
@@ -1099,6 +1107,9 @@ const fn ct_u32_to_f32(ct: u32) -> f32 {
 
     /// Create a floating point value from its representation as a byte array in big endian.
     ///
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
     /// # Examples
     ///
     /// ```
@@ -1115,6 +1126,9 @@ const fn ct_u32_to_f32(ct: u32) -> f32 {
 
     /// Create a floating point value from its representation as a byte array in little endian.
     ///
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
     /// # Examples
     ///
     /// ```
@@ -1138,6 +1152,9 @@ const fn ct_u32_to_f32(ct: u32) -> f32 {
     /// [`from_be_bytes`]: f32::from_be_bytes
     /// [`from_le_bytes`]: f32::from_le_bytes
     ///
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
     /// # Examples
     ///
     /// ```
index b07f201ca4ad282aa08069d21ed06e25586fc761..75c92c2f8834a215fcbefa75c4d89f50e7fa79a6 100644 (file)
@@ -31,7 +31,7 @@
 /// let r = f64::RADIX;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `RADIX` associated constant on `f64`")]
+#[deprecated(since = "TBD", note = "replaced by the `RADIX` associated constant on `f64`")]
 pub const RADIX: u32 = f64::RADIX;
 
 /// Number of significant digits in base 2.
@@ -48,9 +48,9 @@
 /// let d = f64::MANTISSA_DIGITS;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
+#[deprecated(
     since = "TBD",
-    reason = "replaced by the `MANTISSA_DIGITS` associated constant on `f64`"
+    note = "replaced by the `MANTISSA_DIGITS` associated constant on `f64`"
 )]
 pub const MANTISSA_DIGITS: u32 = f64::MANTISSA_DIGITS;
 
@@ -68,7 +68,7 @@
 /// let d = f64::DIGITS;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `DIGITS` associated constant on `f64`")]
+#[deprecated(since = "TBD", note = "replaced by the `DIGITS` associated constant on `f64`")]
 pub const DIGITS: u32 = f64::DIGITS;
 
 /// [Machine epsilon] value for `f64`.
 /// let e = f64::EPSILON;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `EPSILON` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `EPSILON` associated constant on `f64`")]
 pub const EPSILON: f64 = f64::EPSILON;
 
 /// Smallest finite `f64` value.
 /// let min = f64::MIN;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on `f64`")]
+#[deprecated(since = "TBD", note = "replaced by the `MIN` associated constant on `f64`")]
 pub const MIN: f64 = f64::MIN;
 
 /// Smallest positive normal `f64` value.
 /// let min = f64::MIN_POSITIVE;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MIN_POSITIVE` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MIN_POSITIVE` associated constant on `f64`")]
 pub const MIN_POSITIVE: f64 = f64::MIN_POSITIVE;
 
 /// Largest finite `f64` value.
 /// let max = f64::MAX;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on `f64`")]
+#[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on `f64`")]
 pub const MAX: f64 = f64::MAX;
 
 /// One greater than the minimum possible normal power of 2 exponent.
 /// let min = f64::MIN_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MIN_EXP` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MIN_EXP` associated constant on `f64`")]
 pub const MIN_EXP: i32 = f64::MIN_EXP;
 
 /// Maximum possible power of 2 exponent.
 /// let max = f64::MAX_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MAX_EXP` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MAX_EXP` associated constant on `f64`")]
 pub const MAX_EXP: i32 = f64::MAX_EXP;
 
 /// Minimum possible normal power of 10 exponent.
 /// let min = f64::MIN_10_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MIN_10_EXP` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MIN_10_EXP` associated constant on `f64`")]
 pub const MIN_10_EXP: i32 = f64::MIN_10_EXP;
 
 /// Maximum possible power of 10 exponent.
 /// let max = f64::MAX_10_EXP;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `MAX_10_EXP` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `MAX_10_EXP` associated constant on `f64`")]
 pub const MAX_10_EXP: i32 = f64::MAX_10_EXP;
 
 /// Not a Number (NaN).
 /// let nan = f64::NAN;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "TBD", reason = "replaced by the `NAN` associated constant on `f64`")]
+#[deprecated(since = "TBD", note = "replaced by the `NAN` associated constant on `f64`")]
 pub const NAN: f64 = f64::NAN;
 
 /// Infinity (∞).
 /// let inf = f64::INFINITY;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `INFINITY` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `INFINITY` associated constant on `f64`")]
 pub const INFINITY: f64 = f64::INFINITY;
 
 /// Negative infinity (−∞).
 /// let ninf = f64::NEG_INFINITY;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
-    since = "TBD",
-    reason = "replaced by the `NEG_INFINITY` associated constant on `f64`"
-)]
+#[deprecated(since = "TBD", note = "replaced by the `NEG_INFINITY` associated constant on `f64`")]
 pub const NEG_INFINITY: f64 = f64::NEG_INFINITY;
 
 /// Basic mathematical constants.
@@ -416,6 +392,15 @@ impl f64 {
     pub const MAX_10_EXP: i32 = 308;
 
     /// Not a Number (NaN).
+    ///
+    /// Note that IEEE-745 doesn't define just a single NaN value;
+    /// a plethora of bit patterns are considered to be NaN.
+    /// Furthermore, the standard makes a difference
+    /// between a "signaling" and a "quiet" NaN,
+    /// and allows inspecting its "payload" (the unspecified bits in the bit pattern).
+    /// This constant isn't guaranteed to equal to any specific NaN bitpattern,
+    /// and the stability of its representation over Rust versions
+    /// and target platforms isn't guaranteed.
     #[stable(feature = "assoc_int_consts", since = "1.43.0")]
     pub const NAN: f64 = 0.0_f64 / 0.0_f64;
     /// Infinity (∞).
@@ -425,7 +410,7 @@ impl f64 {
     #[stable(feature = "assoc_int_consts", since = "1.43.0")]
     pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64;
 
-    /// Returns `true` if this value is `NaN`.
+    /// Returns `true` if this value is NaN.
     ///
     /// ```
     /// let nan = f64::NAN;
@@ -480,7 +465,7 @@ pub const fn is_infinite(self) -> bool {
         (self == f64::INFINITY) | (self == f64::NEG_INFINITY)
     }
 
-    /// Returns `true` if this number is neither infinite nor `NaN`.
+    /// Returns `true` if this number is neither infinite nor NaN.
     ///
     /// ```
     /// let f = 7.0f64;
@@ -531,7 +516,7 @@ pub const fn is_subnormal(self) -> bool {
     }
 
     /// Returns `true` if the number is neither zero, infinite,
-    /// [subnormal], or `NaN`.
+    /// [subnormal], or NaN.
     ///
     /// ```
     /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64
@@ -638,8 +623,12 @@ const fn classify_bits(b: u64) -> FpCategory {
         }
     }
 
-    /// Returns `true` if `self` has a positive sign, including `+0.0`, `NaN`s with
-    /// positive sign bit and positive infinity.
+    /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
+    /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any
+    /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
+    /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
+    /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
+    /// See [explanation of NaN as a special value](f32) for more info.
     ///
     /// ```
     /// let f = 7.0_f64;
@@ -658,15 +647,19 @@ pub const fn is_sign_positive(self) -> bool {
 
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")]
+    #[deprecated(since = "1.0.0", note = "renamed to is_sign_positive")]
     #[inline]
     #[doc(hidden)]
     pub fn is_positive(self) -> bool {
         self.is_sign_positive()
     }
 
-    /// Returns `true` if `self` has a negative sign, including `-0.0`, `NaN`s with
-    /// negative sign bit and negative infinity.
+    /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
+    /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any
+    /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
+    /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
+    /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
+    /// See [explanation of NaN as a special value](f32) for more info.
     ///
     /// ```
     /// let f = 7.0_f64;
@@ -688,7 +681,7 @@ pub const fn is_sign_negative(self) -> bool {
 
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")]
+    #[deprecated(since = "1.0.0", note = "renamed to is_sign_negative")]
     #[inline]
     #[doc(hidden)]
     pub fn is_negative(self) -> bool {
@@ -748,10 +741,12 @@ pub fn to_radians(self) -> f64 {
         self * (value / 180.0)
     }
 
-    /// Returns the maximum of the two numbers.
+    /// Returns the maximum of the two numbers, ignoring NaN.
     ///
-    /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
-    /// This matches the behavior of libm’s fmax.
+    /// If one of the arguments is NaN, then the other argument is returned.
+    /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs;
+    /// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
+    /// This also matches the behavior of libm’s fmax.
     ///
     /// ```
     /// let x = 1.0_f64;
@@ -759,8 +754,6 @@ pub fn to_radians(self) -> f64 {
     ///
     /// assert_eq!(x.max(y), y);
     /// ```
-    ///
-    /// If one of the arguments is NaN, then the other argument is returned.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -768,10 +761,12 @@ pub fn max(self, other: f64) -> f64 {
         intrinsics::maxnumf64(self, other)
     }
 
-    /// Returns the minimum of the two numbers.
+    /// Returns the minimum of the two numbers, ignoring NaN.
     ///
-    /// Follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs.
-    /// This matches the behavior of libm’s fmin.
+    /// If one of the arguments is NaN, then the other argument is returned.
+    /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs;
+    /// this function handles all NaNs the same way and avoids minNum's problems with associativity.
+    /// This also matches the behavior of libm’s fmin.
     ///
     /// ```
     /// let x = 1.0_f64;
@@ -779,8 +774,6 @@ pub fn max(self, other: f64) -> f64 {
     ///
     /// assert_eq!(x.min(y), x);
     /// ```
-    ///
-    /// If one of the arguments is NaN, then the other argument is returned.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -788,7 +781,7 @@ pub fn min(self, other: f64) -> f64 {
         intrinsics::minnumf64(self, other)
     }
 
-    /// Returns the maximum of the two numbers, propagating NaNs.
+    /// Returns the maximum of the two numbers, propagating NaN.
     ///
     /// This returns NaN when *either* argument is NaN, as opposed to
     /// [`f64::max`] which only returns NaN when *both* arguments are NaN.
@@ -805,6 +798,9 @@ pub fn min(self, other: f64) -> f64 {
     /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
     /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
     /// Note that this follows the semantics specified in IEEE 754-2019.
+    ///
+    /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
+    /// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
@@ -820,7 +816,7 @@ pub fn maximum(self, other: f64) -> f64 {
         }
     }
 
-    /// Returns the minimum of the two numbers, propagating NaNs.
+    /// Returns the minimum of the two numbers, propagating NaN.
     ///
     /// This returns NaN when *either* argument is NaN, as opposed to
     /// [`f64::min`] which only returns NaN when *both* arguments are NaN.
@@ -837,6 +833,9 @@ pub fn maximum(self, other: f64) -> f64 {
     /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
     /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
     /// Note that this follows the semantics specified in IEEE 754-2019.
+    ///
+    /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
+    /// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
     #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
@@ -1031,6 +1030,9 @@ const fn ct_u64_to_f64(ct: u64) -> f64 {
     /// Return the memory representation of this floating point number as a byte array in
     /// big-endian (network) byte order.
     ///
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
     /// # Examples
     ///
     /// ```
@@ -1049,6 +1051,9 @@ const fn ct_u64_to_f64(ct: u64) -> f64 {
     /// Return the memory representation of this floating point number as a byte array in
     /// little-endian byte order.
     ///
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
     /// # Examples
     ///
     /// ```
@@ -1073,6 +1078,9 @@ const fn ct_u64_to_f64(ct: u64) -> f64 {
     /// [`to_be_bytes`]: f64::to_be_bytes
     /// [`to_le_bytes`]: f64::to_le_bytes
     ///
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
     /// # Examples
     ///
     /// ```
@@ -1097,6 +1105,9 @@ const fn ct_u64_to_f64(ct: u64) -> f64 {
 
     /// Create a floating point value from its representation as a byte array in big endian.
     ///
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
     /// # Examples
     ///
     /// ```
@@ -1113,6 +1124,9 @@ const fn ct_u64_to_f64(ct: u64) -> f64 {
 
     /// Create a floating point value from its representation as a byte array in little endian.
     ///
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
     /// # Examples
     ///
     /// ```
@@ -1136,6 +1150,9 @@ const fn ct_u64_to_f64(ct: u64) -> f64 {
     /// [`from_be_bytes`]: f64::from_be_bytes
     /// [`from_le_bytes`]: f64::from_le_bytes
     ///
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
+    ///
     /// # Examples
     ///
     /// ```
index b5c7982a5a871170a21dcdb1395fc827313a2bc0..1f435784be14cd088811357c079606fcae88a52e 100644 (file)
@@ -2717,7 +2717,7 @@ pub const fn is_negative(self) -> bool { self < 0 }
         #[inline(always)]
         #[rustc_promotable]
         #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")]
-        #[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on this type")]
+        #[deprecated(since = "TBD", note = "replaced by the `MIN` associated constant on this type")]
         pub const fn min_value() -> Self {
             Self::MIN
         }
@@ -2730,7 +2730,7 @@ pub const fn min_value() -> Self {
         #[inline(always)]
         #[rustc_promotable]
         #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
-        #[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on this type")]
+        #[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on this type")]
         pub const fn max_value() -> Self {
             Self::MAX
         }
index b37767cd5eb6d9355051ba1fefb7195df4329aab..7b048dc5206bc92fae88c12aef4a210e18e3b994 100644 (file)
@@ -5,9 +5,9 @@
 //! New code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "i128", since = "1.26.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `i128`"
+    note = "all constants in this module replaced by associated constants on `i128`"
 )]
 
 int_module! { i128, #[stable(feature = "i128", since="1.26.0")] }
index 3137e72ca00e5b6dba05a0b12a37669ccefc3a14..5c5812d5c5ecd9233de3e1104afdb504d119b731 100644 (file)
@@ -5,9 +5,9 @@
 //! New code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `i16`"
+    note = "all constants in this module replaced by associated constants on `i16`"
 )]
 
 int_module! { i16 }
index bb70751d8ca1aed0df6f983dcb6b93884fccb917..b283ac64415f60984352a6217b7c8ebaedd9449a 100644 (file)
@@ -5,9 +5,9 @@
 //! New code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `i32`"
+    note = "all constants in this module replaced by associated constants on `i32`"
 )]
 
 int_module! { i32 }
index b08201c2555a88da3214c4705c01440aad386012..a416fa7e9361d38a9ea155d8f46c147745998bb3 100644 (file)
@@ -5,9 +5,9 @@
 //! New code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `i64`"
+    note = "all constants in this module replaced by associated constants on `i64`"
 )]
 
 int_module! { i64 }
index a7ad9bbbbceb84fb34edf84bcc6818c4c4e58012..02465013a4a77b56368ae2656fce22dcff5dd053 100644 (file)
@@ -5,9 +5,9 @@
 //! New code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `i8`"
+    note = "all constants in this module replaced by associated constants on `i8`"
 )]
 
 int_module! { i8 }
index c6a5595d95804b7f2a8f5bb7562cd06ae0d0c539..2b1133e11a571e910a88c59bb78b0c0169a0a381 100644 (file)
@@ -19,7 +19,7 @@ macro_rules! int_module {
         /// ```
         ///
         #[$attr]
-        #[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on this type")]
+        #[deprecated(since = "TBD", note = "replaced by the `MIN` associated constant on this type")]
         pub const MIN: $T = $T::MIN;
 
         #[doc = concat!(
@@ -38,7 +38,7 @@ macro_rules! int_module {
         /// ```
         ///
         #[$attr]
-        #[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on this type")]
+        #[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on this type")]
         pub const MAX: $T = $T::MAX;
     )
 }
index d719936c0b2c0972e6084f64ea7d4f7e8d3fa9ed..1579fbab6d47f454c46f7de60dd34365a0b5d6d8 100644 (file)
@@ -5,9 +5,9 @@
 //! New code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `isize`"
+    note = "all constants in this module replaced by associated constants on `isize`"
 )]
 
 int_module! { isize }
index 49f56c67c37a8e77e5f5afc997053c16e12e8bc5..fe08cee586c3d660eb493aadb1e8214686413ae2 100644 (file)
@@ -5,9 +5,9 @@
 //! New code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "i128", since = "1.26.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `u128`"
+    note = "all constants in this module replaced by associated constants on `u128`"
 )]
 
 int_module! { u128, #[stable(feature = "i128", since="1.26.0")] }
index b1d58ad4b9d8de2ad433157d8dbc6ec04df249dc..36f8c6978789d1148788afbec20ecc929d707524 100644 (file)
@@ -5,9 +5,9 @@
 //! New code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `u16`"
+    note = "all constants in this module replaced by associated constants on `u16`"
 )]
 
 int_module! { u16 }
index b6acf950035f4270a4b358179f7372b634caa5d5..1c369097dcdb0c06c0452d8c328a48d82e1f04f0 100644 (file)
@@ -5,9 +5,9 @@
 //! New code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `u32`"
+    note = "all constants in this module replaced by associated constants on `u32`"
 )]
 
 int_module! { u32 }
index d43726f84fa2fdccc5572706290ca406e1fba8e0..e8b691d155572f44915ea859c0c660b3f9e93dd3 100644 (file)
@@ -5,9 +5,9 @@
 //! New code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `u64`"
+    note = "all constants in this module replaced by associated constants on `u64`"
 )]
 
 int_module! { u64 }
index 0eadf85ec6d275262e867fd56d5e151336773968..817c6a18aaaa3e7cc41d2df44c7574823426629e 100644 (file)
@@ -5,9 +5,9 @@
 //! New code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `u8`"
+    note = "all constants in this module replaced by associated constants on `u8`"
 )]
 
 int_module! { u8 }
index deeed67d4960fe757339b5a0c488cec75a5f0da8..3e1bec5ec481515b27cca53cda8c9eb70d7d6923 100644 (file)
@@ -5,9 +5,9 @@
 //! New code should use the associated constants directly on the primitive type.
 
 #![stable(feature = "rust1", since = "1.0.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "TBD",
-    reason = "all constants in this module replaced by associated constants on `usize`"
+    note = "all constants in this module replaced by associated constants on `usize`"
 )]
 
 int_module! { usize }
index 048d6bafcdecd018dae127660878b36dfe565023..cd4b0e18c4dffd0eb68345b2773d30439910b199 100644 (file)
@@ -2431,7 +2431,7 @@ pub const fn wrapping_next_power_of_two(self) -> Self {
         #[rustc_promotable]
         #[inline(always)]
         #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
-        #[rustc_deprecated(since = "TBD", reason = "replaced by the `MIN` associated constant on this type")]
+        #[deprecated(since = "TBD", note = "replaced by the `MIN` associated constant on this type")]
         pub const fn min_value() -> Self { Self::MIN }
 
         /// New code should prefer to use
@@ -2442,7 +2442,7 @@ pub const fn min_value() -> Self { Self::MIN }
         #[rustc_promotable]
         #[inline(always)]
         #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")]
-        #[rustc_deprecated(since = "TBD", reason = "replaced by the `MAX` associated constant on this type")]
+        #[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on this type")]
         pub const fn max_value() -> Self { Self::MAX }
     }
 }
index 225a679efd22132ced410bf29008fbd7e3212ee0..ac4e668112b94a1248a4141353e033682123eb14 100644 (file)
@@ -977,10 +977,22 @@ mod prim_tuple {}
 ///   like `1.0 / 0.0`.
 /// - [NaN (not a number)](#associatedconstant.NAN): this value results from
 ///   calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected
-///   behavior: it is unequal to any float, including itself! It is also neither
-///   smaller nor greater than any float, making it impossible to sort. Lastly,
-///   it is considered infectious as almost all calculations where one of the
-///   operands is NaN will also result in NaN.
+///   behavior:
+///   - It is unequal to any float, including itself! This is the reason `f32`
+///     doesn't implement the `Eq` trait.
+///   - It is also neither smaller nor greater than any float, making it
+///     impossible to sort by the default comparison operation, which is the
+///     reason `f32` doesn't implement the `Ord` trait.
+///   - It is also considered *infectious* as almost all calculations where one
+///     of the operands is NaN will also result in NaN. The explanations on this
+///     page only explicitly document behavior on NaN operands if this default
+///     is deviated from.
+///   - Lastly, there are multiple bit patterns that are considered NaN.
+///     Rust does not currently guarantee that the bit patterns of NaN are
+///     preserved over arithmetic operations, and they are not guaranteed to be
+///     portable or even fully deterministic! This means that there may be some
+///     surprising results upon inspecting the bit patterns,
+///     as the same calculations might produce NaNs with different bit patterns.
 ///
 /// For more information on floating point numbers, see [Wikipedia][wikipedia].
 ///
index ff5207c1a06e1cd09e48d915ff435f5ebcc06fd7..ed80cdc9bf9e1508e4a61bfc880c4659b7d7553d 100644 (file)
@@ -287,7 +287,7 @@ pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
     /// For the mutable counterpart see [`as_mut`].
     ///
     /// [`as_uninit_ref`]: #method.as_uninit_ref-1
-    /// [`as_mut`]: #method.as_mut
+    /// [`as_mut`]: #method.as_mut-1
     ///
     /// # Safety
     ///
index 5ebe61509063f3a7807bacdc5ace278d7666366b..9946db67db918d66ca2a90d0f7af229b5865ac70 100644 (file)
@@ -9,7 +9,7 @@
 use crate::ptr::Unique;
 use crate::slice::{self, SliceIndex};
 
-/// `*mut T` but non-zero and covariant.
+/// `*mut T` but non-zero and [covariant].
 ///
 /// This is often the correct thing to use when building data structures using
 /// raw pointers, but is ultimately more dangerous to use because of its additional
@@ -42,6 +42,7 @@
 /// it is your responsibility to ensure that `as_mut` is never called, and `as_ptr`
 /// is never used for mutation.
 ///
+/// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
 /// [`PhantomData`]: crate::marker::PhantomData
 /// [`UnsafeCell<T>`]: crate::cell::UnsafeCell
 #[stable(feature = "nonnull", since = "1.25.0")]
index 98dd1521d0e85bea969b63d583f976bd74a023ee..772a9698d84cc9b930d2e73f1cfe8125d33e027c 100644 (file)
@@ -1322,7 +1322,6 @@ fn last(self) -> Option<Self::Item> {
         }
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         // SAFETY: since the caller guarantees that `i` is in bounds,
         // which means that `i` cannot overflow an `isize`, and the
@@ -1478,7 +1477,6 @@ fn last(self) -> Option<Self::Item> {
         }
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         let start = idx * self.chunk_size;
         // SAFETY: the caller guarantees that `i` is in bounds,
@@ -1657,7 +1655,6 @@ fn last(self) -> Option<Self::Item> {
         }
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         let start = idx * self.chunk_size;
         // SAFETY: see comments for `Chunks::__iterator_get_unchecked`.
@@ -1830,7 +1827,6 @@ fn last(mut self) -> Option<Self::Item> {
         self.next_back()
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         let start = idx * self.chunk_size;
         // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`.
@@ -1984,7 +1980,6 @@ fn last(mut self) -> Option<Self::Item> {
         self.next_back()
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         let start = idx * self.chunk_size;
         // SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`.
@@ -2248,7 +2243,6 @@ fn last(self) -> Option<Self::Item> {
         self.iter.last()
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] {
         // SAFETY: The safety guarantees of `__iterator_get_unchecked` are
         // transferred to the caller.
@@ -2367,7 +2361,6 @@ fn last(self) -> Option<Self::Item> {
         self.iter.last()
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a mut [T; N] {
         // SAFETY: The safety guarantees of `__iterator_get_unchecked` are transferred to
         // the caller.
@@ -2520,7 +2513,6 @@ fn last(self) -> Option<Self::Item> {
         }
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         let end = self.v.len() - idx * self.chunk_size;
         let start = match end.checked_sub(self.chunk_size) {
@@ -2689,7 +2681,6 @@ fn last(self) -> Option<Self::Item> {
         }
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         let end = self.v.len() - idx * self.chunk_size;
         let start = match end.checked_sub(self.chunk_size) {
@@ -2856,7 +2847,6 @@ fn last(mut self) -> Option<Self::Item> {
         self.next_back()
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         let end = self.v.len() - idx * self.chunk_size;
         let start = end - self.chunk_size;
@@ -3016,7 +3006,6 @@ fn last(mut self) -> Option<Self::Item> {
         self.next_back()
     }
 
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         let end = self.v.len() - idx * self.chunk_size;
         let start = end - self.chunk_size;
index 78bf3381b4d269f8e6be66741896f2a05046023f..c05242222dde7e54c1b4b5477a2efb397073593b 100644 (file)
@@ -325,7 +325,6 @@ fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
                 None
             }
 
-            #[doc(hidden)]
             #[inline]
             unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
                 // SAFETY: the caller must guarantee that `i` is in bounds of
index e529bccbc7999ee1ea852e4cc6cd90cab17101cc..24083ee6af44f34f2362df3913445b5c906a0aae 100644 (file)
@@ -298,7 +298,6 @@ fn rposition<P>(&mut self, predicate: P) -> Option<usize>
     }
 
     #[inline]
-    #[doc(hidden)]
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 {
         // SAFETY: the caller must uphold the safety contract
         // for `Iterator::__iterator_get_unchecked`.
@@ -1129,7 +1128,7 @@ impl FusedIterator for Lines<'_> {}
 ///
 /// [`lines_any`]: str::lines_any
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")]
+#[deprecated(since = "1.4.0", note = "use lines()/Lines instead now")]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[derive(Clone, Debug)]
 #[allow(deprecated)]
index 86e1afa288535e8fcb468eb27d006b3a21c485a6..ede9a28dcbe7c2f10ffc75eb7814ca96277fb75c 100644 (file)
@@ -591,7 +591,7 @@ pub const fn get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")]
+    #[deprecated(since = "1.29.0", note = "use `get_unchecked(begin..end)` instead")]
     #[must_use]
     #[inline]
     pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
@@ -625,7 +625,7 @@ pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
     /// * `begin` and `end` must be byte positions within the string slice.
     /// * `begin` and `end` must lie on UTF-8 sequence boundaries.
     #[stable(feature = "str_slice_mut", since = "1.5.0")]
-    #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked_mut(begin..end)` instead")]
+    #[deprecated(since = "1.29.0", note = "use `get_unchecked_mut(begin..end)` instead")]
     #[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`;
@@ -1000,7 +1000,7 @@ pub fn lines(&self) -> Lines<'_> {
 
     /// An iterator over the lines of a string.
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")]
+    #[deprecated(since = "1.4.0", note = "use lines() instead now")]
     #[inline]
     #[allow(deprecated)]
     pub fn lines_any(&self) -> LinesAny<'_> {
@@ -1964,11 +1964,7 @@ pub fn trim_end(&self) -> &str {
                   without modifying the original"]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(
-        since = "1.33.0",
-        reason = "superseded by `trim_start`",
-        suggestion = "trim_start"
-    )]
+    #[deprecated(since = "1.33.0", note = "superseded by `trim_start`", suggestion = "trim_start")]
     pub fn trim_left(&self) -> &str {
         self.trim_start()
     }
@@ -2008,11 +2004,7 @@ pub fn trim_left(&self) -> &str {
                   without modifying the original"]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(
-        since = "1.33.0",
-        reason = "superseded by `trim_end`",
-        suggestion = "trim_end"
-    )]
+    #[deprecated(since = "1.33.0", note = "superseded by `trim_end`", suggestion = "trim_end")]
     pub fn trim_right(&self) -> &str {
         self.trim_end()
     }
@@ -2240,9 +2232,9 @@ pub fn trim_end_matches<'a, P>(&'a self, pat: P) -> &'a str
     /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.33.0",
-        reason = "superseded by `trim_start_matches`",
+        note = "superseded by `trim_start_matches`",
         suggestion = "trim_start_matches"
     )]
     pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
@@ -2283,9 +2275,9 @@ pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
     /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.33.0",
-        reason = "superseded by `trim_end_matches`",
+        note = "superseded by `trim_end_matches`",
         suggestion = "trim_end_matches"
     )]
     pub fn trim_right_matches<'a, P>(&'a self, pat: P) -> &'a str
index 6285d1c1cbb564ca275bebd8bc609277294434c8..a01f3fbad565c7fc612393ffa2502ad6122d8be4 100644 (file)
@@ -162,6 +162,7 @@ unsafe impl Sync for AtomicBool {}
 /// loads and stores of pointers. Its size depends on the target pointer's size.
 #[cfg(target_has_atomic_load_store = "ptr")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "AtomicPtr")]
 #[cfg_attr(target_pointer_width = "16", repr(C, align(2)))]
 #[cfg_attr(target_pointer_width = "32", repr(C, align(4)))]
 #[cfg_attr(target_pointer_width = "64", repr(C, align(8)))]
@@ -270,9 +271,9 @@ pub enum Ordering {
 /// An [`AtomicBool`] initialized to `false`.
 #[cfg(target_has_atomic_load_store = "8")]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.34.0",
-    reason = "the `new` function is now preferred",
+    note = "the `new` function is now preferred",
     suggestion = "AtomicBool::new(false)"
 )]
 pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false);
@@ -550,9 +551,9 @@ pub fn swap(&self, val: bool, order: Ordering) -> bool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.50.0",
-        reason = "Use `compare_exchange` or `compare_exchange_weak` instead"
+        note = "Use `compare_exchange` or `compare_exchange_weak` instead"
     )]
     #[cfg(target_has_atomic = "8")]
     pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
@@ -1234,9 +1235,9 @@ pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.50.0",
-        reason = "Use `compare_exchange` or `compare_exchange_weak` instead"
+        note = "Use `compare_exchange` or `compare_exchange_weak` instead"
     )]
     #[cfg(target_has_atomic = "ptr")]
     pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
@@ -1458,6 +1459,7 @@ macro_rules! atomic_int {
      $stable_nand:meta,
      $const_stable:meta,
      $stable_init_const:meta,
+     $diagnostic_item:meta,
      $s_int_type:literal,
      $extra_feature:expr,
      $min_fn:ident, $max_fn:ident,
@@ -1480,6 +1482,7 @@ macro_rules! atomic_int {
         ///
         /// [module-level documentation]: crate::sync::atomic
         #[$stable]
+        #[$diagnostic_item]
         #[repr(C, align($align))]
         pub struct $atomic_type {
             v: UnsafeCell<$int_type>,
@@ -1487,9 +1490,9 @@ pub struct $atomic_type {
 
         /// An atomic integer initialized to `0`.
         #[$stable_init_const]
-        #[rustc_deprecated(
+        #[deprecated(
             since = "1.34.0",
-            reason = "the `new` function is now preferred",
+            note = "the `new` function is now preferred",
             suggestion = $atomic_new,
         )]
         pub const $atomic_init: $atomic_type = $atomic_type::new(0);
@@ -1809,9 +1812,9 @@ pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
             /// ```
             #[inline]
             #[$stable]
-            #[rustc_deprecated(
+            #[deprecated(
                 since = "1.50.0",
-                reason = "Use `compare_exchange` or `compare_exchange_weak` instead")
+                note = "Use `compare_exchange` or `compare_exchange_weak` instead")
             ]
             #[$cfg_cas]
             pub fn compare_and_swap(&self,
@@ -2306,6 +2309,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    cfg_attr(not(test), rustc_diagnostic_item = "AtomicI8"),
     "i8",
     "",
     atomic_min, atomic_max,
@@ -2325,6 +2329,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    cfg_attr(not(test), rustc_diagnostic_item = "AtomicU8"),
     "u8",
     "",
     atomic_umin, atomic_umax,
@@ -2344,6 +2349,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    cfg_attr(not(test), rustc_diagnostic_item = "AtomicI16"),
     "i16",
     "",
     atomic_min, atomic_max,
@@ -2363,6 +2369,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    cfg_attr(not(test), rustc_diagnostic_item = "AtomicU16"),
     "u16",
     "",
     atomic_umin, atomic_umax,
@@ -2382,6 +2389,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    cfg_attr(not(test), rustc_diagnostic_item = "AtomicI32"),
     "i32",
     "",
     atomic_min, atomic_max,
@@ -2401,6 +2409,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    cfg_attr(not(test), rustc_diagnostic_item = "AtomicU32"),
     "u32",
     "",
     atomic_umin, atomic_umax,
@@ -2420,6 +2429,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    cfg_attr(not(test), rustc_diagnostic_item = "AtomicI64"),
     "i64",
     "",
     atomic_min, atomic_max,
@@ -2439,6 +2449,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    cfg_attr(not(test), rustc_diagnostic_item = "AtomicU64"),
     "u64",
     "",
     atomic_umin, atomic_umax,
@@ -2458,6 +2469,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     unstable(feature = "integer_atomics", issue = "32976"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
     "i128",
     "#![feature(integer_atomics)]\n\n",
     atomic_min, atomic_max,
@@ -2477,6 +2489,7 @@ pub fn as_mut_ptr(&self) -> *mut $int_type {
     unstable(feature = "integer_atomics", issue = "32976"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
     "u128",
     "#![feature(integer_atomics)]\n\n",
     atomic_umin, atomic_umax,
@@ -2500,6 +2513,7 @@ macro_rules! atomic_int_ptr_sized {
             stable(feature = "atomic_nand", since = "1.27.0"),
             rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"),
             stable(feature = "rust1", since = "1.0.0"),
+            cfg_attr(not(test), rustc_diagnostic_item = "AtomicIsize"),
             "isize",
             "",
             atomic_min, atomic_max,
@@ -2520,6 +2534,7 @@ macro_rules! atomic_int_ptr_sized {
             stable(feature = "atomic_nand", since = "1.27.0"),
             rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"),
             stable(feature = "rust1", since = "1.0.0"),
+            cfg_attr(not(test), rustc_diagnostic_item = "AtomicUsize"),
             "usize",
             "",
             atomic_umin, atomic_umax,
@@ -3008,7 +3023,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// [`hint::spin_loop`]: crate::hint::spin_loop
 #[inline]
 #[stable(feature = "spin_loop_hint", since = "1.24.0")]
-#[rustc_deprecated(since = "1.51.0", reason = "use hint::spin_loop instead")]
+#[deprecated(since = "1.51.0", note = "use hint::spin_loop instead")]
 pub fn spin_loop_hint() {
     spin_loop()
 }
index 035cd9f243bf87786b189091a994403f0aef2746..c29f015777f1a4ff188a10e32021932d6678f4f0 100644 (file)
@@ -39,7 +39,7 @@
 ///
 /// [combining character]: https://en.wikipedia.org/wiki/Combining_character
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
+#[deprecated(since = "1.26.0", note = "use inherent methods instead")]
 pub trait AsciiExt {
     /// Container type for copied ASCII characters.
     #[stable(feature = "rust1", since = "1.0.0")]
index e38368790e69a10693aa1e7f8e5311c8bd79edd5..977714281fbbea8169a30c44dc26f0ffe2b94547 100644 (file)
@@ -12,7 +12,7 @@
 use crate::fmt::{self, Debug};
 #[allow(deprecated)]
 use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13};
-use crate::iter::{FromIterator, FusedIterator};
+use crate::iter::FusedIterator;
 use crate::ops::Index;
 use crate::sys;
 
index fa471a3c3f323df88416f1f411a6bfe3ea844406..13bba0a6fd8922c613f32f73ba90c2a4795f0277 100644 (file)
@@ -7,7 +7,7 @@
 use crate::collections::TryReserveError;
 use crate::fmt;
 use crate::hash::{BuildHasher, Hash};
-use crate::iter::{Chain, FromIterator, FusedIterator};
+use crate::iter::{Chain, FusedIterator};
 use crate::ops::{BitAnd, BitOr, BitXor, Sub};
 
 use super::map::{map_try_reserve_error, RandomState};
index 0caec8fe05aa7ea6b67b46cb6d12f696c8831ab6..ae2baba09e6836c16f69e5c0352a8444afc6a6b9 100644 (file)
 
 #[stable(feature = "rust1", since = "1.0.0")]
 // FIXME(#82080) The deprecation here is only theoretical, and does not actually produce a warning.
-#[rustc_deprecated(reason = "moved to `std::ops::Bound`", since = "1.26.0")]
+#[deprecated(note = "moved to `std::ops::Bound`", since = "1.26.0")]
 #[doc(hidden)]
 pub use crate::ops::Bound;
 
index f03d298d8699db9f0127835ffa73a919f1def60e..4027a71a06c5f56b0979aa8593a7be4b01cbc32f 100644 (file)
@@ -577,10 +577,10 @@ fn description(&self) -> &str {
 ///     None => println!("Impossible to get your home dir!"),
 /// }
 /// ```
-#[rustc_deprecated(
+#[deprecated(
     since = "1.29.0",
-    reason = "This function's behavior is unexpected and probably not what you want. \
-              Consider using a crate from crates.io instead."
+    note = "This function's behavior is unexpected and probably not what you want. \
+            Consider using a crate from crates.io instead."
 )]
 #[must_use]
 #[stable(feature = "env", since = "1.0.0")]
@@ -644,36 +644,23 @@ pub fn temp_dir() -> PathBuf {
 ///
 /// # Security
 ///
-/// The output of this function should not be used in anything that might have
-/// security implications. For example:
+/// The output of this function should not be trusted for anything
+/// that might have security implications. Basically, if users can run
+/// the executable, they can change the output arbitrarily.
 ///
-/// ```
-/// fn main() {
-///     println!("{:?}", std::env::current_exe());
-/// }
-/// ```
-///
-/// On Linux systems, if this is compiled as `foo`:
+/// As an example, you can easily introduce a race condition. It goes
+/// like this:
 ///
-/// ```bash
-/// $ rustc foo.rs
-/// $ ./foo
-/// Ok("/home/alex/foo")
-/// ```
+/// 1. You get the path to the current executable using `current_exe()`, and
+///    store it in a variable.
+/// 2. Time passes. A malicious actor removes the current executable, and
+///    replaces it with a malicious one.
+/// 3. You then use the stored path to re-execute the current
+///    executable.
 ///
-/// And you make a hard link of the program:
-///
-/// ```bash
-/// $ ln foo bar
-/// ```
-///
-/// When you run it, you won’t get the path of the original executable, you’ll
-/// get the path of the hard link:
-///
-/// ```bash
-/// $ ./bar
-/// Ok("/home/alex/bar")
-/// ```
+/// You expected to safely execute the current executable, but you're
+/// instead executing something completely different. The code you
+/// just executed run with your privileges.
 ///
 /// This sort of behavior has been known to [lead to privilege escalation] when
 /// used incorrectly.
index 3f85c2095cbd4fd44077e7df316508d9783c23e8..361163d1970058c5acca3165137a01542fc5c50e 100644 (file)
@@ -53,6 +53,7 @@
 /// high-level module to provide its own errors while also revealing some of the
 /// implementation for debugging via `source` chains.
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
 pub trait Error: Debug + Display {
     /// The lower-level source of this error, if any.
     ///
@@ -144,15 +145,15 @@ fn backtrace(&self) -> Option<&Backtrace> {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.42.0", reason = "use the Display impl or to_string()")]
+    #[deprecated(since = "1.42.0", note = "use the Display impl or to_string()")]
     fn description(&self) -> &str {
         "description() is deprecated; use Display"
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.33.0",
-        reason = "replaced by Error::source, which can support downcasting"
+        note = "replaced by Error::source, which can support downcasting"
     )]
     #[allow(missing_docs)]
     fn cause(&self) -> Option<&dyn Error> {
index ac288c599f3a4c8b4ecc33904e5b722380353850..933b52b4dccbb2b4d810b0485a7279590f6aa18a 100644 (file)
@@ -29,7 +29,7 @@
 
 #[cfg(not(test))]
 impl f32 {
-    /// Returns the largest integer less than or equal to a number.
+    /// Returns the largest integer less than or equal to `self`.
     ///
     /// # Examples
     ///
@@ -50,7 +50,7 @@ pub fn floor(self) -> f32 {
         unsafe { intrinsics::floorf32(self) }
     }
 
-    /// Returns the smallest integer greater than or equal to a number.
+    /// Returns the smallest integer greater than or equal to `self`.
     ///
     /// # Examples
     ///
@@ -69,7 +69,7 @@ pub fn ceil(self) -> f32 {
         unsafe { intrinsics::ceilf32(self) }
     }
 
-    /// Returns the nearest integer to a number. Round half-way cases away from
+    /// Returns the nearest integer to `self`. Round half-way cases away from
     /// `0.0`.
     ///
     /// # Examples
@@ -89,7 +89,8 @@ pub fn round(self) -> f32 {
         unsafe { intrinsics::roundf32(self) }
     }
 
-    /// Returns the integer part of a number.
+    /// Returns the integer part of `self`.
+    /// This means that non-integer numbers are always truncated towards zero.
     ///
     /// # Examples
     ///
@@ -110,7 +111,7 @@ pub fn trunc(self) -> f32 {
         unsafe { intrinsics::truncf32(self) }
     }
 
-    /// Returns the fractional part of a number.
+    /// Returns the fractional part of `self`.
     ///
     /// # Examples
     ///
@@ -131,8 +132,7 @@ pub fn fract(self) -> f32 {
         self - self.trunc()
     }
 
-    /// Computes the absolute value of `self`. Returns `NAN` if the
-    /// number is `NAN`.
+    /// Computes the absolute value of `self`.
     ///
     /// # Examples
     ///
@@ -160,7 +160,7 @@ pub fn abs(self) -> f32 {
     ///
     /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
     /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
-    /// - `NAN` if the number is `NAN`
+    /// - NaN if the number is NaN
     ///
     /// # Examples
     ///
@@ -184,8 +184,10 @@ pub fn signum(self) -> f32 {
     /// `sign`.
     ///
     /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
-    /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
-    /// `sign` is returned.
+    /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of
+    /// `sign` is returned. Note, however, that conserving the sign bit on NaN
+    /// across arithmetical operations is not generally guaranteed.
+    /// See [explanation of NaN as a special value](primitive@f32) for more info.
     ///
     /// # Examples
     ///
@@ -298,7 +300,9 @@ pub fn rem_euclid(self, rhs: f32) -> f32 {
 
     /// Raises a number to an integer power.
     ///
-    /// Using this function is generally faster than using `powf`
+    /// Using this function is generally faster than using `powf`.
+    /// It might have a different sequence of rounding operations than `powf`,
+    /// so the results are not guaranteed to agree.
     ///
     /// # Examples
     ///
@@ -511,15 +515,15 @@ pub fn log10(self) -> f32 {
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.10.0",
-        reason = "you probably meant `(self - other).abs()`: \
-                  this operation is `(self - other).max(0.0)` \
-                  except that `abs_sub` also propagates NaNs (also \
-                  known as `fdimf` in C). If you truly need the positive \
-                  difference, consider using that expression or the C function \
-                  `fdimf`, depending on how you wish to handle NaN (please consider \
-                  filing an issue describing your use-case too)."
+        note = "you probably meant `(self - other).abs()`: \
+                this operation is `(self - other).max(0.0)` \
+                except that `abs_sub` also propagates NaNs (also \
+                known as `fdimf` in C). If you truly need the positive \
+                difference, consider using that expression or the C function \
+                `fdimf`, depending on how you wish to handle NaN (please consider \
+                filing an issue describing your use-case too)."
     )]
     pub fn abs_sub(self, other: f32) -> f32 {
         unsafe { cmath::fdimf(self, other) }
index 01279f01b0568caa8601f720b137b8fef866604f..a9aa84f70d19e08fcc4341a2a52ffb984afe43d4 100644 (file)
@@ -29,7 +29,7 @@
 
 #[cfg(not(test))]
 impl f64 {
-    /// Returns the largest integer less than or equal to a number.
+    /// Returns the largest integer less than or equal to `self`.
     ///
     /// # Examples
     ///
@@ -50,7 +50,7 @@ pub fn floor(self) -> f64 {
         unsafe { intrinsics::floorf64(self) }
     }
 
-    /// Returns the smallest integer greater than or equal to a number.
+    /// Returns the smallest integer greater than or equal to `self`.
     ///
     /// # Examples
     ///
@@ -69,7 +69,7 @@ pub fn ceil(self) -> f64 {
         unsafe { intrinsics::ceilf64(self) }
     }
 
-    /// Returns the nearest integer to a number. Round half-way cases away from
+    /// Returns the nearest integer to `self`. Round half-way cases away from
     /// `0.0`.
     ///
     /// # Examples
@@ -89,7 +89,8 @@ pub fn round(self) -> f64 {
         unsafe { intrinsics::roundf64(self) }
     }
 
-    /// Returns the integer part of a number.
+    /// Returns the integer part of `self`.
+    /// This means that non-integer numbers are always truncated towards zero.
     ///
     /// # Examples
     ///
@@ -110,7 +111,7 @@ pub fn trunc(self) -> f64 {
         unsafe { intrinsics::truncf64(self) }
     }
 
-    /// Returns the fractional part of a number.
+    /// Returns the fractional part of `self`.
     ///
     /// # Examples
     ///
@@ -131,8 +132,7 @@ pub fn fract(self) -> f64 {
         self - self.trunc()
     }
 
-    /// Computes the absolute value of `self`. Returns `NAN` if the
-    /// number is `NAN`.
+    /// Computes the absolute value of `self`.
     ///
     /// # Examples
     ///
@@ -160,7 +160,7 @@ pub fn abs(self) -> f64 {
     ///
     /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
     /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
-    /// - `NAN` if the number is `NAN`
+    /// - NaN if the number is NaN
     ///
     /// # Examples
     ///
@@ -184,8 +184,10 @@ pub fn signum(self) -> f64 {
     /// `sign`.
     ///
     /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
-    /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
-    /// `sign` is returned.
+    /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of
+    /// `sign` is returned. Note, however, that conserving the sign bit on NaN
+    /// across arithmetical operations is not generally guaranteed.
+    /// See [explanation of NaN as a special value](primitive@f32) for more info.
     ///
     /// # Examples
     ///
@@ -298,7 +300,9 @@ pub fn rem_euclid(self, rhs: f64) -> f64 {
 
     /// Raises a number to an integer power.
     ///
-    /// Using this function is generally faster than using `powf`
+    /// Using this function is generally faster than using `powf`.
+    /// It might have a different sequence of rounding operations than `powf`,
+    /// so the results are not guaranteed to agree.
     ///
     /// # Examples
     ///
@@ -513,15 +517,15 @@ pub fn log10(self) -> f64 {
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.10.0",
-        reason = "you probably meant `(self - other).abs()`: \
-                  this operation is `(self - other).max(0.0)` \
-                  except that `abs_sub` also propagates NaNs (also \
-                  known as `fdim` in C). If you truly need the positive \
-                  difference, consider using that expression or the C function \
-                  `fdim`, depending on how you wish to handle NaN (please consider \
-                  filing an issue describing your use-case too)."
+        note = "you probably meant `(self - other).abs()`: \
+                this operation is `(self - other).max(0.0)` \
+                except that `abs_sub` also propagates NaNs (also \
+                known as `fdim` in C). If you truly need the positive \
+                difference, consider using that expression or the C function \
+                `fdim`, depending on how you wish to handle NaN (please consider \
+                filing an issue describing your use-case too)."
     )]
     pub fn abs_sub(self, other: f64) -> f64 {
         unsafe { cmath::fdim(self, other) }
index dd316bdb2c6ce5476a31b95a23801ba248b92232..ae13275e4b35d7869478db492b25b1efc60720c8 100644 (file)
@@ -6,7 +6,7 @@
 use crate::collections::TryReserveError;
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
-use crate::iter::{Extend, FromIterator};
+use crate::iter::Extend;
 use crate::ops;
 use crate::rc::Rc;
 use crate::str::FromStr;
@@ -1222,23 +1222,6 @@ pub(crate) fn display(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result
     }
 }
 
-#[unstable(feature = "slice_concat_ext", issue = "27747")]
-impl<S: Borrow<OsStr>> alloc::slice::Join<&OsStr> for [S] {
-    type Output = OsString;
-
-    fn join(slice: &Self, sep: &OsStr) -> OsString {
-        let Some(first) = slice.first() else {
-            return OsString::new();
-        };
-        let first = first.borrow().to_owned();
-        slice[1..].iter().fold(first, |mut a, b| {
-            a.push(sep);
-            a.push(b.borrow());
-            a
-        })
-    }
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Borrow<OsStr> for OsString {
     #[inline]
index d7926749aae2090416729d0aec53db4bf0a6b276..283f2b577e89607bdd9940cc8b4c4d4300b35888 100644 (file)
@@ -84,20 +84,6 @@ fn test_os_string_reserve_exact() {
     assert!(os_string.capacity() >= 33)
 }
 
-#[test]
-fn test_os_string_join() {
-    let strings = [OsStr::new("hello"), OsStr::new("dear"), OsStr::new("world")];
-    assert_eq!("hello", strings[..1].join(OsStr::new(" ")));
-    assert_eq!("hello dear world", strings.join(OsStr::new(" ")));
-    assert_eq!("hellodearworld", strings.join(OsStr::new("")));
-    assert_eq!("hello.\n dear.\n world", strings.join(OsStr::new(".\n ")));
-
-    assert_eq!("dear world", strings[1..].join(&OsString::from(" ")));
-
-    let strings_abc = [OsString::from("a"), OsString::from("b"), OsString::from("c")];
-    assert_eq!("a b c", strings_abc.join(OsStr::new(" ")));
-}
-
 #[test]
 fn test_os_string_default() {
     let os_string: OsString = Default::default();
index 433b4d530136b282a9e84d870039c5b1b07eb3de..431a1efc8d1f64d4e7f3d56e9f3b31e3a0728295 100644 (file)
@@ -1851,10 +1851,10 @@ pub fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Re
 /// }
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.1.0",
-    reason = "replaced with std::os::unix::fs::symlink and \
-              std::os::windows::fs::{symlink_file, symlink_dir}"
+    note = "replaced with std::os::unix::fs::symlink and \
+            std::os::windows::fs::{symlink_file, symlink_dir}"
 )]
 pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
     fs_imp::symlink(original.as_ref(), link.as_ref())
@@ -1930,6 +1930,8 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
 ///     Ok(())
 /// }
 /// ```
+#[doc(alias = "realpath")]
+#[doc(alias = "GetFinalPathNameByHandle")]
 #[stable(feature = "fs_canonicalize", since = "1.5.0")]
 pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
     fs_imp::canonicalize(path.as_ref())
index 57f1d628f6ad994c4dea0a9fdd3736f121803b36..0ce6ae00ee250e5054b2072a51bdc4416981a126 100644 (file)
@@ -7,8 +7,6 @@
 use crate::cmp;
 use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
 
-use core::convert::TryInto;
-
 /// A `Cursor` wraps an in-memory buffer and provides it with a
 /// [`Seek`] implementation.
 ///
index cd2197fca350e73e8d8d7a3462487ba724828220..94812e3fe3b2c483b15019c6695d8e2704fa2921 100644 (file)
 mod tests;
 
 use crate::cmp;
-use crate::convert::TryInto;
 use crate::fmt;
 use crate::mem::replace;
 use crate::ops::{Deref, DerefMut};
index c394865d886e85bdc8e120c7753006897b6b9965..6dc3fd9858451910ce5ee74a98970374a325e591 100644 (file)
 #![feature(intra_doc_pointers)]
 #![feature(lang_items)]
 #![feature(let_chains)]
-#![feature(let_else)]
 #![feature(linkage)]
 #![feature(min_specialization)]
 #![feature(must_not_suspend)]
 #![feature(toowned_clone_into)]
 #![feature(try_reserve_kind)]
 #![feature(vec_into_raw_parts)]
-#![feature(slice_concat_trait)]
 //
 // Library features (unwind):
 #![feature(panic_unwind)]
 // to import the prelude implicitly when building crates that depend on std.
 #[prelude_import]
 #[allow(unused)]
-use prelude::v1::*;
+use prelude::rust_2021::*;
 
 // Access to Bencher, etc.
 #[cfg(test)]
index 201cbf3f08d28aad58e73f59350867298114f66f..81dd042425c1d0dfd52addbf74379f6865ecf2af 100644 (file)
@@ -2,7 +2,6 @@
 mod tests;
 
 use crate::cmp::Ordering;
-use crate::convert::TryInto;
 use crate::fmt;
 use crate::hash;
 use crate::io::{self, Write};
index fb292ed29a18a5b90d508aaf81df12247fdb6863..069b66099855956d6d6d41b236baefd05ebfe52d 100644 (file)
@@ -6,7 +6,6 @@
 #[cfg(test)]
 mod tests;
 
-use crate::convert::TryInto as _;
 use crate::error::Error;
 use crate::fmt;
 use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
index f5d3c4905e0813841f86c9c22badd0e0fb69fda9..06300035633b9b498420bd8967f410d41a7fa370 100644 (file)
@@ -915,20 +915,14 @@ pub fn ttl(&self) -> io::Result<u32> {
     }
 
     #[stable(feature = "net2_mutators", since = "1.9.0")]
-    #[rustc_deprecated(
-        since = "1.16.0",
-        reason = "this option can only be set before the socket is bound"
-    )]
+    #[deprecated(since = "1.16.0", note = "this option can only be set before the socket is bound")]
     #[allow(missing_docs)]
     pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
         self.0.set_only_v6(only_v6)
     }
 
     #[stable(feature = "net2_mutators", since = "1.9.0")]
-    #[rustc_deprecated(
-        since = "1.16.0",
-        reason = "this option can only be set before the socket is bound"
-    )]
+    #[deprecated(since = "1.16.0", note = "this option can only be set before the socket is bound")]
     #[allow(missing_docs)]
     pub fn only_v6(&self) -> io::Result<bool> {
         self.0.only_v6()
index 6aeef330dfa24b38e590baf3b4d370bbb3924c07..1beb3cf6e84b59bef3ed676dce6ecd931358374f 100644 (file)
@@ -18,10 +18,10 @@ pub trait MetadataExt {
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor \
-                  methods of this trait"
+        note = "deprecated in favor of the accessor \
+                methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index 2b8ade8a82e65f794b6d80e64aa8ba76bf506eb7..a255d03208623989c716f48cd1e964746c6f8fdb 100644 (file)
@@ -1,12 +1,12 @@
 //! Android-specific raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index e4c4e04cd30aa87a378772280433f5fce7a413a6..1424fc4c69880f38f727a099df678825cebe2227 100644 (file)
@@ -18,10 +18,10 @@ pub trait MetadataExt {
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor \
-                  methods of this trait"
+        note = "deprecated in favor of the accessor \
+                methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index 2a2d29043727e1aec51b7f9ba153f17cf655738c..071bf6199aa23c231b6aaa21d75912f0656f08bc 100644 (file)
@@ -1,12 +1,12 @@
 //! Dragonfly-specific raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index d4f758a3457fe3266bfda5e1d2787177d69fa270..d5ec8e03c00d1477726acd93121862ae1524b766 100644 (file)
@@ -18,10 +18,10 @@ pub trait MetadataExt {
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor \
-                  methods of this trait"
+        note = "deprecated in favor of the accessor \
+                methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index 503645c08ce36568815682962f39117eef6a95db..d23011c7381413e9dab49bf80372032a04333f5a 100644 (file)
@@ -3,12 +3,12 @@
 //! except using the musl-specific stat64 structure in liblibc.
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index 93dc2c0cab7eee510e3f821eb0b27dd08923e484..88701dafe20ce4037b6f0b2db38dc873853f4829 100644 (file)
 #[stable(feature = "metadata_ext", since = "1.1.0")]
 pub trait MetadataExt {
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor \
-                  methods of this trait"
+        note = "deprecated in favor of the accessor \
+                methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index fb18ec6f6f82abf2bdb72c4391a9c40a6b809140..7df0e74b22335656038c7ffc8cb3d3b8004135fc 100644 (file)
@@ -1,12 +1,12 @@
 //! Raw type definitions for the ESP-IDF framework.
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 
 use crate::os::raw::c_long;
index 1eda8690d5d1b0584b4493d6b21a9110a901ad97..8db3a950c40ffefa864b4cf914318d92c4759d3b 100644 (file)
@@ -18,10 +18,10 @@ pub trait MetadataExt {
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor \
-                  methods of this trait"
+        note = "deprecated in favor of the accessor \
+                methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index aeae08fc6aae0a4e86e60b6286058532f7b5e616..ab0bf7923194867213e676507d063989c05c9fcf 100644 (file)
@@ -1,12 +1,12 @@
 //! FreeBSD-specific raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index f94659cd5baabf3731c2f6bb0f19dfc5fdf6ee5d..060d6e86b6c2bcf27d253ed013eafb5f6fac9f54 100644 (file)
@@ -1,12 +1,12 @@
 //! Fuchsia-specific raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index 28015f62526331698937d416eb6810c085072912..a23a2af8f6e7b2b4723a41077bbabadde3e9547d 100644 (file)
@@ -18,10 +18,10 @@ pub trait MetadataExt {
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor \
-                  methods of this trait"
+        note = "deprecated in favor of the accessor \
+                methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index 48117d288ae4799258abe2d88096d2163c922ff5..afbb66ccb5e5d6da3e1a4fa340fc5edff51961d6 100644 (file)
@@ -1,12 +1,12 @@
 //! Haiku-specific raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.53.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index 021d154ff5a8a6e7dd75aae9ecc514297187866f..63be48b8131b249b23e059ef7d41d040674fdc00 100644 (file)
@@ -18,9 +18,9 @@ pub trait MetadataExt {
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor methods of this trait"
+        note = "deprecated in favor of the accessor methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index 88c832ae7c77327ac70f3724d8049fa15d34092a..2bea9ebb3c8369f69411e7a0faec67b59ad03184 100644 (file)
@@ -1,9 +1,9 @@
 //! illumos-specific raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by the standard library, the `libc` \
+    note = "these type aliases are no longer supported by the standard library, the `libc` \
     crate on crates.io should be used instead for the correct definitions"
 )]
 #![allow(deprecated)]
index 2c5e38a803d30a2c4efcf3095679466450eb3f6c..4a4637ce0722d04767c205a6b9f5fb9565d162e5 100644 (file)
@@ -18,10 +18,10 @@ pub trait MetadataExt {
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor \
-                  methods of this trait"
+        note = "deprecated in favor of the accessor \
+                methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index 97b0a96b0f1c006c7656e1766d0783441bd66366..af12aeebe5d0c7cf1cd387ba48c40652955672e7 100644 (file)
@@ -1,12 +1,12 @@
 //! iOS-specific raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index b9b6918292fae7d75f0974b3668e1bed9bd27a24..6d6a535b1e8315a0cba700baf89d445a17a15539 100644 (file)
@@ -38,7 +38,7 @@ pub trait MetadataExt {
     /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(since = "1.8.0", reason = "other methods of this trait are now preferred")]
+    #[deprecated(since = "1.8.0", note = "other methods of this trait are now preferred")]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
 
index 5efd6301fc92b2d411115f61ec59fdf271dfa4fa..699e8be33c8a81cb21699cdac5800dd451ea8257 100644 (file)
@@ -1,12 +1,12 @@
 //! L4Re-specific raw type definitions.
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index 9d18ccbeb2494025374a3f04b99dcd4a60e62eef..479bbcc17a89ec67ae0f175042d38216a87ff84a 100644 (file)
@@ -38,7 +38,7 @@ pub trait MetadataExt {
     /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(since = "1.8.0", reason = "other methods of this trait are now preferred")]
+    #[deprecated(since = "1.8.0", note = "other methods of this trait are now preferred")]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
 
@@ -356,19 +356,34 @@ fn st_size(&self) -> u64 {
         self.as_inner().as_inner().st_size as u64
     }
     fn st_atime(&self) -> i64 {
-        self.as_inner().as_inner().st_atime as i64
+        let file_attr = self.as_inner();
+        #[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
+        if let Some(atime) = file_attr.stx_atime() {
+            return atime.tv_sec;
+        }
+        file_attr.as_inner().st_atime as i64
     }
     fn st_atime_nsec(&self) -> i64 {
         self.as_inner().as_inner().st_atime_nsec as i64
     }
     fn st_mtime(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime as i64
+        let file_attr = self.as_inner();
+        #[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
+        if let Some(mtime) = file_attr.stx_mtime() {
+            return mtime.tv_sec;
+        }
+        file_attr.as_inner().st_mtime as i64
     }
     fn st_mtime_nsec(&self) -> i64 {
         self.as_inner().as_inner().st_mtime_nsec as i64
     }
     fn st_ctime(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime as i64
+        let file_attr = self.as_inner();
+        #[cfg(all(target_env = "gnu", target_pointer_width = "32"))]
+        if let Some(ctime) = file_attr.stx_ctime() {
+            return ctime.tv_sec;
+        }
+        file_attr.as_inner().st_ctime as i64
     }
     fn st_ctime_nsec(&self) -> i64 {
         self.as_inner().as_inner().st_ctime_nsec as i64
index d78049bce24c2dcd3baf624ad04466a64107a2f1..c73791d14529c6976adec84643f01976433c05be 100644 (file)
@@ -1,12 +1,12 @@
 //! Linux-specific raw type definitions.
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index 4152c3529361ded6e8e560da87860fc0bb9eea4d..91915da6a432cc49926e37d2bbc391c602168e06 100644 (file)
@@ -18,10 +18,10 @@ pub trait MetadataExt {
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor \
-                  methods of this trait"
+        note = "deprecated in favor of the accessor \
+                methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index 708261d86bddba769ff859c1bf83522fcff4cc2b..0b21f6ee5e498cd90b0f350e486e784d90851738 100644 (file)
@@ -1,12 +1,12 @@
 //! macOS-specific raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index 6b29a40d2b5452bc08d644c3bd92b8fd89774e1d..fe0be069e5e3f2077a75e63b25a907b68dbda037 100644 (file)
@@ -18,10 +18,10 @@ pub trait MetadataExt {
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor \
-                  methods of this trait"
+        note = "deprecated in favor of the accessor \
+                methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index 475fcdcc4aaabab7bd8626a89f44cabff3b9d3d4..18057291feec820db2c92e5d143d55d8067e2314 100644 (file)
@@ -1,12 +1,12 @@
 //! NetBSD-specific raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index 3143dc95fdf44adb0098920a1a4f78c2791cc2c7..b8d8d31c5b8cf0eac1e39ddde4c9bcbbc317d1e2 100644 (file)
@@ -18,10 +18,10 @@ pub trait MetadataExt {
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor \
-                  methods of this trait"
+        note = "deprecated in favor of the accessor \
+                methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index 8e34e5483b7a0723da078bff431a712a331debfb..6711fb51b1702bb451b0057504e6e6bcb5b82bfe 100644 (file)
@@ -1,12 +1,12 @@
 //! OpenBSD-specific raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index 0f179c8b837dd8708a584aa45338c38770ec9c07..682ca6a2c0309f103b45105b30e2d7438b83fdc5 100644 (file)
@@ -34,10 +34,10 @@ pub trait MetadataExt {
     /// }
     /// ```
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor \
-                  methods of this trait"
+        note = "deprecated in favor of the accessor \
+                methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index 9a6b99684c5231a1baabdf106405613a36c0878e..7b1cd8ae800a4d1026d6b3165f0c95312f7d3f8e 100644 (file)
@@ -1,12 +1,12 @@
 //! Redox-specific raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index 908c5c38a842e83ac4817f684dd06d5e3e24b992..093143737042945143f3b6fcab9e8ce2cdc1b053 100644 (file)
@@ -18,10 +18,10 @@ pub trait MetadataExt {
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(
+    #[deprecated(
         since = "1.8.0",
-        reason = "deprecated in favor of the accessor \
-                  methods of this trait"
+        note = "deprecated in favor of the accessor \
+                methods of this trait"
     )]
     #[allow(deprecated)]
     fn as_raw_stat(&self) -> &raw::stat;
index e78f9992bb32469c457af7877443076805fc109c..63426c96951f5a3fd8d7a596cd690019ef05cc6d 100644 (file)
@@ -1,12 +1,12 @@
 //! Solaris-specific raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index 658c79896eb2e58747f20c5c165989dd86c98748..9e31b8b32a19738744e65362c4241e27df6de127 100644 (file)
@@ -1,5 +1,4 @@
 use super::{sockaddr_un, SocketAddr};
-use crate::convert::TryFrom;
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::marker::PhantomData;
 use crate::mem::{size_of, zeroed};
index aa0df61c1920d628c6e8f3963c936ef488fb0147..c1f11c56b8f65a1a01f78e9857907d45302209c3 100644 (file)
@@ -10,7 +10,6 @@
     target_os = "netbsd",
     target_os = "openbsd",
 ))]
-use crate::iter::FromIterator;
 #[cfg(any(
     target_os = "android",
     target_os = "dragonfly",
index 9a6778c0e869b1ea6852b3ff091b84367b7b2fb0..9dca9b4a4a3f6bf67b39b97a3101c0f0b283f164 100644 (file)
@@ -103,7 +103,7 @@ unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
     ///
     /// [`pre_exec`]: CommandExt::pre_exec
     #[stable(feature = "process_exec", since = "1.15.0")]
-    #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
+    #[deprecated(since = "1.37.0", note = "should be unsafe, use `pre_exec` instead")]
     fn before_exec<F>(&mut self, f: F) -> &mut process::Command
     where
         F: FnMut() -> io::Result<()> + Send + Sync + 'static,
index c292955cb4eea40213a7b6b67840c876924adc02..fe761627bc1f2246a9f7b1786b9e97a148cf6055 100644 (file)
@@ -1,12 +1,12 @@
 //! Unix-specific primitives available on all unix platforms.
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
+#![deprecated(
     since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
+    note = "these type aliases are no longer supported by \
+            the standard library, the `libc` crate on \
+            crates.io should be used instead for the correct \
+            definitions"
 )]
 #![allow(deprecated)]
 
index f3d7be3f95c6b0db39526c217581cc6d3012923c..41758f2ced111caf2ec5f79be494d93cab70cba6 100644 (file)
@@ -3,7 +3,6 @@
 #![unstable(feature = "io_safety", issue = "87074")]
 
 use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
-use crate::convert::TryFrom;
 use crate::fmt;
 use crate::fs;
 use crate::io;
index e189630991436c1994b03b3e94de05d8306e59db..1c7e361c2a4a8d3767ea98b9e140ffce68c71c2c 100644 (file)
@@ -180,3 +180,17 @@ fn raw_arg<S: AsRef<OsStr>>(&mut self, raw_text: S) -> &mut process::Command {
         self
     }
 }
+
+#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
+pub trait ChildExt: Sealed {
+    /// Extracts the main thread raw handle, without taking ownership
+    #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
+    fn main_thread_handle(&self) -> BorrowedHandle<'_>;
+}
+
+#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
+impl ChildExt for process::Child {
+    fn main_thread_handle(&self) -> BorrowedHandle<'_> {
+        self.handle.main_thread_handle()
+    }
+}
index c03d197e0194c9c4f2a6ea9ddc89d873ce81a290..36d6469c02d31e1f46e4c3e1686879e357ffa468 100644 (file)
@@ -725,7 +725,7 @@ fn include_cur_dir(&self) -> bool {
         if self.has_root() {
             return false;
         }
-        let mut iter = self.path[self.prefix_len()..].iter();
+        let mut iter = self.path[self.prefix_remaining()..].iter();
         match (iter.next(), iter.next()) {
             (Some(&b'.'), None) => true,
             (Some(&b'.'), Some(&b)) => self.is_sep_byte(b),
index 225a679efd22132ced410bf29008fbd7e3212ee0..ac4e668112b94a1248a4141353e033682123eb14 100644 (file)
@@ -977,10 +977,22 @@ mod prim_tuple {}
 ///   like `1.0 / 0.0`.
 /// - [NaN (not a number)](#associatedconstant.NAN): this value results from
 ///   calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected
-///   behavior: it is unequal to any float, including itself! It is also neither
-///   smaller nor greater than any float, making it impossible to sort. Lastly,
-///   it is considered infectious as almost all calculations where one of the
-///   operands is NaN will also result in NaN.
+///   behavior:
+///   - It is unequal to any float, including itself! This is the reason `f32`
+///     doesn't implement the `Eq` trait.
+///   - It is also neither smaller nor greater than any float, making it
+///     impossible to sort by the default comparison operation, which is the
+///     reason `f32` doesn't implement the `Ord` trait.
+///   - It is also considered *infectious* as almost all calculations where one
+///     of the operands is NaN will also result in NaN. The explanations on this
+///     page only explicitly document behavior on NaN operands if this default
+///     is deviated from.
+///   - Lastly, there are multiple bit patterns that are considered NaN.
+///     Rust does not currently guarantee that the bit patterns of NaN are
+///     preserved over arithmetic operations, and they are not guaranteed to be
+///     portable or even fully deterministic! This means that there may be some
+///     surprising results upon inspecting the bit patterns,
+///     as the same calculations might produce NaNs with different bit patterns.
 ///
 /// For more information on floating point numbers, see [Wikipedia][wikipedia].
 ///
index b41918ec1cffc6c1f7613b70da2b4732026b87dc..7ff2f330f8a56895730f971befd2b6e1bf2ffc86 100644 (file)
@@ -303,7 +303,7 @@ pub fn wait_while<'a, T, F>(
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")]
+    #[deprecated(since = "1.6.0", note = "replaced by `std::sync::Condvar::wait_timeout`")]
     pub fn wait_timeout_ms<'a, T>(
         &self,
         guard: MutexGuard<'a, T>,
index 3ea0a6c3937605261762f0e9d87845742f44fd09..aacc893ba06468e6f7e2e54e125495c3b1cd4f0b 100644 (file)
@@ -192,6 +192,7 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
                       points can cause deadlocks, delays, \
                       and cause Futures to not implement `Send`"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[clippy::has_significant_drop]
 pub struct MutexGuard<'a, T: ?Sized + 'a> {
     lock: &'a Mutex<T>,
     poison: poison::Guard,
index d2dd4c075d2a942eadb4f626ba96d3b003628b0b..a7feea588598c7f4f35d9bcf30227b368f154dc2 100644 (file)
@@ -152,9 +152,9 @@ pub struct OnceState {
 /// static START: Once = ONCE_INIT;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(
+#[deprecated(
     since = "1.38.0",
-    reason = "the `new` function is now preferred",
+    note = "the `new` function is now preferred",
     suggestion = "Once::new()"
 )]
 pub const ONCE_INIT: Once = Once::new();
index ed62fa977becab7b56065382c333d2b945b8b5b4..9ec0903f037ccf9c40ad24264abaee9f076552db 100644 (file)
@@ -99,6 +99,7 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
                       points can cause deadlocks, delays, \
                       and cause Futures to not implement `Send`"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[clippy::has_significant_drop]
 pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
     lock: &'a RwLock<T>,
 }
@@ -122,6 +123,7 @@ unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {}
                       points can cause deadlocks, delays, \
                       and cause Future's to not implement `Send`"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[clippy::has_significant_drop]
 pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
     lock: &'a RwLock<T>,
     poison: poison::Guard,
index f65fd8e53bdc999a26998c5093124b0b2bba7ee6..74547617150b0b48bd22294456d8fbe43766072e 100644 (file)
@@ -1,4 +1,3 @@
-use crate::convert::TryFrom;
 use crate::fmt;
 use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
 use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
index 27173de6307290c6c2edc0d6d45551f0e152b74b..c17e6c8af62763c6f13ac388f0a32ee48a8e16c6 100644 (file)
@@ -1,7 +1,6 @@
 #![allow(dead_code)]
 
 use crate::cmp::Ordering;
-use crate::convert::TryInto;
 use crate::sys::hermit::abi;
 use crate::sys::hermit::abi::timespec;
 use crate::sys::hermit::abi::{CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC};
index d0149d1f037db82a0a5b9897d11eff0e649058fe..44d409444bca48ec90efdbc059e8ce1bc0f4e8a9 100644 (file)
@@ -1,7 +1,6 @@
 use super::abi;
 use crate::{
     cell::UnsafeCell,
-    convert::TryFrom,
     mem::MaybeUninit,
     sync::atomic::{AtomicBool, AtomicUsize, Ordering},
 };
index 5b718a460dfa9e4c991e49d5e57e623a004090c3..d28f57f33be20566de33bd7a79389a85067105a6 100644 (file)
@@ -8,7 +8,6 @@
 };
 use crate::{
     cell::UnsafeCell,
-    convert::TryFrom,
     ffi::CStr,
     hint, io,
     mem::ManuallyDrop,
index 25f13ee441aca60095c9e93ada5808aef5c33952..427ea0d80e10739aff897e15a162feb833a60d9a 100644 (file)
@@ -1,5 +1,5 @@
 use super::{abi, error::expect_success};
-use crate::{convert::TryInto, mem::MaybeUninit, time::Duration};
+use crate::{mem::MaybeUninit, time::Duration};
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 pub struct Instant(abi::SYSTIM);
index 4030355f13518fb7f56a33487f983f1d35138f31..2f99abba77667a46de92aef2fc10455b1f54ea7f 100644 (file)
@@ -1,5 +1,4 @@
 use crate::cmp;
-use crate::convert::TryFrom;
 use crate::io::{Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult};
 use crate::sys::rand::rdrand64;
 use crate::time::{Duration, Instant};
index feb0b62dcd1f71ec1d3a56d3942df075b508d065..1d899525081b97a1c4ea6e05c3d50f8ed8016161 100644 (file)
@@ -1,4 +1,3 @@
-use crate::convert::TryFrom;
 use crate::error;
 use crate::fmt;
 use crate::io::{self, IoSlice, IoSliceMut};
index ab988be24442a0ad774e5a250c283cc22d3ecb1b..ce31cb45a69a1aef67290687d9b818e26654cf9d 100644 (file)
@@ -1,5 +1,5 @@
 use super::{abi, error::expect_success};
-use crate::{convert::TryInto, mem::MaybeUninit, time::Duration};
+use crate::{mem::MaybeUninit, time::Duration};
 
 pub use super::itron::time::Instant;
 
index 27fc7accdaeca404dbafd7c1add31598a9c9ebd8..5d0fb07900326fd218856b7b2fd923653cdc5d3d 100644 (file)
@@ -113,10 +113,19 @@ struct StatxExtraFields {
         // This is needed to check if btime is supported by the filesystem.
         stx_mask: u32,
         stx_btime: libc::statx_timestamp,
+        // With statx, we can overcome 32-bit `time_t` too.
+        #[cfg(target_pointer_width = "32")]
+        stx_atime: libc::statx_timestamp,
+        #[cfg(target_pointer_width = "32")]
+        stx_ctime: libc::statx_timestamp,
+        #[cfg(target_pointer_width = "32")]
+        stx_mtime: libc::statx_timestamp,
+
     }
 
-    // We prefer `statx` on Linux if available, which contains file creation time.
-    // Default `stat64` contains no creation time.
+    // We prefer `statx` on Linux if available, which contains file creation time,
+    // as well as 64-bit timestamps of all kinds.
+    // Default `stat64` contains no creation time and may have 32-bit `time_t`.
     unsafe fn try_statx(
         fd: c_int,
         path: *const c_char,
@@ -192,6 +201,13 @@ fn statx(
         let extra = StatxExtraFields {
             stx_mask: buf.stx_mask,
             stx_btime: buf.stx_btime,
+            // Store full times to avoid 32-bit `time_t` truncation.
+            #[cfg(target_pointer_width = "32")]
+            stx_atime: buf.stx_atime,
+            #[cfg(target_pointer_width = "32")]
+            stx_ctime: buf.stx_ctime,
+            #[cfg(target_pointer_width = "32")]
+            stx_mtime: buf.stx_mtime,
         };
 
         Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) }))
@@ -310,6 +326,36 @@ impl FileAttr {
         fn from_stat64(stat: stat64) -> Self {
             Self { stat, statx_extra_fields: None }
         }
+
+        #[cfg(target_pointer_width = "32")]
+        pub fn stx_mtime(&self) -> Option<&libc::statx_timestamp> {
+            if let Some(ext) = &self.statx_extra_fields {
+                if (ext.stx_mask & libc::STATX_MTIME) != 0 {
+                    return Some(&ext.stx_mtime);
+                }
+            }
+            None
+        }
+
+        #[cfg(target_pointer_width = "32")]
+        pub fn stx_atime(&self) -> Option<&libc::statx_timestamp> {
+            if let Some(ext) = &self.statx_extra_fields {
+                if (ext.stx_mask & libc::STATX_ATIME) != 0 {
+                    return Some(&ext.stx_atime);
+                }
+            }
+            None
+        }
+
+        #[cfg(target_pointer_width = "32")]
+        pub fn stx_ctime(&self) -> Option<&libc::statx_timestamp> {
+            if let Some(ext) = &self.statx_extra_fields {
+                if (ext.stx_mask & libc::STATX_CTIME) != 0 {
+                    return Some(&ext.stx_ctime);
+                }
+            }
+            None
+        }
     }
 } else {
     impl FileAttr {
@@ -335,24 +381,15 @@ pub fn file_type(&self) -> FileType {
 #[cfg(target_os = "netbsd")]
 impl FileAttr {
     pub fn modified(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_mtime as libc::time_t,
-            tv_nsec: self.stat.st_mtimensec as libc::c_long,
-        }))
+        Ok(SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtimensec as i64))
     }
 
     pub fn accessed(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_atime as libc::time_t,
-            tv_nsec: self.stat.st_atimensec as libc::c_long,
-        }))
+        Ok(SystemTime::new(self.stat.st_atime as i64, self.stat.st_atimensec as i64))
     }
 
     pub fn created(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_birthtime as libc::time_t,
-            tv_nsec: self.stat.st_birthtimensec as libc::c_long,
-        }))
+        Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtimensec as i64))
     }
 }
 
@@ -360,34 +397,36 @@ pub fn created(&self) -> io::Result<SystemTime> {
 impl FileAttr {
     #[cfg(all(not(target_os = "vxworks"), not(target_os = "espidf")))]
     pub fn modified(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_mtime as libc::time_t,
-            tv_nsec: self.stat.st_mtime_nsec as _,
-        }))
+        #[cfg(target_pointer_width = "32")]
+        cfg_has_statx! {
+            if let Some(mtime) = self.stx_mtime() {
+                return Ok(SystemTime::new(mtime.tv_sec, mtime.tv_nsec as i64));
+            }
+        }
+
+        Ok(SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtime_nsec as i64))
     }
 
     #[cfg(any(target_os = "vxworks", target_os = "espidf"))]
     pub fn modified(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_mtime as libc::time_t,
-            tv_nsec: 0,
-        }))
+        Ok(SystemTime::new(self.stat.st_mtime as i64, 0))
     }
 
     #[cfg(all(not(target_os = "vxworks"), not(target_os = "espidf")))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_atime as libc::time_t,
-            tv_nsec: self.stat.st_atime_nsec as _,
-        }))
+        #[cfg(target_pointer_width = "32")]
+        cfg_has_statx! {
+            if let Some(atime) = self.stx_atime() {
+                return Ok(SystemTime::new(atime.tv_sec, atime.tv_nsec as i64));
+            }
+        }
+
+        Ok(SystemTime::new(self.stat.st_atime as i64, self.stat.st_atime_nsec as i64))
     }
 
     #[cfg(any(target_os = "vxworks", target_os = "espidf"))]
     pub fn accessed(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_atime as libc::time_t,
-            tv_nsec: 0,
-        }))
+        Ok(SystemTime::new(self.stat.st_atime as i64, 0))
     }
 
     #[cfg(any(
@@ -397,10 +436,7 @@ pub fn accessed(&self) -> io::Result<SystemTime> {
         target_os = "ios"
     ))]
     pub fn created(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::from(libc::timespec {
-            tv_sec: self.stat.st_birthtime as libc::time_t,
-            tv_nsec: self.stat.st_birthtime_nsec as libc::c_long,
-        }))
+        Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64))
     }
 
     #[cfg(not(any(
@@ -413,10 +449,7 @@ pub fn created(&self) -> io::Result<SystemTime> {
         cfg_has_statx! {
             if let Some(ext) = &self.statx_extra_fields {
                 return if (ext.stx_mask & libc::STATX_BTIME) != 0 {
-                    Ok(SystemTime::from(libc::timespec {
-                        tv_sec: ext.stx_btime.tv_sec as libc::time_t,
-                        tv_nsec: ext.stx_btime.tv_nsec as _,
-                    }))
+                    Ok(SystemTime::new(ext.stx_btime.tv_sec, ext.stx_btime.tv_nsec as i64))
                 } else {
                     Err(io::const_io_error!(
                         io::ErrorKind::Uncategorized,
@@ -910,7 +943,6 @@ unsafe fn os_datasync(fd: c_int) -> c_int {
     }
 
     pub fn truncate(&self, size: u64) -> io::Result<()> {
-        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)
index 678c6f0d6ead1b6ab299a196ba10974517d551d1..8d5ad18997d07859a03e5d1778f878458cf72f52 100644 (file)
@@ -24,8 +24,9 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
     // Calculate the timeout as an absolute timespec.
     //
     // Overflows are rounded up to an infinite timeout (None).
-    let timespec =
-        timeout.and_then(|d| Some(Timespec::now(libc::CLOCK_MONOTONIC).checked_add_duration(&d)?));
+    let timespec = timeout
+        .and_then(|d| Some(Timespec::now(libc::CLOCK_MONOTONIC).checked_add_duration(&d)?))
+        .and_then(|t| t.to_timespec());
 
     loop {
         // No need to wait if the value already changed.
@@ -41,7 +42,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
                     // identical. It supports absolute timeouts through a flag
                     // in the _umtx_time struct.
                     let umtx_timeout = timespec.map(|t| libc::_umtx_time {
-                        _timeout: t.t,
+                        _timeout: t,
                         _flags: libc::UMTX_ABSTIME,
                         _clockid: libc::CLOCK_MONOTONIC as u32,
                     });
@@ -62,7 +63,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
                         futex as *const AtomicU32,
                         libc::FUTEX_WAIT_BITSET | libc::FUTEX_PRIVATE_FLAG,
                         expected,
-                        timespec.as_ref().map_or(null(), |t| &t.t as *const libc::timespec),
+                        timespec.as_ref().map_or(null(), |t| t as *const libc::timespec),
                         null::<u32>(), // This argument is unused for FUTEX_WAIT_BITSET.
                         !0u32,         // A full bitmask, to make it behave like a regular FUTEX_WAIT.
                     )
@@ -135,7 +136,6 @@ pub fn futex_wake_all(futex: &AtomicU32) {
 
 #[cfg(target_os = "openbsd")]
 pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
-    use crate::convert::TryInto;
     use crate::ptr::{null, null_mut};
     let timespec = timeout.and_then(|d| {
         Some(libc::timespec {
@@ -184,8 +184,6 @@ pub fn futex_wake_all(futex: &AtomicU32) {
 
 #[cfg(target_os = "dragonfly")]
 pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
-    use crate::convert::TryFrom;
-
     // A timeout of 0 means infinite.
     // We round smaller timeouts up to 1 millisecond.
     // Overflows are rounded up to an infinite timeout.
index e85e4c5d618ced0a1e679f96cf858cefcabfff44..8f7abb55e237644ef0b03d90c6b58cc09ec20dbd 100644 (file)
@@ -45,7 +45,6 @@
 //! * complexity
 
 use crate::cmp::min;
-use crate::convert::TryInto;
 use crate::fs::{File, Metadata};
 use crate::io::copy::generic_copy;
 use crate::io::{
index f052d8f7f055f3cb23200df5d95122315dc15853..9967588939ac9f675338ab67474bf02f9c92de82 100644 (file)
@@ -9,7 +9,6 @@ macro_rules! unimpl {
 
 pub mod net {
     #![allow(warnings)]
-    use crate::convert::TryFrom;
     use crate::fmt;
     use crate::io::{self, IoSlice, IoSliceMut};
     use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
index e3347ab12a7309e8bca82bd9a6b67a197cf5cda6..73f5d3a618badc12e557e77f9f0af05624b31bed 100644 (file)
@@ -1,4 +1,3 @@
-use crate::convert::{TryFrom, TryInto};
 use crate::fmt;
 use crate::io;
 use crate::mem;
index d48faaa88fb4f56e91082d73172a97ceed6d8cc7..23bb6d6c15f637fe1a36f61b5f5400d8125cefc9 100644 (file)
@@ -1,4 +1,3 @@
-use crate::convert::{TryFrom, TryInto};
 use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
 use crate::mem;
index bbabdf787d994dce53d3d4f6731508d47f54466d..5db57ee9e9e18691e346fa7081cf31d9dc4992da 100644 (file)
@@ -1,4 +1,3 @@
-use crate::convert::{TryFrom, TryInto};
 use crate::fmt;
 use crate::io;
 use crate::io::ErrorKind;
index 016bc20ec0a47dcbd13c8f30612bfef338dcc8ea..200ef6719679845ca7ed9076ebc7a23bc46ccbea 100644 (file)
@@ -1,4 +1,3 @@
-use crate::convert::{TryFrom, TryInto};
 use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
 use crate::num::NonZeroI32;
index 4dfa2b4ff1eb432aaddd2ba69b195249286ad5cb..2e596486f9c8690e1a132bcf07289e5bef02d85c 100644 (file)
@@ -1,6 +1,5 @@
 #![allow(non_camel_case_types, unused)]
 
-use crate::convert::TryInto;
 use crate::io;
 use crate::mem::MaybeUninit;
 use crate::os::raw::c_char;
index cf37c01598bf30efb9c86600559654dc494b9f96..30ed2ec7f5442964b1addc4c2a374ff36a2e721f 100644 (file)
@@ -79,7 +79,8 @@ unsafe fn wait_timeout(
         (Timespec::now(libc::CLOCK_MONOTONIC), dur)
     };
 
-    let timeout = now.checked_add_duration(&dur).map(|t| t.t).unwrap_or(TIMESPEC_MAX);
+    let timeout =
+        now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX);
     let r = libc::pthread_cond_timedwait(cond, lock, &timeout);
     debug_assert!(r == libc::ETIMEDOUT || r == 0);
 }
index d43ceec9c8a59528d617e20f0054455f4b5fadc7..333182bdad4de809d7313d430f8ebc4209952a95 100644 (file)
@@ -1,21 +1,62 @@
-use crate::cmp::Ordering;
+use crate::fmt;
 use crate::time::Duration;
 
-use core::hash::{Hash, Hasher};
-
-pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
-use crate::convert::TryInto;
+pub use self::inner::Instant;
 
 const NSEC_PER_SEC: u64 = 1_000_000_000;
+pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct SystemTime {
+    pub(in crate::sys::unix) t: Timespec,
+}
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub(in crate::sys::unix) struct Timespec {
-    pub t: libc::timespec,
+    tv_sec: i64,
+    tv_nsec: i64,
+}
+
+impl SystemTime {
+    pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime {
+        SystemTime { t: Timespec::new(tv_sec, tv_nsec) }
+    }
+
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        self.t.sub_timespec(&other.t)
+    }
+
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+        Some(SystemTime { t: self.t.checked_add_duration(other)? })
+    }
+
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+        Some(SystemTime { t: self.t.checked_sub_duration(other)? })
+    }
+}
+
+impl From<libc::timespec> for SystemTime {
+    fn from(t: libc::timespec) -> SystemTime {
+        SystemTime { t: Timespec::from(t) }
+    }
+}
+
+impl fmt::Debug for SystemTime {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("SystemTime")
+            .field("tv_sec", &self.t.tv_sec)
+            .field("tv_nsec", &self.t.tv_nsec)
+            .finish()
+    }
 }
 
 impl Timespec {
     const fn zero() -> Timespec {
-        Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }
+        Timespec { tv_sec: 0, tv_nsec: 0 }
+    }
+
+    fn new(tv_sec: i64, tv_nsec: i64) -> Timespec {
+        Timespec { tv_sec, tv_nsec }
     }
 
     pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
@@ -23,22 +64,22 @@ pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
             // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
             // to optimize it into a branchless form (see also #75545):
             //
-            // 1. `self.t.tv_sec - other.t.tv_sec` shows up as a common expression
+            // 1. `self.tv_sec - other.tv_sec` shows up as a common expression
             //    in both branches, i.e. the `else` must have its `- 1`
             //    subtraction after the common one, not interleaved with it
-            //    (it used to be `self.t.tv_sec - 1 - other.t.tv_sec`)
+            //    (it used to be `self.tv_sec - 1 - other.tv_sec`)
             //
             // 2. the `Duration::new` call (or any other additional complexity)
             //    is outside of the `if`-`else`, not duplicated in both branches
             //
             // Ideally this code could be rearranged such that it more
             // directly expresses the lower-cost behavior we want from it.
-            let (secs, nsec) = if self.t.tv_nsec >= other.t.tv_nsec {
-                ((self.t.tv_sec - other.t.tv_sec) as u64, (self.t.tv_nsec - other.t.tv_nsec) as u32)
+            let (secs, nsec) = if self.tv_nsec >= other.tv_nsec {
+                ((self.tv_sec - other.tv_sec) as u64, (self.tv_nsec - other.tv_nsec) as u32)
             } else {
                 (
-                    (self.t.tv_sec - other.t.tv_sec - 1) as u64,
-                    self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32,
+                    (self.tv_sec - other.tv_sec - 1) as u64,
+                    self.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.tv_nsec as u32,
                 )
             };
 
@@ -54,89 +95,64 @@ pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
     pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
         let mut secs = other
             .as_secs()
-            .try_into() // <- target type would be `libc::time_t`
+            .try_into() // <- target type would be `i64`
             .ok()
-            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;
+            .and_then(|secs| self.tv_sec.checked_add(secs))?;
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
-        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
+        let mut nsec = other.subsec_nanos() + self.tv_nsec as u32;
         if nsec >= NSEC_PER_SEC as u32 {
             nsec -= NSEC_PER_SEC as u32;
             secs = secs.checked_add(1)?;
         }
-        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
+        Some(Timespec::new(secs, nsec as i64))
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
         let mut secs = other
             .as_secs()
-            .try_into() // <- target type would be `libc::time_t`
+            .try_into() // <- target type would be `i64`
             .ok()
-            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
+            .and_then(|secs| self.tv_sec.checked_sub(secs))?;
 
         // Similar to above, nanos can't overflow.
-        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
+        let mut nsec = self.tv_nsec as i32 - other.subsec_nanos() as i32;
         if nsec < 0 {
             nsec += NSEC_PER_SEC as i32;
             secs = secs.checked_sub(1)?;
         }
-        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
-    }
-}
-
-impl PartialEq for Timespec {
-    fn eq(&self, other: &Timespec) -> bool {
-        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
-    }
-}
-
-impl Eq for Timespec {}
-
-impl PartialOrd for Timespec {
-    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
-        Some(self.cmp(other))
+        Some(Timespec::new(secs, nsec as i64))
     }
-}
 
-impl Ord for Timespec {
-    fn cmp(&self, other: &Timespec) -> Ordering {
-        let me = (self.t.tv_sec, self.t.tv_nsec);
-        let other = (other.t.tv_sec, other.t.tv_nsec);
-        me.cmp(&other)
+    pub fn to_timespec(&self) -> Option<libc::timespec> {
+        Some(libc::timespec {
+            tv_sec: self.tv_sec.try_into().ok()?,
+            tv_nsec: self.tv_nsec.try_into().ok()?,
+        })
     }
 }
 
-impl Hash for Timespec {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.t.tv_sec.hash(state);
-        self.t.tv_nsec.hash(state);
+impl From<libc::timespec> for Timespec {
+    fn from(t: libc::timespec) -> Timespec {
+        Timespec::new(t.tv_sec as i64, t.tv_nsec as i64)
     }
 }
 
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 mod inner {
-    use crate::fmt;
     use crate::sync::atomic::{AtomicU64, Ordering};
     use crate::sys::cvt;
     use crate::sys_common::mul_div_u64;
     use crate::time::Duration;
 
-    use super::Timespec;
-    use super::NSEC_PER_SEC;
+    use super::{SystemTime, Timespec, NSEC_PER_SEC};
 
     #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
     pub struct Instant {
         t: u64,
     }
 
-    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-    pub struct SystemTime {
-        pub(in crate::sys::unix) t: Timespec,
-    }
-
-    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
-
     #[repr(C)]
     #[derive(Copy, Clone)]
     struct mach_timebase_info {
@@ -178,41 +194,17 @@ pub fn now() -> SystemTime {
             cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap();
             return SystemTime::from(s);
         }
+    }
 
-        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-            self.t.sub_timespec(&other.t)
-        }
-
-        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
-            Some(SystemTime { t: self.t.checked_add_duration(other)? })
-        }
-
-        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
-            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
+    impl From<libc::timeval> for Timespec {
+        fn from(t: libc::timeval) -> Timespec {
+            Timespec::new(t.tv_sec as i64, 1000 * t.tv_usec as i64)
         }
     }
 
     impl From<libc::timeval> for SystemTime {
         fn from(t: libc::timeval) -> SystemTime {
-            SystemTime::from(libc::timespec {
-                tv_sec: t.tv_sec,
-                tv_nsec: (t.tv_usec * 1000) as libc::c_long,
-            })
-        }
-    }
-
-    impl From<libc::timespec> for SystemTime {
-        fn from(t: libc::timespec) -> SystemTime {
-            SystemTime { t: Timespec { t } }
-        }
-    }
-
-    impl fmt::Debug for SystemTime {
-        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            f.debug_struct("SystemTime")
-                .field("tv_sec", &self.t.t.tv_sec)
-                .field("tv_nsec", &self.t.t.tv_nsec)
-                .finish()
+            SystemTime { t: Timespec::from(t) }
         }
     }
 
@@ -270,20 +262,13 @@ mod inner {
     use crate::sys::cvt;
     use crate::time::Duration;
 
-    use super::Timespec;
+    use super::{SystemTime, Timespec};
 
     #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
     pub struct Instant {
         t: Timespec,
     }
 
-    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-    pub struct SystemTime {
-        pub(in crate::sys::unix) t: Timespec,
-    }
-
-    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
-
     impl Instant {
         pub fn now() -> Instant {
             Instant { t: Timespec::now(libc::CLOCK_MONOTONIC) }
@@ -305,8 +290,8 @@ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
     impl fmt::Debug for Instant {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             f.debug_struct("Instant")
-                .field("tv_sec", &self.t.t.tv_sec)
-                .field("tv_nsec", &self.t.t.tv_nsec)
+                .field("tv_sec", &self.t.tv_sec)
+                .field("tv_nsec", &self.t.tv_nsec)
                 .finish()
         }
     }
@@ -315,33 +300,6 @@ impl SystemTime {
         pub fn now() -> SystemTime {
             SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
         }
-
-        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-            self.t.sub_timespec(&other.t)
-        }
-
-        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
-            Some(SystemTime { t: self.t.checked_add_duration(other)? })
-        }
-
-        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
-            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
-        }
-    }
-
-    impl From<libc::timespec> for SystemTime {
-        fn from(t: libc::timespec) -> SystemTime {
-            SystemTime { t: Timespec { t } }
-        }
-    }
-
-    impl fmt::Debug for SystemTime {
-        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            f.debug_struct("SystemTime")
-                .field("tv_sec", &self.t.t.tv_sec)
-                .field("tv_nsec", &self.t.t.tv_nsec)
-                .finish()
-        }
     }
 
     #[cfg(not(any(target_os = "dragonfly", target_os = "espidf")))]
@@ -351,9 +309,36 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
     impl Timespec {
         pub fn now(clock: clock_t) -> Timespec {
+            // Try to use 64-bit time in preparation for Y2038.
+            #[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32"))]
+            {
+                use crate::sys::weak::weak;
+
+                // __clock_gettime64 was added to 32-bit arches in glibc 2.34,
+                // and it handles both vDSO calls and ENOSYS fallbacks itself.
+                weak!(fn __clock_gettime64(libc::clockid_t, *mut __timespec64) -> libc::c_int);
+
+                #[repr(C)]
+                struct __timespec64 {
+                    tv_sec: i64,
+                    #[cfg(target_endian = "big")]
+                    _padding: i32,
+                    tv_nsec: i32,
+                    #[cfg(target_endian = "little")]
+                    _padding: i32,
+                }
+
+                if let Some(clock_gettime64) = __clock_gettime64.get() {
+                    let mut t = MaybeUninit::uninit();
+                    cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap();
+                    let t = unsafe { t.assume_init() };
+                    return Timespec { tv_sec: t.tv_sec, tv_nsec: t.tv_nsec as i64 };
+                }
+            }
+
             let mut t = MaybeUninit::uninit();
             cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap();
-            Timespec { t: unsafe { t.assume_init() } }
+            Timespec::from(unsafe { t.assume_init() })
         }
     }
 }
index dbb6ce22c22de18cd99c6df1483a4efeb2e835cc..360115d5033747c298c23d1d8a9c48d3bc1eaefc 100644 (file)
@@ -1,4 +1,3 @@
-use crate::convert::TryFrom;
 use crate::fmt;
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
index c66e0e4d328ad09a3401fa7517419090d9be5604..937b1b850e7ba7201a61161c3d42ff41efa127d6 100644 (file)
@@ -2,7 +2,6 @@
 
 use super::err2io;
 use super::fd::WasiFd;
-use crate::convert::TryFrom;
 use crate::fmt;
 use crate::io::{self, IoSlice, IoSliceMut};
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
index 11413ba3bf5642d484b1a3de09f3c0579b18e426..f4fbe9f48554b0e19fb2db3db3ceb2adf5b09c6d 100644 (file)
@@ -1,5 +1,4 @@
 use crate::arch::wasm32;
-use crate::convert::TryInto;
 use crate::sync::atomic::AtomicU32;
 use crate::time::Duration;
 
index 95903899297b601a8ad84679c8699b21d492c497..157d8a044d3cd815ff2cda9c7fc69c01314c52bb 100644 (file)
@@ -1,6 +1,5 @@
 use crate::os::windows::prelude::*;
 
-use crate::convert::TryInto;
 use crate::ffi::OsString;
 use crate::fmt;
 use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
index 78e92a3331a1c4678ced79fe119cc263cdb5567b..11883f15022f659817f06e23faffe6df5ed1af07 100644 (file)
@@ -44,6 +44,7 @@ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+#[repr(transparent)]
 pub struct Slice {
     pub inner: Wtf8,
 }
index 8656b04e4f410320befd75d198bd9c9a1690d254..2f7ec433bf26119fff40524224ca5463aa341d52 100644 (file)
@@ -114,3 +114,15 @@ fn test_parse_prefix_verbatim_device() {
     assert_eq!(prefix, parse_prefix(r"/\?\C:\windows\system32\notepad.exe"));
     assert_eq!(prefix, parse_prefix(r"\\?/C:\windows\system32\notepad.exe"));
 }
+
+// See #93586 for more infomation.
+#[test]
+fn test_windows_prefix_components() {
+    use crate::path::Path;
+
+    let path = Path::new("C:");
+    let mut components = path.components();
+    let drive = components.next().expect("drive is expected here");
+    assert_eq!(drive.as_os_str(), OsStr::new("C:"));
+    assert_eq!(components.as_path(), Path::new(""));
+}
index cc29d1a72fbf416cbed51c007e396b7002f55813..8e5325b80e4a50564b86bb70eda44b08028611cf 100644 (file)
@@ -5,7 +5,6 @@
 
 use crate::cmp;
 use crate::collections::BTreeMap;
-use crate::convert::{TryFrom, TryInto};
 use crate::env;
 use crate::env::consts::{EXE_EXTENSION, EXE_SUFFIX};
 use crate::ffi::{OsStr, OsString};
@@ -14,7 +13,7 @@
 use crate::mem;
 use crate::num::NonZeroI32;
 use crate::os::windows::ffi::{OsStrExt, OsStringExt};
-use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle};
+use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
 use crate::sys::args::{self, Arg};
@@ -334,13 +333,14 @@ pub fn spawn(
             ))
         }?;
 
-        // We close the thread handle because we don't care about keeping
-        // the thread id valid, and we aren't keeping the thread handle
-        // around to be able to close it later.
         unsafe {
-            drop(Handle::from_raw_handle(pi.hThread));
-
-            Ok((Process { handle: Handle::from_raw_handle(pi.hProcess) }, pipes))
+            Ok((
+                Process {
+                    handle: Handle::from_raw_handle(pi.hProcess),
+                    main_thread_handle: Handle::from_raw_handle(pi.hThread),
+                },
+                pipes,
+            ))
         }
     }
 }
@@ -609,6 +609,7 @@ fn from(file: File) -> Stdio {
 /// for the process to terminate.
 pub struct Process {
     handle: Handle,
+    main_thread_handle: Handle,
 }
 
 impl Process {
@@ -621,6 +622,10 @@ pub fn id(&self) -> u32 {
         unsafe { c::GetProcessId(self.handle.as_raw_handle()) as u32 }
     }
 
+    pub fn main_thread_handle(&self) -> BorrowedHandle<'_> {
+        self.main_thread_handle.as_handle()
+    }
+
     pub fn wait(&mut self) -> io::Result<ExitStatus> {
         unsafe {
             let res = c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE);
index be3a0f4ed52a981ae13d23b25ad81af8d27665a0..3fc0c75240c33c0adede4c91f73c1d77fcde74e2 100644 (file)
@@ -24,6 +24,31 @@ fn test_raw_args() {
     );
 }
 
+#[test]
+fn test_thread_handle() {
+    use crate::os::windows::io::BorrowedHandle;
+    use crate::os::windows::process::{ChildExt, CommandExt};
+    const CREATE_SUSPENDED: u32 = 0x00000004;
+
+    let p = Command::new("cmd").args(&["/C", "exit 0"]).creation_flags(CREATE_SUSPENDED).spawn();
+    assert!(p.is_ok());
+    let mut p = p.unwrap();
+
+    extern "system" {
+        fn ResumeThread(_: BorrowedHandle<'_>) -> u32;
+    }
+    unsafe {
+        ResumeThread(p.main_thread_handle());
+    }
+
+    crate::thread::sleep(crate::time::Duration::from_millis(100));
+
+    let res = p.try_wait();
+    assert!(res.is_ok());
+    assert!(res.unwrap().is_some());
+    assert!(p.try_wait().unwrap().unwrap().success());
+}
+
 #[test]
 fn test_make_command_line() {
     fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
index 2f469513eb4fd63ac50c2b9f022ea1eab90ec30e..c5c9e97e646fb94fa6960c1da38ba09f1265f04b 100644 (file)
@@ -1,4 +1,3 @@
-use crate::convert::TryInto;
 use crate::ffi::CStr;
 use crate::io;
 use crate::num::NonZeroUsize;
index 5144834447503414a9ea832e1b9b930ff1d44dd9..d876e0f6f3c03b5bf8a590d78c4461b1429585de 100644 (file)
@@ -57,7 +57,6 @@
 // [3]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2012/november/windows-with-c-the-evolution-of-synchronization-in-windows-and-c
 // [4]: Windows Internals, Part 1, ISBN 9780735671300
 
-use crate::convert::TryFrom;
 use crate::pin::Pin;
 use crate::ptr;
 use crate::sync::atomic::{
index a04908b541cdb58a859eba464d989be62c8ad2df..8f46781c7534092a6f11d8d4205eebff812b2fcc 100644 (file)
@@ -1,5 +1,4 @@
 use crate::cmp::Ordering;
-use crate::convert::TryInto;
 use crate::fmt;
 use crate::mem;
 use crate::sys::c;
index 3b7cdd55a081c3149114346fe835416b832ed5e6..05425f4a3622ce04167f4df5dca684774bfd17ce 100644 (file)
@@ -2,7 +2,6 @@
 mod tests;
 
 use crate::cmp;
-use crate::convert::{TryFrom, TryInto};
 use crate::ffi::CString;
 use crate::fmt;
 use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
index 7d66973bed6f58736e13f2923ad571f6b26388cf..57fa4989358a4f5d880aa142a6dcfdf907693610 100644 (file)
@@ -25,7 +25,7 @@
 use crate::collections::TryReserveError;
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
-use crate::iter::{FromIterator, FusedIterator};
+use crate::iter::FusedIterator;
 use crate::mem;
 use crate::ops;
 use crate::rc::Rc;
index b4b1037a3cd392a60131aa18bc65f8333c10207d..7f9b297e9dc3a581c26dd651fb525edd5ea13a96 100644 (file)
@@ -789,7 +789,7 @@ pub fn panicking() -> bool {
 /// thread::sleep_ms(2000);
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::sleep`")]
+#[deprecated(since = "1.6.0", note = "replaced by `std::thread::sleep`")]
 pub fn sleep_ms(ms: u32) {
     sleep(Duration::from_millis(ms as u64))
 }
@@ -943,7 +943,7 @@ pub fn park() {
 ///
 /// See the [park documentation][`park`] for more detail.
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::park_timeout`")]
+#[deprecated(since = "1.6.0", note = "replaced by `std::thread::park_timeout`")]
 pub fn park_timeout_ms(ms: u32) {
     park_timeout(Duration::from_millis(ms as u64))
 }
index e38a574ca2310de1b230e2c0009a9e9d4f31d414..ab4338e1c85ef1bad52b1d165350e73edd795a36 100644 (file)
@@ -998,6 +998,10 @@ class RustBuild(object):
             "library/backtrace",
             "library/stdarch"
         ]
+        # If build.vendor is set in config.toml, we must update rust-analyzer also.
+        # Otherwise, the bootstrap will fail (#96456).
+        if self.use_vendored_sources:
+            submodules.append("src/tools/rust-analyzer")
         filtered_submodules = []
         submodules_names = []
         for module in submodules:
index fe60c6da92bfb0f67bf93ae8a735b5c88689b509..7d838c0a61d22f521012c1a787564949d1c6a715 100644 (file)
@@ -534,7 +534,7 @@ macro_rules! describe {
                 native::Lld,
                 native::CrtBeginEnd
             ),
-            Kind::Check => describe!(
+            Kind::Check | Kind::Clippy | Kind::Fix => describe!(
                 check::Std,
                 check::Rustc,
                 check::Rustdoc,
@@ -664,7 +664,7 @@ macro_rules! describe {
             ),
             Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest, run::BumpStage0),
             // These commands either don't use paths, or they're special-cased in Build::build()
-            Kind::Clean | Kind::Clippy | Kind::Fix | Kind::Format | Kind::Setup => vec![],
+            Kind::Clean | Kind::Format | Kind::Setup => vec![],
         }
     }
 
@@ -1143,13 +1143,22 @@ pub fn cargo(
             rustflags.arg("-Zunstable-options");
         }
 
-        // #[cfg(not(bootstrap)]
+        // FIXME(Urgau): This a hack as it shouldn't be gated on stage 0 but until `rustc_llvm`
+        // is made to work with `--check-cfg` which is currently not easly possible until cargo
+        // get some support for setting `--check-cfg` within build script, it's the least invasive
+        // hack that still let's us have cfg checking for the vast majority of the codebase.
         if stage != 0 {
-            // Enable cfg checking of cargo features
-            // FIXME: De-comment this when cargo beta get support for it
-            // cargo.arg("-Zcheck-cfg-features");
+            // Enable cfg checking of cargo features for everything but std.
+            //
+            // Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like
+            // backtrace, core_simd, std_float, ...), those dependencies have their own features
+            // but cargo isn't involved in the #[path] and so cannot pass the complete list of
+            // features, so for that reason we don't enable checking of features for std.
+            if mode != Mode::Std {
+                cargo.arg("-Zcheck-cfg-features");
+            }
 
-            // Enable cfg checking of rustc well-known names
+            // Enable cfg checking of well known names/values
             rustflags
                 .arg("-Zunstable-options")
                 // Enable checking of well known names
index 011ff6821b771acb8ed4b8a7e5b8c216b7007652..088cbd1057ec568186ed89eba6b2738e64bdda25 100644 (file)
@@ -1,4 +1,8 @@
 # These defaults are meant for contributors to the compiler who modify codegen or LLVM
+[build]
+# Contributors working on the compiler will probably expect compiler docs to be generated.
+compiler-docs = true
+
 [llvm]
 # This enables debug-assertions in LLVM,
 # catching logic errors in codegen much earlier in the process.
index 4d689d117bc0d0731c0805c7ffb8e241704c97f1..2f4ccb825c4d8738199976676b69195e5345a445 100644 (file)
@@ -1,4 +1,8 @@
 # These defaults are meant for contributors to the compiler who do not modify codegen or LLVM
+[build]
+# Contributors working on the compiler will probably expect compiler docs to be generated.
+compiler-docs = true
+
 [rust]
 # This enables `RUSTC_LOG=debug`, avoiding confusing situations
 # where adding `debug!()` appears to do nothing.
index 88359fff191e3978076da84f206a7a49a9de529a..6b6625342a67e03bfbfa12bc185388ac6a52a5e9 100644 (file)
@@ -14,6 +14,8 @@ download-rustc = "if-unchanged"
 [build]
 # Document with the in-tree rustdoc by default, since `download-rustc` makes it quick to compile.
 doc-stage = 2
+# Contributors working on tools will probably expect compiler docs to be generated, so they can figure out how to use the API.
+compiler-docs = true
 
 [llvm]
 # Will download LLVM from CI if available on your platform.
index b4b973b42479e942099f69a109786506371b737f..b2279bc8b5614ca1288faeea1ee83b11745ef6eb 100644 (file)
@@ -609,7 +609,7 @@ fn dir_is_empty(dir: &Path) -> bool {
     /// This avoids contributors checking in a submodule change by accident.
     pub fn maybe_update_submodules(&self) {
         // WARNING: keep this in sync with the submodules hard-coded in bootstrap.py
-        const BOOTSTRAP_SUBMODULES: &[&str] = &[
+        let mut bootstrap_submodules: Vec<&str> = vec![
             "src/tools/rust-installer",
             "src/tools/cargo",
             "src/tools/rls",
@@ -617,6 +617,11 @@ pub fn maybe_update_submodules(&self) {
             "library/backtrace",
             "library/stdarch",
         ];
+        // As in bootstrap.py, we include `rust-analyzer` if `build.vendor` was set in
+        // `config.toml`.
+        if self.config.vendor {
+            bootstrap_submodules.push("src/tools/rust-analyzer");
+        }
         // Avoid running git when there isn't a git checkout.
         if !self.config.submodules(&self.rust_info) {
             return;
@@ -632,7 +637,7 @@ pub fn maybe_update_submodules(&self) {
             // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
             let submodule = Path::new(line.splitn(2, ' ').nth(1).unwrap());
             // avoid updating submodules twice
-            if !BOOTSTRAP_SUBMODULES.iter().any(|&p| Path::new(p) == submodule)
+            if !bootstrap_submodules.iter().any(|&p| Path::new(p) == submodule)
                 && channel::GitInfo::new(false, submodule).is_git()
             {
                 self.update_submodule(submodule);
@@ -1492,20 +1497,14 @@ fn install(&self, src: &Path, dstdir: &Path, perms: u32) {
         let dst = dstdir.join(src.file_name().unwrap());
         self.verbose_than(1, &format!("Install {:?} to {:?}", src, dst));
         t!(fs::create_dir_all(dstdir));
-        drop(fs::remove_file(&dst));
         {
             if !src.exists() {
                 panic!("Error: File \"{}\" not found!", src.display());
             }
-            let metadata = t!(src.symlink_metadata());
-            if let Err(e) = fs::copy(&src, &dst) {
-                panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e)
-            }
-            t!(fs::set_permissions(&dst, metadata.permissions()));
-            let atime = FileTime::from_last_access_time(&metadata);
-            let mtime = FileTime::from_last_modification_time(&metadata);
-            t!(filetime::set_file_times(&dst, atime, mtime));
+            self.copy(src, &dst);
         }
+        // NOTE: when using hard-links, this will also update the permissions on the original file.
+        // We never use permissions that are more restrictive than the original, so this shouldn't cause any issues.
         chmod(&dst, perms);
     }
 
index fd39944e176fe991405a2a01f9da9c9745e0fb85..5a1f2e70413781ddd529ffdb38ccb20cba236826 100644 (file)
@@ -45,8 +45,6 @@ check-aux:
                src/tools/cargo \
                src/tools/cargotest \
                $(BOOTSTRAP_ARGS)
-check-bootstrap:
-       $(Q)$(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap_test.py
 dist:
        $(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
 distcheck:
index c96e6f9a3678f222937714e4561fa472aae0cbec..64c5dd7aea7202ef50a4ba49cc3738c6727c7f16 100644 (file)
@@ -94,7 +94,18 @@ pub fn check(build: &mut Build) {
             .any(|build_llvm_ourselves| build_llvm_ourselves);
     let need_cmake = building_llvm || build.config.any_sanitizers_enabled();
     if need_cmake {
-        cmd_finder.must_have("cmake");
+        if cmd_finder.maybe_have("cmake").is_none() {
+            eprintln!(
+                "
+Couldn't find required command: cmake
+
+You should install cmake, or set `download-ci-llvm = true` in the
+`[llvm]` section section of `config.toml` to download LLVM rather
+than building it.
+"
+            );
+            std::process::exit(1);
+        }
     }
 
     build.config.python = build
index 4dfc02dea460572b8a724338f2f95319fd36b1f0..bc851568f896b95076ef5926dc01af6f66d380ae 100644 (file)
@@ -664,8 +664,6 @@ fn run(self, builder: &Builder<'_>) {
             &[],
         );
 
-        // clippy tests need to know about the stage sysroot
-        cargo.env("SYSROOT", builder.sysroot(compiler));
         cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
         cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
         let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
@@ -2353,6 +2351,10 @@ impl Step for Bootstrap {
 
     /// Tests the build system itself.
     fn run(self, builder: &Builder<'_>) {
+        let mut check_bootstrap = Command::new(&builder.python());
+        check_bootstrap.arg("bootstrap_test.py").current_dir(builder.src.join("src/bootstrap/"));
+        try_run(builder, &mut check_bootstrap);
+
         let mut cmd = Command::new(&builder.initial_cargo);
         cmd.arg("test")
             .current_dir(builder.src.join("src/bootstrap"))
index fc1c2f04fabff08239adcb8a261a7b2ab4f886f4..3b30e6de12a63abed65ed9388ea05a4e339e63ee 100644 (file)
@@ -250,6 +250,10 @@ pub fn prepare_tool_cargo(
         }
     }
 
+    // clippy tests need to know about the stage sysroot. Set them consistently while building to
+    // avoid rebuilding when running tests.
+    cargo.env("SYSROOT", builder.sysroot(compiler));
+
     // if tools are using lzma we want to force the build script to build its
     // own copy
     cargo.env("LZMA_API_STATIC", "1");
index 948445427d95bcabb11d119d6bb8f72ae54906e3..5f843a13bcd9b574ddbed4e71bf61ed3a12ce5e1 100755 (executable)
@@ -141,8 +141,6 @@ $SRC/configure $RUST_CONFIGURE_ARGS
 
 retry make prepare
 
-make check-bootstrap
-
 # Display the CPU and memory information. This helps us know why the CI timing
 # is fluctuating.
 if isMacOS; then
index 3b0cf92bbb763d1450443947a5792ea71b83f02e..02011325d687881c02174adbd61ac1148d95fe80 100644 (file)
@@ -550,6 +550,21 @@ Supported values for this option are:
 - `symbols` - same as `debuginfo`, but the rest of the symbol table section is
   stripped as well if the linker supports it.
 
+## symbol-mangling-version
+
+This option controls the [name mangling] format for encoding Rust item names
+for the purpose of generating object code and linking.
+
+Supported values for this option are:
+
+* `v0` â€” The "v0" mangling scheme. The specific format is not specified at
+  this time.
+
+The default if not specified will use a compiler-chosen default which may
+change in the future.
+
+[name mangling]: https://en.wikipedia.org/wiki/Name_mangling
+
 ## target-cpu
 
 This instructs `rustc` to generate code specifically for a particular processor.
index bee9a8d808fb4afcdb47a9091981661b9349c1f7..0d02fa7bd6b3e996422d3b6fa9ac652f302365af 100644 (file)
@@ -408,6 +408,9 @@ to customize the output:
   argument](#option-emit), and as soon as the artifact is available on the
   filesystem a notification will be emitted.
 
+- `future-incompat` - includes a JSON message that contains a report if the
+  crate contains any code that may fail to compile in the future.
+
 Note that it is invalid to combine the `--json` argument with the
 [`--color`](#option-color) argument, and it is required to combine `--json`
 with `--error-format=json`.
index 5dee603142dcd006067653828627192ac6023f52..efbf861eaa68c1ede60a0c71d27e7e87454cc020 100644 (file)
@@ -229,6 +229,32 @@ flag][option-emit] documentation.
 }
 ```
 
+## Future-incompatible reports
+
+If the [`--json=future-incompat`][option-json] flag is used, then a separate
+JSON structure will be emitted if the crate may stop compiling in the future.
+This contains diagnostic information about the particular warnings that may be
+turned into a hard error in the future. This will include the diagnostic
+information, even if the diagnostics have been suppressed (such as with an
+`#[allow]` attribute or the `--cap-lints` option).
+
+```javascript
+{
+    /* An array of objects describing a warning that will become a hard error
+       in the future.
+    */
+    "future_incompat_report":
+    [
+        {
+            /* A diagnostic structure as defined in
+               https://doc.rust-lang.org/rustc/json.html#diagnostics
+            */
+            "diagnostic": {...},
+        }
+    ]
+}
+```
+
 [option-emit]: command-line-arguments.md#option-emit
 [option-error-format]: command-line-arguments.md#option-error-format
 [option-json]: command-line-arguments.md#option-json
index eea4eef90654796db86af4b8fc1bc8e741ffdff5..7cc96183d6da48cb4eb6bc41b946023b29a66133 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::PredicateOrigin;
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc_middle::middle::resolve_lifetime as rl;
 use rustc_middle::ty::fold::TypeFolder;
@@ -493,7 +494,7 @@ fn clean_generic_param(
             let bounds = if let Some(generics) = generics {
                 generics
                     .bounds_for_param(did)
-                    .filter(|bp| !bp.in_where_clause)
+                    .filter(|bp| bp.origin != PredicateOrigin::WhereClause)
                     .flat_map(|bp| bp.bounds)
                     .filter_map(|x| x.clean(cx))
                     .collect()
index 1db6064551cae362fc30911ba5528b00e052b1c7..17644aeed85691dc23abe80ab30316a608c9c693 100644 (file)
@@ -232,6 +232,8 @@ impl<'tcx> DocContext<'tcx> {
         rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(),
         rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(),
         rustc_lint::builtin::UNEXPECTED_CFGS.name.to_string(),
+        // this lint is needed to support `#[expect]` attributes
+        rustc_lint::builtin::UNFULFILLED_LINT_EXPECTATIONS.name.to_string(),
     ];
     lints_to_show.extend(crate::lint::RUSTDOC_LINTS.iter().map(|lint| lint.name.to_string()));
 
@@ -463,6 +465,8 @@ fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler, sp: Span) {
         }
     }
 
+    tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc)));
+
     if tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() {
         rustc_errors::FatalError.raise();
     }
index 19582481910173dd3c7ff86ec2b690f716b05cb1..c13ae1e431a6c3c151c26a6d72b09b77231d5c59 100644 (file)
@@ -531,8 +531,8 @@ fn short_item_info(
     if let Some(depr @ Deprecation { note, since, is_since_rustc_version: _, suggestion: _ }) =
         item.deprecation(cx.tcx())
     {
-        // We display deprecation messages for #[deprecated] and #[rustc_deprecated]
-        // but only display the future-deprecation messages for #[rustc_deprecated].
+        // We display deprecation messages for #[deprecated], but only display
+        // the future-deprecation messages for rustc versions.
         let mut message = if let Some(since) = since {
             let since = since.as_str();
             if !stability::deprecation_in_effect(&depr) {
index e118ee5d5edc5648c9d5323b216681343d533618..52577b228aa1399e59057e451cb0b599d26d6804 100644 (file)
@@ -17,6 +17,15 @@ module.exports = {
             "error",
             "always"
         ],
+        "quotes": [
+            "error",
+            "double"
+        ],
+        "linebreak-style": [
+            "error",
+            "unix"
+        ],
+        "no-trailing-spaces": "error",
         "no-var": ["error"],
         "prefer-const": ["error"],
         "prefer-arrow-callback": ["error"],
index ea20f6e28ecd624856c1085f9cb59d609b34757b..336223ad28f329b02fc32cbad6ad895bf546d7e3 100644 (file)
@@ -291,7 +291,7 @@ function loadCss(cssFileName) {
 
 (function() {
     function loadScript(url) {
-        const script = document.createElement('script');
+        const script = document.createElement("script");
         script.src = url;
         document.head.append(script);
     }
@@ -344,7 +344,7 @@ function loadCss(cssFileName) {
             searchState.input.blur();
         },
         showResults: search => {
-            if (search === null || typeof search === 'undefined') {
+            if (search === null || typeof search === "undefined") {
                 search = searchState.outputElement();
             }
             switchDisplayedElement(search);
@@ -390,7 +390,7 @@ function loadCss(cssFileName) {
                 loadSearch();
             });
 
-            if (search_input.value !== '') {
+            if (search_input.value !== "") {
                 loadSearch();
             }
 
@@ -968,7 +968,7 @@ function loadCss(cssFileName) {
 
     onEachLazy(document.getElementsByClassName("notable-traits"), e => {
         e.onclick = function() {
-            this.getElementsByClassName('notable-traits-tooltiptext')[0]
+            this.getElementsByClassName("notable-traits-tooltiptext")[0]
                 .classList.toggle("force-tooltip");
         };
     });
@@ -1070,29 +1070,29 @@ function loadCss(cssFileName) {
         const path = [];
 
         onEach(parent.childNodes, child => {
-            if (child.tagName === 'A') {
+            if (child.tagName === "A") {
                 path.push(child.textContent);
             }
         });
 
-        const el = document.createElement('textarea');
-        el.value = path.join('::');
-        el.setAttribute('readonly', '');
+        const el = document.createElement("textarea");
+        el.value = path.join("::");
+        el.setAttribute("readonly", "");
         // To not make it appear on the screen.
-        el.style.position = 'absolute';
-        el.style.left = '-9999px';
+        el.style.position = "absolute";
+        el.style.left = "-9999px";
 
         document.body.appendChild(el);
         el.select();
-        document.execCommand('copy');
+        document.execCommand("copy");
         document.body.removeChild(el);
 
         // There is always one children, but multiple childNodes.
-        but.children[0].style.display = 'none';
+        but.children[0].style.display = "none";
 
         let tmp;
         if (but.childNodes.length < 2) {
-            tmp = document.createTextNode('✓');
+            tmp = document.createTextNode("✓");
             but.appendChild(tmp);
         } else {
             onEachLazy(but.childNodes, e => {
@@ -1101,7 +1101,7 @@ function loadCss(cssFileName) {
                     return true;
                 }
             });
-            tmp.textContent = '✓';
+            tmp.textContent = "✓";
         }
 
         if (reset_button_timeout !== null) {
@@ -1109,7 +1109,7 @@ function loadCss(cssFileName) {
         }
 
         function reset_button() {
-            tmp.textContent = '';
+            tmp.textContent = "";
             reset_button_timeout = null;
             but.children[0].style.display = "";
         }
index 544bced4c5afdd11120605c7fc92f4c29ee1f662..408b7e19feadd0cd09d72aa63e64c636200c5aca 100644 (file)
@@ -8,7 +8,7 @@
 
     // Scroll code block to the given code location
     function scrollToLoc(elt, loc) {
-        const lines = elt.querySelector('.line-numbers');
+        const lines = elt.querySelector(".line-numbers");
         let scrollOffset;
 
         // If the block is greater than the size of the viewer,
     function updateScrapedExample(example) {
         const locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
         let locIndex = 0;
-        const highlights = Array.prototype.slice.call(example.querySelectorAll('.highlight'));
-        const link = example.querySelector('.scraped-example-title a');
+        const highlights = Array.prototype.slice.call(example.querySelectorAll(".highlight"));
+        const link = example.querySelector(".scraped-example-title a");
 
         if (locs.length > 1) {
             // Toggle through list of examples in a given file
             const onChangeLoc = changeIndex => {
-                removeClass(highlights[locIndex], 'focus');
+                removeClass(highlights[locIndex], "focus");
                 changeIndex();
                 scrollToLoc(example, locs[locIndex][0]);
-                addClass(highlights[locIndex], 'focus');
+                addClass(highlights[locIndex], "focus");
 
                 const url = locs[locIndex][1];
                 const title = locs[locIndex][2];
                 link.innerHTML = title;
             };
 
-            example.querySelector('.prev')
-                .addEventListener('click', () => {
+            example.querySelector(".prev")
+                .addEventListener("click", () => {
                     onChangeLoc(() => {
                         locIndex = (locIndex - 1 + locs.length) % locs.length;
                     });
                 });
 
-            example.querySelector('.next')
-                .addEventListener('click', () => {
+            example.querySelector("next")
+                .addEventListener("click", () => {
                     onChangeLoc(() => {
                         locIndex = (locIndex + 1) % locs.length;
                     });
                 });
         }
 
-        const expandButton = example.querySelector('.expand');
+        const expandButton = example.querySelector(".expand");
         if (expandButton) {
-            expandButton.addEventListener('click', () => {
+            expandButton.addEventListener("click", () => {
                 if (hasClass(example, "expanded")) {
                     removeClass(example, "expanded");
                     scrollToLoc(example, locs[0][0]);
         scrollToLoc(example, locs[0][0]);
     }
 
-    const firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example');
+    const firstExamples = document.querySelectorAll(".scraped-example-list > .scraped-example");
     onEachLazy(firstExamples, updateScrapedExample);
-    onEachLazy(document.querySelectorAll('.more-examples-toggle'), toggle => {
+    onEachLazy(document.querySelectorAll(".more-examples-toggle"), toggle => {
         // Allow users to click the left border of the <details> section to close it,
         // since the section can be large and finding the [+] button is annoying.
-        onEachLazy(toggle.querySelectorAll('.toggle-line, .hide-more'), button => {
-            button.addEventListener('click', () => {
+        onEachLazy(toggle.querySelectorAll(".toggle-line, .hide-more"), button => {
+            button.addEventListener("click", () => {
                 toggle.open = false;
             });
         });
 
-        const moreExamples = toggle.querySelectorAll('.scraped-example');
-        toggle.querySelector('summary').addEventListener('click', () => {
+        const moreExamples = toggle.querySelectorAll(".scraped-example");
+        toggle.querySelector("summary").addEventListener("click", () => {
             // Wrapping in setTimeout ensures the update happens after the elements are actually
             // visible. This is necessary since updateScrapedExample calls scrollToLoc which
             // depends on offsetHeight, a property that requires an element to be visible to
index 3d8cfeecbed6d27a70f9cb0a9243abbe1512ba3f..7754d626e209ef179ef6ced58973c4af34eb1538 100644 (file)
@@ -204,7 +204,7 @@ window.initSearch = rawSearchIndex => {
      * @return {boolean}
      */
     function isPathStart(parserState) {
-        return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '::';
+        return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == "::";
     }
 
     /**
@@ -215,7 +215,7 @@ window.initSearch = rawSearchIndex => {
      * @return {boolean}
      */
     function isReturnArrow(parserState) {
-        return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '->';
+        return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == "->";
     }
 
     /**
@@ -227,10 +227,10 @@ window.initSearch = rawSearchIndex => {
      */
     function isIdentCharacter(c) {
         return (
-            c === '_' ||
-            (c >= '0' && c <= '9') ||
-            (c >= 'a' && c <= 'z') ||
-            (c >= 'A' && c <= 'Z'));
+            c === "_" ||
+            (c >= "0" && c <= "9") ||
+            (c >= "a" && c <= "z") ||
+            (c >= "A" && c <= "Z"));
     }
 
     /**
@@ -264,7 +264,7 @@ window.initSearch = rawSearchIndex => {
      * @return {QueryElement}                - The newly created `QueryElement`.
      */
     function createQueryElement(query, parserState, name, generics, isInGenerics) {
-        if (name === '*' || (name.length === 0 && generics.length === 0)) {
+        if (name === "*" || (name.length === 0 && generics.length === 0)) {
             return;
         }
         if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
@@ -1089,7 +1089,7 @@ window.initSearch = rawSearchIndex => {
             return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
         }
 
-        function checkPath(contains, lastElem, ty) {
+        function checkPath(contains, ty) {
             if (contains.length === 0) {
                 return 0;
             }
@@ -1306,7 +1306,7 @@ window.initSearch = rawSearchIndex => {
             }
 
             if (elem.fullPath.length > 1) {
-                lev = checkPath(elem.pathWithoutLast, elem.pathLast, row);
+                lev = checkPath(elem.pathWithoutLast, row);
                 if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
                     return;
                 } else if (lev > 0) {
@@ -1323,7 +1323,6 @@ window.initSearch = rawSearchIndex => {
                 }
             }
             lev = levenshtein(searchWord, elem.pathLast);
-            lev += lev_add;
             if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1)
             {
                 if (elem.pathLast.length < 6) {
@@ -1332,6 +1331,7 @@ window.initSearch = rawSearchIndex => {
                     lev = 0;
                 }
             }
+            lev += lev_add;
             if (lev > MAX_LEV_DISTANCE) {
                 return;
             } else if (index !== -1 && elem.fullPath.length < 2) {
@@ -1708,11 +1708,12 @@ window.initSearch = rawSearchIndex => {
 
         let crates = "";
         if (window.ALL_CRATES.length > 1) {
-            crates = ` in <select id="crate-search"><option value="All crates">All crates</option>`;
+            crates = " in <select id=\"crate-search\"><option value=\"All crates\">" +
+                "All crates</option>";
             for (const c of window.ALL_CRATES) {
                 crates += `<option value="${c}" ${c == filterCrates && "selected"}>${c}</option>`;
             }
-            crates += `</select>`;
+            crates += "</select>";
         }
 
         let typeFilter = "";
@@ -1720,17 +1721,17 @@ window.initSearch = rawSearchIndex => {
             typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
         }
 
-        let output = `<div id="search-settings">` +
+        let output = "<div id=\"search-settings\">" +
             `<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
             `${typeFilter}</h1> in ${crates} </div>`;
         if (results.query.error !== null) {
             output += `<h3>Query parser error: "${results.query.error}".</h3>`;
-            output += '<div id="titles">' +
+            output += "<div id=\"titles\">" +
                 makeTabHeader(0, "In Names", ret_others[1]) +
                 "</div>";
             currentTab = 0;
         } else if (results.query.foundElems <= 1 && results.query.returned.length === 0) {
-            output += `<div id="titles">` +
+            output += "<div id=\"titles\">" +
                 makeTabHeader(0, "In Names", ret_others[1]) +
                 makeTabHeader(1, "In Parameters", ret_in_args[1]) +
                 makeTabHeader(2, "In Return Types", ret_returned[1]) +
@@ -1740,7 +1741,7 @@ window.initSearch = rawSearchIndex => {
                 results.query.elems.length === 0 ? "In Function Return Types" :
                 results.query.returned.length === 0 ? "In Function Parameters" :
                 "In Function Signatures";
-            output += '<div id="titles">' +
+            output += "<div id=\"titles\">" +
                 makeTabHeader(0, signatureTabTitle, ret_others[1]) +
                 "</div>";
             currentTab = 0;
index a7b60a496890c4cdd8bba790dde466cb04fb1848..ad32a193893896a6be5ea62162f6b863fde22544 100644 (file)
         let output = "";
 
         for (const setting of settings) {
-            output += `<div class="setting-line">`;
+            output += "<div class=\"setting-line\">";
             const js_data_name = setting["js_name"];
             const setting_name = setting["name"];
 
 
         if (isSettingsPage) {
             innerHTML +=
-                `<a id="back" href="javascript:void(0)" onclick="history.back();">Back</a>`;
+                "<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">Back</a>";
         } else {
-            innerHTML +=
-                `<a id="back" href="javascript:void(0)" onclick="switchDisplayedElement(null);">\
-                    Back</a>`;
+            innerHTML += "<a id=\"back\" href=\"javascript:void(0)\" " +
+                "onclick=\"switchDisplayedElement(null);\">Back</a>";
         }
         innerHTML += `</span>
             </div>
index 69940bb89df2110b7a0431b0604975611abcee62..21de7d77d64e7f60a3b449051e1758539d64e337 100644 (file)
@@ -24,7 +24,7 @@ function getSettingValue(settingName) {
     if (settingsDataset !== null) {
         // See the comment for `default_settings.into_iter()` etc. in
         // `Options::from_matches` in `librustdoc/config.rs`.
-        const def = settingsDataset[settingName.replace(/-/g,'_')];
+        const def = settingsDataset[settingName.replace(/-/g,"_")];
         if (def !== undefined) {
             return def;
         }
@@ -173,7 +173,7 @@ const updateSystemTheme = (function () {
         // fallback to the CSS computed value
         return () => {
             const cssTheme = getComputedStyle(document.documentElement)
-                .getPropertyValue('content');
+                .getPropertyValue("content");
 
             switchTheme(
                 window.currentTheme,
index fc10370ef7d91babf512c10505f8f2176bc8519d..593484fc1596707406b0b0b45b97feb08d2a1bfc 160000 (submodule)
@@ -1 +1 @@
-Subproject commit fc10370ef7d91babf512c10505f8f2176bc8519d
+Subproject commit 593484fc1596707406b0b0b45b97feb08d2a1bfc
index acc5a2d5499ffb7158ce5691f43578cacf71e01c..f129f073e98ded94b27ff273a5c1b15721f6a1a7 100644 (file)
@@ -19,7 +19,7 @@ pub enum Enum4 {
     A(i32),
     B(i32),
 }
-// CHECK: %"Enum4::A" = type { [1 x i32], i32 }
+// No Aggregate type, and hence nothing in LLVM IR.
 
 pub enum Enum64 {
     A(Align64),
diff --git a/src/test/rustdoc-js-std/path-ordering.js b/src/test/rustdoc-js-std/path-ordering.js
new file mode 100644 (file)
index 0000000..7dcdd40
--- /dev/null
@@ -0,0 +1,12 @@
+const QUERY = 'hashset::insert';
+
+const EXPECTED = {
+    'others': [
+        // ensure hashset::insert comes first
+        { 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' },
+        { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert' },
+        { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_with' },
+        { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_owned' },
+        { 'path': 'std::collections::hash_map::HashMap', 'name': 'insert' },
+    ],
+};
diff --git a/src/test/rustdoc-js/path-ordering.js b/src/test/rustdoc-js/path-ordering.js
new file mode 100644 (file)
index 0000000..4aee569
--- /dev/null
@@ -0,0 +1,14 @@
+// exact-check
+
+const QUERY = 'b::ccccccc';
+
+const EXPECTED = {
+    'others': [
+        // `ccccccc` is an exact match for all three of these.
+        // However `b` is a closer match for `bb` than for any
+        // of the others, so it ought to go first.
+        { 'path': 'path_ordering::bb', 'name': 'Ccccccc' },
+        { 'path': 'path_ordering::aa', 'name': 'Ccccccc' },
+        { 'path': 'path_ordering::dd', 'name': 'Ccccccc' },
+    ],
+};
diff --git a/src/test/rustdoc-js/path-ordering.rs b/src/test/rustdoc-js/path-ordering.rs
new file mode 100644 (file)
index 0000000..7843cf7
--- /dev/null
@@ -0,0 +1,9 @@
+pub mod dd {
+    pub struct Ccccccc;
+}
+pub mod aa {
+    pub struct Ccccccc;
+}
+pub mod bb {
+    pub struct Ccccccc;
+}
diff --git a/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.rs b/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.rs
new file mode 100644 (file)
index 0000000..0901ac3
--- /dev/null
@@ -0,0 +1,157 @@
+// check-pass
+#![feature(lint_reasons)]
+
+//! This file tests the `#[expect]` attribute implementation for tool lints. The same
+//! file is used to test clippy and rustdoc. Any changes to this file should be synced
+//! to the other test files as well.
+//!
+//! Expectations:
+//! * rustc: only rustc lint expectations are emitted
+//! * clippy: rustc and Clippy's expectations are emitted
+//! * rustdoc: only rustdoc lint expectations are emitted
+//!
+//! This test can't cover every lint from Clippy, rustdoc and potentially other
+//! tools that will be developed. This therefore only tests a small subset of lints
+
+#![expect(rustdoc::missing_crate_level_docs)]
+//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+
+mod rustc_ok {
+    //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+    #[expect(dead_code)]
+    pub fn rustc_lints() {
+        let x = 42.0;
+
+        #[expect(illegal_floating_point_literal_pattern)]
+        match x {
+            5.0 => {}
+            6.0 => {}
+            _ => {}
+        }
+    }
+}
+
+mod rustc_warn {
+    //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+    #[expect(dead_code)]
+    pub fn rustc_lints() {
+        let x = 42;
+
+        #[expect(illegal_floating_point_literal_pattern)]
+        match x {
+            5 => {}
+            6 => {}
+            _ => {}
+        }
+    }
+}
+
+pub mod rustdoc_ok {
+    //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+    #[expect(rustdoc::broken_intra_doc_links)]
+    /// I want to link to [`Nonexistent`] but it doesn't exist!
+    pub fn foo() {}
+
+    #[expect(rustdoc::invalid_html_tags)]
+    /// <h1>
+    pub fn bar() {}
+
+    #[expect(rustdoc::bare_urls)]
+    /// http://example.org
+    pub fn baz() {}
+}
+
+pub mod rustdoc_warn {
+    //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+    #[expect(rustdoc::broken_intra_doc_links)]
+    //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+    /// I want to link to [`bar`] but it doesn't exist!
+    pub fn foo() {}
+
+    #[expect(rustdoc::invalid_html_tags)]
+    //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+    /// <h1></h1>
+    pub fn bar() {}
+
+    #[expect(rustdoc::bare_urls)]
+    //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+    /// <http://example.org>
+    pub fn baz() {}
+}
+
+mod clippy_ok {
+    //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+    #[expect(clippy::almost_swapped)]
+    fn foo() {
+        let mut a = 0;
+        let mut b = 9;
+        a = b;
+        b = a;
+    }
+
+    #[expect(clippy::bytes_nth)]
+    fn bar() {
+        let _ = "Hello".bytes().nth(3);
+    }
+
+    #[expect(clippy::if_same_then_else)]
+    fn baz() {
+        let _ = if true {
+            42
+        } else {
+            42
+        };
+    }
+
+    #[expect(clippy::logic_bug)]
+    fn burger() {
+        let a = false;
+        let b = true;
+
+        if a && b || a {}
+    }
+}
+
+mod clippy_warn {
+    //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+    #[expect(clippy::almost_swapped)]
+    fn foo() {
+        let mut a = 0;
+        let mut b = 9;
+        a = b;
+    }
+
+    #[expect(clippy::bytes_nth)]
+    fn bar() {
+        let _ = "Hello".as_bytes().get(3);
+    }
+
+    #[expect(clippy::if_same_then_else)]
+    fn baz() {
+        let _ = if true {
+            33
+        } else {
+            42
+        };
+    }
+
+    #[expect(clippy::logic_bug)]
+    fn burger() {
+        let a = false;
+        let b = true;
+        let c = false;
+
+        if a && b || c {}
+    }
+}
+
+fn main() {
+    rustc_warn::rustc_lints();
+}
diff --git a/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.stderr b/src/test/rustdoc-ui/expect-tool-lint-rfc-2383.stderr
new file mode 100644 (file)
index 0000000..efc5f34
--- /dev/null
@@ -0,0 +1,28 @@
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect-tool-lint-rfc-2383.rs:16:11
+   |
+LL | #![expect(rustdoc::missing_crate_level_docs)]
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect-tool-lint-rfc-2383.rs:71:14
+   |
+LL |     #[expect(rustdoc::broken_intra_doc_links)]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect-tool-lint-rfc-2383.rs:76:14
+   |
+LL |     #[expect(rustdoc::invalid_html_tags)]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect-tool-lint-rfc-2383.rs:81:14
+   |
+LL |     #[expect(rustdoc::bare_urls)]
+   |              ^^^^^^^^^^^^^^^^^^
+
+warning: 4 warnings emitted
+
diff --git a/src/test/rustdoc/deprecated-future-staged-api.rs b/src/test/rustdoc/deprecated-future-staged-api.rs
new file mode 100644 (file)
index 0000000..2670e7f
--- /dev/null
@@ -0,0 +1,18 @@
+#![feature(staged_api)]
+#![stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+
+// @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \
+//      'Deprecation planned'
+// @has deprecated_future_staged_api/struct.S1.html '//*[@class="stab deprecated"]' \
+//      'Deprecating in 99.99.99: effectively never'
+#[deprecated(since = "99.99.99", note = "effectively never")]
+#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+pub struct S1;
+
+// @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \
+//      'Deprecation planned'
+// @has deprecated_future_staged_api/struct.S2.html '//*[@class="stab deprecated"]' \
+//      'Deprecating in a future Rust version: literally never'
+#[deprecated(since = "TBD", note = "literally never")]
+#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")]
+pub struct S2;
index 2165be9745229f19d35bb5606388c6f3e1fcc1a3..651ae2f1ae8754397b980461eb933214742948e3 100644 (file)
@@ -1,11 +1,10 @@
 #![feature(staged_api)]
-
 #![stable(feature = "rust1", since = "1.0.0")]
 
 /// docs for my_macro
 #[unstable(feature = "macro_test", issue = "none")]
-#[rustc_deprecated(since = "1.2.3", reason = "text")]
+#[deprecated(since = "1.2.3", note = "text")]
 #[macro_export]
 macro_rules! my_macro {
-    () => ()
+    () => {};
 }
index 9cb933c177bf0dd96e00cff460734d476ce3668f..13b4c3c7f61a47604d16920cdd03f653d758345d 100644 (file)
@@ -2,7 +2,6 @@
 // build-aux-docs
 
 #![feature(macro_test)]
-
 #![crate_name = "foo"]
 
 extern crate macros;
@@ -16,5 +15,5 @@
 // @has - '//*[@class="docblock"]' 'docs for my_macro'
 // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.2.3: text'
 // @has - '//*[@class="stab unstable"]' 'macro_test'
-// @has - '//a/@href' '../src/macros/macros.rs.html#9-11'
+// @has - '//a/@href' '../src/macros/macros.rs.html#8-10'
 pub use macros::my_macro;
index 7654a5615275ac17e4d074ed04e42df5c2e88d48..01f95538196f06925c7338a83ce8dd18607452cf 100644 (file)
@@ -14,7 +14,7 @@
 // @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \
 //      '🔬 This is a nightly-only experimental API. \(test\s#32374\)$'
 /// Docs
-#[rustc_deprecated(since = "1.0.0", reason = "text")]
+#[deprecated(since = "1.0.0", note = "text")]
 #[unstable(feature = "test", issue = "32374")]
 pub struct T;
 
@@ -22,6 +22,6 @@
 //      '👎 Deprecated since 1.0.0: deprecated'
 // @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \
 //      '🔬 This is a nightly-only experimental API. (test #32374)'
-#[rustc_deprecated(since = "1.0.0", reason = "deprecated")]
+#[deprecated(since = "1.0.0", note = "deprecated")]
 #[unstable(feature = "test", issue = "32374", reason = "unstable")]
 pub struct U;
diff --git a/src/test/rustdoc/rustc_deprecated-future.rs b/src/test/rustdoc/rustc_deprecated-future.rs
deleted file mode 100644 (file)
index 95a767a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#![feature(staged_api)]
-
-#![stable(feature = "rustc_deprecated-future-test", since = "1.0.0")]
-
-// @has rustc_deprecated_future/index.html '//*[@class="stab deprecated"]' \
-//      'Deprecation planned'
-// @has rustc_deprecated_future/struct.S1.html '//*[@class="stab deprecated"]' \
-//      'Deprecating in 99.99.99: effectively never'
-#[rustc_deprecated(since = "99.99.99", reason = "effectively never")]
-#[stable(feature = "rustc_deprecated-future-test", since = "1.0.0")]
-pub struct S1;
-
-// @has rustc_deprecated_future/index.html '//*[@class="stab deprecated"]' \
-//      'Deprecation planned'
-// @has rustc_deprecated_future/struct.S2.html '//*[@class="stab deprecated"]' \
-//      'Deprecating in a future Rust version: literally never'
-#[rustc_deprecated(since = "TBD", reason = "literally never")]
-#[stable(feature = "rustc_deprecated-future-test", since = "1.0.0")]
-pub struct S2;
index 765b2d5d68e4abf4e9f3f1af499cde8755e65e8d..3e96322d67efb815cbf227a383db2b0e0d4afd23 100644 (file)
@@ -22,4 +22,7 @@ fn main() {
     missing(); //~ ERROR this function takes
     swapped("", 1); //~ ERROR arguments to this function are incorrect
     permuted(Y {}, Z {}, X {}); //~ ERROR arguments to this function are incorrect
+
+    let closure = |x| x;
+    closure(); //~ ERROR this function takes
 }
index 78f82b076198a91b812e944b91f1c11db32f4a5f..8300a22c5483dcdbf630d0f7eb30d80bb5af3655 100644 (file)
@@ -81,7 +81,23 @@ help: reorder these arguments
 LL |     permuted(X {}, Y {}, Z {});
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-error: aborting due to 5 previous errors
+error[E0057]: this function takes 1 argument but 0 arguments were supplied
+  --> $DIR/basic.rs:27:5
+   |
+LL |     closure();
+   |     ^^^^^^^-- an argument is missing
+   |
+note: closure defined here
+  --> $DIR/basic.rs:26:19
+   |
+LL |     let closure = |x| x;
+   |                   ^^^
+help: provide the argument
+   |
+LL |     closure({_});
+   |     ~~~~~~~~~~~~
+
+error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0061, E0308.
-For more information about an error, try `rustc --explain E0061`.
+Some errors have detailed explanations: E0057, E0061, E0308.
+For more information about an error, try `rustc --explain E0057`.
index 516057e53d25efd466daf4da7f03eda9337d4b37..a67cf99283cfaaa1d6a5b3b67cc799643cf35e23 100644 (file)
@@ -12,8 +12,8 @@ note: expected this to be `Option<T>`
    |
 LL |     type Item = T;
    |                 ^
-   = note: expected enum `Option<T>`
-              found type `T`
+   = note:        expected enum `Option<T>`
+           found type parameter `T`
 note: required by a bound in `is_iterator_of`
   --> $DIR/associated-types-issue-20346.rs:15:34
    |
index 1ac72e4b90c75d0f4455b760b83e14e30608158e..65533f93c94135e27367e78b8dcfe4e031c0e197 100644 (file)
@@ -5,7 +5,7 @@ LL |     foo(());
    |     ^^^ lifetime mismatch
    |
    = note: expected reference `&'a ()`
-                   found type `&()`
+              found reference `&()`
 note: the lifetime requirement is introduced here
   --> $DIR/higher-ranked-projection.rs:15:33
    |
index b205fd619155e447de187a27327f1ef846728640..3be8c552063e7893e3e217a8d6cc470903fda009 100644 (file)
@@ -24,13 +24,18 @@ LL |     fun(one(), two());
    |     |
    |     arguments to this function are incorrect
    |
+note: while checking the return type of the `async fn`
+  --> $DIR/generator-desc.rs:5:16
+   |
+LL | async fn one() {}
+   |                ^ checked the `Output` of this `async fn`, expected opaque type
 note: while checking the return type of the `async fn`
   --> $DIR/generator-desc.rs:6:16
    |
 LL | async fn two() {}
    |                ^ checked the `Output` of this `async fn`, found opaque type
-   = note:     expected type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:5:16>)
-           found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:6:16>)
+   = note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:5:16>)
+              found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:6:16>)
    = help: consider `await`ing on both `Future`s
    = note: distinct uses of `impl Trait` result in different opaque types
 note: function defined here
@@ -43,26 +48,26 @@ error[E0308]: mismatched types
   --> $DIR/generator-desc.rs:14:26
    |
 LL |     fun((async || {})(), (async || {})());
-   |     ---                  ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
-   |     |
+   |     ---           --     ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
+   |     |             |
+   |     |             the expected `async` closure body
    |     arguments to this function are incorrect
    |
   ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
    |
 LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
-   |                                           ------------------------------- the found opaque type
+   |                                           -------------------------------
+   |                                           |
+   |                                           the expected opaque type
+   |                                           the found opaque type
    |
-   = note:     expected type `impl Future<Output = ()>` (`async` closure body)
-           found opaque type `impl Future<Output = ()>` (`async` closure body)
+   = note: expected opaque type `impl Future<Output = ()>` (`async` closure body)
+              found opaque type `impl Future<Output = ()>` (`async` closure body)
 note: function defined here
   --> $DIR/generator-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
    |    ^^^                         -----  -----
-help: consider `await`ing on the `Future`
-   |
-LL |     fun((async || {})(), (async || {})().await);
-   |                                         ++++++
 
 error: aborting due to 3 previous errors
 
index ba9ed5cb65fc9b716ec4ae1285ec1a5a695a8783..1196601ace09087eb0433a807758f949eb2657d7 100644 (file)
@@ -60,8 +60,13 @@ LL | |
 LL | |     };
    | |_____- `if` and `else` have incompatible types
    |
-   = note:   expected type `impl Future<Output = ()>`
-           found unit type `()`
+note: while checking the return type of the `async fn`
+  --> $DIR/suggest-missing-await.rs:18:18
+   |
+LL | async fn dummy() {}
+   |                  ^ checked the `Output` of this `async fn`, expected opaque type
+   = note: expected opaque type `impl Future<Output = ()>`
+                found unit type `()`
 help: consider `await`ing on the `Future`
    |
 LL |         dummy().await
diff --git a/src/test/ui/borrowck/issue-28934.rs b/src/test/ui/borrowck/issue-28934.rs
new file mode 100644 (file)
index 0000000..1e48878
--- /dev/null
@@ -0,0 +1,25 @@
+// Regression test: issue had to do with "givens" in region inference,
+// which were not being considered during the contraction phase.
+
+// run-fail
+// error-pattern:explicit panic
+// ignore-emscripten no processes
+
+struct Parser<'i: 't, 't>(&'i u8, &'t u8);
+
+impl<'i, 't> Parser<'i, 't> {
+    fn parse_nested_block<F, T>(&mut self, parse: F) -> Result<T, ()>
+        where for<'tt> F: FnOnce(&mut Parser<'i, 'tt>) -> T
+    {
+        panic!()
+    }
+
+    fn expect_exhausted(&mut self) -> Result<(), ()> {
+        Ok(())
+    }
+}
+
+fn main() {
+    let x = 0u8;
+    Parser(&x, &x).parse_nested_block(|input| input.expect_exhausted()).unwrap();
+}
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
deleted file mode 100644 (file)
index eb934e7..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-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`.
index bd2e31648cc5f910e0d250a4014e7937763b6752..e25b33bbcdb06d2713f7d1d48118a686917e03d4 100644 (file)
@@ -11,8 +11,8 @@ LL | |         _ => unimplemented!(),
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected type `fn(i32, i32) -> i32 {add}`
-           found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43]`
+   = note: expected fn item `fn(i32, i32) -> i32 {add}`
+              found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43]`
 
 error[E0308]: `match` arms have incompatible types
   --> $DIR/closure_cap_coerce_many_fail.rs:18:16
@@ -20,15 +20,18 @@ error[E0308]: `match` arms have incompatible types
 LL |       let _ = match "+" {
    |  _____________-
 LL | |         "+" => |a, b| (a + b) as i32,
-   | |                --------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
+   | |                ---------------------
+   | |                |
+   | |                the expected closure
+   | |                this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
 LL | |         "-" => |a, b| (a - b + cap) as i32,
    | |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
 LL | |         _ => unimplemented!(),
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
-           found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43]`
+   = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
+              found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43]`
    = note: no two closures, even if identical, have the same type
    = help: consider boxing your closure and/or using it as a trait object
 
@@ -38,15 +41,18 @@ error[E0308]: `match` arms have incompatible types
 LL |       let _ = match "+" {
    |  _____________-
 LL | |         "+" => |a, b| (a + b + cap) as i32,
-   | |                --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]`
+   | |                ---------------------------
+   | |                |
+   | |                the expected closure
+   | |                this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]`
 LL | |         "-" => |a, b| (a - b) as i32,
    | |                ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
 LL | |         _ => unimplemented!(),
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]`
-           found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]`
+   = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]`
+              found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]`
    = note: no two closures, even if identical, have the same type
    = help: consider boxing your closure and/or using it as a trait object
 
@@ -56,15 +62,18 @@ error[E0308]: `match` arms have incompatible types
 LL |       let _ = match "+" {
    |  _____________-
 LL | |         "+" => |a, b| (a + b + cap) as i32,
-   | |                --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]`
+   | |                ---------------------------
+   | |                |
+   | |                the expected closure
+   | |                this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]`
 LL | |         "-" => |a, b| (a - b + cap) as i32,
    | |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
 LL | |         _ => unimplemented!(),
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]`
-           found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43]`
+   = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]`
+              found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43]`
    = note: no two closures, even if identical, have the same type
    = help: consider boxing your closure and/or using it as a trait object
 
diff --git a/src/test/ui/closures/issue-6801.rs b/src/test/ui/closures/issue-6801.rs
new file mode 100644 (file)
index 0000000..694d86f
--- /dev/null
@@ -0,0 +1,21 @@
+// Creating a stack closure which references a box and then
+// transferring ownership of the box before invoking the stack
+// closure results in a crash.
+
+#![feature(box_syntax)]
+
+fn twice(x: Box<usize>) -> usize {
+     *x * 2
+}
+
+fn invoke<F>(f: F) where F: FnOnce() -> usize {
+     f();
+}
+
+fn main() {
+      let x  : Box<usize>  = box 9;
+      let sq =  || { *x * *x };
+
+      twice(x); //~ ERROR: cannot move out of
+      invoke(sq);
+}
diff --git a/src/test/ui/closures/issue-6801.stderr b/src/test/ui/closures/issue-6801.stderr
new file mode 100644 (file)
index 0000000..48c6acd
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/issue-6801.rs:19:13
+   |
+LL |       let sq =  || { *x * *x };
+   |                 --   -- borrow occurs due to use in closure
+   |                 |
+   |                 borrow of `x` occurs here
+LL | 
+LL |       twice(x);
+   |             ^ move out of `x` occurs here
+LL |       invoke(sq);
+   |              -- borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
index ab9cc707aa0be37bdca812ae9a83c74bcbb40bf0..3350d1efb53182bb9220f24abbdff33afb66e827 100644 (file)
@@ -4,16 +4,6 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied
 LL |     /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
    |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
    |
-   = help: the following other types implement trait `std::error::Error`:
-             !
-             &'a T
-             AccessError
-             AddrParseError
-             Arc<T>
-             BorrowError
-             BorrowMutError
-             Box<T>
-           and 45 others
    = note: required for the cast to the object type `dyn std::error::Error`
 
 error[E0277]: the trait bound `(): std::error::Error` is not satisfied
@@ -22,16 +12,6 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied
 LL |     /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
    |
-   = help: the following other types implement trait `std::error::Error`:
-             !
-             &'a T
-             AccessError
-             AddrParseError
-             Arc<T>
-             BorrowError
-             BorrowMutError
-             Box<T>
-           and 45 others
    = note: required for the cast to the object type `(dyn std::error::Error + 'static)`
 
 error: aborting due to 2 previous errors
index 1daa91f025a8925827efe68655f3792b1c06c805..fcd2d7f78ff75fb2d756ae3d818faf52be07ac37 100644 (file)
@@ -4,16 +4,6 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied
 LL |     /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
    |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
    |
-   = help: the following other types implement trait `std::error::Error`:
-             !
-             &'a T
-             AccessError
-             AddrParseError
-             Arc<T>
-             BorrowError
-             BorrowMutError
-             Box<T>
-           and 43 others
    = note: required for the cast to the object type `dyn std::error::Error`
 
 error[E0277]: the trait bound `(): std::error::Error` is not satisfied
@@ -22,16 +12,6 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied
 LL |     /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
    |
-   = help: the following other types implement trait `std::error::Error`:
-             !
-             &'a T
-             AccessError
-             AddrParseError
-             Arc<T>
-             BorrowError
-             BorrowMutError
-             Box<T>
-           and 43 others
    = note: required for the cast to the object type `(dyn std::error::Error + 'static)`
 
 error: aborting due to 2 previous errors
index 4f266b166d6987753d81957f2371962a8121661e..36551e5afc6c65e7f8cb59fb8cf59edabe8e4986 100644 (file)
@@ -6,8 +6,8 @@ LL |     test(&mut 7, &7);
    |     |
    |     arguments to this function are incorrect
    |
-   = note:   expected type `&mut {integer}`
-           found reference `&{integer}`
+   = note: expected mutable reference `&mut {integer}`
+                      found reference `&{integer}`
 note: function defined here
   --> $DIR/coerce-reborrow-multi-arg-fail.rs:1:4
    |
diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr
deleted file mode 100644 (file)
index e9854f0..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-error[E0308]: arguments to this function are incorrect
-  --> $DIR/const-argument-cross-crate-mismatch.rs:7:41
-   |
-LL |     let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8]));
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^----------^
-   |                                                                   |
-   |                                                                   expected `[u8; 3]`, found `[u8; 2]`
-   |
-help: provide an argument of the correct type
-   |
-LL |     let _ = const_generic_lib::function(({[u8; 3]}));
-   |                                         ^^^^^^^^^^^
-
-error[E0308]: arguments to this function are incorrect
-  --> $DIR/const-argument-cross-crate-mismatch.rs:9:39
-   |
-LL |     let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]);
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^---------------^
-   |                                                                 |
-   |                                                                 expected `[u8; 2]`, found `[u8; 3]`
-   |
-help: provide an argument of the correct type
-   |
-LL |     let _: const_generic_lib::Alias = ({[u8; 2]});
-   |                                       ^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
index 2792bb7df85471f544b488f4b6f8eb374f71d3cd..36a569784adf7b1347a8036e34663ca7dcdce6d7 100644 (file)
@@ -1,4 +1,4 @@
-// [full] run-pass
+// [full] check-pass
 // revisions: full min
 
 // regression test for #78180
diff --git a/src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs b/src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.rs
new file mode 100644 (file)
index 0000000..5c93232
--- /dev/null
@@ -0,0 +1,41 @@
+trait Trait {
+    fn foo<U>() {}
+}
+impl Trait for () {
+    fn foo<const M: u64>() {}
+    //~^ error: method `foo` has an incompatible generic parameter for trait
+}
+
+trait Other {
+    fn bar<const M: u8>() {}
+}
+impl Other for () {
+    fn bar<T>() {}
+    //~^ error: method `bar` has an incompatible generic parameter for trait
+}
+
+trait Uwu {
+    fn baz<const N: u32>() {}
+}
+impl Uwu for () {
+    fn baz<const N: i32>() {}
+    //~^ error: method `baz` has an incompatible generic parameter for trait
+}
+
+trait Aaaaaa {
+    fn bbbb<const N: u32, T>() {}
+}
+impl Aaaaaa for () {
+    fn bbbb<T, const N: u32>() {}
+    //~^ error: method `bbbb` has an incompatible generic parameter for trait
+}
+
+trait Names {
+    fn abcd<T, const N: u32>() {}
+}
+impl Names for () {
+    fn abcd<const N: u32, T>() {}
+    //~^ error: method `abcd` has an incompatible generic parameter for trait
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr b/src/test/ui/const-generics/defaults/mismatched_ty_const_in_trait_impl.stderr
new file mode 100644 (file)
index 0000000..3455f2c
--- /dev/null
@@ -0,0 +1,68 @@
+error[E0053]: method `foo` has an incompatible generic parameter for trait `Trait`
+  --> $DIR/mismatched_ty_const_in_trait_impl.rs:5:12
+   |
+LL | trait Trait {
+   |       -----
+LL |     fn foo<U>() {}
+   |            - expected type parameter
+LL | }
+LL | impl Trait for () {
+   | -----------------
+LL |     fn foo<const M: u64>() {}
+   |            ^^^^^^^^^^^^ found const parameter of type `u64`
+
+error[E0053]: method `bar` has an incompatible generic parameter for trait `Other`
+  --> $DIR/mismatched_ty_const_in_trait_impl.rs:13:12
+   |
+LL | trait Other {
+   |       -----
+LL |     fn bar<const M: u8>() {}
+   |            ----------- expected const parameter of type `u8`
+LL | }
+LL | impl Other for () {
+   | -----------------
+LL |     fn bar<T>() {}
+   |            ^ found type parameter
+
+error[E0053]: method `baz` has an incompatible generic parameter for trait `Uwu`
+  --> $DIR/mismatched_ty_const_in_trait_impl.rs:21:12
+   |
+LL | trait Uwu {
+   |       ---
+LL |     fn baz<const N: u32>() {}
+   |            ------------ expected const parameter of type `u32`
+LL | }
+LL | impl Uwu for () {
+   | ---------------
+LL |     fn baz<const N: i32>() {}
+   |            ^^^^^^^^^^^^ found const parameter of type `i32`
+
+error[E0053]: method `bbbb` has an incompatible generic parameter for trait `Aaaaaa`
+  --> $DIR/mismatched_ty_const_in_trait_impl.rs:29:13
+   |
+LL | trait Aaaaaa {
+   |       ------
+LL |     fn bbbb<const N: u32, T>() {}
+   |             ------------ expected const parameter of type `u32`
+LL | }
+LL | impl Aaaaaa for () {
+   | ------------------
+LL |     fn bbbb<T, const N: u32>() {}
+   |             ^ found type parameter
+
+error[E0053]: method `abcd` has an incompatible generic parameter for trait `Names`
+  --> $DIR/mismatched_ty_const_in_trait_impl.rs:37:13
+   |
+LL | trait Names {
+   |       -----
+LL |     fn abcd<T, const N: u32>() {}
+   |             - expected type parameter
+LL | }
+LL | impl Names for () {
+   | -----------------
+LL |     fn abcd<const N: u32, T>() {}
+   |             ^^^^^^^^^^^^ found const parameter of type `u32`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/src/test/ui/const-generics/issues/issue-77357.rs b/src/test/ui/const-generics/issues/issue-77357.rs
new file mode 100644 (file)
index 0000000..3cb8d38
--- /dev/null
@@ -0,0 +1,11 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait MyTrait<T> {}
+
+fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
+    //~^ ERROR overly complex generic constant
+    todo!()
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-77357.stderr b/src/test/ui/const-generics/issues/issue-77357.stderr
new file mode 100644 (file)
index 0000000..804c0ae
--- /dev/null
@@ -0,0 +1,11 @@
+error: overly complex generic constant
+  --> $DIR/issue-77357.rs:6:46
+   |
+LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant
+   |
+   = help: consider moving this anonymous constant into a `const` function
+   = note: this operation may be supported in the future
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/issues/issue-775377.rs b/src/test/ui/const-generics/issues/issue-775377.rs
deleted file mode 100644 (file)
index 3cb8d38..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(generic_const_exprs)]
-#![allow(incomplete_features)]
-
-trait MyTrait<T> {}
-
-fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
-    //~^ ERROR overly complex generic constant
-    todo!()
-}
-
-fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-775377.stderr b/src/test/ui/const-generics/issues/issue-775377.stderr
deleted file mode 100644 (file)
index 83946df..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error: overly complex generic constant
-  --> $DIR/issue-775377.rs:6:46
-   |
-LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant
-   |
-   = help: consider moving this anonymous constant into a `const` function
-   = note: this operation may be supported in the future
-
-error: aborting due to previous error
-
index 04650403c6bafe70b6b1c7c8be14ff44555d36c7..ae4bd943fd415d1414731414603902c6bfb62967 100644 (file)
@@ -1,6 +1,6 @@
 // Regression test for the ICE described in #86820.
 
-#![allow(unused,dead_code)]
+#![allow(unused, dead_code)]
 use std::ops::BitAnd;
 
 const C: fn() = || is_set();
@@ -9,13 +9,12 @@ fn is_set() {
 }
 
 trait Bits {
-    fn bit<const I : u8>(self) -> bool;
-    //~^ NOTE: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
+    fn bit<const I: u8>(self) -> bool;
 }
 
 impl Bits for u8 {
-    fn bit<const I : usize>(self) -> bool {
-    //~^ ERROR: method `bit` has an incompatible const parameter type for trait [E0053]
+    fn bit<const I: usize>(self) -> bool {
+        //~^ ERROR: method `bit` has an incompatible generic parameter for trait `Bits` [E0053]
         let i = 1 << I;
         let mask = u8::from(i);
         mask & self == mask
index f7b8d80eeca7f03c73d7823f18d3e371b24b8a26..3a9cd957f35e7a65c3e1959d7a5ce878fa59ac09 100644 (file)
@@ -1,14 +1,15 @@
-error[E0053]: method `bit` has an incompatible const parameter type for trait
-  --> $DIR/issue-86820.rs:17:12
+error[E0053]: method `bit` has an incompatible generic parameter for trait `Bits`
+  --> $DIR/issue-86820.rs:16:12
    |
-LL |     fn bit<const I : usize>(self) -> bool {
-   |            ^^^^^^^^^^^^^^^
-   |
-note: the const parameter `I` has type `usize`, but the declaration in trait `Bits::bit` has type `u8`
-  --> $DIR/issue-86820.rs:12:12
-   |
-LL |     fn bit<const I : u8>(self) -> bool;
-   |            ^^^^^^^^^^^^
+LL | trait Bits {
+   |       ----
+LL |     fn bit<const I: u8>(self) -> bool;
+   |            ----------- expected const parameter of type `u8`
+...
+LL | impl Bits for u8 {
+   | ----------------
+LL |     fn bit<const I: usize>(self) -> bool {
+   |            ^^^^^^^^^^^^^^ found const parameter of type `usize`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-96654.rs b/src/test/ui/const-generics/issues/issue-96654.rs
new file mode 100644 (file)
index 0000000..8cf786d
--- /dev/null
@@ -0,0 +1,15 @@
+// check-pass
+
+struct A<const M: u32> {}
+
+struct B<const M: u32> {}
+
+impl<const M: u32> B<M> {
+    const M: u32 = M;
+}
+
+struct C<const M: u32> {
+    a: A<{ B::<1>::M }>,
+}
+
+fn main() {}
diff --git a/src/test/ui/continue-after-missing-main.nll.stderr b/src/test/ui/continue-after-missing-main.nll.stderr
deleted file mode 100644 (file)
index ebebabe..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0601]: `main` function not found in crate `continue_after_missing_main`
-  --> $DIR/continue-after-missing-main.rs:30:2
-   |
-LL | }
-   |  ^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/continue-after-missing-main.rs b/src/test/ui/continue-after-missing-main.rs
deleted file mode 100644 (file)
index 1019cac..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#![allow(dead_code)]
-
-struct Tableau<'a, MP> {
-    provider: &'a MP,
-}
-
-impl<'adapted_matrix_provider, 'original_data, MP>
-    Tableau<'adapted_matrix_provider, AdaptedMatrixProvider<'original_data, MP>>
-{
-    fn provider(&self) -> &'adapted_matrix_provider AdaptedMatrixProvider</*'original_data,*/ MP> {
-        self.provider
-    }
-}
-
-struct AdaptedMatrixProvider<'a, T> {
-    original_problem: &'a T,
-}
-
-impl<'a, T> AdaptedMatrixProvider<'a, T> {
-    fn clone_with_extra_bound(&self) -> Self {
-        AdaptedMatrixProvider { original_problem: self.original_problem }
-    }
-}
-
-fn create_and_solve_subproblems<'data_provider, 'original_data, MP>(
-    tableau: Tableau<'data_provider, AdaptedMatrixProvider<'original_data, MP>>,
-) {
-    let _: AdaptedMatrixProvider<'original_data, MP> = tableau.provider().clone_with_extra_bound();
-    //~^ ERROR lifetime mismatch
-} //~ ERROR `main` function not found in crate
diff --git a/src/test/ui/continue-after-missing-main.stderr b/src/test/ui/continue-after-missing-main.stderr
deleted file mode 100644 (file)
index 29e7dc1..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0601]: `main` function not found in crate `continue_after_missing_main`
-  --> $DIR/continue-after-missing-main.rs:30:2
-   |
-LL | }
-   |  ^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
-
-error[E0623]: lifetime mismatch
-  --> $DIR/continue-after-missing-main.rs:28:56
-   |
-LL |     tableau: Tableau<'data_provider, AdaptedMatrixProvider<'original_data, MP>>,
-   |              ------------------------------------------------------------------ these two types are declared with different lifetimes...
-LL | ) {
-LL |     let _: AdaptedMatrixProvider<'original_data, MP> = tableau.provider().clone_with_extra_bound();
-   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...but data from `tableau` flows into `tableau` here
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0601, E0623.
-For more information about an error, try `rustc --explain E0601`.
index 53826183d06dab5f8405d03a56ec8821cdcfe4a6..fb2a9a401ed22f47066fff6e6efcae491b423122 100644 (file)
@@ -6,7 +6,7 @@
 pub fn deprecated_future() {}
 
 fn test() {
-    deprecated_future(); // ok; deprecated_in_future only applies to rustc_deprecated
+    deprecated_future(); // ok; deprecated_in_future only applies with `#![feature(staged_api)]`
     //~^ WARNING use of deprecated function `deprecated_future`: text [deprecated]
 }
 
index 6561ec74349e8938afb6babb4cee53a33c095a04..99d1c73413af4f084b2671da6ad51cd160ddbb2b 100644 (file)
@@ -1,7 +1,7 @@
 warning: use of deprecated function `deprecated_future`: text
   --> $DIR/deprecation-in-future.rs:9:5
    |
-LL |     deprecated_future(); // ok; deprecated_in_future only applies to rustc_deprecated
+LL |     deprecated_future(); // ok; deprecated_in_future only applies with `#![feature(staged_api)]`
    |     ^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(deprecated)]` on by default
index a1a149ab3a0e1c7386f67e8baf786b13c6300d98..65cc4e2ef1e41b07a22e2de10beff53d6728132b 100644 (file)
@@ -260,7 +260,7 @@ fn test() {
         <Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
         <Foo as Trait>::trait_deprecated_text(&foo); //~ ERROR use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
 
-        // Future deprecations are only permitted for rustc_deprecated.
+        // Future deprecations are only permitted with `#![feature(staged_api)]`
         deprecated_future(); //~ ERROR use of deprecated function
         deprecated_future_text(); //~ ERROR use of deprecated function
 
index 4fc3fddadb99ee279f568b83eaad84b846af206f..9ea75b68f81ce0c5f209b905e2883e110c7cf40d 100644 (file)
@@ -24,7 +24,7 @@ fn f8() { }
 }
 
 #[deprecated(since = "a", note = "b")]
-#[deprecated(since = "a", note = "b")] //~ ERROR multiple deprecated attributes
+#[deprecated(since = "a", note = "b")] //~ ERROR multiple `deprecated` attributes
 fn multiple1() { }
 
 #[deprecated(since = "a", since = "b", note = "c")] //~ ERROR multiple 'since' items
index 7e70c35eeabdf37b11fcba42dd2395eebb66819a..973c672df91c3c2b933496205ed8b9f7797335fc 100644 (file)
@@ -1,3 +1,15 @@
+error: multiple `deprecated` attributes
+  --> $DIR/deprecation-sanity.rs:27:1
+   |
+LL | #[deprecated(since = "a", note = "b")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/deprecation-sanity.rs:26:1
+   |
+LL | #[deprecated(since = "a", note = "b")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0541]: unknown meta item 'reason'
   --> $DIR/deprecation-sanity.rs:4:43
    |
@@ -40,14 +52,6 @@ error[E0565]: item in `deprecated` must be a key/value pair
 LL |     #[deprecated("test")]
    |                  ^^^^^^
 
-error[E0550]: multiple deprecated attributes
-  --> $DIR/deprecation-sanity.rs:27:1
-   |
-LL | #[deprecated(since = "a", note = "b")]
-   | -------------------------------------- first deprecation attribute
-LL | #[deprecated(since = "a", note = "b")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ repeated deprecation attribute
-
 error[E0538]: multiple 'since' items
   --> $DIR/deprecation-sanity.rs:30:27
    |
@@ -64,5 +68,5 @@ LL | #[deprecated = "hello"]
 
 error: aborting due to 10 previous errors
 
-Some errors have detailed explanations: E0538, E0541, E0550, E0551, E0565.
+Some errors have detailed explanations: E0538, E0541, E0551, E0565.
 For more information about an error, try `rustc --explain E0538`.
diff --git a/src/test/ui/deprecation/rustc_deprecated.rs b/src/test/ui/deprecation/rustc_deprecated.rs
new file mode 100644 (file)
index 0000000..b87bd06
--- /dev/null
@@ -0,0 +1,13 @@
+// compile-flags: --crate-type=lib
+
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "rust1")]
+
+#[rustc_deprecated( //~ ERROR `#[rustc_deprecated]` has been removed
+    //~^ HELP use `#[deprecated]` instead
+    since = "1.100.0",
+    reason = "text" //~ ERROR `reason` has been renamed
+    //~^ HELP use `note` instead
+)]
+#[stable(feature = "rust1", since = "1.0.0")]
+fn foo() {}
diff --git a/src/test/ui/deprecation/rustc_deprecated.stderr b/src/test/ui/deprecation/rustc_deprecated.stderr
new file mode 100644 (file)
index 0000000..4413e19
--- /dev/null
@@ -0,0 +1,21 @@
+error: `#[rustc_deprecated]` has been removed
+  --> $DIR/rustc_deprecated.rs:6:1
+   |
+LL | / #[rustc_deprecated(
+LL | |
+LL | |     since = "1.100.0",
+LL | |     reason = "text"
+LL | |
+LL | | )]
+   | |__^
+   |
+   = help: use `#[deprecated]` instead
+
+error: `reason` has been renamed
+  --> $DIR/rustc_deprecated.rs:9:5
+   |
+LL |     reason = "text"
+   |     ^^^^^^^^^^^^^^^ help: use `note` instead: `note = "text"`
+
+error: aborting due to 2 previous errors
+
index 3d472bf63094d90db1d3c17e423876b8b0406690..950e0223e2201161bd8c5e459684fe53899d4840 100644 (file)
@@ -6,8 +6,8 @@ LL |     (x, y) = &(1, 2);
    |     |
    |     expected reference, found tuple
    |
-   = note: expected type `&({integer}, {integer})`
-             found tuple `(_, _)`
+   = note: expected reference `&({integer}, {integer})`
+                  found tuple `(_, _)`
 
 error: aborting due to previous error
 
index 55b08b74af0620a0edd598c7aded9e46d23825f1..a3004cbbe1067cce9022f101dcf5e088c1d6365a 100644 (file)
@@ -14,8 +14,8 @@ LL |     (a, a, b) = (1, 2);
    |     |
    |     expected a tuple with 2 elements, found one with 3 elements
    |
-   = note: expected type `({integer}, {integer})`
-             found tuple `(_, _, _)`
+   = note: expected tuple `({integer}, {integer})`
+              found tuple `(_, _, _)`
 
 error[E0070]: invalid left-hand side of assignment
   --> $DIR/tuple_destructure_fail.rs:7:13
@@ -33,8 +33,8 @@ LL |     (_,) = (1, 2);
    |     |
    |     expected a tuple with 2 elements, found one with 1 element
    |
-   = note: expected type `({integer}, {integer})`
-             found tuple `(_,)`
+   = note: expected tuple `({integer}, {integer})`
+              found tuple `(_,)`
 
 error: aborting due to 4 previous errors
 
index a151b20f865b22866e7e6ed8ee906486b145f241..4b4d30a8387fe762134ade788d221ed8bfa3b00d 100644 (file)
@@ -4,6 +4,11 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied
 LL |     let a = f();
    |             ^-- an argument is missing
    |
+note: closure defined here
+  --> $DIR/E0057.rs:2:13
+   |
+LL |     let f = |x| x * 3;
+   |             ^^^
 help: provide the argument
    |
 LL |     let a = f({_});
@@ -15,6 +20,11 @@ error[E0057]: this function takes 1 argument but 2 arguments were supplied
 LL |     let c = f(2, 3);
    |             ^    - argument unexpected
    |
+note: closure defined here
+  --> $DIR/E0057.rs:2:13
+   |
+LL |     let f = |x| x * 3;
+   |             ^^^
 help: remove the extra argument
    |
 LL |     let c = f(2);
diff --git a/src/test/ui/error-codes/E0502.nll.stderr b/src/test/ui/error-codes/E0502.nll.stderr
deleted file mode 100644 (file)
index 94cc897..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0502]: cannot borrow `*a` as mutable because it is also borrowed as immutable
-  --> $DIR/E0502.rs:4:5
-   |
-LL |     let ref y = a;
-   |         ----- immutable borrow occurs here
-LL |     bar(a);
-   |     ^^^^^^ mutable borrow occurs here
-LL |     y.use_ref();
-   |     ----------- immutable borrow later used here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/estr-subtyping.rs b/src/test/ui/estr-subtyping.rs
deleted file mode 100644 (file)
index 9c5825f..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-fn wants_uniq(x: String) { }
-fn wants_slice(x: &str) { }
-
-fn has_uniq(x: String) {
-   wants_uniq(x);
-   wants_slice(&*x);
-}
-
-fn has_slice(x: &str) {
-   wants_uniq(x); //~ ERROR mismatched types
-   wants_slice(x);
-}
-
-fn main() {
-}
diff --git a/src/test/ui/estr-subtyping.stderr b/src/test/ui/estr-subtyping.stderr
deleted file mode 100644 (file)
index adebb7d..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/estr-subtyping.rs:10:15
-   |
-LL |    wants_uniq(x);
-   |    ---------- ^- help: try using a conversion method: `.to_string()`
-   |    |          |
-   |    |          expected struct `String`, found `&str`
-   |    arguments to this function are incorrect
-   |
-note: function defined here
-  --> $DIR/estr-subtyping.rs:1:4
-   |
-LL | fn wants_uniq(x: String) { }
-   |    ^^^^^^^^^^ ---------
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
index 16a0c10ea3a3a8f3d8ac7702953bbb72a0bab97b..1831e6cbf10507ecb102cb432c32feb1c856da16 100644 (file)
@@ -12,7 +12,7 @@ impl<T> Foo for T { /* `foo` is still default here */ }
 fn main() {
     eq(foo::<u8>, bar::<u8>);
     //~^ ERROR mismatched types
-    //~| expected type `fn(_) -> _ {foo::<u8>}`
+    //~| expected fn item `fn(_) -> _ {foo::<u8>}`
     //~| found fn item `fn(_) -> _ {bar::<u8>}`
     //~| expected fn item, found a different fn item
     //~| different `fn` items always have unique types, even if their signatures are the same
@@ -28,7 +28,6 @@ fn main() {
 
     eq(bar::<String>, bar::<Vec<u8>>);
     //~^ ERROR mismatched types
-    //~| expected type `fn(_) -> _ {bar::<String>}`
     //~| found fn item `fn(_) -> _ {bar::<Vec<u8>>}`
     //~| expected struct `String`, found struct `Vec`
     //~| different `fn` items always have unique types, even if their signatures are the same
@@ -45,7 +44,6 @@ fn main() {
 
     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
     //~^ ERROR mismatched types
-    //~| expected type `fn(_) -> _ {foo::<u8>}`
     //~| found fn pointer `fn(_) -> _`
     //~| expected fn item, found fn pointer
     //~| change the expected type to be function pointer
index 1fb120eb7a77839cc708dde3f1b7b204789749bf..ecc6485d6d2b5c1d5375e33ac22d32cd5eede579 100644 (file)
@@ -6,8 +6,8 @@ LL |     eq(foo::<u8>, bar::<u8>);
    |     |
    |     arguments to this function are incorrect
    |
-   = note: expected type `fn(_) -> _ {foo::<u8>}`
-           found fn item `fn(_) -> _ {bar::<u8>}`
+   = note: expected fn item `fn(_) -> _ {foo::<u8>}`
+              found fn item `fn(_) -> _ {bar::<u8>}`
    = note: different `fn` items always have unique types, even if their signatures are the same
    = help: change the expected type to be function pointer `fn(isize) -> isize`
    = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
@@ -25,8 +25,8 @@ LL |     eq(foo::<u8>, foo::<i8>);
    |     |
    |     arguments to this function are incorrect
    |
-   = note: expected type `fn(_) -> _ {foo::<u8>}`
-           found fn item `fn(_) -> _ {foo::<i8>}`
+   = note: expected fn item `fn(_) -> _ {foo::<u8>}`
+              found fn item `fn(_) -> _ {foo::<i8>}`
    = note: different `fn` items always have unique types, even if their signatures are the same
    = help: change the expected type to be function pointer `fn(isize) -> isize`
    = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
@@ -44,8 +44,8 @@ LL |     eq(bar::<String>, bar::<Vec<u8>>);
    |     |
    |     arguments to this function are incorrect
    |
-   = note: expected type `fn(_) -> _ {bar::<String>}`
-           found fn item `fn(_) -> _ {bar::<Vec<u8>>}`
+   = note: expected fn item `fn(_) -> _ {bar::<String>}`
+              found fn item `fn(_) -> _ {bar::<Vec<u8>>}`
    = note: different `fn` items always have unique types, even if their signatures are the same
    = help: change the expected type to be function pointer `fn(isize) -> isize`
    = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `bar::<String> as fn(isize) -> isize`
@@ -56,15 +56,15 @@ LL | fn eq<T>(x: T, y: T) { }
    |    ^^    ----  ----
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:39:26
+  --> $DIR/fn-item-type.rs:38:26
    |
 LL |     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
    |     --                   ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
    |     |
    |     arguments to this function are incorrect
    |
-   = note: expected type `fn() {<u8 as Foo>::foo}`
-           found fn item `fn() {<u16 as Foo>::foo}`
+   = note: expected fn item `fn() {<u8 as Foo>::foo}`
+              found fn item `fn() {<u16 as Foo>::foo}`
    = note: different `fn` items always have unique types, even if their signatures are the same
    = help: change the expected type to be function pointer `fn()`
    = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `<u8 as Foo>::foo as fn()`
@@ -75,14 +75,14 @@ LL | fn eq<T>(x: T, y: T) { }
    |    ^^    ----  ----
 
 error[E0308]: mismatched types
-  --> $DIR/fn-item-type.rs:46:19
+  --> $DIR/fn-item-type.rs:45:19
    |
 LL |     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
    |     --            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
    |     |
    |     arguments to this function are incorrect
    |
-   = note:    expected type `fn(_) -> _ {foo::<u8>}`
+   = note: expected fn item `fn(_) -> _ {foo::<u8>}`
            found fn pointer `fn(_) -> _`
    = help: change the expected type to be function pointer `fn(isize) -> isize`
    = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `foo::<u8> as fn(isize) -> isize`
index f05faedf21b827dd18c3fcc46b5fdcb6712a8531..d78a5929a896d8c2f3621a60c32ce283911078a8 100644 (file)
@@ -4,7 +4,7 @@ error[E0308]: mismatched types
 LL |         5
    |         ^ expected enum `Result`, found integer
    |
-   = note: expected type `Result<{integer}, _>`
+   = note: expected enum `Result<{integer}, _>`
               found type `{integer}`
 note: return type inferred to be `Result<{integer}, _>` here
   --> $DIR/type-mismatch-signature-deduction.rs:9:20
diff --git a/src/test/ui/generic-associated-types/const_params_have_right_type.rs b/src/test/ui/generic-associated-types/const_params_have_right_type.rs
new file mode 100644 (file)
index 0000000..6bed8e3
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(generic_associated_types)]
+
+trait Trait {
+    type Foo<const N: u8>;
+}
+
+impl Trait for () {
+    type Foo<const N: u64> = u32;
+    //~^ error: type `Foo` has an incompatible generic parameter for trait
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/const_params_have_right_type.stderr b/src/test/ui/generic-associated-types/const_params_have_right_type.stderr
new file mode 100644 (file)
index 0000000..89c993d
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0053]: type `Foo` has an incompatible generic parameter for trait `Trait`
+  --> $DIR/const_params_have_right_type.rs:8:14
+   |
+LL | trait Trait {
+   |       -----
+LL |     type Foo<const N: u8>;
+   |              ----------- expected const parameter of type `u8`
+...
+LL | impl Trait for () {
+   | -----------------
+LL |     type Foo<const N: u64> = u32;
+   |              ^^^^^^^^^^^^ found const parameter of type `u64`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
index a9adff4faded9e5f4913e204002ae3e218202ab4..0a24855a6a79c96e648876a955934215533451bb 100644 (file)
@@ -21,6 +21,10 @@ note: function defined here
    |
 LL |     fn bar<T>(_: T) {}
    |        ^^^    ----
+help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit
+   |
+LL |     bar::<isize>(i.try_into().unwrap());  // i should not be re-coerced back to an isize
+   |                   ++++++++++++++++++++
 
 error: aborting due to 2 previous errors
 
index db6283ea11f506577305f91eabc5d5f56bec2423..fef63680a86767e913c91cf8b787c018067eb193 100644 (file)
@@ -11,6 +11,10 @@ note: function defined here
    |
 LL | fn foo(_s: i16) { }
    |    ^^^ -------
+help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit
+   |
+LL |     foo((1*(1 as isize)).try_into().unwrap());
+   |         +              +++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/issue-13359.rs:10:9
@@ -25,6 +29,10 @@ note: function defined here
    |
 LL | fn bar(_s: u32) { }
    |    ^^^ -------
+help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit
+   |
+LL |     bar((1*(1 as usize)).try_into().unwrap());
+   |         +              +++++++++++++++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-14940.rs b/src/test/ui/issues/issue-14940.rs
deleted file mode 100644 (file)
index 98a4af0..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// run-pass
-// ignore-emscripten no processes
-// ignore-sgx no processes
-
-use std::env;
-use std::process::Command;
-use std::io::{self, Write};
-
-fn main() {
-    let mut args = env::args();
-    if args.len() > 1 {
-        let mut out = io::stdout();
-        out.write(&['a' as u8; 128 * 1024]).unwrap();
-    } else {
-        let out = Command::new(&args.next().unwrap()).arg("child").output();
-        let out = out.unwrap();
-        assert!(out.status.success());
-    }
-}
diff --git a/src/test/ui/issues/issue-28934.rs b/src/test/ui/issues/issue-28934.rs
deleted file mode 100644 (file)
index 1e48878..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Regression test: issue had to do with "givens" in region inference,
-// which were not being considered during the contraction phase.
-
-// run-fail
-// error-pattern:explicit panic
-// ignore-emscripten no processes
-
-struct Parser<'i: 't, 't>(&'i u8, &'t u8);
-
-impl<'i, 't> Parser<'i, 't> {
-    fn parse_nested_block<F, T>(&mut self, parse: F) -> Result<T, ()>
-        where for<'tt> F: FnOnce(&mut Parser<'i, 'tt>) -> T
-    {
-        panic!()
-    }
-
-    fn expect_exhausted(&mut self) -> Result<(), ()> {
-        Ok(())
-    }
-}
-
-fn main() {
-    let x = 0u8;
-    Parser(&x, &x).parse_nested_block(|input| input.expect_exhausted()).unwrap();
-}
diff --git a/src/test/ui/issues/issue-38715.rs b/src/test/ui/issues/issue-38715.rs
deleted file mode 100644 (file)
index 9a9a501..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#[macro_export]
-macro_rules! foo { ($i:ident) => {} }
-
-#[macro_export]
-macro_rules! foo { () => {} } //~ ERROR the name `foo` is defined multiple times
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-38715.stderr b/src/test/ui/issues/issue-38715.stderr
deleted file mode 100644 (file)
index c87d9f7..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0428]: the name `foo` is defined multiple times
-  --> $DIR/issue-38715.rs:5:1
-   |
-LL | macro_rules! foo { ($i:ident) => {} }
-   | ---------------- previous definition of the macro `foo` here
-...
-LL | macro_rules! foo { () => {} }
-   | ^^^^^^^^^^^^^^^^ `foo` redefined here
-   |
-   = note: `foo` must be defined only once in the macro namespace of this module
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0428`.
diff --git a/src/test/ui/issues/issue-48803.rs b/src/test/ui/issues/issue-48803.rs
deleted file mode 100644 (file)
index f7fd041..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-fn flatten<'a, 'b, T>(x: &'a &'b T) -> &'a T {
-    x
-}
-
-fn main() {
-    let mut x = "original";
-    let y = &x;
-    let z = &y;
-    let w = flatten(z);
-    x = "modified";
-    //~^ ERROR cannot assign to `x` because it is borrowed [E0506]
-    println!("{}", w); // prints "modified"
-}
diff --git a/src/test/ui/issues/issue-48803.stderr b/src/test/ui/issues/issue-48803.stderr
deleted file mode 100644 (file)
index 2f94039..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/issue-48803.rs:10:5
-   |
-LL |     let y = &x;
-   |             -- borrow of `x` occurs here
-...
-LL |     x = "modified";
-   |     ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
-LL |
-LL |     println!("{}", w); // prints "modified"
-   |                    - borrow later used here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0506`.
diff --git a/src/test/ui/issues/issue-52533-1.nll.stderr b/src/test/ui/issues/issue-52533-1.nll.stderr
deleted file mode 100644 (file)
index 20f19b2..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error: lifetime may not live long enough
-  --> $DIR/issue-52533-1.rs:9:18
-   |
-LL |     gimme(|x, y| y)
-   |            -  -  ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
-   |            |  |
-   |            |  has type `&Foo<'_, '1, u32>`
-   |            has type `&Foo<'_, '2, u32>`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/issues/issue-52533-1.rs b/src/test/ui/issues/issue-52533-1.rs
deleted file mode 100644 (file)
index c80f432..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#![allow(warnings)]
-
-struct Foo<'a, 'b, T: 'a + 'b> { x: &'a T, y: &'b T }
-
-fn gimme(_: impl for<'a, 'b, 'c> FnOnce(&'a Foo<'a, 'b, u32>,
-                                        &'a Foo<'a, 'c, u32>) -> &'a Foo<'a, 'b, u32>) { }
-
-fn main() {
-    gimme(|x, y| y)
-    //~^ ERROR mismatched types [E0308]
-}
diff --git a/src/test/ui/issues/issue-52533-1.stderr b/src/test/ui/issues/issue-52533-1.stderr
deleted file mode 100644 (file)
index 475c7d0..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-52533-1.rs:9:18
-   |
-LL |     gimme(|x, y| y)
-   |                  ^ lifetime mismatch
-   |
-   = note: expected reference `&Foo<'_, '_, u32>`
-              found reference `&Foo<'_, '_, u32>`
-note: the anonymous lifetime #3 defined here...
-  --> $DIR/issue-52533-1.rs:9:11
-   |
-LL |     gimme(|x, y| y)
-   |           ^^^^^^^^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined here
-  --> $DIR/issue-52533-1.rs:9:11
-   |
-LL |     gimme(|x, y| y)
-   |           ^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-6801.rs b/src/test/ui/issues/issue-6801.rs
deleted file mode 100644 (file)
index 694d86f..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Creating a stack closure which references a box and then
-// transferring ownership of the box before invoking the stack
-// closure results in a crash.
-
-#![feature(box_syntax)]
-
-fn twice(x: Box<usize>) -> usize {
-     *x * 2
-}
-
-fn invoke<F>(f: F) where F: FnOnce() -> usize {
-     f();
-}
-
-fn main() {
-      let x  : Box<usize>  = box 9;
-      let sq =  || { *x * *x };
-
-      twice(x); //~ ERROR: cannot move out of
-      invoke(sq);
-}
diff --git a/src/test/ui/issues/issue-6801.stderr b/src/test/ui/issues/issue-6801.stderr
deleted file mode 100644 (file)
index 48c6acd..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0505]: cannot move out of `x` because it is borrowed
-  --> $DIR/issue-6801.rs:19:13
-   |
-LL |       let sq =  || { *x * *x };
-   |                 --   -- borrow occurs due to use in closure
-   |                 |
-   |                 borrow of `x` occurs here
-LL | 
-LL |       twice(x);
-   |             ^ move out of `x` occurs here
-LL |       invoke(sq);
-   |              -- borrow later used here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0505`.
index 56a1337e6a5ea55eb001159862fdedd99012ca30..7dbcc151855016fa5ab0545924ccb3693ee6385d 100644 (file)
@@ -184,9 +184,22 @@ error: layout_of(std::result::Result<i32, i32>) = Layout {
                        variants: Single {
                            index: 0,
                        },
-                       abi: Aggregate {
-                           sized: true,
-                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   true,
+                               ),
+                               valid_range: 0..=4294967295,
+                           },
+                       ),
                        largest_niche: None,
                        align: AbiAndPrefAlign {
                            abi: Align(4 bytes),
@@ -206,9 +219,22 @@ error: layout_of(std::result::Result<i32, i32>) = Layout {
                        variants: Single {
                            index: 1,
                        },
-                       abi: Aggregate {
-                           sized: true,
-                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   true,
+                               ),
+                               valid_range: 0..=4294967295,
+                           },
+                       ),
                        largest_niche: None,
                        align: AbiAndPrefAlign {
                            abi: Align(4 bytes),
index 1a724e6f59be1ed2ec5690cc6dd3e7f5fdc9d0b7..33dfa307c1d271a9ac819e53ebf5cd2967f60a4c 100644 (file)
@@ -30,9 +30,21 @@ error: layout_of(MissingPayloadField) = Layout {
                        variants: Single {
                            index: 0,
                        },
-                       abi: Aggregate {
-                           sized: true,
-                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
                        largest_niche: None,
                        align: AbiAndPrefAlign {
                            abi: Align(1 bytes),
@@ -131,9 +143,22 @@ error: layout_of(CommonPayloadField) = Layout {
                        variants: Single {
                            index: 0,
                        },
-                       abi: Aggregate {
-                           sized: true,
-                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=255,
+                           },
+                       ),
                        largest_niche: None,
                        align: AbiAndPrefAlign {
                            abi: Align(1 bytes),
@@ -153,9 +178,22 @@ error: layout_of(CommonPayloadField) = Layout {
                        variants: Single {
                            index: 1,
                        },
-                       abi: Aggregate {
-                           sized: true,
-                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=255,
+                           },
+                       ),
                        largest_niche: None,
                        align: AbiAndPrefAlign {
                            abi: Align(1 bytes),
@@ -237,9 +275,21 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
                        variants: Single {
                            index: 0,
                        },
-                       abi: Aggregate {
-                           sized: true,
-                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
                        largest_niche: None,
                        align: AbiAndPrefAlign {
                            abi: Align(1 bytes),
@@ -259,9 +309,21 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout {
                        variants: Single {
                            index: 1,
                        },
-                       abi: Aggregate {
-                           sized: true,
-                       },
+                       abi: ScalarPair(
+                           Initialized {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                               valid_range: 0..=1,
+                           },
+                           Union {
+                               value: Int(
+                                   I8,
+                                   false,
+                               ),
+                           },
+                       ),
                        largest_niche: None,
                        align: AbiAndPrefAlign {
                            abi: Align(1 bytes),
index fd5a18ce7ea51278921b65d6723a052e41f33792..b961b16b6f6efefd16d5d1c3cec50609a1684497 100644 (file)
@@ -5,7 +5,7 @@ LL |     let Some(x) = Some(1) else { Some(2) };
    |                                ^^^^^^^^^^^ expected `!`, found enum `Option`
    |
    = note: expected type `!`
-              found type `Option<{integer}>`
+              found enum `Option<{integer}>`
    = help: try adding a diverging expression, such as `return` or `panic!(..)`
    = help: ...or use `match` instead of `let...else`
 
@@ -20,8 +20,8 @@ LL | |         }
 LL | |     };
    | |_____^ expected `!`, found `()`
    |
-   = note: expected type `!`
-              found type `()`
+   = note:   expected type `!`
+           found unit type `()`
    = help: try adding a diverging expression, such as `return` or `panic!(..)`
    = help: ...or use `match` instead of `let...else`
 
@@ -35,7 +35,7 @@ LL | |     };
    | |_____^ expected `!`, found enum `Option`
    |
    = note: expected type `!`
-              found type `Option<{integer}>`
+              found enum `Option<{integer}>`
    = help: try adding a diverging expression, such as `return` or `panic!(..)`
    = help: ...or use `match` instead of `let...else`
 
diff --git a/src/test/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs b/src/test/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.rs
new file mode 100644 (file)
index 0000000..f80fe88
--- /dev/null
@@ -0,0 +1,155 @@
+// check-pass
+#![feature(lint_reasons)]
+
+//! This file tests the `#[expect]` attribute implementation for tool lints. The same
+//! file is used to test clippy and rustdoc. Any changes to this file should be synced
+//! to the other test files.
+//!
+//! Expectations:
+//! * rustc: only rustc lint expectations are emitted
+//! * clippy: rustc and Clippy's expectations are emitted
+//! * rustdoc: only rustdoc lint expectations are emitted
+//!
+//! This test can't cover every lint from Clippy, rustdoc and potentially other
+//! tools that will be developed. This therefore only tests a small subset of lints
+
+#![expect(rustdoc::missing_crate_level_docs)]
+
+mod rustc_ok {
+    //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+    #[expect(dead_code)]
+    pub fn rustc_lints() {
+        let x = 42.0;
+
+        #[expect(illegal_floating_point_literal_pattern)]
+        match x {
+            5.0 => {}
+            6.0 => {}
+            _ => {}
+        }
+    }
+}
+
+mod rustc_warn {
+    //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+    #[expect(dead_code)]
+    //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+    //~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
+    pub fn rustc_lints() {
+        let x = 42;
+
+        #[expect(illegal_floating_point_literal_pattern)]
+        //~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
+        match x {
+            5 => {}
+            6 => {}
+            _ => {}
+        }
+    }
+}
+
+pub mod rustdoc_ok {
+    //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+    #[expect(rustdoc::broken_intra_doc_links)]
+    /// I want to link to [`Nonexistent`] but it doesn't exist!
+    pub fn foo() {}
+
+    #[expect(rustdoc::invalid_html_tags)]
+    /// <h1>
+    pub fn bar() {}
+
+    #[expect(rustdoc::bare_urls)]
+    /// http://example.org
+    pub fn baz() {}
+}
+
+pub mod rustdoc_warn {
+    //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+    #[expect(rustdoc::broken_intra_doc_links)]
+    /// I want to link to [`bar`] but it doesn't exist!
+    pub fn foo() {}
+
+    #[expect(rustdoc::invalid_html_tags)]
+    /// <h1></h1>
+    pub fn bar() {}
+
+    #[expect(rustdoc::bare_urls)]
+    /// <http://example.org>
+    pub fn baz() {}
+}
+
+mod clippy_ok {
+    //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+    #[expect(clippy::almost_swapped)]
+    fn foo() {
+        let mut a = 0;
+        let mut b = 9;
+        a = b;
+        b = a;
+    }
+
+    #[expect(clippy::bytes_nth)]
+    fn bar() {
+        let _ = "Hello".bytes().nth(3);
+    }
+
+    #[expect(clippy::if_same_then_else)]
+    fn baz() {
+        let _ = if true {
+            42
+        } else {
+            42
+        };
+    }
+
+    #[expect(clippy::logic_bug)]
+    fn burger() {
+        let a = false;
+        let b = true;
+
+        if a && b || a {}
+    }
+}
+
+mod clippy_warn {
+    //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+    #[expect(clippy::almost_swapped)]
+    fn foo() {
+        let mut a = 0;
+        let mut b = 9;
+        a = b;
+    }
+
+    #[expect(clippy::bytes_nth)]
+    fn bar() {
+        let _ = "Hello".as_bytes().get(3);
+    }
+
+    #[expect(clippy::if_same_then_else)]
+    fn baz() {
+        let _ = if true {
+            33
+        } else {
+            42
+        };
+    }
+
+    #[expect(clippy::logic_bug)]
+    fn burger() {
+        let a = false;
+        let b = true;
+        let c = false;
+
+        if a && b || c {}
+    }
+}
+
+fn main() {
+    rustc_warn::rustc_lints();
+}
diff --git a/src/test/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr b/src/test/ui/lint/rfc-2383-lint-reason/expect_tool_lint_rfc_2383.stderr
new file mode 100644 (file)
index 0000000..6d49e75
--- /dev/null
@@ -0,0 +1,16 @@
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect_tool_lint_rfc_2383.rs:37:14
+   |
+LL |     #[expect(dead_code)]
+   |              ^^^^^^^^^
+   |
+   = note: `#[warn(unfulfilled_lint_expectations)]` on by default
+
+warning: this lint expectation is unfulfilled
+  --> $DIR/expect_tool_lint_rfc_2383.rs:43:18
+   |
+LL |         #[expect(illegal_floating_point_literal_pattern)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs b/src/test/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs
new file mode 100644 (file)
index 0000000..2b6c3c6
--- /dev/null
@@ -0,0 +1,16 @@
+// This ensures that ICEs like rust#94953 don't happen
+// check-pass
+// compile-flags: -Z unpretty=expanded
+
+#![feature(lint_reasons)]
+
+// This `expect` will create an expectation with an unstable expectation id
+#[expect(while_true)]
+fn create_early_lint_pass_expectation() {
+    // `while_true` is an early lint
+    while true {}
+}
+
+fn main() {
+    create_early_lint_pass_expectation();
+}
diff --git a/src/test/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout b/src/test/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout
new file mode 100644 (file)
index 0000000..0ee3a03
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(prelude_import)]
+#![no_std]
+// This ensures that ICEs like rust#94953 don't happen
+// check-pass
+// compile-flags: -Z unpretty=expanded
+
+#![feature(lint_reasons)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+// This `expect` will create an expectation with an unstable expectation id
+#[expect(while_true)]
+fn create_early_lint_pass_expectation() {
+    // `while_true` is an early lint
+    while true {}
+}
+
+fn main() { create_early_lint_pass_expectation(); }
diff --git a/src/test/ui/lint/unused/unused-attr-doc-hidden.fixed b/src/test/ui/lint/unused/unused-attr-doc-hidden.fixed
new file mode 100644 (file)
index 0000000..36a1409
--- /dev/null
@@ -0,0 +1,42 @@
+#![deny(unused_attributes)]
+#![crate_type = "lib"]
+// run-rustfix
+
+pub trait Trait {
+    type It;
+    const IT: ();
+    fn it0();
+    fn it1();
+    fn it2();
+}
+
+pub struct Implementor;
+
+impl Trait for Implementor {
+    
+    type It = ();
+    //~^^ ERROR `#[doc(hidden)]` is ignored
+    //~|  WARNING this was previously accepted
+
+    
+    const IT: () = ();
+    //~^^ ERROR `#[doc(hidden)]` is ignored
+    //~|  WARNING this was previously accepted
+
+    #[doc(alias = "aka")]
+    fn it0() {}
+    //~^^ ERROR `#[doc(hidden)]` is ignored
+    //~|  WARNING this was previously accepted
+
+    #[doc(alias = "this", )]
+    fn it1() {}
+    //~^^ ERROR `#[doc(hidden)]` is ignored
+    //~|  WARNING this was previously accepted
+
+    #[doc()]
+    fn it2() {}
+    //~^^ ERROR `#[doc(hidden)]` is ignored
+    //~|  WARNING this was previously accepted
+    //~|  ERROR `#[doc(hidden)]` is ignored
+    //~|  WARNING this was previously accepted
+}
diff --git a/src/test/ui/lint/unused/unused-attr-doc-hidden.rs b/src/test/ui/lint/unused/unused-attr-doc-hidden.rs
new file mode 100644 (file)
index 0000000..e58c4f2
--- /dev/null
@@ -0,0 +1,42 @@
+#![deny(unused_attributes)]
+#![crate_type = "lib"]
+// run-rustfix
+
+pub trait Trait {
+    type It;
+    const IT: ();
+    fn it0();
+    fn it1();
+    fn it2();
+}
+
+pub struct Implementor;
+
+impl Trait for Implementor {
+    #[doc(hidden)]
+    type It = ();
+    //~^^ ERROR `#[doc(hidden)]` is ignored
+    //~|  WARNING this was previously accepted
+
+    #[doc(hidden)]
+    const IT: () = ();
+    //~^^ ERROR `#[doc(hidden)]` is ignored
+    //~|  WARNING this was previously accepted
+
+    #[doc(hidden, alias = "aka")]
+    fn it0() {}
+    //~^^ ERROR `#[doc(hidden)]` is ignored
+    //~|  WARNING this was previously accepted
+
+    #[doc(alias = "this", hidden,)]
+    fn it1() {}
+    //~^^ ERROR `#[doc(hidden)]` is ignored
+    //~|  WARNING this was previously accepted
+
+    #[doc(hidden, hidden)]
+    fn it2() {}
+    //~^^ ERROR `#[doc(hidden)]` is ignored
+    //~|  WARNING this was previously accepted
+    //~|  ERROR `#[doc(hidden)]` is ignored
+    //~|  WARNING this was previously accepted
+}
diff --git a/src/test/ui/lint/unused/unused-attr-doc-hidden.stderr b/src/test/ui/lint/unused/unused-attr-doc-hidden.stderr
new file mode 100644 (file)
index 0000000..fd1202a
--- /dev/null
@@ -0,0 +1,67 @@
+error: `#[doc(hidden)]` is ignored on trait impl items
+  --> $DIR/unused-attr-doc-hidden.rs:16:5
+   |
+LL |     #[doc(hidden)]
+   |     ^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: the lint level is defined here
+  --> $DIR/unused-attr-doc-hidden.rs:1:9
+   |
+LL | #![deny(unused_attributes)]
+   |         ^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
+
+error: `#[doc(hidden)]` is ignored on trait impl items
+  --> $DIR/unused-attr-doc-hidden.rs:21:5
+   |
+LL |     #[doc(hidden)]
+   |     ^^^^^^^^^^^^^^ help: remove this attribute
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
+
+error: `#[doc(hidden)]` is ignored on trait impl items
+  --> $DIR/unused-attr-doc-hidden.rs:26:11
+   |
+LL |     #[doc(hidden, alias = "aka")]
+   |           ^^^^^^--
+   |           |
+   |           help: remove this attribute
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
+
+error: `#[doc(hidden)]` is ignored on trait impl items
+  --> $DIR/unused-attr-doc-hidden.rs:31:27
+   |
+LL |     #[doc(alias = "this", hidden,)]
+   |                           ^^^^^^-
+   |                           |
+   |                           help: remove this attribute
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
+
+error: `#[doc(hidden)]` is ignored on trait impl items
+  --> $DIR/unused-attr-doc-hidden.rs:36:11
+   |
+LL |     #[doc(hidden, hidden)]
+   |           ^^^^^^--
+   |           |
+   |           help: remove this attribute
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
+
+error: `#[doc(hidden)]` is ignored on trait impl items
+  --> $DIR/unused-attr-doc-hidden.rs:36:19
+   |
+LL |     #[doc(hidden, hidden)]
+   |                   ^^^^^^ help: remove this attribute
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/macros/issue-38715.rs b/src/test/ui/macros/issue-38715.rs
new file mode 100644 (file)
index 0000000..9a9a501
--- /dev/null
@@ -0,0 +1,7 @@
+#[macro_export]
+macro_rules! foo { ($i:ident) => {} }
+
+#[macro_export]
+macro_rules! foo { () => {} } //~ ERROR the name `foo` is defined multiple times
+
+fn main() {}
diff --git a/src/test/ui/macros/issue-38715.stderr b/src/test/ui/macros/issue-38715.stderr
new file mode 100644 (file)
index 0000000..c87d9f7
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0428]: the name `foo` is defined multiple times
+  --> $DIR/issue-38715.rs:5:1
+   |
+LL | macro_rules! foo { ($i:ident) => {} }
+   | ---------------- previous definition of the macro `foo` here
+...
+LL | macro_rules! foo { () => {} }
+   | ^^^^^^^^^^^^^^^^ `foo` redefined here
+   |
+   = note: `foo` must be defined only once in the macro namespace of this module
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0428`.
index 579a5b7ecb98ceec6f58c6b28aa1e726b38a7532..ae10a00671e61e3ce921204abacb22c701adb28f 100644 (file)
@@ -15,6 +15,10 @@ note: function defined here
 LL |     fn write(fildes: i32, buf: *const i8, nbyte: u64) -> i64;
    |        ^^^^^
    = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit
+   |
+LL |                   ($arr.len() * size_of($arr[0])).try_into().unwrap());
+   |                   +                             +++++++++++++++++++++
 
 error[E0605]: non-primitive cast: `{integer}` as `()`
   --> $DIR/issue-26480.rs:22:19
diff --git a/src/test/ui/nll/continue-after-missing-main.nll.stderr b/src/test/ui/nll/continue-after-missing-main.nll.stderr
new file mode 100644 (file)
index 0000000..ebebabe
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0601]: `main` function not found in crate `continue_after_missing_main`
+  --> $DIR/continue-after-missing-main.rs:30:2
+   |
+LL | }
+   |  ^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/nll/continue-after-missing-main.rs b/src/test/ui/nll/continue-after-missing-main.rs
new file mode 100644 (file)
index 0000000..1019cac
--- /dev/null
@@ -0,0 +1,30 @@
+#![allow(dead_code)]
+
+struct Tableau<'a, MP> {
+    provider: &'a MP,
+}
+
+impl<'adapted_matrix_provider, 'original_data, MP>
+    Tableau<'adapted_matrix_provider, AdaptedMatrixProvider<'original_data, MP>>
+{
+    fn provider(&self) -> &'adapted_matrix_provider AdaptedMatrixProvider</*'original_data,*/ MP> {
+        self.provider
+    }
+}
+
+struct AdaptedMatrixProvider<'a, T> {
+    original_problem: &'a T,
+}
+
+impl<'a, T> AdaptedMatrixProvider<'a, T> {
+    fn clone_with_extra_bound(&self) -> Self {
+        AdaptedMatrixProvider { original_problem: self.original_problem }
+    }
+}
+
+fn create_and_solve_subproblems<'data_provider, 'original_data, MP>(
+    tableau: Tableau<'data_provider, AdaptedMatrixProvider<'original_data, MP>>,
+) {
+    let _: AdaptedMatrixProvider<'original_data, MP> = tableau.provider().clone_with_extra_bound();
+    //~^ ERROR lifetime mismatch
+} //~ ERROR `main` function not found in crate
diff --git a/src/test/ui/nll/continue-after-missing-main.stderr b/src/test/ui/nll/continue-after-missing-main.stderr
new file mode 100644 (file)
index 0000000..29e7dc1
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0601]: `main` function not found in crate `continue_after_missing_main`
+  --> $DIR/continue-after-missing-main.rs:30:2
+   |
+LL | }
+   |  ^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
+
+error[E0623]: lifetime mismatch
+  --> $DIR/continue-after-missing-main.rs:28:56
+   |
+LL |     tableau: Tableau<'data_provider, AdaptedMatrixProvider<'original_data, MP>>,
+   |              ------------------------------------------------------------------ these two types are declared with different lifetimes...
+LL | ) {
+LL |     let _: AdaptedMatrixProvider<'original_data, MP> = tableau.provider().clone_with_extra_bound();
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...but data from `tableau` flows into `tableau` here
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0601, E0623.
+For more information about an error, try `rustc --explain E0601`.
diff --git a/src/test/ui/nll/issue-48803.rs b/src/test/ui/nll/issue-48803.rs
new file mode 100644 (file)
index 0000000..f7fd041
--- /dev/null
@@ -0,0 +1,13 @@
+fn flatten<'a, 'b, T>(x: &'a &'b T) -> &'a T {
+    x
+}
+
+fn main() {
+    let mut x = "original";
+    let y = &x;
+    let z = &y;
+    let w = flatten(z);
+    x = "modified";
+    //~^ ERROR cannot assign to `x` because it is borrowed [E0506]
+    println!("{}", w); // prints "modified"
+}
diff --git a/src/test/ui/nll/issue-48803.stderr b/src/test/ui/nll/issue-48803.stderr
new file mode 100644 (file)
index 0000000..2f94039
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/issue-48803.rs:10:5
+   |
+LL |     let y = &x;
+   |             -- borrow of `x` occurs here
+...
+LL |     x = "modified";
+   |     ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here
+LL |
+LL |     println!("{}", w); // prints "modified"
+   |                    - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/src/test/ui/nll/issue-52533-1.nll.stderr b/src/test/ui/nll/issue-52533-1.nll.stderr
new file mode 100644 (file)
index 0000000..20f19b2
--- /dev/null
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-52533-1.rs:9:18
+   |
+LL |     gimme(|x, y| y)
+   |            -  -  ^ closure was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+   |            |  |
+   |            |  has type `&Foo<'_, '1, u32>`
+   |            has type `&Foo<'_, '2, u32>`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/issue-52533-1.rs b/src/test/ui/nll/issue-52533-1.rs
new file mode 100644 (file)
index 0000000..c80f432
--- /dev/null
@@ -0,0 +1,11 @@
+#![allow(warnings)]
+
+struct Foo<'a, 'b, T: 'a + 'b> { x: &'a T, y: &'b T }
+
+fn gimme(_: impl for<'a, 'b, 'c> FnOnce(&'a Foo<'a, 'b, u32>,
+                                        &'a Foo<'a, 'c, u32>) -> &'a Foo<'a, 'b, u32>) { }
+
+fn main() {
+    gimme(|x, y| y)
+    //~^ ERROR mismatched types [E0308]
+}
diff --git a/src/test/ui/nll/issue-52533-1.stderr b/src/test/ui/nll/issue-52533-1.stderr
new file mode 100644 (file)
index 0000000..475c7d0
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-52533-1.rs:9:18
+   |
+LL |     gimme(|x, y| y)
+   |                  ^ lifetime mismatch
+   |
+   = note: expected reference `&Foo<'_, '_, u32>`
+              found reference `&Foo<'_, '_, u32>`
+note: the anonymous lifetime #3 defined here...
+  --> $DIR/issue-52533-1.rs:9:11
+   |
+LL |     gimme(|x, y| y)
+   |           ^^^^^^^^
+note: ...does not necessarily outlive the anonymous lifetime #2 defined here
+  --> $DIR/issue-52533-1.rs:9:11
+   |
+LL |     gimme(|x, y| y)
+   |           ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 66112165622b95ff35a27d74a4fdf908cf172567..368782c1e0d01c43ce3e4a2d27dc7d134580add8 100644 (file)
@@ -92,7 +92,7 @@ LL |     let (B(A(a, _) | B(a)) | A(a, A(a, _) | B(a))) = B(B(1));
    |              first introduced with type `{integer}` here
    |
    = note: expected type `{integer}`
-              found type `E<{integer}>`
+              found enum `E<{integer}>`
    = note: a binding must have the same type in all alternatives
 
 error: aborting due to 15 previous errors
index dae6bb41e74e296b67127be90a874cbcde098403..f6367ef8234058bc23deae3ea0bbc1bed3cfcd5a 100644 (file)
@@ -57,8 +57,8 @@ LL |     let (Ok(ref a) | Err(ref mut a)): Result<&u8, &mut u8> = Ok(&0);
    |             |            types differ in mutability
    |             first introduced with type `&&u8` here
    |
-   = note: expected type `&&u8`
-              found type `&mut &mut u8`
+   = note:      expected reference `&&u8`
+           found mutable reference `&mut &mut u8`
    = note: a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
@@ -70,8 +70,8 @@ LL |     let (Ok((ref a, b)) | Err((ref mut a, ref b))) = Ok((0, &0));
    |              |                 types differ in mutability
    |              first introduced with type `&{integer}` here
    |
-   = note: expected type `&{integer}`
-              found type `&mut _`
+   = note:      expected reference `&{integer}`
+           found mutable reference `&mut _`
    = note: a binding must have the same type in all alternatives
 
 error: aborting due to 9 previous errors
index 8063ba8e9f7bdaf80fb202df86c230b8c4ddd41e..d0979b23f60cd4955c96218995b3678b198462ab 100644 (file)
@@ -316,6 +316,9 @@ LL |     if let X.. .0 = 0 {}
    |            |   |
    |            |   expected integer, found floating-point number
    |            this is of type `u8`
+   |
+   = note: expected type `u8`
+              found type `{float}`
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:33:12
@@ -350,6 +353,9 @@ LL |     if let X..=.0 = 0 {}
    |            |   |
    |            |   expected integer, found floating-point number
    |            this is of type `u8`
+   |
+   = note: expected type `u8`
+              found type `{float}`
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:54:12
@@ -384,6 +390,9 @@ LL |     if let X... .0 = 0 {}
    |            |    |
    |            |    expected integer, found floating-point number
    |            this is of type `u8`
+   |
+   = note: expected type `u8`
+              found type `{float}`
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
   --> $DIR/recover-range-pats.rs:73:12
diff --git a/src/test/ui/process/issue-14940.rs b/src/test/ui/process/issue-14940.rs
new file mode 100644 (file)
index 0000000..98a4af0
--- /dev/null
@@ -0,0 +1,19 @@
+// run-pass
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+use std::env;
+use std::process::Command;
+use std::io::{self, Write};
+
+fn main() {
+    let mut args = env::args();
+    if args.len() > 1 {
+        let mut out = io::stdout();
+        out.write(&['a' as u8; 128 * 1024]).unwrap();
+    } else {
+        let out = Command::new(&args.next().unwrap()).arg("child").output();
+        let out = out.unwrap();
+        assert!(out.status.success());
+    }
+}
index dff4ca68d3103bbccb799a24de968004217995c6..70a64446f6a7d8e522957223cd28e99b47a77a81 100644 (file)
@@ -25,8 +25,8 @@ error[E0308]: cannot coerce intrinsics to function pointers
 LL |         std::intrinsics::unlikely,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
    |
-   = note: expected type `extern "rust-intrinsic" fn(_) -> _ {likely}`
-           found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}`
+   = note: expected fn item `extern "rust-intrinsic" fn(_) -> _ {likely}`
+              found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}`
 
 error: aborting due to 3 previous errors
 
index c14dfa3601a8c0bf9d8919e74611bb4dd2c3ae61..96c1869b4e726c3aaf679ac7c1d95be863cb7d06 100644 (file)
@@ -54,8 +54,8 @@ LL |         Opts::A(ref mut i) | Opts::B(ref i) => {}
    |                 |
    |                 first introduced with type `&mut isize` here
    |
-   = note: expected type `&mut isize`
-              found type `&isize`
+   = note: expected mutable reference `&mut isize`
+                      found reference `&isize`
    = note: in the same arm, a binding must have the same type in all alternatives
 
 error: aborting due to 6 previous errors
index 6d18a39606ccf04362eff220d28c3fabb1ffddc8..11bc170cdfa1ba5b5b9adc7dafcb092db0b63a8d 100644 (file)
@@ -6,8 +6,8 @@ LL |     match &s {
 LL |             "abc" => true,
    |             ^^^^^ expected `&str`, found `str`
    |
-   = note:   expected type `&&str`
-           found reference `&'static str`
+   = note: expected reference `&&str`
+              found reference `&'static str`
 
 error[E0308]: mismatched types
   --> $DIR/lit.rs:16:9
@@ -17,8 +17,8 @@ LL |     match &s {
 LL |         b"abc" => true,
    |         ^^^^^^ expected `&[u8]`, found array `[u8; 3]`
    |
-   = note:   expected type `&&[u8]`
-           found reference `&'static [u8; 3]`
+   = note: expected reference `&&[u8]`
+              found reference `&'static [u8; 3]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/rust-2018/auxiliary/edition-lint-infer-outlives-macro.rs b/src/test/ui/rust-2018/auxiliary/edition-lint-infer-outlives-macro.rs
new file mode 100644 (file)
index 0000000..d45fa10
--- /dev/null
@@ -0,0 +1,6 @@
+pub fn foo() {}
+
+#[macro_export]
+macro_rules! gimme_a {
+    ($($mac:tt)*) => { $($mac)* { 'a } }
+}
diff --git a/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.rs b/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.rs
new file mode 100644 (file)
index 0000000..d7a8328
--- /dev/null
@@ -0,0 +1,28 @@
+// edition:2018
+// aux-build:edition-lint-infer-outlives-macro.rs
+
+// Test that the lint does not fire if the where predicate
+// is from the local crate, but all the bounds are from an
+// external macro.
+
+#![deny(explicit_outlives_requirements)]
+
+#[macro_use]
+extern crate edition_lint_infer_outlives_macro;
+
+macro_rules! make_foo {
+    ($a:tt) => {
+        struct Foo<$a, 'b> where 'b: $a {
+            foo: &$a &'b (),
+        }
+    }
+}
+
+gimme_a! {make_foo!}
+
+struct Bar<'a, 'b: 'a> {
+    //~^ ERROR: outlives requirements can be inferred
+    bar: &'a &'b (),
+}
+
+fn main() {}
diff --git a/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.stderr b/src/test/ui/rust-2018/edition-lint-infer-outlives-macro.stderr
new file mode 100644 (file)
index 0000000..553b1cd
--- /dev/null
@@ -0,0 +1,14 @@
+error: outlives requirements can be inferred
+  --> $DIR/edition-lint-infer-outlives-macro.rs:23:18
+   |
+LL | struct Bar<'a, 'b: 'a> {
+   |                  ^^^^ help: remove this bound
+   |
+note: the lint level is defined here
+  --> $DIR/edition-lint-infer-outlives-macro.rs:8:9
+   |
+LL | #![deny(explicit_outlives_requirements)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/span/E0057.rs b/src/test/ui/span/E0057.rs
deleted file mode 100644 (file)
index 83f941f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-fn main() {
-    let f = |x| x * 3;
-    let a = f(); //~ ERROR E0057
-    let b = f(4);
-    let c = f(2, 3); //~ ERROR E0057
-}
diff --git a/src/test/ui/span/E0057.stderr b/src/test/ui/span/E0057.stderr
deleted file mode 100644 (file)
index a151b20..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0057]: this function takes 1 argument but 0 arguments were supplied
-  --> $DIR/E0057.rs:3:13
-   |
-LL |     let a = f();
-   |             ^-- an argument is missing
-   |
-help: provide the argument
-   |
-LL |     let a = f({_});
-   |             ~~~~~~
-
-error[E0057]: this function takes 1 argument but 2 arguments were supplied
-  --> $DIR/E0057.rs:5:13
-   |
-LL |     let c = f(2, 3);
-   |             ^    - argument unexpected
-   |
-help: remove the extra argument
-   |
-LL |     let c = f(2);
-   |             ~~~~
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0057`.
index f37a8f328a75ae3e839ac8a18195191597d5223e..cc30e6ab9a9b31b73aca2905aa7037ec1d4bd48c 100644 (file)
@@ -59,7 +59,7 @@ fn multiple3() { }
 
 #[stable(feature = "a", since = "b")] //~ ERROR invalid stability version found
 #[deprecated(since = "b", note = "text")]
-#[deprecated(since = "b", note = "text")] //~ ERROR multiple deprecated attributes
+#[deprecated(since = "b", note = "text")] //~ ERROR multiple `deprecated` attributes
 #[rustc_const_unstable(feature = "c", issue = "none")]
 #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels
 pub const fn multiple4() { }
index 9e2d9f2708489c57489fd1c8265c36723f53215b..fcb1eefddbcef733b7777a3273d27a903b1a8c50 100644 (file)
@@ -1,3 +1,15 @@
+error: multiple `deprecated` attributes
+  --> $DIR/stability-attribute-sanity.rs:62:1
+   |
+LL | #[deprecated(since = "b", note = "text")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/stability-attribute-sanity.rs:61:1
+   |
+LL | #[deprecated(since = "b", note = "text")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0541]: unknown meta item 'reason'
   --> $DIR/stability-attribute-sanity.rs:8:42
    |
@@ -82,14 +94,6 @@ error[E0544]: multiple stability levels
 LL | #[stable(feature = "a", since = "b")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0550]: multiple deprecated attributes
-  --> $DIR/stability-attribute-sanity.rs:62:1
-   |
-LL | #[deprecated(since = "b", note = "text")]
-   | ----------------------------------------- first deprecation attribute
-LL | #[deprecated(since = "b", note = "text")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ repeated deprecation attribute
-
 error[E0544]: multiple stability levels
   --> $DIR/stability-attribute-sanity.rs:64:1
    |
@@ -128,5 +132,5 @@ LL | #[stable(feature = "a", since = "1.0.0")]
 
 error: aborting due to 20 previous errors
 
-Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0544, E0546, E0547, E0549, E0550.
+Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0544, E0546, E0547, E0549.
 For more information about an error, try `rustc --explain E0539`.
index 0b1c41b837f6a9d334104ce46d87d1531c9bd48b..fae474cedb886831c23d45c676942da10da6d1a2 100644 (file)
@@ -19,8 +19,8 @@ note: while checking the return type of the `async fn`
    |
 LL |     pub async fn answer_str(&self, _s: &str) -> Test {
    |                                                 ^^^^ checked the `Output` of this `async fn`, found opaque type
-   = note:     expected type `()`
-           found opaque type `impl Future<Output = Test>`
+   = note: expected unit type `()`
+            found opaque type `impl Future<Output = Test>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/issue-96555.rs b/src/test/ui/suggestions/issue-96555.rs
new file mode 100644 (file)
index 0000000..9f0a047
--- /dev/null
@@ -0,0 +1,19 @@
+// edition:2018
+
+async fn f() {
+    m::f1().await; //~ ERROR `()` is not a future
+    m::f2().await; //~ ERROR `()` is not a future
+    m::f3().await; //~ ERROR `()` is not a future
+}
+
+mod m {
+    pub fn f1() {}
+
+    pub(crate) fn f2() {}
+
+    pub
+    fn
+    f3() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-96555.stderr b/src/test/ui/suggestions/issue-96555.stderr
new file mode 100644 (file)
index 0000000..6d3b884
--- /dev/null
@@ -0,0 +1,66 @@
+error[E0277]: `()` is not a future
+  --> $DIR/issue-96555.rs:4:12
+   |
+LL |     m::f1().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 -     m::f1().await;
+LL +     m::f1();
+   | 
+help: alternatively, consider making `fn f1` asynchronous
+   |
+LL |     pub async fn f1() {}
+   |         +++++
+
+error[E0277]: `()` is not a future
+  --> $DIR/issue-96555.rs:5:12
+   |
+LL |     m::f2().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 -     m::f2().await;
+LL +     m::f2();
+   | 
+help: alternatively, consider making `fn f2` asynchronous
+   |
+LL |     pub(crate) async fn f2() {}
+   |                +++++
+
+error[E0277]: `()` is not a future
+  --> $DIR/issue-96555.rs:6:12
+   |
+LL |     m::f3().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 -     m::f3().await;
+LL +     m::f3();
+   | 
+help: alternatively, consider making `fn f3` asynchronous
+   |
+LL |     pub async
+   |         +++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 6aa93a24d2f04badad96d70142113ee6b07a00f6..8c8abe047c2abd7413844f3d940eadf9ffff06d2 100644 (file)
@@ -16,6 +16,9 @@ fn extra_semicolon() {
 async fn async_dummy() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
 //~| NOTE while checking the return type of the `async fn`
 //~| NOTE in this expansion of desugaring of `async` block or function
+//~| NOTE checked the `Output` of this `async fn`, expected opaque type
+//~| NOTE while checking the return type of the `async fn`
+//~| NOTE in this expansion of desugaring of `async` block or function
 async fn async_dummy2() {} //~ NOTE checked the `Output` of this `async fn`, found opaque type
 //~| NOTE checked the `Output` of this `async fn`, found opaque type
 //~| NOTE while checking the return type of the `async fn`
@@ -31,7 +34,7 @@ async fn async_extra_semicolon_same() {
         }
         false => async_dummy(), //~ ERROR `match` arms have incompatible types
         //~^ NOTE expected `()`, found opaque type
-        //~| NOTE expected type `()`
+        //~| NOTE expected unit type `()`
         //~| HELP consider `await`ing on the `Future`
     };
 }
@@ -44,7 +47,7 @@ async fn async_extra_semicolon_different() {
         }
         false => async_dummy2(), //~ ERROR `match` arms have incompatible types
         //~^ NOTE expected `()`, found opaque type
-        //~| NOTE expected type `()`
+        //~| NOTE expected unit type `()`
         //~| HELP consider `await`ing on the `Future`
     };
 }
@@ -55,7 +58,7 @@ async fn async_different_futures() {
         //~| HELP consider `await`ing on both `Future`s
         false => async_dummy2(), //~ ERROR `match` arms have incompatible types
         //~^ NOTE expected opaque type, found a different opaque type
-        //~| NOTE expected type `impl Future<Output = ()>`
+        //~| NOTE expected opaque type `impl Future<Output = ()>`
         //~| NOTE distinct uses of `impl Trait` result in different opaque types
     };
 }
index b55c51b92809a35f5d9e020a6d0db9ee332d5afa..4c4b782bd6fb17047767617efbe86e64c2906b3d 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:32:18
+  --> $DIR/match-prev-arm-needing-semi.rs:35:18
    |
 LL |       let _ = match true {
    |  _____________-
@@ -20,8 +20,8 @@ note: while checking the return type of the `async fn`
    |
 LL | async fn async_dummy() {}
    |                        ^ checked the `Output` of this `async fn`, found opaque type
-   = note:     expected type `()`
-           found opaque type `impl Future<Output = ()>`
+   = note: expected unit type `()`
+            found opaque type `impl Future<Output = ()>`
 help: consider `await`ing on the `Future`
    |
 LL |         false => async_dummy().await,
@@ -33,7 +33,7 @@ LL +             async_dummy()
    | 
 
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:45:18
+  --> $DIR/match-prev-arm-needing-semi.rs:48:18
    |
 LL |       let _ = match true {
    |  _____________-
@@ -50,12 +50,12 @@ LL | |     };
    | |_____- `match` arms have incompatible types
    |
 note: while checking the return type of the `async fn`
-  --> $DIR/match-prev-arm-needing-semi.rs:19:25
+  --> $DIR/match-prev-arm-needing-semi.rs:22:25
    |
 LL | async fn async_dummy2() {}
    |                         ^ checked the `Output` of this `async fn`, found opaque type
-   = note:     expected type `()`
-           found opaque type `impl Future<Output = ()>`
+   = note: expected unit type `()`
+            found opaque type `impl Future<Output = ()>`
 help: consider `await`ing on the `Future`
    |
 LL |         false => async_dummy2().await,
@@ -69,7 +69,7 @@ LL ~         false => Box::new(async_dummy2()),
    |
 
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/match-prev-arm-needing-semi.rs:56:18
+  --> $DIR/match-prev-arm-needing-semi.rs:59:18
    |
 LL |       let _ = match true {
    |  _____________-
@@ -84,12 +84,17 @@ LL | |     };
    | |_____- `match` arms have incompatible types
    |
 note: while checking the return type of the `async fn`
-  --> $DIR/match-prev-arm-needing-semi.rs:19:25
+  --> $DIR/match-prev-arm-needing-semi.rs:16:24
+   |
+LL | async fn async_dummy() {}
+   |                        ^ checked the `Output` of this `async fn`, expected opaque type
+note: while checking the return type of the `async fn`
+  --> $DIR/match-prev-arm-needing-semi.rs:22:25
    |
 LL | async fn async_dummy2() {}
    |                         ^ checked the `Output` of this `async fn`, found opaque type
-   = note:     expected type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
-           found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:19:25>)
+   = note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:16:24>)
+              found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/match-prev-arm-needing-semi.rs:22:25>)
    = note: distinct uses of `impl Trait` result in different opaque types
 help: consider `await`ing on both `Future`s
    |
index 60f423a1163172c71e446c78c5bf4830ef367259..be6fc261562ebc690b412eef6743340aac3444b8 100644 (file)
@@ -20,8 +20,8 @@ LL | |         _ => Box::new(Bar),
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected type `Box<Baz>`
-            found struct `Box<Bar>`
+   = note: expected struct `Box<Baz>`
+              found struct `Box<Bar>`
 note: you might have meant to return the `match` expression
   --> $DIR/match-with-different-arm-types-as-stmt-instead-of-expr.rs:27:6
    |
index e065e0aaa8e0622480eef0c1d5d679d706a8ce28..133ffb058739250011df2fe7c15174346a1213d9 100644 (file)
@@ -1,6 +1,9 @@
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/opaque-type-error.rs:20:9
    |
+LL |   fn thing_one() -> impl Future<Output = Result<(), ()>> {
+   |                     ------------------------------------ the expected opaque type
+...
 LL |   fn thing_two() -> impl Future<Output = Result<(), ()>> {
    |                     ------------------------------------ the found opaque type
 ...
@@ -13,8 +16,8 @@ LL | |         thing_two()
 LL | |     }.await
    | |_____- `if` and `else` have incompatible types
    |
-   = note:     expected type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:8:19>)
-           found opaque type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:12:19>)
+   = note: expected opaque type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:8:19>)
+              found opaque type `impl Future<Output = Result<(), ()>>` (opaque type at <$DIR/opaque-type-error.rs:12:19>)
    = note: distinct uses of `impl Trait` result in different opaque types
 help: consider `await`ing on both `Future`s
    |
index 99589edb535ff93acaab556546c14c37ff833c46..e9e846c2ff39ab1d2eff75bfc24d7eb6cf4ddd4c 100644 (file)
@@ -1,12 +1,18 @@
 error[E0224]: at least one trait is required for an object type
   --> $DIR/only-maybe-bound.rs:13:12
    |
+LL | trait _1 = _0;
+   | -------------- this alias does not contain a trait
+...
 LL | type _T0 = dyn _1;
    |            ^^^^^^
 
 error[E0224]: at least one trait is required for an object type
   --> $DIR/only-maybe-bound.rs:19:12
    |
+LL | trait _2 = _1 + _1;
+   | ------------------- this alias does not contain a trait
+LL | 
 LL | type _T1 = dyn _2;
    |            ^^^^^^
 
index f0c718c7a16db853d7538fe0577eb602c9de73c8..0ee44921bf5f8c82a5621e813813bda2b7619b8d 100644 (file)
@@ -9,8 +9,8 @@ LL |         builder.push(output);
    |                 |
    |                 arguments to this function are incorrect
    |
-   = note: expected type `F`
-            found struct `Class<P>`
+   = note: expected type parameter `F`
+                      found struct `Class<P>`
 note: associated function defined here
   --> $DIR/issue-52893.rs:11:8
    |
index 4b47bd493a5680659e3d21d99addecadad9e9760..e5c2fccb2b5dbabedfff2bc4a51670fa6fd9a143 100644 (file)
@@ -7,6 +7,6 @@ trait WithType {
 
 impl<T> WithType for T {
     type Ctx = dyn Alias<T>;
-//~^ ERROR the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
+    //~^ ERROR at least one trait is required for an object type [E0224]
 }
 fn main() {}
index 245c4ee525eab7292f989d6c5de1740224db54e6..71f3a0e7c7caa115060fff02eb74a12a83092e23 100644 (file)
@@ -1,16 +1,12 @@
-error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
+error[E0224]: at least one trait is required for an object type
   --> $DIR/issue-65673.rs:9:16
    |
+LL | trait Alias<T> = where T: Trait;
+   | -------------------------------- this alias does not contain a trait
+...
 LL |     type Ctx = dyn Alias<T>;
-   |                ^^^^^^^^^^^^ 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`
-  --> $DIR/issue-65673.rs:4:5
-   |
-LL |     type Ctx;
-   |     ^^^^^^^^^ required by this bound in `WithType::Ctx`
+   |                ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0224`.
diff --git a/src/test/ui/traits/issue-96664.rs b/src/test/ui/traits/issue-96664.rs
new file mode 100644 (file)
index 0000000..3c5314a
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+#![feature(trait_alias)]
+
+pub trait State = Clone + Send + Sync + PartialOrd + PartialEq + std::fmt::Display;
+pub trait RandState<S: State> = FnMut() -> S + Send;
+
+pub trait Evaluator {
+    type State;
+}
+
+pub struct Evolver<E: Evaluator> {
+    rand_state: Box<dyn RandState<E::State>>,
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/issue-96665.rs b/src/test/ui/traits/issue-96665.rs
new file mode 100644 (file)
index 0000000..a571d48
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+pub trait Sequence<Item, Subsequence: Sequence<Item, Subsequence>> {}
+
+pub trait NodeWalk<Graph: GraphBase, NodeSubwalk: NodeWalk<Graph, NodeSubwalk>>:
+    Sequence<Graph::NodeIndex, NodeSubwalk>
+{
+}
+
+pub trait GraphBase {
+    type NodeIndex;
+}
+
+pub trait WalkableGraph: GraphBase {}
+
+fn main() {}
index 0c25b6801dc8efff0e11bf11f848cb420676cf45..f8dfc4cd043cd07c4310b7c14575f14c7cbe3620 100644 (file)
@@ -8,6 +8,11 @@ LL | |         let b = 1;
 LL | |     });
    | |_____- argument unexpected
    |
+note: closure defined here
+  --> $DIR/wrong_argument_ice-4.rs:2:6
+   |
+LL |     (|| {})(|| {
+   |      ^^
 help: remove the extra argument
    |
 LL |     (|| {})();
diff --git a/src/test/ui/type-alias-impl-trait/auxiliary/collect_hidden_types.rs b/src/test/ui/type-alias-impl-trait/auxiliary/collect_hidden_types.rs
new file mode 100644 (file)
index 0000000..75d20a6
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(type_alias_impl_trait)]
+
+// edition:2018
+
+use std::future::Future;
+
+pub trait Service<Request> {
+    type Future: Future<Output = ()>;
+    fn call(&mut self, req: Request) -> Self::Future;
+}
+
+// NOTE: the pub(crate) here is critical
+pub(crate) fn new() -> () {}
+
+pub struct A;
+impl Service<()> for A {
+    type Future = impl Future<Output = ()>;
+    fn call(&mut self, _: ()) -> Self::Future {
+        async { new() }
+    }
+}
diff --git a/src/test/ui/type-alias-impl-trait/collect_hidden_types.rs b/src/test/ui/type-alias-impl-trait/collect_hidden_types.rs
new file mode 100644 (file)
index 0000000..e78f178
--- /dev/null
@@ -0,0 +1,22 @@
+// aux-build:collect_hidden_types.rs
+use collect_hidden_types::Service;
+use std::future::Future;
+use std::pin::Pin;
+use std::task::Context;
+
+// build-pass
+
+// edition:2018
+
+extern crate collect_hidden_types;
+
+fn broken(mut a: collect_hidden_types::A, cx: &mut Context<'_>) {
+    let mut fut = a.call(());
+    let _ = unsafe { Pin::new_unchecked(&mut fut) }.poll(cx);
+}
+
+pub async fn meeb(cx: &mut Context<'_>) {
+    broken(collect_hidden_types::A, cx);
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/cross_inference.rs b/src/test/ui/type-alias-impl-trait/cross_inference.rs
new file mode 100644 (file)
index 0000000..dafaf40
--- /dev/null
@@ -0,0 +1,10 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+fn main() {
+    type T = impl Copy;
+    let foo: T = (1u32, 2u32);
+    let x: (_, _) = foo;
+    println!("{:?}", x);
+}
diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.rs
new file mode 100644 (file)
index 0000000..9ad7cad
--- /dev/null
@@ -0,0 +1,24 @@
+// known-bug
+// failure-status: 101
+// compile-flags: --edition=2021 --crate-type=lib
+// rustc-env:RUST_BACKTRACE=0
+
+// normalize-stderr-test "thread 'rustc' panicked.*" -> "thread 'rustc' panicked"
+// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
+// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
+// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "#.*\n" -> ""
+// normalize-stderr-test ".*delayed.*\n" -> ""
+
+// tracked in https://github.com/rust-lang/rust/issues/96572
+
+#![feature(type_alias_impl_trait)]
+
+fn main() {
+    type T = impl Copy;
+    let foo: T = (1u32, 2u32);
+    let (a, b): (u32, u32) = foo;
+}
diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.stderr b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug.stderr
new file mode 100644 (file)
index 0000000..84d2705
--- /dev/null
@@ -0,0 +1,32 @@
+error: internal compiler error: no errors encountered even though `delay_span_bug` issued
+
+error: internal compiler error: broken MIR in DefId(0:3 ~ cross_inference_pattern_bug[646d]::main) ((_1.0: u32)): can't project out of PlaceTy { ty: main::T, variant_index: None }
+  --> $DIR/cross_inference_pattern_bug.rs:23:10
+   |
+LL |     let (a, b): (u32, u32) = foo;
+   |          ^
+   |
+
+error: internal compiler error: TyKind::Error constructed but no error reported
+   |
+
+error: internal compiler error: TyKind::Error constructed but no error reported
+   |
+
+error: internal compiler error: broken MIR in DefId(0:3 ~ cross_inference_pattern_bug[646d]::main) ((_1.1: u32)): can't project out of PlaceTy { ty: main::T, variant_index: None }
+  --> $DIR/cross_inference_pattern_bug.rs:23:13
+   |
+LL |     let (a, b): (u32, u32) = foo;
+   |             ^
+   |
+
+error: internal compiler error: TyKind::Error constructed but no error reported
+   |
+
+error: internal compiler error: TyKind::Error constructed but no error reported
+   |
+
+thread 'rustc' panicked
+
+query stack during panic:
+end of query stack
diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs
new file mode 100644 (file)
index 0000000..179f525
--- /dev/null
@@ -0,0 +1,13 @@
+// known-bug
+// compile-flags: --edition=2021 --crate-type=lib
+// rustc-env:RUST_BACKTRACE=0
+
+// tracked in https://github.com/rust-lang/rust/issues/96572
+
+#![feature(type_alias_impl_trait)]
+
+fn main() {
+    type T = impl Copy;  // error: unconstrained opaque type
+    let foo: T = (1u32, 2u32);
+    let (a, b) = foo; // removing this line makes the code compile
+}
diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.stderr b/src/test/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.stderr
new file mode 100644 (file)
index 0000000..8aa1f49
--- /dev/null
@@ -0,0 +1,10 @@
+error: unconstrained opaque type
+  --> $DIR/cross_inference_pattern_bug_no_type.rs:10:14
+   |
+LL |     type T = impl Copy;  // error: unconstrained opaque type
+   |              ^^^^^^^^^
+   |
+   = note: `T` must be used in combination with a concrete type within the same module
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/cross_inference_rpit.rs b/src/test/ui/type-alias-impl-trait/cross_inference_rpit.rs
new file mode 100644 (file)
index 0000000..f6affbf
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+
+fn foo(b: bool) -> impl Copy {
+    if b {
+        return (5,6)
+    }
+    let x: (_, _) = foo(true);
+    println!("{:?}", x);
+    (1u32, 2u32)
+}
+
+fn main() {
+    foo(false);
+}
index 7f1d1428eb9b4c054e2f4f02ade89c8653884891..ce2556f869c7c13e942e64c3017813f30a60cbed 100644 (file)
@@ -1,3 +1,4 @@
 fn main() {
     Some.nonexistent_method(); //~ ERROR: no method named `nonexistent_method` found
+    Some.nonexistent_field; //~ ERROR: no field `nonexistent_field`
 }
index 58c83a36a3bdc1c4998583ad5812a1bb8fc52d9c..32f53849848c75abd5e599818799c2fa87215c99 100644 (file)
@@ -11,6 +11,20 @@ help: call the constructor
 LL |     (Some)(_).nonexistent_method();
    |     +    ++++
 
-error: aborting due to previous error
+error[E0609]: no field `nonexistent_field` on type `fn(_) -> Option<_> {Option::<_>::Some}`
+  --> $DIR/issue-96738.rs:3:10
+   |
+LL |     Some.nonexistent_field;
+   |     ---- ^^^^^^^^^^^^^^^^^
+   |     |
+   |     this is the constructor of an enum variant
+   |
+help: call the constructor
+   |
+LL |     (Some)(_).nonexistent_field;
+   |     +    ++++
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0599`.
+Some errors have detailed explanations: E0599, E0609.
+For more information about an error, try `rustc --explain E0599`.
index ea1ca380b1c7a853c20c2b15e007f85f325649e6..3241c9f8521c0811b9dae14916c3443f2c8b6ccf 100644 (file)
@@ -6,6 +6,11 @@ LL |     let z = f(1_usize, 2);
    |             |
    |             arguments to this function are incorrect
    |
+note: closure defined here
+  --> $DIR/unboxed-closures-type-mismatch.rs:4:17
+   |
+LL |     let mut f = |x: isize, y: isize| -> isize { x + y };
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: change the type of the numeric literal from `usize` to `isize`
    |
 LL |     let z = f(1_isize, 2);
index 80f61cb3eae11724071bdedda531f4dd80d706e9..b9d51d21e9af246fb08c27bc6180bbec657ecc0d 100644 (file)
@@ -3,7 +3,10 @@ error[E0308]: `if` and `else` have incompatible types
    |
 LL | /     if a % 2 == 0 {
 LL | |         move || println!("{a}")
-   | |         ----------------------- expected because of this
+   | |         -----------------------
+   | |         |
+   | |         the expected closure
+   | |         expected because of this
 LL | |     } else {
 LL | |         Box::new(move || println!("{}", b))
    | |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found struct `Box`
@@ -11,8 +14,8 @@ LL | |
 LL | |     }
    | |_____- `if` and `else` have incompatible types
    |
-   = note: expected type `[closure@$DIR/box-instead-of-dyn-fn.rs:8:9: 8:32]`
-            found struct `Box<[closure@$DIR/box-instead-of-dyn-fn.rs:10:18: 10:43]>`
+   = note: expected closure `[closure@$DIR/box-instead-of-dyn-fn.rs:8:9: 8:32]`
+               found struct `Box<[closure@$DIR/box-instead-of-dyn-fn.rs:10:18: 10:43]>`
 
 error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/box-instead-of-dyn-fn.rs:5:56
index 9dbd41ca368a18a123b8a745fb520dc4ddf12bc4..3f297d222dce7ab01059317a55118871300f2b8c 100644 (file)
@@ -9,8 +9,8 @@ LL | |         None => &R,
 LL | |     }
    | |_____- `match` arms have incompatible types
    |
-   = note:   expected type `&S`
-           found reference `&R`
+   = note: expected reference `&S`
+              found reference `&R`
 
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/wf-unsafe-trait-obj-match.rs:26:21
index 751f9fccd88d4389866d835eb08ebd0a3d3547a7..d25ad0ac6fa16806f92561934b9735a2ddb64c5a 100644 (file)
@@ -3696,6 +3696,7 @@ Released 2018-09-13
 [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
 [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
 [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
+[`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee
 [`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
 [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
 [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
index 5768edc501884feee3e529445ff01f79188cf533..c888a5feda2aeff8aa9a24951c2e66928682d3b5 100644 (file)
     size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
     slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
     stable_sort_primitive::STABLE_SORT_PRIMITIVE,
+    significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE,
     strings::STRING_ADD,
     strings::STRING_ADD_ASSIGN,
     strings::STRING_FROM_UTF8_AS_BYTES,
index ec187563b3f645a1c3c50d774cc8f2e26bf0d2ab..34d1555049da58bbe21e562bec1cd0b3c123a9a6 100644 (file)
     LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
     LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
     LintId::of(regex::TRIVIAL_REGEX),
+    LintId::of(significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(strings::STRING_LIT_AS_BYTES),
     LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
     LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
-    LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
-    LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
     LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR),
     LintId::of(transmute::USELESS_TRANSMUTE),
     LintId::of(use_self::USE_SELF),
index 2ee2c6e3358cd030ffd32a1b8287fc379932e348..63232fd41130538765c6b4f547c8c9ba7e9d9ab8 100644 (file)
@@ -84,6 +84,8 @@
     LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
     LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
     LintId::of(strings::STRING_ADD_ASSIGN),
+    LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
+    LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
     LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
     LintId::of(types::LINKEDLIST),
     LintId::of(types::OPTION_OPTION),
index 3bb821a14829535e924d08c81fadab601d68ce53..09071a255c5e68ef0f94862dbe09afbeae472489 100644 (file)
@@ -364,6 +364,7 @@ macro_rules! declare_clippy_lint {
 mod semicolon_if_nothing_returned;
 mod serde_api;
 mod shadow;
+mod significant_drop_in_scrutinee;
 mod single_char_lifetime_names;
 mod single_component_path_imports;
 mod size_of_in_element_count;
@@ -874,6 +875,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv)));
     store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation));
     store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion));
+    store.register_late_pass(|| Box::new(significant_drop_in_scrutinee::SignificantDropInScrutinee));
     store.register_late_pass(|| Box::new(dbg_macro::DbgMacro));
     let cargo_ignore_publish = conf.cargo_ignore_publish;
     store.register_late_pass(move || {
index ab5d3fa7b6d9c98b55a5c82c0a192e75f68dde13..51d5b510ab93053e155d1b6ec3cbb0ade5ceb101 100644 (file)
@@ -9,8 +9,8 @@
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::{
     BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
-    ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier,
-    TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
+    ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin,
+    TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter as middle_nested_filter;
@@ -145,7 +145,7 @@ fn check_fn_inner<'tcx>(
         .filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
     for typ in types {
         for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) {
-            if pred.in_where_clause {
+            if pred.origin == PredicateOrigin::WhereClause {
                 // has_where_lifetimes checked that this predicate contains no lifetime.
                 continue;
             }
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/significant_drop_in_scrutinee.rs
new file mode 100644 (file)
index 0000000..94ae0c8
--- /dev/null
@@ -0,0 +1,408 @@
+use crate::FxHashSet;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::get_attr;
+use clippy_utils::source::{indent_of, snippet};
+use rustc_errors::{Applicability, Diagnostic};
+use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::{Ty, TypeAndMut};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Check for temporaries returned from function calls in a match scrutinee that have the
+    /// `clippy::has_significant_drop` attribute.
+    ///
+    /// ### Why is this bad?
+    /// The `clippy::has_significant_drop` attribute can be added to types whose Drop impls have
+    /// an important side-effect, such as unlocking a mutex, making it important for users to be
+    /// able to accurately understand their lifetimes. When a temporary is returned in a function
+    /// call in a match scrutinee, its lifetime lasts until the end of the match block, which may
+    /// be surprising.
+    ///
+    /// For `Mutex`es this can lead to a deadlock. This happens when the match scrutinee uses a
+    /// function call that returns a `MutexGuard` and then tries to lock again in one of the match
+    /// arms. In that case the `MutexGuard` in the scrutinee will not be dropped until the end of
+    /// the match block and thus will not unlock.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::sync::Mutex;
+    ///
+    /// # struct State {}
+    ///
+    /// # impl State {
+    /// #     fn foo(&self) -> bool {
+    /// #         true
+    /// #     }
+    ///
+    /// #     fn bar(&self) {}
+    /// # }
+    ///
+    ///
+    /// let mutex = Mutex::new(State {});
+    ///
+    /// match mutex.lock().unwrap().foo() {
+    ///     true => {
+    ///         mutex.lock().unwrap().bar(); // Deadlock!
+    ///     }
+    ///     false => {}
+    /// };
+    ///
+    /// println!("All done!");
+    ///
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::sync::Mutex;
+    ///
+    /// # struct State {}
+    ///
+    /// # impl State {
+    /// #     fn foo(&self) -> bool {
+    /// #         true
+    /// #     }
+    ///
+    /// #     fn bar(&self) {}
+    /// # }
+    ///
+    /// let mutex = Mutex::new(State {});
+    ///
+    /// let is_foo = mutex.lock().unwrap().foo();
+    /// match is_foo {
+    ///     true => {
+    ///         mutex.lock().unwrap().bar();
+    ///     }
+    ///     false => {}
+    /// };
+    ///
+    /// println!("All done!");
+    /// ```
+    #[clippy::version = "1.60.0"]
+    pub SIGNIFICANT_DROP_IN_SCRUTINEE,
+    nursery,
+    "warns when a temporary of a type with a drop with a significant side-effect might have a surprising lifetime"
+}
+
+declare_lint_pass!(SignificantDropInScrutinee => [SIGNIFICANT_DROP_IN_SCRUTINEE]);
+
+impl<'tcx> LateLintPass<'tcx> for SignificantDropInScrutinee {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if let Some(suggestions) = has_significant_drop_in_scrutinee(cx, expr) {
+            for found in suggestions {
+                span_lint_and_then(
+                    cx,
+                    SIGNIFICANT_DROP_IN_SCRUTINEE,
+                    found.found_span,
+                    "temporary with significant drop in match scrutinee",
+                    |diag| set_diagnostic(diag, cx, expr, found),
+                )
+            }
+        }
+    }
+}
+
+fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) {
+    if found.lint_suggestion == LintSuggestion::MoveAndClone {
+        // If our suggestion is to move and clone, then we want to leave it to the user to
+        // decide how to address this lint, since it may be that cloning is inappropriate.
+        // Therefore, we won't to emit a suggestion.
+        return;
+    }
+
+    let original = snippet(cx, found.found_span, "..");
+    let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0));
+
+    let replacement = if found.lint_suggestion == LintSuggestion::MoveAndDerefToCopy {
+        format!("let value = *{};\n{}", original, trailing_indent)
+    } else if found.is_unit_return_val {
+        // If the return value of the expression to be moved is unit, then we don't need to
+        // capture the result in a temporary -- we can just replace it completely with `()`.
+        format!("{};\n{}", original, trailing_indent)
+    } else {
+        format!("let value = {};\n{}", original, trailing_indent)
+    };
+
+    let suggestion_message = if found.lint_suggestion == LintSuggestion::MoveOnly {
+        "try moving the temporary above the match"
+    } else {
+        "try moving the temporary above the match and create a copy"
+    };
+
+    let scrutinee_replacement = if found.is_unit_return_val {
+        "()".to_owned()
+    } else {
+        "value".to_owned()
+    };
+
+    diag.multipart_suggestion(
+        suggestion_message,
+        vec![
+            (expr.span.shrink_to_lo(), replacement),
+            (found.found_span, scrutinee_replacement),
+        ],
+        Applicability::MaybeIncorrect,
+    );
+}
+
+/// If the expression is an ExprKind::Match, check if the scrutinee has a significant drop that may
+/// have a surprising lifetime.
+fn has_significant_drop_in_scrutinee<'tcx, 'a>(
+    cx: &'a LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+) -> Option<Vec<FoundSigDrop>> {
+    let mut helper = SigDropHelper::new(cx);
+    match expr.kind {
+        ExprKind::Match(match_expr, _, _) => helper.find_sig_drop(match_expr),
+        _ => None,
+    }
+}
+
+struct SigDropHelper<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    is_chain_end: bool,
+    seen_types: FxHashSet<Ty<'tcx>>,
+    has_significant_drop: bool,
+    current_sig_drop: Option<FoundSigDrop>,
+    sig_drop_spans: Option<Vec<FoundSigDrop>>,
+    special_handling_for_binary_op: bool,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+enum LintSuggestion {
+    MoveOnly,
+    MoveAndDerefToCopy,
+    MoveAndClone,
+}
+
+#[derive(Clone, Copy)]
+struct FoundSigDrop {
+    found_span: Span,
+    is_unit_return_val: bool,
+    lint_suggestion: LintSuggestion,
+}
+
+impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
+    fn new(cx: &'a LateContext<'tcx>) -> SigDropHelper<'a, 'tcx> {
+        SigDropHelper {
+            cx,
+            is_chain_end: true,
+            seen_types: FxHashSet::default(),
+            has_significant_drop: false,
+            current_sig_drop: None,
+            sig_drop_spans: None,
+            special_handling_for_binary_op: false,
+        }
+    }
+
+    fn find_sig_drop(&mut self, match_expr: &'tcx Expr<'_>) -> Option<Vec<FoundSigDrop>> {
+        self.visit_expr(match_expr);
+
+        // If sig drop spans is empty but we found a significant drop, it means that we didn't find
+        // a type that was trivially copyable as we moved up the chain after finding a significant
+        // drop, so move the entire scrutinee.
+        if self.has_significant_drop && self.sig_drop_spans.is_none() {
+            self.try_setting_current_suggestion(match_expr, true);
+            self.move_current_suggestion();
+        }
+
+        self.sig_drop_spans.take()
+    }
+
+    /// This will try to set the current suggestion (so it can be moved into the suggestions vec
+    /// later). If allow_move_and_clone is false, the suggestion *won't* be set -- this gives us
+    /// an opportunity to look for another type in the chain that will be trivially copyable.
+    /// However, if we are at the the end of the chain, we want to accept whatever is there. (The
+    /// suggestion won't actually be output, but the diagnostic message will be output, so the user
+    /// can determine the best way to handle the lint.)
+    fn try_setting_current_suggestion(&mut self, expr: &'tcx Expr<'_>, allow_move_and_clone: bool) {
+        if self.current_sig_drop.is_some() {
+            return;
+        }
+        let ty = self.get_type(expr);
+        if ty.is_ref() {
+            // We checked that the type was ref, so builtin_deref will return Some TypeAndMut,
+            // but let's avoid any chance of an ICE
+            if let Some(TypeAndMut { ty, .. }) = ty.builtin_deref(true) {
+                if ty.is_trivially_pure_clone_copy() {
+                    self.current_sig_drop.replace(FoundSigDrop {
+                        found_span: expr.span,
+                        is_unit_return_val: false,
+                        lint_suggestion: LintSuggestion::MoveAndDerefToCopy,
+                    });
+                } else if allow_move_and_clone {
+                    self.current_sig_drop.replace(FoundSigDrop {
+                        found_span: expr.span,
+                        is_unit_return_val: false,
+                        lint_suggestion: LintSuggestion::MoveAndClone,
+                    });
+                }
+            }
+        } else if ty.is_trivially_pure_clone_copy() {
+            self.current_sig_drop.replace(FoundSigDrop {
+                found_span: expr.span,
+                is_unit_return_val: false,
+                lint_suggestion: LintSuggestion::MoveOnly,
+            });
+        }
+    }
+
+    fn move_current_suggestion(&mut self) {
+        if let Some(current) = self.current_sig_drop.take() {
+            self.sig_drop_spans.get_or_insert_with(Vec::new).push(current);
+        }
+    }
+
+    fn get_type(&self, ex: &'tcx Expr<'_>) -> Ty<'tcx> {
+        self.cx.typeck_results().expr_ty(ex)
+    }
+
+    fn has_seen_type(&mut self, ty: Ty<'tcx>) -> bool {
+        !self.seen_types.insert(ty)
+    }
+
+    fn visit_exprs_for_binary_ops(
+        &mut self,
+        left: &'tcx Expr<'_>,
+        right: &'tcx Expr<'_>,
+        is_unit_return_val: bool,
+        span: Span,
+    ) {
+        self.special_handling_for_binary_op = true;
+        self.visit_expr(left);
+        self.visit_expr(right);
+
+        // If either side had a significant drop, suggest moving the entire scrutinee to avoid
+        // unnecessary copies and to simplify cases where both sides have significant drops.
+        if self.has_significant_drop {
+            self.current_sig_drop.replace(FoundSigDrop {
+                found_span: span,
+                is_unit_return_val,
+                lint_suggestion: LintSuggestion::MoveOnly,
+            });
+        }
+
+        self.special_handling_for_binary_op = false;
+    }
+
+    fn has_sig_drop_attr(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+        if let Some(adt) = ty.ty_adt_def() {
+            if get_attr(cx.sess(), cx.tcx.get_attrs(adt.did()), "has_significant_drop").count() > 0 {
+                return true;
+            }
+        }
+
+        match ty.kind() {
+            rustc_middle::ty::Adt(a, b) => {
+                for f in a.all_fields() {
+                    let ty = f.ty(cx.tcx, b);
+                    if !self.has_seen_type(ty) && self.has_sig_drop_attr(cx, ty) {
+                        return true;
+                    }
+                }
+
+                for generic_arg in b.iter() {
+                    if let GenericArgKind::Type(ty) = generic_arg.unpack() {
+                        if self.has_sig_drop_attr(cx, ty) {
+                            return true;
+                        }
+                    }
+                }
+                false
+            },
+            rustc_middle::ty::Array(ty, _) => self.has_sig_drop_attr(cx, *ty),
+            rustc_middle::ty::RawPtr(TypeAndMut { ty, .. }) => self.has_sig_drop_attr(cx, *ty),
+            rustc_middle::ty::Ref(_, ty, _) => self.has_sig_drop_attr(cx, *ty),
+            rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(cx, *ty),
+            _ => false,
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
+    fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
+        if !self.is_chain_end && self.has_sig_drop_attr(self.cx, self.get_type(ex)) {
+            self.has_significant_drop = true;
+            return;
+        }
+        self.is_chain_end = false;
+
+        match ex.kind {
+            ExprKind::MethodCall(_, [ref expr, ..], _) => {
+                self.visit_expr(expr)
+            }
+            ExprKind::Binary(_, left, right) => {
+                self.visit_exprs_for_binary_ops(left, right, false, ex.span);
+            }
+            ExprKind::Assign(left, right, _) => {
+                self.visit_exprs_for_binary_ops(left, right, true, ex.span);
+            }
+            ExprKind::AssignOp(_, left, right) => {
+                self.visit_exprs_for_binary_ops(left, right, true, ex.span);
+            }
+            ExprKind::Tup(exprs) => {
+                for expr in exprs {
+                    self.visit_expr(expr);
+                    if self.has_significant_drop {
+                        // We may have not have set current_sig_drop if all the suggestions were
+                        // MoveAndClone, so add this tuple item's full expression in that case.
+                        if self.current_sig_drop.is_none() {
+                            self.try_setting_current_suggestion(expr, true);
+                        }
+
+                        // Now we are guaranteed to have something, so add it to the final vec.
+                        self.move_current_suggestion();
+                    }
+                    // Reset `has_significant_drop` after each tuple expression so we can look for
+                    // additional cases.
+                    self.has_significant_drop = false;
+                }
+                if self.sig_drop_spans.is_some() {
+                    self.has_significant_drop = true;
+                }
+            }
+            ExprKind::Box(..) |
+                ExprKind::Array(..) |
+                ExprKind::Call(..) |
+                ExprKind::Unary(..) |
+                ExprKind::If(..) |
+                ExprKind::Match(..) |
+                ExprKind::Field(..) |
+                ExprKind::Index(..) |
+                ExprKind::Ret(..) |
+                ExprKind::Repeat(..) |
+                ExprKind::Yield(..) |
+                ExprKind::MethodCall(..) => walk_expr(self, ex),
+            ExprKind::AddrOf(_, _, _) |
+                ExprKind::Block(_, _) |
+                ExprKind::Break(_, _) |
+                ExprKind::Cast(_, _) |
+                // Don't want to check the closure itself, only invocation, which is covered by MethodCall
+                ExprKind::Closure(_, _, _, _, _) |
+                ExprKind::ConstBlock(_) |
+                ExprKind::Continue(_) |
+                ExprKind::DropTemps(_) |
+                ExprKind::Err |
+                ExprKind::InlineAsm(_) |
+                ExprKind::Let(_) |
+                ExprKind::Lit(_) |
+                ExprKind::Loop(_, _, _, _) |
+                ExprKind::Path(_) |
+                ExprKind::Struct(_, _, _) |
+                ExprKind::Type(_, _) => {
+                return;
+            }
+        }
+
+        // Once a significant temporary has been found, we need to go back up at least 1 level to
+        // find the span to extract for replacement, so the temporary gets dropped. However, for
+        // binary ops, we want to move the whole scrutinee so we avoid unnecessary copies and to
+        // simplify cases where both sides have significant drops.
+        if self.has_significant_drop && !self.special_handling_for_binary_op {
+            self.try_setting_current_suggestion(ex, false);
+        }
+    }
+}
index 78e388a49af1d470291e93a36958e66e6c2c6572..911da3997ae451160af7106915e89e3a1243c093 100644 (file)
@@ -8,7 +8,8 @@
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{
-    GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, QPath, TraitItem, Ty, TyKind, WherePredicate,
+    GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, PredicateOrigin, QPath, TraitItem, Ty, TyKind,
+    WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -35,7 +36,7 @@
     /// ```
     #[clippy::version = "1.38.0"]
     pub TYPE_REPETITION_IN_BOUNDS,
-    nursery,
+    pedantic,
     "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`"
 }
 
@@ -65,7 +66,7 @@
     /// ```
     #[clippy::version = "1.47.0"]
     pub TRAIT_DUPLICATION_IN_BOUNDS,
-    nursery,
+    pedantic,
     "Check if the same trait bounds are specified twice during a function declaration"
 }
 
@@ -95,6 +96,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tc
         for predicate in item.generics.predicates {
             if_chain! {
                 if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
+                if bound_predicate.origin != PredicateOrigin::ImplTrait;
                 if !bound_predicate.span.from_expansion();
                 if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
                 if let Some(PathSegment {
@@ -168,6 +170,7 @@ impl Eq for SpanlessTy<'_, '_> {}
         for bound in gen.predicates {
             if_chain! {
                 if let WherePredicate::BoundPredicate(ref p) = bound;
+                if p.origin != PredicateOrigin::ImplTrait;
                 if p.bounds.len() as u64 <= self.max_trait_bounds;
                 if !p.span.from_expansion();
                 if let Some(ref v) = map.insert(
@@ -223,6 +226,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
     for predicate in gen.predicates {
         if_chain! {
             if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
+            if bound_predicate.origin != PredicateOrigin::ImplTrait;
             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();
index 25a84d16650896e090c49bfa0f68237f9a616b9d..7f448175e3267c7db0fb9e58ba735a40978efb86 100644 (file)
@@ -22,6 +22,7 @@ pub enum DeprecationStatus {
     ("cyclomatic_complexity", DeprecationStatus::Replaced("cognitive_complexity")),
     ("dump",                  DeprecationStatus::None),
     ("msrv",                  DeprecationStatus::None),
+    ("has_significant_drop",  DeprecationStatus::None),
 ];
 
 pub struct LimitStack {
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
new file mode 100644 (file)
index 0000000..28b37f9
--- /dev/null
@@ -0,0 +1,142 @@
+// check-pass
+#![feature(lint_reasons)]
+//! This file tests the `#[expect]` attribute implementation for tool lints. The same
+//! file is used to test clippy and rustdoc. Any changes to this file should be synced
+//! to the other test files as well.
+//!
+//! Expectations:
+//! * rustc: only rustc lint expectations are emitted
+//! * clippy: rustc and Clippy's expectations are emitted
+//! * rustdoc: only rustdoc lint expectations are emitted
+//!
+//! This test can't cover every lint from Clippy, rustdoc and potentially other
+//! tools that will be developed. This therefore only tests a small subset of lints
+#![expect(rustdoc::missing_crate_level_docs)]
+
+mod rustc_ok {
+    //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+    #[expect(dead_code)]
+    pub fn rustc_lints() {
+        let x = 42.0;
+
+        #[expect(illegal_floating_point_literal_pattern)]
+        match x {
+            5.0 => {}
+            6.0 => {}
+            _ => {}
+        }
+    }
+}
+
+mod rustc_warn {
+    //! See <https://doc.rust-lang.org/rustc/lints/index.html>
+
+    #[expect(dead_code)]
+    pub fn rustc_lints() {
+        let x = 42;
+
+        #[expect(illegal_floating_point_literal_pattern)]
+        match x {
+            5 => {}
+            6 => {}
+            _ => {}
+        }
+    }
+}
+
+pub mod rustdoc_ok {
+    //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+    #[expect(rustdoc::broken_intra_doc_links)]
+    /// I want to link to [`Nonexistent`] but it doesn't exist!
+    pub fn foo() {}
+
+    #[expect(rustdoc::invalid_html_tags)]
+    /// <h1>
+    pub fn bar() {}
+
+    #[expect(rustdoc::bare_urls)]
+    /// http://example.org
+    pub fn baz() {}
+}
+
+pub mod rustdoc_warn {
+    //! See <https://doc.rust-lang.org/rustdoc/lints.html>
+
+    #[expect(rustdoc::broken_intra_doc_links)]
+    /// I want to link to [`bar`] but it doesn't exist!
+    pub fn foo() {}
+
+    #[expect(rustdoc::invalid_html_tags)]
+    /// <h1></h1>
+    pub fn bar() {}
+
+    #[expect(rustdoc::bare_urls)]
+    /// <http://example.org>
+    pub fn baz() {}
+}
+
+mod clippy_ok {
+    //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+    #[expect(clippy::almost_swapped)]
+    fn foo() {
+        let mut a = 0;
+        let mut b = 9;
+        a = b;
+        b = a;
+    }
+
+    #[expect(clippy::bytes_nth)]
+    fn bar() {
+        let _ = "Hello".bytes().nth(3);
+    }
+
+    #[expect(clippy::if_same_then_else)]
+    fn baz() {
+        let _ = if true { 42 } else { 42 };
+    }
+
+    #[expect(clippy::logic_bug)]
+    fn burger() {
+        let a = false;
+        let b = true;
+
+        if a && b || a {}
+    }
+}
+
+mod clippy_warn {
+    //! See <https://rust-lang.github.io/rust-clippy/master/index.html>
+
+    #[expect(clippy::almost_swapped)]
+    fn foo() {
+        let mut a = 0;
+        let mut b = 9;
+        a = b;
+    }
+
+    #[expect(clippy::bytes_nth)]
+    fn bar() {
+        let _ = "Hello".as_bytes().get(3);
+    }
+
+    #[expect(clippy::if_same_then_else)]
+    fn baz() {
+        let _ = if true { 33 } else { 42 };
+    }
+
+    #[expect(clippy::logic_bug)]
+    fn burger() {
+        let a = false;
+        let b = true;
+        let c = false;
+
+        if a && b || c {}
+    }
+}
+
+fn main() {
+    rustc_warn::rustc_lints();
+}
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
new file mode 100644 (file)
index 0000000..db29e85
--- /dev/null
@@ -0,0 +1,40 @@
+error: this lint expectation is unfulfilled
+  --> $DIR/expect_tool_lint_rfc_2383.rs:35:14
+   |
+LL |     #[expect(dead_code)]
+   |              ^^^^^^^^^
+   |
+   = note: `-D unfulfilled-lint-expectations` implied by `-D warnings`
+
+error: this lint expectation is unfulfilled
+  --> $DIR/expect_tool_lint_rfc_2383.rs:39:18
+   |
+LL |         #[expect(illegal_floating_point_literal_pattern)]
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this lint expectation is unfulfilled
+  --> $DIR/expect_tool_lint_rfc_2383.rs:113:14
+   |
+LL |     #[expect(clippy::almost_swapped)]
+   |              ^^^^^^^^^^^^^^^^^^^^^^
+
+error: this lint expectation is unfulfilled
+  --> $DIR/expect_tool_lint_rfc_2383.rs:120:14
+   |
+LL |     #[expect(clippy::bytes_nth)]
+   |              ^^^^^^^^^^^^^^^^^
+
+error: this lint expectation is unfulfilled
+  --> $DIR/expect_tool_lint_rfc_2383.rs:125:14
+   |
+LL |     #[expect(clippy::if_same_then_else)]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this lint expectation is unfulfilled
+  --> $DIR/expect_tool_lint_rfc_2383.rs:130:14
+   |
+LL |     #[expect(clippy::logic_bug)]
+   |              ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
new file mode 100644 (file)
index 0000000..c4a3301
--- /dev/null
@@ -0,0 +1,526 @@
+// FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934
+// // run-rustfix
+
+#![warn(clippy::significant_drop_in_scrutinee)]
+#![allow(clippy::single_match)]
+#![allow(clippy::match_single_binding)]
+#![allow(unused_assignments)]
+#![allow(dead_code)]
+
+use std::ops::Deref;
+use std::sync::atomic::{AtomicU64, Ordering};
+use std::sync::{Mutex, MutexGuard};
+
+struct State {}
+
+impl State {
+    fn foo(&self) -> bool {
+        true
+    }
+
+    fn bar(&self) {}
+}
+
+fn should_not_trigger_lint_with_mutex_guard_outside_match() {
+    let mutex = Mutex::new(State {});
+
+    // Should not trigger lint because the temporary should drop at the `;` on line before the match
+    let is_foo = mutex.lock().unwrap().foo();
+    match is_foo {
+        true => {
+            mutex.lock().unwrap().bar();
+        }
+        false => {}
+    };
+}
+
+fn should_not_trigger_lint_with_mutex_guard_when_taking_ownership_in_match() {
+    let mutex = Mutex::new(State {});
+
+    // Should not trigger lint because the scrutinee is explicitly returning the MutexGuard,
+    // so its lifetime should not be surprising.
+    match mutex.lock() {
+        Ok(guard) => {
+            guard.foo();
+            mutex.lock().unwrap().bar();
+        }
+        _ => {}
+    };
+}
+
+fn should_trigger_lint_with_mutex_guard_in_match_scrutinee() {
+    let mutex = Mutex::new(State {});
+
+    // Should trigger lint because the lifetime of the temporary MutexGuard is surprising because it
+    // is preserved until the end of the match, but there is no clear indication that this is the
+    // case.
+    match mutex.lock().unwrap().foo() {
+        true => {
+            mutex.lock().unwrap().bar();
+        }
+        false => {}
+    };
+}
+
+fn should_not_trigger_lint_for_insignificant_drop() {
+    // Should not trigger lint because there are no temporaries whose drops have a significant
+    // side effect.
+    match 1u64.to_string().is_empty() {
+        true => {
+            println!("It was empty")
+        }
+        false => {
+            println!("It was not empty")
+        }
+    }
+}
+
+struct StateWithMutex {
+    m: Mutex<u64>,
+}
+
+struct MutexGuardWrapper<'a> {
+    mg: MutexGuard<'a, u64>,
+}
+
+impl<'a> MutexGuardWrapper<'a> {
+    fn get_the_value(&self) -> u64 {
+        *self.mg.deref()
+    }
+}
+
+struct MutexGuardWrapperWrapper<'a> {
+    mg: MutexGuardWrapper<'a>,
+}
+
+impl<'a> MutexGuardWrapperWrapper<'a> {
+    fn get_the_value(&self) -> u64 {
+        *self.mg.mg.deref()
+    }
+}
+
+impl StateWithMutex {
+    fn lock_m(&self) -> MutexGuardWrapper<'_> {
+        MutexGuardWrapper {
+            mg: self.m.lock().unwrap(),
+        }
+    }
+
+    fn lock_m_m(&self) -> MutexGuardWrapperWrapper<'_> {
+        MutexGuardWrapperWrapper {
+            mg: MutexGuardWrapper {
+                mg: self.m.lock().unwrap(),
+            },
+        }
+    }
+
+    fn foo(&self) -> bool {
+        true
+    }
+
+    fn bar(&self) {}
+}
+
+fn should_trigger_lint_with_wrapped_mutex() {
+    let s = StateWithMutex { m: Mutex::new(1) };
+
+    // Should trigger lint because a temporary contains a type with a significant drop and its
+    // lifetime is not obvious. Additionally, it is not obvious from looking at the scrutinee that
+    // the temporary contains such a type, making it potentially even more surprising.
+    match s.lock_m().get_the_value() {
+        1 => {
+            println!("Got 1. Is it still 1?");
+            println!("{}", s.lock_m().get_the_value());
+        }
+        2 => {
+            println!("Got 2. Is it still 2?");
+            println!("{}", s.lock_m().get_the_value());
+        }
+        _ => {}
+    }
+    println!("All done!");
+}
+
+fn should_trigger_lint_with_double_wrapped_mutex() {
+    let s = StateWithMutex { m: Mutex::new(1) };
+
+    // Should trigger lint because a temporary contains a type which further contains a type with a
+    // significant drop and its lifetime is not obvious. Additionally, it is not obvious from
+    // looking at the scrutinee that the temporary contains such a type, making it potentially even
+    // more surprising.
+    match s.lock_m_m().get_the_value() {
+        1 => {
+            println!("Got 1. Is it still 1?");
+            println!("{}", s.lock_m().get_the_value());
+        }
+        2 => {
+            println!("Got 2. Is it still 2?");
+            println!("{}", s.lock_m().get_the_value());
+        }
+        _ => {}
+    }
+    println!("All done!");
+}
+
+struct Counter {
+    i: AtomicU64,
+}
+
+#[clippy::has_significant_drop]
+struct CounterWrapper<'a> {
+    counter: &'a Counter,
+}
+
+impl<'a> CounterWrapper<'a> {
+    fn new(counter: &Counter) -> CounterWrapper {
+        counter.i.fetch_add(1, Ordering::Relaxed);
+        CounterWrapper { counter }
+    }
+}
+
+impl<'a> Drop for CounterWrapper<'a> {
+    fn drop(&mut self) {
+        self.counter.i.fetch_sub(1, Ordering::Relaxed);
+    }
+}
+
+impl Counter {
+    fn temp_increment(&self) -> Vec<CounterWrapper> {
+        vec![CounterWrapper::new(self), CounterWrapper::new(self)]
+    }
+}
+
+fn should_trigger_lint_for_vec() {
+    let counter = Counter { i: AtomicU64::new(0) };
+
+    // Should trigger lint because the temporary in the scrutinee returns a collection of types
+    // which have significant drops. The types with significant drops are also non-obvious when
+    // reading the expression in the scrutinee.
+    match counter.temp_increment().len() {
+        2 => {
+            let current_count = counter.i.load(Ordering::Relaxed);
+            println!("Current count {}", current_count);
+            assert_eq!(current_count, 0);
+        }
+        1 => {}
+        3 => {}
+        _ => {}
+    };
+}
+
+struct StateWithField {
+    s: String,
+}
+
+// Should trigger lint only on the type in the tuple which is created using a temporary
+// with a significant drop. Additionally, this test ensures that the format of the tuple
+// is preserved correctly in the suggestion.
+fn should_trigger_lint_for_tuple_in_scrutinee() {
+    let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
+
+    {
+        match (mutex1.lock().unwrap().s.len(), true) {
+            (3, _) => {
+                println!("started");
+                mutex1.lock().unwrap().s.len();
+                println!("done");
+            }
+            (_, _) => {}
+        };
+
+        match (true, mutex1.lock().unwrap().s.len(), true) {
+            (_, 3, _) => {
+                println!("started");
+                mutex1.lock().unwrap().s.len();
+                println!("done");
+            }
+            (_, _, _) => {}
+        };
+
+        let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() });
+        match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
+            (3, _, 3) => {
+                println!("started");
+                mutex1.lock().unwrap().s.len();
+                mutex2.lock().unwrap().s.len();
+                println!("done");
+            }
+            (_, _, _) => {}
+        };
+
+        let mutex3 = Mutex::new(StateWithField { s: "three".to_owned() });
+        match mutex3.lock().unwrap().s.as_str() {
+            "three" => {
+                println!("started");
+                mutex1.lock().unwrap().s.len();
+                mutex2.lock().unwrap().s.len();
+                println!("done");
+            }
+            _ => {}
+        };
+
+
+        match (true, mutex3.lock().unwrap().s.as_str()) {
+            (_, "three") => {
+                println!("started");
+                mutex1.lock().unwrap().s.len();
+                mutex2.lock().unwrap().s.len();
+                println!("done");
+            }
+            (_, _) => {}
+        };
+    }
+}
+
+// Should trigger lint when either side of a binary operation creates a temporary with a
+// significant drop.
+// To avoid potential unnecessary copies or creating references that would trigger the significant
+// drop problem, the lint recommends moving the entire binary operation.
+fn should_trigger_lint_for_accessing_field_in_mutex_in_one_side_of_binary_op() {
+    let mutex = Mutex::new(StateWithField { s: "state".to_owned() });
+
+    match mutex.lock().unwrap().s.len() > 1 {
+        true => {
+            mutex.lock().unwrap().s.len();
+        }
+        false => {}
+    };
+
+    match 1 < mutex.lock().unwrap().s.len() {
+        true => {
+            mutex.lock().unwrap().s.len();
+        }
+        false => {}
+    };
+}
+
+// Should trigger lint when both sides of a binary operation creates a temporary with a
+// significant drop.
+// To avoid potential unnecessary copies or creating references that would trigger the significant
+// drop problem, the lint recommends moving the entire binary operation.
+fn should_trigger_lint_for_accessing_fields_in_mutex_in_both_sides_of_binary_op() {
+    let mutex1 = Mutex::new(StateWithField { s: "state".to_owned() });
+    let mutex2 = Mutex::new(StateWithField { s: "statewithfield".to_owned() });
+
+    match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() {
+        true => {
+            println!("{} < {}", mutex1.lock().unwrap().s.len(), mutex2.lock().unwrap().s.len());
+        }
+        false => {}
+    };
+
+    match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() {
+        true => {
+            println!("{} >= {}", mutex1.lock().unwrap().s.len(), mutex2.lock().unwrap().s.len());
+        }
+        false => {}
+    };
+}
+
+fn should_not_trigger_lint_for_closure_in_scrutinee() {
+    let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
+
+    let get_mutex_guard = || mutex1.lock().unwrap().s.len();
+
+    // Should not trigger lint because the temporary with a significant drop will be dropped
+    // at the end of the closure, so the MutexGuard will be unlocked and not have a potentially
+    // surprising lifetime.
+    match get_mutex_guard() > 1 {
+        true => {
+            mutex1.lock().unwrap().s.len();
+        }
+        false => {}
+    };
+}
+
+fn should_trigger_lint_for_return_from_closure_in_scrutinee() {
+    let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
+
+    let get_mutex_guard = || mutex1.lock().unwrap();
+
+    // Should trigger lint because the temporary with a significant drop is returned from the
+    // closure but not used directly in any match arms, so it has a potentially surprising lifetime.
+    match get_mutex_guard().s.len() > 1 {
+        true => {
+            mutex1.lock().unwrap().s.len();
+        }
+        false => {}
+    };
+}
+
+fn should_trigger_lint_for_return_from_match_in_scrutinee() {
+    let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
+    let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() });
+
+    let i = 100;
+
+    // Should trigger lint because the nested match within the scrutinee returns a temporary with a
+    // significant drop is but not used directly in any match arms, so it has a potentially
+    // surprising lifetime.
+    match match i { 100 => mutex1.lock().unwrap(), _ => mutex2.lock().unwrap() }.s.len() > 1 {
+        true => {
+            mutex1.lock().unwrap().s.len();
+        }
+        false => {
+            println!("nothing to do here");
+        }
+    };
+}
+
+fn should_trigger_lint_for_return_from_if_in_scrutinee() {
+    let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() });
+    let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() });
+
+    let i = 100;
+
+    // Should trigger lint because the nested if-expression within the scrutinee returns a temporary
+    // with a significant drop is but not used directly in any match arms, so it has a potentially
+    // surprising lifetime.
+    match if i > 1 { mutex1.lock().unwrap() } else { mutex2.lock().unwrap() }.s.len() > 1 {
+        true => {
+            mutex1.lock().unwrap().s.len();
+        }
+        false => {}
+    };
+}
+
+fn should_not_trigger_lint_for_if_in_scrutinee() {
+    let mutex = Mutex::new(StateWithField { s: "state".to_owned() });
+
+    let i = 100;
+
+    // Should not trigger the lint because the temporary with a significant drop *is* dropped within
+    // the body of the if-expression nested within the match scrutinee, and therefore does not have
+    // a potentially surprising lifetime.
+    match if i > 1 { mutex.lock().unwrap().s.len() > 1 } else { false } {
+        true => {
+            mutex.lock().unwrap().s.len();
+        }
+        false => {}
+    };
+}
+
+struct StateWithBoxedMutexGuard {
+    u: Mutex<u64>,
+}
+
+impl StateWithBoxedMutexGuard {
+    fn new() -> StateWithBoxedMutexGuard {
+        StateWithBoxedMutexGuard { u: Mutex::new(42) }
+    }
+    fn lock(&self) -> Box<MutexGuard<u64>> {
+        Box::new(self.u.lock().unwrap())
+    }
+}
+
+fn should_trigger_lint_for_boxed_mutex_guard() {
+    let s = StateWithBoxedMutexGuard::new();
+
+    // Should trigger lint because a temporary Box holding a type with a significant drop in a match
+    // scrutinee may have a potentially surprising lifetime.
+    match s.lock().deref().deref() {
+        0 | 1 => println!("Value was less than 2"),
+        _ => println!("Value is {}", s.lock().deref()),
+    };
+}
+
+struct StateStringWithBoxedMutexGuard {
+    s: Mutex<String>,
+}
+
+impl StateStringWithBoxedMutexGuard {
+    fn new() -> StateStringWithBoxedMutexGuard {
+        StateStringWithBoxedMutexGuard { s: Mutex::new("A String".to_owned()) }
+    }
+    fn lock(&self) -> Box<MutexGuard<String>> {
+        Box::new(self.s.lock().unwrap())
+    }
+}
+
+fn should_trigger_lint_for_boxed_mutex_guard_holding_string() {
+    let s = StateStringWithBoxedMutexGuard::new();
+
+    let matcher = String::from("A String");
+
+    // Should trigger lint because a temporary Box holding a type with a significant drop in a match
+    // scrutinee may have a potentially surprising lifetime.
+    match s.lock().deref().deref() {
+        matcher => println!("Value is {}", s.lock().deref()),
+        _ => println!("Value was not a match"),
+    };
+}
+
+
+struct StateWithIntField {
+    i: u64,
+}
+
+// Should trigger lint when either side of an assign expression contains a temporary with a
+// significant drop, because the temporary's lifetime will be extended to the end of the match.
+// To avoid potential unnecessary copies or creating references that would trigger the significant
+// drop problem, the lint recommends moving the entire binary operation.
+fn should_trigger_lint_in_assign_expr() {
+    let mutex = Mutex::new(StateWithIntField { i: 10 });
+
+    let mut i = 100;
+
+    match mutex.lock().unwrap().i = i {
+        _ => {
+            println!("{}", mutex.lock().unwrap().i);
+        }
+    };
+
+    match i = mutex.lock().unwrap().i {
+        _ => {
+            println!("{}", mutex.lock().unwrap().i);
+        }
+    };
+
+    match mutex.lock().unwrap().i += 1 {
+        _ => {
+            println!("{}", mutex.lock().unwrap().i);
+        }
+    };
+
+    match i += mutex.lock().unwrap().i {
+        _ => {
+            println!("{}", mutex.lock().unwrap().i);
+        }
+    };
+}
+
+#[derive(Debug)]
+enum RecursiveEnum {
+    Foo(Option<Box<RecursiveEnum>>)
+}
+
+#[derive(Debug)]
+enum GenericRecursiveEnum<T> {
+    Foo(T, Option<Box<GenericRecursiveEnum<T>>>)
+}
+
+fn should_not_cause_stack_overflow() {
+    // Test that when a type recursively contains itself, a stack overflow does not occur when
+    // checking sub-types for significant drops.
+    let f = RecursiveEnum::Foo(Some(Box::new(RecursiveEnum::Foo(None))));
+    match f {
+        RecursiveEnum::Foo(Some(f)) => {
+            println!("{:?}", f)
+        }
+        RecursiveEnum::Foo(f) => {
+            println!("{:?}", f)
+        }
+    }
+
+    let f = GenericRecursiveEnum::Foo(1u64, Some(Box::new(GenericRecursiveEnum::Foo(2u64, None))));
+    match f {
+        GenericRecursiveEnum::Foo(i, Some(f)) => {
+            println!("{} {:?}", i, f)
+        }
+        GenericRecursiveEnum::Foo(i, f) => {
+            println!("{} {:?}", i, f)
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
new file mode 100644 (file)
index 0000000..c442e93
--- /dev/null
@@ -0,0 +1,261 @@
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:57:11
+   |
+LL |     match mutex.lock().unwrap().foo() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::significant-drop-in-scrutinee` implied by `-D warnings`
+help: try moving the temporary above the match
+   |
+LL ~     let value = mutex.lock().unwrap().foo();
+LL ~     match value {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:130:11
+   |
+LL |     match s.lock_m().get_the_value() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     let value = s.lock_m().get_the_value();
+LL ~     match value {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:151:11
+   |
+LL |     match s.lock_m_m().get_the_value() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     let value = s.lock_m_m().get_the_value();
+LL ~     match value {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:199:11
+   |
+LL |     match counter.temp_increment().len() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     let value = counter.temp_increment().len();
+LL ~     match value {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:222:16
+   |
+LL |         match (mutex1.lock().unwrap().s.len(), true) {
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~         let value = mutex1.lock().unwrap().s.len();
+LL ~         match (value, true) {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:231:22
+   |
+LL |         match (true, mutex1.lock().unwrap().s.len(), true) {
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~         let value = mutex1.lock().unwrap().s.len();
+LL ~         match (true, value, true) {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:241:16
+   |
+LL |         match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~         let value = mutex1.lock().unwrap().s.len();
+LL ~         match (value, true, mutex2.lock().unwrap().s.len()) {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:241:54
+   |
+LL |         match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
+   |                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~         let value = mutex2.lock().unwrap().s.len();
+LL ~         match (mutex1.lock().unwrap().s.len(), true, value) {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:252:15
+   |
+LL |         match mutex3.lock().unwrap().s.as_str() {
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:263:22
+   |
+LL |         match (true, mutex3.lock().unwrap().s.as_str()) {
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:282:11
+   |
+LL |     match mutex.lock().unwrap().s.len() > 1 {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     let value = mutex.lock().unwrap().s.len() > 1;
+LL ~     match value {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:289:11
+   |
+LL |     match 1 < mutex.lock().unwrap().s.len() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     let value = 1 < mutex.lock().unwrap().s.len();
+LL ~     match value {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:305:11
+   |
+LL |     match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     let value = mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len();
+LL ~     match value {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:312:11
+   |
+LL |     match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     let value = mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len();
+LL ~     match value {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:343:11
+   |
+LL |     match get_mutex_guard().s.len() > 1 {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     let value = get_mutex_guard().s.len() > 1;
+LL ~     match value {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:360:11
+   |
+LL |     match match i { 100 => mutex1.lock().unwrap(), _ => mutex2.lock().unwrap() }.s.len() > 1 {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     let value = match i { 100 => mutex1.lock().unwrap(), _ => mutex2.lock().unwrap() }.s.len() > 1;
+LL ~     match value {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:379:11
+   |
+LL |     match if i > 1 { mutex1.lock().unwrap() } else { mutex2.lock().unwrap() }.s.len() > 1 {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     let value = if i > 1 { mutex1.lock().unwrap() } else { mutex2.lock().unwrap() }.s.len() > 1;
+LL ~     match value {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:421:11
+   |
+LL |     match s.lock().deref().deref() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match and create a copy
+   |
+LL ~     let value = *s.lock().deref().deref();
+LL ~     match value {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:447:11
+   |
+LL |     match s.lock().deref().deref() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:467:11
+   |
+LL |     match mutex.lock().unwrap().i = i {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     mutex.lock().unwrap().i = i;
+LL ~     match () {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:473:11
+   |
+LL |     match i = mutex.lock().unwrap().i {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     i = mutex.lock().unwrap().i;
+LL ~     match () {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:479:11
+   |
+LL |     match mutex.lock().unwrap().i += 1 {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     mutex.lock().unwrap().i += 1;
+LL ~     match () {
+   |
+
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:485:11
+   |
+LL |     match i += mutex.lock().unwrap().i {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try moving the temporary above the match
+   |
+LL ~     i += mutex.lock().unwrap().i;
+LL ~     match () {
+   |
+
+error: aborting due to 23 previous errors
+
index d0a4cfb88370e2060620137f7e015632a96ff3e7..6f8c8e47dfbf1fe56589a06f80017513e69167e8 100644 (file)
@@ -67,13 +67,5 @@ LL |         Self: Iterator<Item = Foo>,
    |
    = help: consider removing this trait bound
 
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:99:23
-   |
-LL | fn impl_trait(_: impl AsRef<str>, _: impl AsRef<str>) {}
-   |                       ^^^^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
 
index abc25e59496bfa13262c3a5b938ce282a7b25edb..148c19c7d0701dc2910de718d175a03122d26e03 100644 (file)
@@ -19,13 +19,5 @@ LL |     Self: Copy + Default + Ord,
    |
    = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord`
 
-error: this type has already been used as a bound predicate
-  --> $DIR/type_repetition_in_bounds.rs:83:43
-   |
-LL | fn impl_trait(_: impl AsRef<str>, _: impl AsRef<str>) {}
-   |                                           ^^^^^^^^^^
-   |
-   = help: consider combining the bounds: `impl AsRef<str>: AsRef<str> + AsRef<str>`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
index 6b715f727b2234a2c4295dbf71b1b362a5dd8740..5712e84adbc202475fdb25752c0095610f5448b6 100644 (file)
@@ -7,8 +7,8 @@
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 977;
-const ISSUES_ENTRY_LIMIT: usize = 2278;
+const ROOT_ENTRY_LIMIT: usize = 974;
+const ISSUES_ENTRY_LIMIT: usize = 2248;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     let dirs = walkdir::WalkDir::new(&path.join("test/ui"))