diff options
| author | The Miri Cronjob Bot <miri@cron.bot> | 2024-08-26 05:08:44 +0000 |
|---|---|---|
| committer | The Miri Cronjob Bot <miri@cron.bot> | 2024-08-26 05:08:44 +0000 |
| commit | 55fba66f0c5d88270f83273babf40043e5fe3503 (patch) | |
| tree | 32527d0b15cfce7b59d287269a1071c1df43bfda | |
| parent | e01bc0424cc0d6caa3b9108eaf103c733739976c (diff) | |
| parent | f48062e7d040579ac5705e1b36b34675000da5dd (diff) | |
| download | rust-55fba66f0c5d88270f83273babf40043e5fe3503.tar.gz rust-55fba66f0c5d88270f83273babf40043e5fe3503.zip | |
Merge from rustc
857 files changed, 10883 insertions, 6882 deletions
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 5e54ceea3d7..83b92b7fa09 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -64,6 +64,10 @@ jobs: - name: cargo update # Remove first line that always just says "Updating crates.io index" run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log + - name: cargo update library + run: | + echo -e "\nlibrary dependencies:" >> cargo_update.log + cargo update --manifest-path library/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log - name: cargo update rustbook run: | echo -e "\nrustbook dependencies:" >> cargo_update.log @@ -74,6 +78,7 @@ jobs: name: Cargo-lock path: | Cargo.lock + library/Cargo.lock src/tools/rustbook/Cargo.lock retention-days: 1 - name: upload cargo-update log artifact for use in PR @@ -119,7 +124,7 @@ jobs: git config user.name github-actions git config user.email github-actions@github.com git switch --force-create cargo_update - git add ./Cargo.lock ./src/tools/rustbook/Cargo.lock + git add ./Cargo.lock ./library/Cargo.lock ./src/tools/rustbook/Cargo.lock git commit --no-verify --file=commit.txt - name: push diff --git a/.gitignore b/.gitignore index a36cb51de33..2e6499081a6 100644 --- a/.gitignore +++ b/.gitignore @@ -56,7 +56,9 @@ build/ /src/tools/x/target # Created by default with `src/ci/docker/run.sh` /obj/ -/rustc-ice* + +## ICE reports +rustc-ice-*.txt ## Temporary files *~ diff --git a/Cargo.lock b/Cargo.lock index ac347d02af7..6ea4cd8f5ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,16 +96,6 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9b665789884a7e8fb06c84b295e923b03ca51edbb7d08f91a6a50322ecbfe6" -dependencies = [ - "anstyle", - "unicode-width", -] - -[[package]] -name = "annotate-snippets" version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991" @@ -205,9 +195,9 @@ dependencies = [ [[package]] name = "ar_archive_writer" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de11a9d32db3327f981143bdf699ade4d637c6887b13b97e6e91a9154666963c" +checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4" dependencies = [ "object 0.36.3", ] @@ -420,12 +410,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.1.13" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" -dependencies = [ - "shlex", -] +checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437" [[package]] name = "cfg-if" @@ -549,6 +536,7 @@ name = "clippy" version = "0.1.82" dependencies = [ "anstream", + "cargo_metadata 0.18.1", "clippy_config", "clippy_lints", "clippy_utils", @@ -562,6 +550,7 @@ dependencies = [ "regex", "rustc_tools_util", "serde", + "serde_json", "syn 2.0.75", "tempfile", "termize", @@ -576,7 +565,6 @@ name = "clippy_config" version = "0.1.82" dependencies = [ "itertools", - "rustc-semver", "serde", "toml 0.7.8", "walkdir", @@ -608,7 +596,6 @@ dependencies = [ "quine-mc_cluskey", "regex", "regex-syntax 0.8.4", - "rustc-semver", "semver", "serde", "serde_json", @@ -627,7 +614,6 @@ dependencies = [ "arrayvec", "clippy_config", "itertools", - "rustc-semver", "rustc_apfloat", ] @@ -2240,9 +2226,12 @@ dependencies = [ [[package]] name = "minifier" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95bbbf96b9ac3482c2a25450b67a15ed851319bc5fabf3b40742ea9066e84282" +checksum = "9aa3f302fe0f8de065d4a2d1ed64f60204623cac58b80cd3c2a83a25d5a7d437" +dependencies = [ + "clap", +] [[package]] name = "minimal-lexical" @@ -3139,6 +3128,7 @@ dependencies = [ "bstr", "build_helper", "gimli 0.31.0", + "libc", "object 0.36.3", "regex", "serde_json", @@ -3212,12 +3202,6 @@ dependencies = [ ] [[package]] -name = "rustc-semver" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be1bdc7edf596692617627bbfeaba522131b18e06ca4df2b6b689e3c5d5ce84" - -[[package]] name = "rustc-stable-hash" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3642,7 +3626,7 @@ dependencies = [ name = "rustc_errors" version = "0.0.0" dependencies = [ - "annotate-snippets 0.10.2", + "annotate-snippets 0.11.4", "derive_setters", "rustc_ast", "rustc_ast_pretty", @@ -3702,7 +3686,7 @@ dependencies = [ name = "rustc_fluent_macro" version = "0.0.0" dependencies = [ - "annotate-snippets 0.10.2", + "annotate-snippets 0.11.4", "fluent-bundle", "fluent-syntax", "proc-macro2", @@ -4552,6 +4536,7 @@ dependencies = [ "bitflags 2.6.0", "derive-where", "indexmap", + "rustc-hash", "rustc_ast_ir", "rustc_data_structures", "rustc_index", diff --git a/RELEASES.md b/RELEASES.md index 2c91ddf7826..5e4827be4ec 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -143,6 +143,8 @@ Compatibility Notes - [Turn `proc_macro_back_compat` lint into a hard error.](https://github.com/rust-lang/rust/pull/125596/) - [Detect unused structs even when implementing private traits](https://github.com/rust-lang/rust/pull/122382/) - [`std::sync::ReentrantLockGuard<T>` is no longer `Sync` if `T: !Sync`](https://github.com/rust-lang/rust/pull/125527) which means [`std::io::StdoutLock` and `std::io::StderrLock` are no longer Sync](https://github.com/rust-lang/rust/issues/127340) +- [Type inference will fail in some cases due to new implementations of `FromIterator for Box<str>`.](https://github.com/rust-lang/rust/pull/99969/) + Notably, this breaks versions of the `time` crate before 0.3.35, due to no longer inferring the implementation for `Box<[_]>`. <a id="1.80-Internal-Changes"></a> diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a44ed828504..85d38a0e28b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2902,6 +2902,17 @@ pub struct AttrItem { pub tokens: Option<LazyAttrTokenStream>, } +impl AttrItem { + pub fn is_valid_for_outer_style(&self) -> bool { + self.path == sym::cfg_attr + || self.path == sym::cfg + || self.path == sym::forbid + || self.path == sym::warn + || self.path == sym::allow + || self.path == sym::deny + } +} + /// `TraitRef`s appear in impls. /// /// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 7d9d689e6d7..e077c544965 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -86,9 +86,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Multiple different abi names may actually be the same ABI // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI let source_map = self.tcx.sess.source_map(); - let equivalent = (source_map.span_to_snippet(*prev_sp) - != source_map.span_to_snippet(*abi_span)) - .then_some(()); + let equivalent = source_map.span_to_snippet(*prev_sp) + != source_map.span_to_snippet(*abi_span); self.dcx().emit_err(AbiSpecifiedMultipleTimes { abi_span: *abi_span, @@ -221,7 +220,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let parent_def_id = self.current_def_id_parent; let node_id = self.next_node_id(); // HACK(min_generic_const_args): see lower_anon_const - if !expr.is_potential_trivial_const_arg() { + if !self.tcx.features().const_arg_path + || !expr.is_potential_trivial_const_arg() + { self.create_def( parent_def_id, node_id, diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 7a6c9d8d0d3..8237bfd6792 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -184,7 +184,7 @@ pub struct AbiSpecifiedMultipleTimes { #[label] pub prev_span: Span, #[note] - pub equivalent: Option<()>, + pub equivalent: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b5d8a547a8f..bb86e5c9325 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -387,7 +387,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let node_id = self.next_node_id(); // HACK(min_generic_const_args): see lower_anon_const - if !arg.is_potential_trivial_const_arg() { + if !self.tcx.features().const_arg_path || !arg.is_potential_trivial_const_arg() { // Add a definition for the in-band const def. self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f6065259d8d..eef87879c24 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1421,7 +1421,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }; hir::FnHeader { safety: self.lower_safety(h.safety, default_safety), - asyncness: asyncness, + asyncness, constness: self.lower_constness(h.constness), abi: self.lower_extern(h.ext), } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 81d17a9dec2..4b8c47ac4b4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2358,7 +2358,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, ) -> &'hir hir::ConstArg<'hir> { let ct_kind = match res { - Res::Def(DefKind::ConstParam, _) => { + Res::Def(DefKind::ConstParam, _) if self.tcx.features().const_arg_path => { let qpath = self.lower_qpath( ty_id, &None, @@ -2433,7 +2433,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); debug!("res={:?}", maybe_res); // FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path - if let Some(res) = maybe_res + if self.tcx.features().const_arg_path + && let Some(res) = maybe_res && let Res::Def(DefKind::ConstParam, _) = res && let ExprKind::Path(qself, path) = &expr.kind { @@ -2464,7 +2465,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// See [`hir::ConstArg`] for when to use this function vs /// [`Self::lower_anon_const_to_const_arg`]. fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst { - if c.value.is_potential_trivial_const_arg() { + if self.tcx.features().const_arg_path && c.value.is_potential_trivial_const_arg() { // HACK(min_generic_const_args): see DefCollector::visit_anon_const // Over there, we guess if this is a bare param and only create a def if // we think it's not. However we may can guess wrong (see there for example) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 837cb805700..a9b65456b8c 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -562,10 +562,8 @@ impl<'a> AstValidator<'a> { FnHeader { safety: _, coroutine_kind, constness, ext }: FnHeader, ) { let report_err = |span| { - self.dcx().emit_err(errors::FnQualifierInExtern { - span: span, - block: self.current_extern_span(), - }); + self.dcx() + .emit_err(errors::FnQualifierInExtern { span, block: self.current_extern_span() }); }; match coroutine_kind { Some(knd) => report_err(knd.span()), @@ -963,14 +961,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self_ty, items, }) => { - let error = - |annotation_span, annotation, only_trait: bool| errors::InherentImplCannot { - span: self_ty.span, - annotation_span, - annotation, - self_ty: self_ty.span, - only_trait: only_trait.then_some(()), - }; + let error = |annotation_span, annotation, only_trait| errors::InherentImplCannot { + span: self_ty.span, + annotation_span, + annotation, + self_ty: self_ty.span, + only_trait, + }; self.with_in_trait_impl(None, |this| { this.visibility_not_permitted( @@ -1195,7 +1192,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } else if where_clauses.after.has_where_token { self.dcx().emit_err(errors::WhereClauseAfterTypeAlias { span: where_clauses.after.span, - help: self.session.is_nightly_build().then_some(()), + help: self.session.is_nightly_build(), }); } } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 9e403680837..de1b3f55e80 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -484,7 +484,7 @@ pub struct InherentImplCannot<'a> { #[label(ast_passes_type)] pub self_ty: Span, #[note(ast_passes_only_trait)] - pub only_trait: Option<()>, + pub only_trait: bool, } #[derive(Diagnostic)] @@ -528,7 +528,7 @@ pub struct WhereClauseAfterTypeAlias { #[primary_span] pub span: Span, #[help] - pub help: Option<()>, + pub help: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5ab99fbac86..45e397a58c0 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -556,7 +556,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); gate_all!(postfix_match, "postfix match is experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental"); - gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental"); gate_all!(global_registration, "global registration is experimental"); gate_all!(return_type_notation, "return type notation is experimental"); diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index d057dcfdf9d..e46dabc7a6e 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -846,7 +846,7 @@ pub fn find_deprecation( sess.dcx().emit_err( session_diagnostics::DeprecatedItemSuggestion { span: mi.span, - is_nightly: sess.is_nightly_build().then_some(()), + is_nightly: sess.is_nightly_build(), details: (), }, ); diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 92a3a385a74..9b69325a053 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -342,7 +342,7 @@ pub(crate) struct DeprecatedItemSuggestion { pub span: Span, #[help] - pub is_nightly: Option<()>, + pub is_nightly: bool, #[note] pub details: (), diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 76e39fe94af..70f89e80dc9 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -290,7 +290,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { ty: Ty<'_>, is_index: Option<bool>, ) -> Diag<'infcx> { - let type_name = match (&ty.kind(), is_index) { + let type_name = match (ty.kind(), is_index) { (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", (&ty::Slice(_), _) => "slice", _ => span_bug!(move_from_span, "this path should not cause illegal move"), diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 42d0c2038f8..311f17f15b9 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -201,7 +201,7 @@ fn place_components_conflict<'tcx>( let base_ty = base.ty(body, tcx).ty; - match (elem, &base_ty.kind(), access) { + match (elem, base_ty.kind(), access) { (_, _, Shallow(Some(ArtificialField::ArrayLength))) | (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => { // The array length is like additional fields on the diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 6983cda6ddf..3b3898ccd4d 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2043,9 +2043,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig); - if let Err(terr) = self.eq_types( - *ty, + if let Err(terr) = self.sub_types( ty_fn_ptr_from, + *ty, location.to_locations(), ConstraintCategory::Cast { unsize_to: None }, ) { diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 8fb31082793..b4f3784a31a 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -149,7 +149,7 @@ fn create_wrapper_function( } llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden); - let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr().cast()); + let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr()); let llbuilder = llvm::LLVMCreateBuilderInContext(llcx); llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb); diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index f68155f523a..aac446f3149 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -616,7 +616,7 @@ pub(crate) fn run_pass_manager( llvm::LLVMRustAddModuleFlagU32( module.module_llvm.llmod(), llvm::LLVMModFlagBehavior::Error, - c"LTOPostLink".as_ptr().cast(), + c"LTOPostLink".as_ptr(), 1, ); } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index a1f2433ab6f..51b02891d02 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1031,7 +1031,7 @@ unsafe fn embed_bitcode( let llglobal = llvm::LLVMAddGlobal( llmod, common::val_ty(llconst), - c"rustc.embedded.module".as_ptr().cast(), + c"rustc.embedded.module".as_ptr(), ); llvm::LLVMSetInitializer(llglobal, llconst); @@ -1044,7 +1044,7 @@ unsafe fn embed_bitcode( let llglobal = llvm::LLVMAddGlobal( llmod, common::val_ty(llconst), - c"rustc.embedded.cmdline".as_ptr().cast(), + c"rustc.embedded.cmdline".as_ptr(), ); llvm::LLVMSetInitializer(llglobal, llconst); let section = if is_apple { @@ -1054,7 +1054,7 @@ unsafe fn embed_bitcode( } else { c".llvmcmd" }; - llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); + llvm::LLVMSetSection(llglobal, section.as_ptr()); llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); } else { // We need custom section flags, so emit module-level inline assembly. @@ -1107,7 +1107,7 @@ fn create_msvc_imps( .collect::<Vec<_>>(); for (imp_name, val) in globals { - let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr().cast()); + let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr()); llvm::LLVMSetInitializer(imp, val); llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage); } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 75b298f14ca..a764b263ec7 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -525,7 +525,7 @@ impl<'ll> CodegenCx<'ll, '_> { let val = llvm::LLVMMetadataAsValue(self.llcx, meta); llvm::LLVMAddNamedMetadataOperand( self.llmod, - c"wasm.custom_sections".as_ptr().cast(), + c"wasm.custom_sections".as_ptr(), val, ); } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 1fd9f9e8116..fe71b2e669e 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -11,6 +11,7 @@ use rustc_data_structures::base_n::{ToBaseN, ALPHANUMERIC_ONLY}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::DefId; +use rustc_middle::middle::codegen_fn_attrs::PatchableFunctionEntry; use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers, @@ -207,7 +208,7 @@ pub unsafe fn create_module<'ll>( // If skipping the PLT is enabled, we need to add some module metadata // to ensure intrinsic calls don't use it. if !sess.needs_plt() { - let avoid_plt = c"RtLibUseGOT".as_ptr().cast(); + let avoid_plt = c"RtLibUseGOT".as_ptr(); unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); } @@ -215,7 +216,7 @@ pub unsafe fn create_module<'ll>( // Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.) if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() { - let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast(); + let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr(); unsafe { llvm::LLVMRustAddModuleFlagU32( llmod, @@ -226,9 +227,23 @@ pub unsafe fn create_module<'ll>( } } + // If we're normalizing integers with CFI, ensure LLVM generated functions do the same. + // See https://github.com/llvm/llvm-project/pull/104826 + if sess.is_sanitizer_cfi_normalize_integers_enabled() { + let cfi_normalize_integers = c"cfi-normalize-integers".as_ptr().cast(); + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Override, + cfi_normalize_integers, + 1, + ); + } + } + // Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.) if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() { - let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast(); + let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr(); unsafe { llvm::LLVMRustAddModuleFlagU32( llmod, @@ -241,10 +256,26 @@ pub unsafe fn create_module<'ll>( // Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.) if sess.is_sanitizer_kcfi_enabled() { - let kcfi = c"kcfi".as_ptr().cast(); + let kcfi = c"kcfi".as_ptr(); unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); } + + // Add "kcfi-offset" module flag with -Z patchable-function-entry (See + // https://reviews.llvm.org/D141172). + let pfe = + PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry); + if pfe.prefix() > 0 { + let kcfi_offset = c"kcfi-offset".as_ptr().cast(); + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Override, + kcfi_offset, + pfe.prefix().into(), + ); + } + } } // Control Flow Guard is currently only supported by the MSVC linker on Windows. @@ -280,26 +311,26 @@ pub unsafe fn create_module<'ll>( llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Min, - c"branch-target-enforcement".as_ptr().cast(), + c"branch-target-enforcement".as_ptr(), bti.into(), ); llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Min, - c"sign-return-address".as_ptr().cast(), + c"sign-return-address".as_ptr(), pac_ret.is_some().into(), ); let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Min, - c"sign-return-address-all".as_ptr().cast(), + c"sign-return-address-all".as_ptr(), pac_opts.leaf.into(), ); llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Min, - c"sign-return-address-with-bkey".as_ptr().cast(), + c"sign-return-address-with-bkey".as_ptr(), u32::from(pac_opts.key == PAuthKey::B), ); } @@ -317,7 +348,7 @@ pub unsafe fn create_module<'ll>( llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Override, - c"cf-protection-branch".as_ptr().cast(), + c"cf-protection-branch".as_ptr(), 1, ); } @@ -327,7 +358,7 @@ pub unsafe fn create_module<'ll>( llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Override, - c"cf-protection-return".as_ptr().cast(), + c"cf-protection-return".as_ptr(), 1, ); } @@ -338,7 +369,7 @@ pub unsafe fn create_module<'ll>( llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Error, - c"Virtual Function Elim".as_ptr().cast(), + c"Virtual Function Elim".as_ptr(), 1, ); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 5a08f2f00e5..e91bcea16a2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -34,8 +34,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, ' let c_section_var_name = c"__rustc_debug_gdb_scripts_section__"; let section_var_name = c_section_var_name.to_str().unwrap(); - let section_var = - unsafe { llvm::LLVMGetNamedGlobal(cx.llmod, c_section_var_name.as_ptr().cast()) }; + let section_var = unsafe { llvm::LLVMGetNamedGlobal(cx.llmod, c_section_var_name.as_ptr()) }; section_var.unwrap_or_else(|| { let mut section_contents = Vec::new(); @@ -70,7 +69,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, ' let section_var = cx .define_global(section_var_name, llvm_type) .unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name)); - llvm::LLVMSetSection(section_var, c".debug_gdb_scripts".as_ptr().cast()); + llvm::LLVMSetSection(section_var, c".debug_gdb_scripts".as_ptr()); llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 87bea22d8dd..30f90bada9a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -952,7 +952,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( producer.as_ptr().cast(), producer.len(), tcx.sess.opts.optimize != config::OptLevel::No, - c"".as_ptr().cast(), + c"".as_ptr(), 0, // NB: this doesn't actually have any perceptible effect, it seems. LLVM will instead // put the path supplied to `MCSplitDwarfFile` into the debug info of the final diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index b23e05182ca..eb446d2d7b2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -109,7 +109,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { llvm::LLVMRustAddModuleFlagU32( self.llmod, llvm::LLVMModFlagBehavior::Warning, - c"Dwarf Version".as_ptr().cast(), + c"Dwarf Version".as_ptr(), dwarf_version, ); } else { @@ -117,7 +117,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { llvm::LLVMRustAddModuleFlagU32( self.llmod, llvm::LLVMModFlagBehavior::Warning, - c"CodeView".as_ptr().cast(), + c"CodeView".as_ptr(), 1, ) } @@ -126,7 +126,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { llvm::LLVMRustAddModuleFlagU32( self.llmod, llvm::LLVMModFlagBehavior::Warning, - c"Debug Info Version".as_ptr().cast(), + c"Debug Info Version".as_ptr(), llvm::LLVMRustDebugMetadataVersion(), ); } @@ -570,7 +570,17 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { inlined_at: Option<&'ll DILocation>, span: Span, ) -> &'ll DILocation { - let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo()); + // When emitting debugging information, DWARF (i.e. everything but MSVC) + // treats line 0 as a magic value meaning that the code could not be + // attributed to any line in the source. That's also exactly what dummy + // spans are. Make that equivalence here, rather than passing dummy spans + // to lookup_debug_loc, which will return line 1 for them. + let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc { + (0, 0) + } else { + let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo()); + (line, col) + }; unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation(line, col, scope, inlined_at) } } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index e3033b332ca..e78039bafd8 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -5,10 +5,10 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -ar_archive_writer = "0.4.0" +ar_archive_writer = "0.4.2" arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" -cc = "1.0.90" +cc = "=1.0.105" # FIXME(cc): pinned to keep support for VS2013 either = "1.5.0" itertools = "0.12" jobserver = "0.1.28" diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 38a440a707a..76a94de5433 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -108,7 +108,11 @@ pub trait ArchiveBuilderBuilder { &exports, machine, !sess.target.is_like_msvc, - /*comdat=*/ false, + // Enable compatibility with MSVC's `/WHOLEARCHIVE` flag. + // Without this flag a duplicate symbol error would be emitted + // when linking a rust staticlib using `/WHOLEARCHIVE`. + // See #129020 + true, ) { sess.dcx() .emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }); @@ -121,7 +125,7 @@ pub trait ArchiveBuilderBuilder { rlib: &'a Path, outdir: &Path, bundled_lib_file_names: &FxIndexSet<Symbol>, - ) -> Result<(), ExtractBundledLibsError<'_>> { + ) -> Result<(), ExtractBundledLibsError<'a>> { let archive_map = unsafe { Mmap::map( File::open(rlib) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index febeb7093a3..fbab988a32b 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1500,7 +1500,7 @@ impl<'a> Linker for L4Bender<'a> { impl<'a> L4Bender<'a> { pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> { - L4Bender { cmd, sess: sess, hinted_static: false } + L4Bender { cmd, sess, hinted_static: false } } fn hint_static(&mut self) { @@ -1520,7 +1520,7 @@ pub struct AixLinker<'a> { impl<'a> AixLinker<'a> { pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> { - AixLinker { cmd, sess: sess, hinted_static: None } + AixLinker { cmd, sess, hinted_static: None } } fn hint_static(&mut self) { diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 1442f1832b9..d7d64180ec9 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -419,7 +419,7 @@ const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn const_eval_unstable_in_stable = const-stable function cannot use `#[feature({$gate})]` .unstable_sugg = if it is not part of the public API, make this function unstably const - .bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks + .bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval) const_eval_unterminated_c_string = reading a null-terminated string starting at {$pointer} with no null found before end of allocation diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 86a5afa65ba..c80b3e673b0 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -575,10 +575,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(self.body, self.tcx); - if is_int_bool_or_char(ty) { - // Int, bool, and char operations are fine. - } else if ty.is_floating_point() { - self.check_op(ops::FloatingPointOp); + if is_int_bool_float_or_char(ty) { + // Int, bool, float, and char operations are fine. } else { span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty); } @@ -588,8 +586,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { let lhs_ty = lhs.ty(self.body, self.tcx); let rhs_ty = rhs.ty(self.body, self.tcx); - if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) { - // Int, bool, and char operations are fine. + if is_int_bool_float_or_char(lhs_ty) && is_int_bool_float_or_char(rhs_ty) { + // Int, bool, float, and char operations are fine. } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() { assert_matches!( op, @@ -603,8 +601,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { ); self.check_op(ops::RawPtrComparison); - } else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() { - self.check_op(ops::FloatingPointOp); } else { span_bug!( self.span, @@ -1009,8 +1005,8 @@ fn place_as_reborrow<'tcx>( } } -fn is_int_bool_or_char(ty: Ty<'_>) -> bool { - ty.is_bool() || ty.is_integral() || ty.is_char() +fn is_int_bool_float_or_char(ty: Ty<'_>) -> bool { + ty.is_bool() || ty.is_integral() || ty.is_char() || ty.is_floating_point() } fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) { diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index c6361710ac9..93fafa60557 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -55,28 +55,6 @@ pub trait NonConstOp<'tcx>: std::fmt::Debug { fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx>; } -#[derive(Debug)] -pub struct FloatingPointOp; -impl<'tcx> NonConstOp<'tcx> for FloatingPointOp { - fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { - if ccx.const_kind() == hir::ConstContext::ConstFn { - Status::Unstable(sym::const_fn_floating_point_arithmetic) - } else { - Status::Allowed - } - } - - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - feature_err( - &ccx.tcx.sess, - sym::const_fn_floating_point_arithmetic, - span, - format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()), - ) - } -} - /// A function call where the callee is a pointer. #[derive(Debug)] pub struct FnCallIndirect; @@ -384,7 +362,7 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation { ccx.dcx().create_err(errors::UnallowedHeapAllocations { span, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0010).then_some(()), + teach: ccx.tcx.sess.teach(E0010), }) } } @@ -440,22 +418,12 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow { DiagImportance::Secondary } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - // FIXME: Maybe a more elegant solution to this if else case - if let hir::ConstContext::Static(_) = ccx.const_kind() { - ccx.dcx().create_err(errors::InteriorMutableDataRefer { - span, - opt_help: Some(()), - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0492).then_some(()), - }) - } else { - ccx.dcx().create_err(errors::InteriorMutableDataRefer { - span, - opt_help: None, - kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0492).then_some(()), - }) - } + ccx.dcx().create_err(errors::InteriorMutableDataRefer { + span, + opt_help: matches!(ccx.const_kind(), hir::ConstContext::Static(_)), + kind: ccx.const_kind(), + teach: ccx.tcx.sess.teach(E0492), + }) } } @@ -481,12 +449,12 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow { hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::UnallowedMutableRaw { span, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0764).then_some(()), + teach: ccx.tcx.sess.teach(E0764), }), hir::BorrowKind::Ref => ccx.dcx().create_err(errors::UnallowedMutableRefs { span, kind: ccx.const_kind(), - teach: ccx.tcx.sess.teach(E0764).then_some(()), + teach: ccx.tcx.sess.teach(E0764), }), } } diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 00bbd9337f7..25b32785b7d 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -22,6 +22,7 @@ pub enum ConstEvalErrKind { RecursiveStatic, AssertFailure(AssertKind<ConstInt>), Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, + WriteThroughImmutablePointer, } impl MachineStopType for ConstEvalErrKind { @@ -35,12 +36,16 @@ impl MachineStopType for ConstEvalErrKind { Panic { .. } => const_eval_panic, RecursiveStatic => const_eval_recursive_static, AssertFailure(x) => x.diagnostic_message(), + WriteThroughImmutablePointer => const_eval_write_through_immutable_pointer, } } fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) { use ConstEvalErrKind::*; match *self { - RecursiveStatic | ConstAccessesMutGlobal | ModifiedGlobal => {} + RecursiveStatic + | ConstAccessesMutGlobal + | ModifiedGlobal + | WriteThroughImmutablePointer => {} AssertFailure(kind) => kind.add_args(adder), Panic { msg, line, col, file } => { adder("msg".into(), msg.into_diag_arg()); @@ -159,6 +164,7 @@ where /// Emit a lint from a const-eval situation, with a backtrace. // Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future! +#[allow(unused)] pub(super) fn lint<'tcx, L>( tcx: TyCtxtAt<'tcx>, machine: &CompileTimeMachine<'tcx>, diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index a075bdc1911..9c1fef095f5 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -12,7 +12,6 @@ use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{bug, mir}; -use rustc_session::lint::builtin::WRITES_THROUGH_IMMUTABLE_POINTER; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use rustc_target::abi::{Align, Size}; @@ -40,7 +39,10 @@ const TINY_LINT_TERMINATOR_LIMIT: usize = 20; /// power of two of interpreted terminators. const PROGRESS_INDICATOR_START: usize = 4_000_000; -/// Extra machine state for CTFE, and the Machine instance +/// Extra machine state for CTFE, and the Machine instance. +// +// Should be public because out-of-tree rustc consumers need this +// if they want to interact with constant values. pub struct CompileTimeMachine<'tcx> { /// The number of terminators that have been evaluated. /// @@ -160,7 +162,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> { } } -pub(crate) type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>; +pub type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum MemoryKind { @@ -729,8 +731,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } fn before_memory_write( - tcx: TyCtxtAt<'tcx>, - machine: &mut Self, + _tcx: TyCtxtAt<'tcx>, + _machine: &mut Self, _alloc_extra: &mut Self::AllocExtra, (_alloc_id, immutable): (AllocId, bool), range: AllocRange, @@ -741,9 +743,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } // Reject writes through immutable pointers. if immutable { - super::lint(tcx, machine, WRITES_THROUGH_IMMUTABLE_POINTER, |frames| { - crate::errors::WriteThroughImmutablePointer { frames } - }); + return Err(ConstEvalErrKind::WriteThroughImmutablePointer.into()); } // Everything else is fine. Ok(()) diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 7afb92c08ec..0b366b43f95 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -151,7 +151,7 @@ pub(crate) struct UnallowedMutableRefs { pub span: Span, pub kind: ConstContext, #[note(const_eval_teach_note)] - pub teach: Option<()>, + pub teach: bool, } #[derive(Diagnostic)] @@ -161,7 +161,7 @@ pub(crate) struct UnallowedMutableRaw { pub span: Span, pub kind: ConstContext, #[note(const_eval_teach_note)] - pub teach: Option<()>, + pub teach: bool, } #[derive(Diagnostic)] #[diag(const_eval_non_const_fmt_macro_call, code = E0015)] @@ -196,7 +196,7 @@ pub(crate) struct UnallowedHeapAllocations { pub span: Span, pub kind: ConstContext, #[note(const_eval_teach_note)] - pub teach: Option<()>, + pub teach: bool, } #[derive(Diagnostic)] @@ -214,10 +214,10 @@ pub(crate) struct InteriorMutableDataRefer { #[label] pub span: Span, #[help] - pub opt_help: Option<()>, + pub opt_help: bool, pub kind: ConstContext, #[note(const_eval_teach_note)] - pub teach: Option<()>, + pub teach: bool, } #[derive(Diagnostic)] @@ -407,13 +407,6 @@ pub struct ConstEvalError { pub frame_notes: Vec<FrameNote>, } -#[derive(LintDiagnostic)] -#[diag(const_eval_write_through_immutable_pointer)] -pub struct WriteThroughImmutablePointer { - #[subdiagnostic] - pub frames: Vec<FrameNote>, -} - #[derive(Diagnostic)] #[diag(const_eval_nullary_intrinsic_fail)] pub struct NullaryIntrinsicError { diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 4901e4b2a41..e8c9f145eea 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -388,7 +388,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.param_env); - match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) { + match (src_pointee_ty.kind(), dest_pointee_ty.kind()) { (&ty::Array(_, length), &ty::Slice(_)) => { let ptr = self.read_pointer(src)?; let val = Immediate::new_slice( @@ -478,9 +478,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty); - match (&src.layout.ty.kind(), &cast_ty.ty.kind()) { + match (src.layout.ty.kind(), cast_ty.ty.kind()) { (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _)) - | (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, *s, *c), + | (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, s, c), (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { assert_eq!(def_a, def_b); // implies same number of fields diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index ad87d6953d3..9a8ccaa7cc5 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -319,6 +319,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { // some fieldless enum variants can have non-zero size but still `Aggregate` ABI... try // to detect those here and also give them no data _ if matches!(layout.abi, Abi::Aggregate { .. }) + && matches!(layout.variants, abi::Variants::Single { .. }) && matches!(&layout.fields, abi::FieldsShape::Arbitrary { offsets, .. } if offsets.len() == 0) => { Immediate::Uninit @@ -328,8 +329,9 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { assert_eq!(offset.bytes(), 0); assert!( match (self.layout.abi, layout.abi) { - (Abi::Scalar(..), Abi::Scalar(..)) => true, - (Abi::ScalarPair(..), Abi::ScalarPair(..)) => true, + (Abi::Scalar(l), Abi::Scalar(r)) => l.size(cx) == r.size(cx), + (Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) => + l1.size(cx) == r1.size(cx) && l2.size(cx) == r2.size(cx), _ => false, }, "cannot project into {} immediate with equally-sized field {}\nouter ABI: {:#?}\nfield ABI: {:#?}", @@ -344,16 +346,23 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { assert_matches!(layout.abi, Abi::Scalar(..)); Immediate::from(if offset.bytes() == 0 { - debug_assert_eq!(layout.size, a.size(cx)); + // It is "okay" to transmute from `usize` to a pointer (GVN relies on that). + // So only compare the size. + assert_eq!(layout.size, a.size(cx)); a_val } else { - debug_assert_eq!(offset, a.size(cx).align_to(b.align(cx).abi)); - debug_assert_eq!(layout.size, b.size(cx)); + assert_eq!(offset, a.size(cx).align_to(b.align(cx).abi)); + assert_eq!(layout.size, b.size(cx)); b_val }) } // everything else is a bug - _ => bug!("invalid field access on immediate {}, layout {:#?}", self, self.layout), + _ => bug!( + "invalid field access on immediate {} at offset {}, original layout {:#?}", + self, + offset.bytes(), + self.layout + ), }; ImmTy::from_immediate(inner_val, layout) diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 2fff9f2de50..59cf4e5f210 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -annotate-snippets = "0.10" +annotate-snippets = "0.11" derive_setters = "0.1.6" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index df4e9792f95..d71ae9d210d 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -5,7 +5,7 @@ //! //! [annotate_snippets]: https://docs.rs/crate/annotate-snippets/ -use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation}; +use annotate_snippets::{Renderer, Snippet}; use rustc_data_structures::sync::Lrc; use rustc_error_messages::FluentArgs; use rustc_span::source_map::SourceMap; @@ -83,15 +83,17 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String { file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or_default() } -/// Maps `diagnostic::Level` to `snippet::AnnotationType` -fn annotation_type_for_level(level: Level) -> AnnotationType { +/// Maps [`crate::Level`] to [`annotate_snippets::Level`] +fn annotation_level_for_level(level: Level) -> annotate_snippets::Level { match level { - Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => AnnotationType::Error, - Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning, - Level::Note | Level::OnceNote => AnnotationType::Note, - Level::Help | Level::OnceHelp => AnnotationType::Help, + Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => { + annotate_snippets::Level::Error + } + Level::ForceWarning(_) | Level::Warning => annotate_snippets::Level::Warning, + Level::Note | Level::OnceNote => annotate_snippets::Level::Note, + Level::Help | Level::OnceHelp => annotate_snippets::Level::Help, // FIXME(#59346): Not sure how to map this level - Level::FailureNote => AnnotationType::Error, + Level::FailureNote => annotate_snippets::Level::Error, Level::Allow => panic!("Should not call with Allow"), Level::Expect(_) => panic!("Should not call with Expect"), } @@ -180,42 +182,29 @@ impl AnnotateSnippetEmitter { }) .collect(); let code = code.map(|code| code.to_string()); - let snippet = Snippet { - title: Some(Annotation { - label: Some(&message), - id: code.as_deref(), - annotation_type: annotation_type_for_level(*level), - }), - footer: vec![], - slices: annotated_files - .iter() - .map(|(file_name, source, line_index, annotations)| { - Slice { - source, - line_start: *line_index, - origin: Some(file_name), - // FIXME(#59346): Not really sure when `fold` should be true or false - fold: false, - annotations: annotations - .iter() - .map(|annotation| SourceAnnotation { - range: ( - annotation.start_col.display, - annotation.end_col.display, - ), - label: annotation.label.as_deref().unwrap_or_default(), - annotation_type: annotation_type_for_level(*level), - }) - .collect(), - } - }) - .collect(), - }; + + let snippets = + annotated_files.iter().map(|(file_name, source, line_index, annotations)| { + Snippet::source(source) + .line_start(*line_index) + .origin(file_name) + // FIXME(#59346): Not really sure when `fold` should be true or false + .fold(false) + .annotations(annotations.iter().map(|annotation| { + annotation_level_for_level(*level) + .span(annotation.start_col.display..annotation.end_col.display) + .label(annotation.label.as_deref().unwrap_or_default()) + })) + }); + let mut message = annotation_level_for_level(*level).title(&message).snippets(snippets); + if let Some(code) = code.as_deref() { + message = message.id(code) + } // FIXME(#59346): Figure out if we can _always_ print to stderr or not. // `emitter.rs` has the `Destination` enum that lists various possible output // destinations. let renderer = Renderer::plain().anonymized_line_numbers(self.ui_testing); - eprintln!("{}", renderer.render(snippet)) + eprintln!("{}", renderer.render(message)) } // FIXME(#59346): Is it ok to return None if there's no source_map? } diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs index c44f136120a..46f8959b6f2 100644 --- a/compiler/rustc_errors/src/markdown/parse.rs +++ b/compiler/rustc_errors/src/markdown/parse.rs @@ -80,7 +80,7 @@ pub fn entrypoint(txt: &str) -> MdStream<'_> { } /// Parse a buffer with specified context -fn parse_recursive<'a>(buf: &'a [u8], ctx: Context) -> MdStream<'_> { +fn parse_recursive<'a>(buf: &'a [u8], ctx: Context) -> MdStream<'a> { use ParseOpt as Po; use Prev::{Escape, Newline, Whitespace}; diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index a44e794ee12..e0b64b276eb 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -59,7 +59,7 @@ pub trait Translate { &'a self, message: &'a DiagMessage, args: &'a FluentArgs<'_>, - ) -> Result<Cow<'_, str>, TranslateError<'_>> { + ) -> Result<Cow<'a, str>, TranslateError<'a>> { trace!(?message, ?args); let (identifier, attr) = match message { DiagMessage::Str(msg) | DiagMessage::Translated(msg) => { diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index c30a9b0c357..f6b5cd394b6 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -281,7 +281,7 @@ pub(crate) struct IncompleteParse<'a> { pub macro_path: &'a ast::Path, pub kind_name: &'a str, #[note(expand_macro_expands_to_match_arm)] - pub expands_to_match_arm: Option<()>, + pub expands_to_match_arm: bool, #[suggestion( expand_suggestion_add_semi, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index cb6b13282a2..0d56a005f15 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1031,7 +1031,7 @@ pub(crate) fn ensure_complete_parse<'a>( label_span: span, macro_path, kind_name, - expands_to_match_arm: expands_to_match_arm.then_some(()), + expands_to_match_arm, add_semicolon, }); } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 7838abca9b8..9223c3c322a 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -115,6 +115,8 @@ declare_features! ( (accepted, conservative_impl_trait, "1.26.0", Some(34511)), /// Allows calling constructor functions in `const fn`. (accepted, const_constructor, "1.40.0", Some(61456)), + /// Allows basic arithmetic on floating point types in a `const fn`. + (accepted, const_fn_floating_point_arithmetic, "CURRENT_RUSTC_VERSION", Some(57241)), /// Allows using and casting function pointers in a `const fn`. (accepted, const_fn_fn_ptr_basics, "1.61.0", Some(57563)), /// Allows trait bounds in `const fn`. @@ -309,6 +311,8 @@ declare_features! ( (accepted, param_attrs, "1.39.0", Some(60406)), /// Allows parentheses in patterns. (accepted, pattern_parentheses, "1.31.0", Some(51087)), + /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. + (accepted, precise_capturing, "CURRENT_RUSTC_VERSION", Some(123432)), /// Allows procedural macros in `proc-macro` crates. (accepted, proc_macro, "1.29.0", Some(38356)), /// Allows multi-segment paths in attributes and derives. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index d4c54b67f24..2747a14d60a 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -641,6 +641,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ErrorFollowing, EncodeCrossCrate::Yes, "rustc_deprecated_safe_2024 is supposed to be used in libstd only", ), + rustc_attr!( + rustc_pub_transparent, Normal, template!(Word), + WarnFollowing, EncodeCrossCrate::Yes, + "used internally to mark types with a `transparent` representation when it is guaranteed by the documentation", + ), // ========================================================================== diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 14e353f13ca..4524458023d 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -193,6 +193,8 @@ declare_features! ( (unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None), /// Allows identifying the `compiler_builtins` crate. (internal, compiler_builtins, "1.13.0", None), + /// Gating for a new desugaring of const arguments of usages of const parameters + (internal, const_arg_path, "1.81.0", None), /// Allows writing custom MIR (internal, custom_mir, "1.65.0", None), /// Outputs useful `assert!` messages @@ -400,8 +402,6 @@ declare_features! ( (incomplete, const_closures, "1.68.0", Some(106003)), /// Allows the definition of `const extern fn` and `const unsafe extern fn`. (unstable, const_extern_fn, "1.40.0", Some(64926)), - /// Allows basic arithmetic on floating point types in a `const fn`. - (unstable, const_fn_floating_point_arithmetic, "1.48.0", Some(57241)), /// Allows `for _ in _` loops in const contexts. (unstable, const_for, "1.56.0", Some(87575)), /// Allows using `&mut` in constant functions. @@ -561,8 +561,6 @@ declare_features! ( (unstable, patchable_function_entry, "1.81.0", Some(123115)), /// Allows postfix match `expr.match { ... }` (unstable, postfix_match, "1.79.0", Some(121618)), - /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. - (unstable, precise_capturing, "1.79.0", Some(123432)), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. diff --git a/compiler/rustc_fluent_macro/Cargo.toml b/compiler/rustc_fluent_macro/Cargo.toml index c5a53ae8313..eeceaa4691a 100644 --- a/compiler/rustc_fluent_macro/Cargo.toml +++ b/compiler/rustc_fluent_macro/Cargo.toml @@ -8,7 +8,7 @@ proc-macro = true [dependencies] # tidy-alphabetical-start -annotate-snippets = "0.10" +annotate-snippets = "0.11" fluent-bundle = "0.15.2" fluent-syntax = "0.11" proc-macro2 = "1" diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs index 23795a96b92..ca8bace28f3 100644 --- a/compiler/rustc_fluent_macro/src/fluent.rs +++ b/compiler/rustc_fluent_macro/src/fluent.rs @@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet}; use std::fs::read_to_string; use std::path::{Path, PathBuf}; -use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation}; +use annotate_snippets::{Renderer, Snippet}; use fluent_bundle::{FluentBundle, FluentError, FluentResource}; use fluent_syntax::ast::{ Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern, PatternElement, @@ -154,27 +154,15 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok .unwrap() .0; - let snippet = Snippet { - title: Some(Annotation { - label: Some(&err), - id: None, - annotation_type: AnnotationType::Error, - }), - footer: vec![], - slices: vec![Slice { - source: this.source(), - line_start, - origin: Some(&relative_ftl_path), - fold: true, - annotations: vec![SourceAnnotation { - label: "", - annotation_type: AnnotationType::Error, - range: (pos.start, pos.end - 1), - }], - }], - }; + let message = annotate_snippets::Level::Error.title(&err).snippet( + Snippet::source(this.source()) + .line_start(line_start) + .origin(&relative_ftl_path) + .fold(true) + .annotation(annotate_snippets::Level::Error.span(pos.start..pos.end - 1)), + ); let renderer = Renderer::plain(); - eprintln!("{}\n", renderer.render(snippet)); + eprintln!("{}\n", renderer.render(message)); } return failed(&crate_name); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6c7125b75db..57c47d29857 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2773,7 +2773,6 @@ impl PreciseCapturingArg<'_> { /// resolution to. Lifetimes don't have this problem, and for them, it's actually /// kind of detrimental to use a custom node type versus just using [`Lifetime`], /// since resolve_bound_vars operates on `Lifetime`s. -// FIXME(precise_capturing): Investigate storing this as a path instead? #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct PreciseCapturingNonLifetimeArg { pub hir_id: HirId, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 0135cdf1e90..728c3790098 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -529,7 +529,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe match tcx.named_bound_var(hir_id) { Some(ResolvedArg::EarlyBound(def_id)) => { - expected_captures.insert(def_id); + expected_captures.insert(def_id.to_def_id()); // Make sure we allow capturing these lifetimes through `Self` and // `T::Assoc` projection syntax, too. These will occur when we only @@ -538,7 +538,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe // feature -- see <https://github.com/rust-lang/rust/pull/115659>. if let DefKind::LifetimeParam = tcx.def_kind(def_id) && let Some(def_id) = tcx - .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local()) + .map_opaque_lifetime_to_parent_lifetime(def_id) .opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id())) { shadowed_captures.insert(def_id); @@ -1259,7 +1259,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)), ty::Array(ty, _) => check_non_exhaustive(tcx, *ty), ty::Adt(def, args) => { - if !def.did().is_local() { + if !def.did().is_local() && !tcx.has_attr(def.did(), sym::rustc_pub_transparent) + { let non_exhaustive = def.is_variant_list_non_exhaustive() || def .variants() @@ -1564,7 +1565,7 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD // * compare the param span to the pred span to detect lone user-written `Sized` bounds let has_explicit_bounds = bounded_params.is_empty() || (*bounded_params).get(¶m.index).is_some_and(|&&pred_sp| pred_sp != span); - let const_param_help = (!has_explicit_bounds).then_some(()); + let const_param_help = !has_explicit_bounds; let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter { span, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 80daaa60324..d2b7ede6523 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -7,7 +7,8 @@ use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, Reveal}; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitor, + self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, }; use rustc_span::Span; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -177,6 +178,10 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( return; }; + if trait_bounds.references_error() || impl_bounds.references_error() { + return; + } + // For quicker lookup, use an `IndexSet` (we don't use one earlier because // it's not foldable..). // Also, We have to anonymize binders in these types because they may contain diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 1f724580564..83d2c2c1e28 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -216,7 +216,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { } if sig.header.asyncness.is_async() { let span = tcx.def_span(it.owner_id); - tcx.dcx().emit_err(errors::StartAsync { span: span }); + tcx.dcx().emit_err(errors::StartAsync { span }); error = true; } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index bdf2914fc50..fb9bcc113c6 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -747,7 +747,7 @@ fn region_known_to_outlive<'tcx>( region_b: ty::Region<'tcx>, ) -> bool { test_region_obligations(tcx, id, param_env, wf_tys, |infcx| { - infcx.sub_regions(infer::RelateRegionParamBound(DUMMY_SP), region_b, region_a); + infcx.sub_regions(infer::RelateRegionParamBound(DUMMY_SP, None), region_b, region_a); }) } @@ -1972,8 +1972,7 @@ fn report_bivariance<'tcx>( } let const_param_help = - matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds) - .then_some(()); + matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds); let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter { span: param.span, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f75954c9edf..9e6c431a6e6 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -392,7 +392,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { } fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> { - if let RegionInferReason::BorrowedObjectLifetimeDefault = reason { + if let RegionInferReason::ObjectLifetimeDefault = reason { let e = struct_span_code_err!( self.dcx(), span, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index ae0c70d2326..0cf9e128bce 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -13,7 +13,6 @@ use rustc_ast::visit::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirId, HirIdMap, LifetimeName, Node}; use rustc_macros::extension; @@ -22,7 +21,7 @@ use rustc_middle::middle::resolve_bound_vars::*; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_middle::{bug, span_bug}; -use rustc_span::def_id::DefId; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -32,7 +31,7 @@ use crate::errors; impl ResolvedArg { fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { debug!("ResolvedArg::early: def_id={:?}", param.def_id); - (param.def_id, ResolvedArg::EarlyBound(param.def_id.to_def_id())) + (param.def_id, ResolvedArg::EarlyBound(param.def_id)) } fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { @@ -41,10 +40,10 @@ impl ResolvedArg { "ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}", idx, param, depth, param.def_id, ); - (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id.to_def_id())) + (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id)) } - fn id(&self) -> Option<DefId> { + fn id(&self) -> Option<LocalDefId> { match *self { ResolvedArg::StaticLifetime | ResolvedArg::Error(_) => None, @@ -288,13 +287,14 @@ fn late_arg_as_bound_arg<'tcx>( ) -> ty::BoundVariableKind { match arg { ResolvedArg::LateBound(_, _, def_id) => { - let name = tcx.hir().name(tcx.local_def_id_to_hir_id(def_id.expect_local())); + let def_id = def_id.to_def_id(); + let name = tcx.item_name(def_id); match param.kind { GenericParamKind::Lifetime { .. } => { - ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name)) + ty::BoundVariableKind::Region(ty::BrNamed(def_id, name)) } GenericParamKind::Type { .. } => { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(*def_id, name)) + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) } GenericParamKind::Const { .. } => ty::BoundVariableKind::Const, } @@ -717,7 +717,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // In the future, this should be fixed and this error should be removed. let def = self.map.defs.get(&lifetime.hir_id).copied(); let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue }; - let Some(lifetime_def_id) = lifetime_def_id.as_local() else { continue }; let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id)) @@ -1150,7 +1149,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { .param_def_id_to_index(self.tcx, region_def_id.to_def_id()) .is_some() { - break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id())); + break Some(ResolvedArg::EarlyBound(region_def_id)); } break None; } @@ -1259,7 +1258,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { kind => span_bug!( use_span, "did not expect to resolve lifetime to {}", - kind.descr(param_def_id) + kind.descr(param_def_id.to_def_id()) ), }; def = ResolvedArg::Error(guar); @@ -1277,10 +1276,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { kind: hir::ImplItemKind::Fn(..), .. }) => { - def = ResolvedArg::Free(owner_id.to_def_id(), def.id().unwrap()); + def = ResolvedArg::Free(owner_id.def_id, def.id().unwrap()); } Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) => { - def = ResolvedArg::Free(closure.def_id.to_def_id(), def.id().unwrap()); + def = ResolvedArg::Free(closure.def_id, def.id().unwrap()); } _ => {} } @@ -1351,7 +1350,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { .param_def_id_to_index(self.tcx, param_def_id.to_def_id()) .is_some() { - break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id())); + break Some(ResolvedArg::EarlyBound(param_def_id)); } break None; } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index d1048b742a0..c8b0f03a929 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -331,7 +331,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, owner_def_id: LocalDefId, -) -> Ty<'_> { +) -> Ty<'tcx> { let tables = tcx.typeck(owner_def_id); // Check that all of the opaques we inferred during HIR are compatible. diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 7034735aec0..821f79505f0 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1606,7 +1606,7 @@ pub(crate) struct UnusedGenericParameter { #[subdiagnostic] pub help: UnusedGenericParameterHelp, #[help(hir_analysis_const_param_help)] - pub const_param_help: Option<()>, + pub const_param_help: bool, } #[derive(Diagnostic)] @@ -1643,9 +1643,9 @@ pub(crate) struct UnconstrainedGenericParameter { pub param_name: Symbol, pub param_def_kind: &'static str, #[note(hir_analysis_const_param_note)] - pub const_param_note: Option<()>, + pub const_param_note: bool, #[note(hir_analysis_const_param_note2)] - pub const_param_note2: Option<()>, + pub const_param_note2: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index d77cbe30536..af319fd53bd 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -608,7 +608,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| { let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation }); - match &self_ty.kind() { + match self_ty.kind() { // Point at the type that couldn't satisfy the bound. ty::Adt(def, _) => { bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 6aff518390f..7be45463f15 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -15,11 +15,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`. /// In edition 2021 and onward we emit a hard error for them. - pub(super) fn prohibit_or_lint_bare_trait_object_ty( - &self, - self_ty: &hir::Ty<'_>, - in_path: bool, - ) { + pub(super) fn prohibit_or_lint_bare_trait_object_ty(&self, self_ty: &hir::Ty<'_>) { let tcx = self.tcx(); let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = @@ -28,6 +24,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return; }; + let in_path = match tcx.parent_hir_node(self_ty.hir_id) { + hir::Node::Ty(hir::Ty { + kind: hir::TyKind::Path(hir::QPath::TypeRelative(qself, _)), + .. + }) + | hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)), + .. + }) + | hir::Node::Pat(hir::Pat { + kind: hir::PatKind::Path(hir::QPath::TypeRelative(qself, _)), + .. + }) if qself.hir_id == self_ty.hir_id => true, + _ => false, + }; let needs_bracket = in_path && !tcx .sess diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d865357b829..0cdd3e4a1c6 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -85,10 +85,9 @@ pub enum PredicateFilter { #[derive(Debug)] pub enum RegionInferReason<'a> { - /// Lifetime on a trait object behind a reference. - /// This allows inferring information from the reference. - BorrowedObjectLifetimeDefault, - /// A trait object's lifetime. + /// Lifetime on a trait object that is spelled explicitly, e.g. `+ 'a` or `+ '_`. + ExplicitObjectLifetime, + /// A trait object's lifetime when it is elided, e.g. `dyn Any`. ObjectLifetimeDefault, /// Generic lifetime parameter Param(&'a ty::GenericParamDef), @@ -296,25 +295,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(rbv::ResolvedArg::StaticLifetime) => tcx.lifetimes.re_static, Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { - let name = lifetime_name(def_id.expect_local()); + let name = lifetime_name(def_id); let br = ty::BoundRegion { var: ty::BoundVar::from_u32(index), - kind: ty::BrNamed(def_id, name), + kind: ty::BrNamed(def_id.to_def_id(), name), }; ty::Region::new_bound(tcx, debruijn, br) } Some(rbv::ResolvedArg::EarlyBound(def_id)) => { - let name = tcx.hir().ty_param_name(def_id.expect_local()); - let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); + let name = tcx.hir().ty_param_name(def_id); + let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; + let index = generics.param_def_id_to_index[&def_id.to_def_id()]; ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name }) } Some(rbv::ResolvedArg::Free(scope, id)) => { - let name = lifetime_name(id.expect_local()); - ty::Region::new_late_param(tcx, scope, ty::BrNamed(id, name)) + let name = lifetime_name(id); + ty::Region::new_late_param( + tcx, + scope.to_def_id(), + ty::BrNamed(id.to_def_id(), name), + ) // (*) -- not late-bound, won't change } @@ -959,11 +962,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { \n where\n T: {qself_str},\n{}", where_bounds.join(",\n"), )); - } - let reported = err.emit(); - if !where_bounds.is_empty() { + let reported = err.emit(); return Err(reported); } + err.emit(); } Ok(bound) @@ -1054,7 +1056,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Find the type of the associated item, and the trait where the associated // item is declared. - let bound = match (&qself_ty.kind(), qself_res) { + let bound = match (qself_ty.kind(), qself_res) { (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => { // `Self` in an impl of a trait -- we have a concrete self type and a // trait reference. @@ -1954,15 +1956,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); match tcx.named_bound_var(hir_id) { Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { - let name = tcx.item_name(def_id); + let name = tcx.item_name(def_id.to_def_id()); let br = ty::BoundTy { var: ty::BoundVar::from_u32(index), - kind: ty::BoundTyKind::Param(def_id, name), + kind: ty::BoundTyKind::Param(def_id.to_def_id(), name), }; Ty::new_bound(tcx, debruijn, br) } Some(rbv::ResolvedArg::EarlyBound(def_id)) => { - let def_id = def_id.expect_local(); let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; @@ -1983,10 +1984,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(rbv::ResolvedArg::EarlyBound(def_id)) => { // Find the name and index of the const parameter by indexing the generics of // the parent item and construct a `ParamConst`. - let item_def_id = tcx.parent(def_id); + let item_def_id = tcx.local_parent(def_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - let name = tcx.item_name(def_id); + let index = generics.param_def_id_to_index[&def_id.to_def_id()]; + let name = tcx.item_name(def_id.to_def_id()); ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { @@ -1997,16 +1998,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Lower a type from the HIR to our internal notion of a type. - pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { - self.lower_ty_common(hir_ty, false, false) - } - - /// Lower a type inside of a path from the HIR to our internal notion of a type. - pub fn lower_ty_in_path(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { - self.lower_ty_common(hir_ty, false, true) - } - fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> { let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id()); match idx { @@ -2024,7 +2015,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// 2. `in_path`: Whether the type appears inside of a path. /// Used to provide correct diagnostics for bare trait object types. #[instrument(level = "debug", skip(self), ret)] - fn lower_ty_common(&self, hir_ty: &hir::Ty<'tcx>, borrowed: bool, in_path: bool) -> Ty<'tcx> { + pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let tcx = self.tcx(); let result_ty = match &hir_ty.kind { @@ -2034,7 +2025,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::TyKind::Ref(region, mt) => { let r = self.lower_lifetime(region, RegionInferReason::Reference); debug!(?r); - let t = self.lower_ty_common(mt.ty, true, false); + let t = self.lower_ty(mt.ty); Ty::new_ref(tcx, r, t, mt.mutbl) } hir::TyKind::Never => tcx.types.never, @@ -2063,20 +2054,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) } hir::TyKind::TraitObject(bounds, lifetime, repr) => { - self.prohibit_or_lint_bare_trait_object_ty(hir_ty, in_path); + self.prohibit_or_lint_bare_trait_object_ty(hir_ty); let repr = match repr { TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn, TraitObjectSyntax::DynStar => ty::DynStar, }; - self.lower_trait_object_ty( - hir_ty.span, - hir_ty.hir_id, - bounds, - lifetime, - borrowed, - repr, - ) + self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr) } hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); @@ -2104,7 +2088,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => { debug!(?qself, ?segment); - let ty = self.lower_ty_common(qself, false, true); + let ty = self.lower_ty(qself); self.lower_assoc_path(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false) .map(|(ty, _, _)| ty) .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index 31d1750f33d..52e167379b5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -30,7 +30,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_id: hir::HirId, hir_trait_bounds: &[(hir::PolyTraitRef<'tcx>, hir::TraitBoundModifier)], lifetime: &hir::Lifetime, - borrowed: bool, representation: DynKind, ) -> Ty<'tcx> { let tcx = self.tcx(); @@ -325,22 +324,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { v.dedup(); let existential_predicates = tcx.mk_poly_existential_predicates(&v); - // Use explicitly-specified region bound. + // Use explicitly-specified region bound, unless the bound is missing. let region_bound = if !lifetime.is_elided() { - self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault) + self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime) } else { self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { + // Curiously, we prefer object lifetime default for `+ '_`... if tcx.named_bound_var(lifetime.hir_id).is_some() { - self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault) + self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime) } else { - self.re_infer( - span, - if borrowed { - RegionInferReason::ObjectLifetimeDefault + let reason = + if let hir::LifetimeName::ImplicitObjectLifetimeDefault = lifetime.res { + if let hir::Node::Ty(hir::Ty { + kind: hir::TyKind::Ref(parent_lifetime, _), + .. + }) = tcx.parent_hir_node(hir_id) + && tcx.named_bound_var(parent_lifetime.hir_id).is_none() + { + // Parent lifetime must have failed to resolve. Don't emit a redundant error. + RegionInferReason::ExplicitObjectLifetime + } else { + RegionInferReason::ObjectLifetimeDefault + } } else { - RegionInferReason::BorrowedObjectLifetimeDefault - }, - ) + RegionInferReason::ExplicitObjectLifetime + }; + self.re_infer(span, reason) } }) }; diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index ab441ed4cde..02520c472b9 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -137,8 +137,7 @@ fn enforce_impl_params_are_constrained( } }; if err { - let const_param_note = - matches!(param.kind, ty::GenericParamDefKind::Const { .. }).then_some(()); + let const_param_note = matches!(param.kind, ty::GenericParamDefKind::Const { .. }); let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter { span: tcx.def_span(param.def_id), param_name: param.name, diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs index 1a17dabb677..ace183986bd 100644 --- a/compiler/rustc_hir_analysis/src/variance/dump.rs +++ b/compiler/rustc_hir_analysis/src/variance/dump.rs @@ -1,18 +1,36 @@ +use std::fmt::Write; + use rustc_hir::def::DefKind; -use rustc_hir::def_id::CRATE_DEF_ID; -use rustc_middle::ty::TyCtxt; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_middle::ty::{GenericArgs, TyCtxt}; use rustc_span::symbol::sym; +fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String { + let variances = tcx.variances_of(def_id); + let generics = GenericArgs::identity_for_item(tcx, def_id); + // 7 = 2-letter parameter + ": " + 1-letter variance + ", " + let mut ret = String::with_capacity(2 + 7 * variances.len()); + ret.push('['); + for (arg, variance) in generics.iter().zip(variances.iter()) { + write!(ret, "{arg}: {variance:?}, ").unwrap(); + } + // Remove trailing `, `. + if !variances.is_empty() { + ret.pop(); + ret.pop(); + } + ret.push(']'); + ret +} + pub(crate) fn variances(tcx: TyCtxt<'_>) { if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { for id in tcx.hir().items() { let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue }; - let variances = tcx.variances_of(id.owner_id); - tcx.dcx().emit_err(crate::errors::VariancesOf { span: tcx.def_span(id.owner_id), - variances: format!("{variances:?}"), + variances: format_variances(tcx, id.owner_id.def_id), }); } } @@ -22,11 +40,9 @@ pub(crate) fn variances(tcx: TyCtxt<'_>) { continue; } - let variances = tcx.variances_of(id.owner_id); - tcx.dcx().emit_err(crate::errors::VariancesOf { span: tcx.def_span(id.owner_id), - variances: format!("{variances:?}"), + variances: format_variances(tcx, id.owner_id.def_id), }); } } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 03a76d44cc9..3a309d2ec0b 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -505,7 +505,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { span: self.span, expr_ty: self.expr_ty, cast_ty: fcx.ty_to_string(self.cast_ty), - teach: fcx.tcx.sess.teach(E0607).then_some(()), + teach: fcx.tcx.sess.teach(E0607), }); } CastError::IntToFatCast(known_metadata) => { diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 9b34c59f1f1..b47d8a97bce 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -106,7 +106,7 @@ fn identity(_: Ty<'_>) -> Vec<Adjustment<'_>> { vec![] } -fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'_>> { +fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> { move |target| vec![Adjustment { kind, target }] } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index f802b8cf9cc..c35f7a84c4f 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -706,7 +706,7 @@ pub(crate) struct CastThinPointerToFatPointer<'tcx> { pub expr_ty: Ty<'tcx>, pub cast_ty: String, #[note(hir_typeck_teach_help)] - pub(crate) teach: Option<()>, + pub(crate) teach: bool, } #[derive(Diagnostic)] @@ -720,7 +720,7 @@ pub(crate) struct PassToVariadicFunction<'tcx, 'a> { pub sugg_span: Option<Span>, pub replace: String, #[help] - pub help: Option<()>, + pub help: bool, #[note(hir_typeck_teach_help)] - pub(crate) teach: Option<()>, + pub(crate) teach: bool, } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index fec6efdc0f7..91778a36668 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -841,6 +841,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ret_ty = ret_coercion.borrow().expected_ty(); let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty); let mut span = return_expr.span; + let mut hir_id = return_expr.hir_id; // Use the span of the trailing expression for our cause, // not the span of the entire function if !explicit_return @@ -848,6 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(last_expr) = body.expr { span = last_expr.span; + hir_id = last_expr.hir_id; } ret_coercion.borrow_mut().coerce( self, @@ -864,6 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.select_obligations_where_possible(|errors| { self.point_at_return_for_opaque_ty_error( errors, + hir_id, span, return_expr_ty, return_expr.span, @@ -921,6 +924,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn point_at_return_for_opaque_ty_error( &self, errors: &mut Vec<traits::FulfillmentError<'tcx>>, + hir_id: HirId, span: Span, return_expr_ty: Ty<'tcx>, return_span: Span, @@ -935,7 +939,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let new_cause = ObligationCause::new( cause.span, cause.body_id, - ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, span))), + ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, hir_id))), ); *cause = new_cause; } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index b169f75796b..21e6ac9332c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -798,7 +798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // to be object-safe. // We manually call `register_wf_obligation` in the success path // below. - let ty = self.lowerer().lower_ty_in_path(qself); + let ty = self.lowerer().lower_ty(qself); (LoweredTy::from_raw(self, span, ty), qself, segment) } QPath::LangItem(..) => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 7720faddba3..aca29d47587 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -406,9 +406,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let (sugg_span, replace, help) = if let Ok(snippet) = sess.source_map().span_to_snippet(span) { - (Some(span), format!("{snippet} as {cast_ty}"), None) + (Some(span), format!("{snippet} as {cast_ty}"), false) } else { - (None, "".to_string(), Some(())) + (None, "".to_string(), true) }; sess.dcx().emit_err(errors::PassToVariadicFunction { @@ -418,7 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { help, replace, sugg_span, - teach: sess.teach(E0617).then_some(()), + teach: sess.teach(E0617), }); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 703273968c5..11c6e65a211 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2975,7 +2975,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut suffix_suggestion = sugg.clone(); suffix_suggestion.push(( if matches!( - (&expected_ty.kind(), &checked_ty.kind()), + (expected_ty.kind(), checked_ty.kind()), (ty::Int(_) | ty::Uint(_), ty::Float(_)) ) { // Remove fractional part from literal, for example `42.0f32` into `42` @@ -3077,7 +3077,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable); }; - match (&expected_ty.kind(), &checked_ty.kind()) { + match (expected_ty.kind(), checked_ty.kind()) { (ty::Int(exp), ty::Int(found)) => { let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 9ec101196a4..8ff4c11f24a 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -87,14 +87,17 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDef &tcx.typeck(def_id).used_trait_imports } -fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { +fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { let fallback = move || tcx.type_of(def_id.to_def_id()).instantiate_identity(); typeck_with_fallback(tcx, def_id, fallback, None) } /// Used only to get `TypeckResults` for type inference during error recovery. /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors. -fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { +fn diagnostic_only_typeck<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> &'tcx ty::TypeckResults<'tcx> { let fallback = move || { let span = tcx.hir().span(tcx.local_def_id_to_hir_id(def_id)); Ty::new_error_with_message(tcx, span, "diagnostic only typeck table used") diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index b3cf73bac1a..ffd46ea13b9 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -527,7 +527,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { if self.check_and_add_sugg_binding(LetStmt { ty_hir_id_opt: if let Some(ty) = ty { Some(ty.hir_id) } else { None }, - binding_id: binding_id, + binding_id, span: pat.span, init_hir_id: init.hir_id, }) { @@ -1012,7 +1012,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| { let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation }); - match &self_ty.kind() { + match self_ty.kind() { // Point at the type that couldn't satisfy the bound. ty::Adt(def, _) => { bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index c4f74adb420..a8e5e09c8bb 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1336,7 +1336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // More generally, the expected type wants a tuple variant with one field of an // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`. - let missing_parentheses = match (&expected.kind(), fields, had_err) { + let missing_parentheses = match (expected.kind(), fields, had_err) { // #67037: only do this if we could successfully type-check the expected type against // the tuple struct pattern. Otherwise the args could get out of range on e.g., // `let P() = U;` where `P != U` with `struct P<T>(T);`. diff --git a/compiler/rustc_incremental/messages.ftl b/compiler/rustc_incremental/messages.ftl index de2177ebb6e..2a65101d360 100644 --- a/compiler/rustc_incremental/messages.ftl +++ b/compiler/rustc_incremental/messages.ftl @@ -99,6 +99,4 @@ incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name} incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized -incremental_write_dep_graph = failed to write dependency graph to `{$path}`: {$err} - incremental_write_new = failed to write {$name} to `{$path}`: {$err} diff --git a/compiler/rustc_incremental/src/errors.rs b/compiler/rustc_incremental/src/errors.rs index f8910030634..c6f8b99bcd6 100644 --- a/compiler/rustc_incremental/src/errors.rs +++ b/compiler/rustc_incremental/src/errors.rs @@ -189,10 +189,10 @@ pub struct CreateLock<'a> { pub lock_err: std::io::Error, pub session_dir: &'a Path, #[note(incremental_lock_unsupported)] - pub is_unsupported_lock: Option<()>, + pub is_unsupported_lock: bool, #[help(incremental_cargo_help_1)] #[help(incremental_cargo_help_2)] - pub is_cargo: Option<()>, + pub is_cargo: bool, } #[derive(Diagnostic)] @@ -273,13 +273,6 @@ pub struct LoadDepGraph { } #[derive(Diagnostic)] -#[diag(incremental_write_dep_graph)] -pub struct WriteDepGraph<'a> { - pub path: &'a Path, - pub err: std::io::Error, -} - -#[derive(Diagnostic)] #[diag(incremental_move_dep_graph)] pub struct MoveDepGraph<'a> { pub from: &'a Path, diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 5f85e622e89..0e87bc1e692 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -486,12 +486,12 @@ fn lock_directory( // the lock should be exclusive Ok(lock) => Ok((lock, lock_file_path)), Err(lock_err) => { - let is_unsupported_lock = flock::Lock::error_unsupported(&lock_err).then_some(()); + let is_unsupported_lock = flock::Lock::error_unsupported(&lock_err); Err(sess.dcx().emit_err(errors::CreateLock { lock_err, session_dir, is_unsupported_lock, - is_cargo: rustc_session::utils::was_invoked_from_cargo().then_some(()), + is_cargo: rustc_session::utils::was_invoked_from_cargo(), })) } } @@ -851,7 +851,7 @@ fn delete_old(sess: &Session, path: &Path) { debug!("garbage_collect_session_directories() - deleting `{}`", path.display()); if let Err(err) = safe_remove_dir_all(path) { - sess.dcx().emit_warn(errors::SessionGcFailed { path: path, err }); + sess.dcx().emit_warn(errors::SessionGcFailed { path, err }); } else { delete_session_dir_lock_file(sess, &lock_file_path(path)); } diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index b5e4f02a8d1..b9d2a43206b 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -2,6 +2,7 @@ #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))] #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", feature(extend_one, new_uninit, step_trait, test))] +#![cfg_attr(feature = "nightly", feature(new_zeroed_alloc))] // tidy-alphabetical-end pub mod bit_set; diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index f35a8162d96..95888beb6b1 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -167,7 +167,7 @@ impl<'tcx> InferCtxtLike for InferCtxt<'tcx> { } fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) { - self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup) + self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None), sub, sup) } fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index f2fc25a2d2e..5aa7f259685 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -390,7 +390,7 @@ pub enum SubregionOrigin<'tcx> { /// The given region parameter was instantiated with a region /// that must outlive some other region. - RelateRegionParamBound(Span), + RelateRegionParamBound(Span, Option<Ty<'tcx>>), /// Creating a pointer `b` to contents of another reference. Reborrow(Span), @@ -859,7 +859,7 @@ impl<'tcx> InferCtxt<'tcx> { ) { self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| { let origin = SubregionOrigin::from_obligation_cause(cause, || { - RelateRegionParamBound(cause.span) + RelateRegionParamBound(cause.span, None) }); self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` }) @@ -1685,7 +1685,7 @@ impl<'tcx> SubregionOrigin<'tcx> { Subtype(ref a) => a.span(), RelateObjectBound(a) => a, RelateParamBound(a, ..) => a, - RelateRegionParamBound(a) => a, + RelateRegionParamBound(a, _) => a, Reborrow(a) => a, ReferenceOutlivesReferent(_, a) => a, CompareImplItemObligation { span, .. } => span, @@ -1726,6 +1726,10 @@ impl<'tcx> SubregionOrigin<'tcx> { SubregionOrigin::AscribeUserTypeProvePredicate(span) } + traits::ObligationCauseCode::ObjectTypeBound(ty, _reg) => { + SubregionOrigin::RelateRegionParamBound(cause.span, Some(ty)) + } + _ => default(), } } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index c5d56c15c6e..44e07b36b61 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -98,7 +98,7 @@ impl<'tcx> Queries<'tcx> { self.parse.compute(|| passes::parse(&self.compiler.sess)) } - pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> { + pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'tcx, &'tcx GlobalCtxt<'tcx>>> { self.gcx.compute(|| { let krate = self.parse()?.steal(); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7a394a6d6c1..08a50050a36 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -361,6 +361,11 @@ lint_improper_ctypes_box = box cannot be represented as a single pointer lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead lint_improper_ctypes_char_reason = the `char` type has no C equivalent + +lint_improper_ctypes_cstr_help = + consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` +lint_improper_ctypes_cstr_reason = `CStr`/`CString` do not have a guaranteed layout + lint_improper_ctypes_dyn = trait objects have no C equivalent lint_improper_ctypes_enum_repr_help = @@ -758,6 +763,9 @@ lint_suspicious_double_ref_clone = lint_suspicious_double_ref_deref = using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type +lint_tail_expr_drop_order = these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 + .label = these values have significant drop implementation and will observe changes in drop order under Edition 2024 + lint_trailing_semi_macro = trailing semicolon in macro used in expression position .note1 = macro invocations at the end of a block are treated as expressions .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}` diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5f6e7fb314d..d8482567bbe 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1330,7 +1330,7 @@ impl UnreachablePub { BuiltinUnreachablePub { what, suggestion: (vis_span, applicability), - help: exportable.then_some(()), + help: exportable, }, ); } @@ -1925,8 +1925,8 @@ impl ExplicitOutlivesRequirements { fn lifetimes_outliving_lifetime<'tcx>( tcx: TyCtxt<'tcx>, inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>, - item: DefId, - lifetime: DefId, + item: LocalDefId, + lifetime: LocalDefId, ) -> Vec<ty::Region<'tcx>> { let item_generics = tcx.generics_of(item); @@ -1934,7 +1934,7 @@ impl ExplicitOutlivesRequirements { .filter_map(|(clause, _)| match clause.kind().skip_binder() { ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { ty::ReEarlyParam(ebr) - if item_generics.region_param(ebr, tcx).def_id == lifetime => + if item_generics.region_param(ebr, tcx).def_id == lifetime.to_def_id() => { Some(b) } @@ -1982,7 +1982,7 @@ impl ExplicitOutlivesRequirements { let is_inferred = match tcx.named_bound_var(lifetime.hir_id) { Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives .iter() - .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id })), + .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id.to_def_id() })), _ => false, }; @@ -2097,7 +2097,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { inferred_outlives .iter() .filter(|(_, span)| !predicate.span.contains(*span)), - item.owner_id.to_def_id(), + item.owner_id.def_id, region_def_id, ), &predicate.bounds, diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index 2060858cc8a..a9de258e005 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -151,10 +151,11 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { && let Node::Stmt(stmt) = node && let StmtKind::Semi(e) = stmt.kind && e.hir_id == expr.hir_id + && let Some(arg_span) = arg.span.find_ancestor_inside(expr.span) { UseLetUnderscoreIgnoreSuggestion::Suggestion { - start_span: expr.span.shrink_to_lo().until(arg.span), - end_span: arg.span.shrink_to_hi().until(expr.span.shrink_to_hi()), + start_span: expr.span.shrink_to_lo().until(arg_span), + end_span: arg_span.shrink_to_hi().until(expr.span.shrink_to_hi()), } } else { UseLetUnderscoreIgnoreSuggestion::Note diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 23e6b73ee37..85ee18aba8f 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -77,7 +77,7 @@ pub struct UnknownToolInScopedLint { pub tool_name: Symbol, pub lint_name: String, #[help] - pub is_nightly_build: Option<()>, + pub is_nightly_build: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 35af694213d..42b33f9882d 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -24,7 +24,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) { && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter)) { let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale }); - let note = expectation.is_unfulfilled_lint_expectations.then_some(()); + let note = expectation.is_unfulfilled_lint_expectations; tcx.emit_node_span_lint( UNFULFILLED_LINT_EXPECTATIONS, *hir_id, diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index e914169f4c3..2e0da69e920 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -27,8 +27,6 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail - /// # #![feature(precise_capturing)] - /// # #![allow(incomplete_features)] /// # #![deny(impl_trait_overcaptures)] /// # use std::fmt::Display; /// let mut x = vec![]; @@ -56,7 +54,6 @@ declare_lint! { pub IMPL_TRAIT_OVERCAPTURES, Allow, "`impl Trait` will capture more lifetimes than possibly intended in edition 2024", - @feature_gate = precise_capturing; //@future_incompatible = FutureIncompatibleInfo { // reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), // reference: "<FIXME>", @@ -75,8 +72,7 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail - /// # #![feature(precise_capturing, lifetime_capture_rules_2024)] - /// # #![allow(incomplete_features)] + /// # #![feature(lifetime_capture_rules_2024)] /// # #![deny(impl_trait_redundant_captures)] /// fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x } /// ``` @@ -90,7 +86,6 @@ declare_lint! { pub IMPL_TRAIT_REDUNDANT_CAPTURES, Warn, "redundant precise-capturing `use<...>` syntax on an `impl Trait`", - @feature_gate = precise_capturing; } declare_lint_pass!( @@ -305,16 +300,17 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> { Some( ResolvedArg::EarlyBound(def_id) | ResolvedArg::LateBound(_, _, def_id), ) => { - if self.tcx.def_kind(self.tcx.parent(def_id)) == DefKind::OpaqueTy { + if self.tcx.def_kind(self.tcx.local_parent(def_id)) == DefKind::OpaqueTy + { let def_id = self .tcx - .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local()) + .map_opaque_lifetime_to_parent_lifetime(def_id) .opt_param_def_id(self.tcx, self.parent_def_id.to_def_id()) .expect("variable should have been duplicated from parent"); explicitly_captured.insert(def_id); } else { - explicitly_captured.insert(def_id); + explicitly_captured.insert(def_id.to_def_id()); } } _ => { diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 044c9413f0b..65571815019 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -8,7 +8,7 @@ use rustc_hir::{ BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat, PatKind, Path, PathSegment, QPath, Ty, TyKind, }; -use rustc_middle::ty::{self, Ty as MiddleTy}; +use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::symbol::{kw, sym, Symbol}; @@ -415,14 +415,17 @@ declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE impl LateLintPass<'_> for Diagnostics { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + let collect_args_tys_and_spans = |args: &[Expr<'_>], reserve_one_extra: bool| { + let mut result = Vec::with_capacity(args.len() + usize::from(reserve_one_extra)); + result.extend(args.iter().map(|arg| (cx.typeck_results().expr_ty(arg), arg.span))); + result + }; // Only check function calls and method calls. - let (span, def_id, fn_gen_args, call_tys) = match expr.kind { + let (span, def_id, fn_gen_args, arg_tys_and_spans) = match expr.kind { ExprKind::Call(callee, args) => { match cx.typeck_results().node_type(callee.hir_id).kind() { &ty::FnDef(def_id, fn_gen_args) => { - let call_tys: Vec<_> = - args.iter().map(|arg| cx.typeck_results().expr_ty(arg)).collect(); - (callee.span, def_id, fn_gen_args, call_tys) + (callee.span, def_id, fn_gen_args, collect_args_tys_and_spans(args, false)) } _ => return, // occurs for fns passed as args } @@ -432,38 +435,40 @@ impl LateLintPass<'_> for Diagnostics { else { return; }; - let mut call_tys: Vec<_> = - args.iter().map(|arg| cx.typeck_results().expr_ty(arg)).collect(); - call_tys.insert(0, cx.tcx.types.self_param); // dummy inserted for `self` - (span, def_id, fn_gen_args, call_tys) + let mut args = collect_args_tys_and_spans(args, true); + args.insert(0, (cx.tcx.types.self_param, _recv.span)); // dummy inserted for `self` + (span, def_id, fn_gen_args, args) } _ => return, }; - // Is the callee marked with `#[rustc_lint_diagnostics]`? - let has_attr = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, fn_gen_args) - .ok() - .flatten() - .is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics)); - - // Closure: is the type `{D,Subd}iagMessage`? - let is_diag_message = |ty: MiddleTy<'_>| { - if let Some(adt_def) = ty.ty_adt_def() - && let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did()) - && matches!(name, sym::DiagMessage | sym::SubdiagMessage) - { - true - } else { - false - } - }; + Self::diagnostic_outside_of_impl(cx, span, expr.hir_id, def_id, fn_gen_args); + Self::untranslatable_diagnostic(cx, def_id, &arg_tys_and_spans); + } +} - // Does the callee have one or more `impl Into<{D,Subd}iagMessage>` parameters? - let mut impl_into_diagnostic_message_params = vec![]; +impl Diagnostics { + // Is the type `{D,Subd}iagMessage`? + fn is_diag_message<'cx>(cx: &LateContext<'cx>, ty: MiddleTy<'cx>) -> bool { + if let Some(adt_def) = ty.ty_adt_def() + && let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did()) + && matches!(name, sym::DiagMessage | sym::SubdiagMessage) + { + true + } else { + false + } + } + + fn untranslatable_diagnostic<'cx>( + cx: &LateContext<'cx>, + def_id: DefId, + arg_tys_and_spans: &[(MiddleTy<'cx>, Span)], + ) { let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); let predicates = cx.tcx.predicates_of(def_id).instantiate_identity(cx.tcx).predicates; for (i, ¶m_ty) in fn_sig.inputs().iter().enumerate() { - if let ty::Param(p) = param_ty.kind() { + if let ty::Param(sig_param) = param_ty.kind() { // It is a type parameter. Check if it is `impl Into<{D,Subd}iagMessage>`. for pred in predicates.iter() { if let Some(trait_pred) = pred.as_trait_clause() @@ -471,27 +476,53 @@ impl LateLintPass<'_> for Diagnostics { && trait_ref.self_ty() == param_ty // correct predicate for the param? && cx.tcx.is_diagnostic_item(sym::Into, trait_ref.def_id) && let ty1 = trait_ref.args.type_at(1) - && is_diag_message(ty1) + && Self::is_diag_message(cx, ty1) { - impl_into_diagnostic_message_params.push((i, p.name)); + // Calls to methods with an `impl Into<{D,Subd}iagMessage>` parameter must be passed an arg + // with type `{D,Subd}iagMessage` or `impl Into<{D,Subd}iagMessage>`. Otherwise, emit an + // `UNTRANSLATABLE_DIAGNOSTIC` lint. + let (arg_ty, arg_span) = arg_tys_and_spans[i]; + + // Is the arg type `{Sub,D}iagMessage`or `impl Into<{Sub,D}iagMessage>`? + let is_translatable = Self::is_diag_message(cx, arg_ty) + || matches!(arg_ty.kind(), ty::Param(arg_param) if arg_param.name == sig_param.name); + if !is_translatable { + cx.emit_span_lint( + UNTRANSLATABLE_DIAGNOSTIC, + arg_span, + UntranslatableDiag, + ); + } } } } } + } - // Is the callee interesting? - if !has_attr && impl_into_diagnostic_message_params.is_empty() { + fn diagnostic_outside_of_impl<'cx>( + cx: &LateContext<'cx>, + span: Span, + current_id: HirId, + def_id: DefId, + fn_gen_args: GenericArgsRef<'cx>, + ) { + // Is the callee marked with `#[rustc_lint_diagnostics]`? + let Some(inst) = + ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, fn_gen_args).ok().flatten() + else { return; - } + }; + let has_attr = cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics); + if !has_attr { + return; + }; - // Is the parent method marked with `#[rustc_lint_diagnostics]`? - let mut parent_has_attr = false; - for (hir_id, _parent) in cx.tcx.hir().parent_iter(expr.hir_id) { + for (hir_id, _parent) in cx.tcx.hir().parent_iter(current_id) { if let Some(owner_did) = hir_id.as_owner() && cx.tcx.has_attr(owner_did, sym::rustc_lint_diagnostics) { - parent_has_attr = true; - break; + // The parent method is marked with `#[rustc_lint_diagnostics]` + return; } } @@ -500,37 +531,22 @@ impl LateLintPass<'_> for Diagnostics { // - inside a parent function that is itself marked with `#[rustc_lint_diagnostics]`. // // Otherwise, emit a `DIAGNOSTIC_OUTSIDE_OF_IMPL` lint. - if has_attr && !parent_has_attr { - let mut is_inside_appropriate_impl = false; - for (_hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) { - debug!(?parent); - if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent - && let Impl { of_trait: Some(of_trait), .. } = impl_ - && let Some(def_id) = of_trait.trait_def_id() - && let Some(name) = cx.tcx.get_diagnostic_name(def_id) - && matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic) - { - is_inside_appropriate_impl = true; - break; - } - } - debug!(?is_inside_appropriate_impl); - if !is_inside_appropriate_impl { - cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl); + let mut is_inside_appropriate_impl = false; + for (_hir_id, parent) in cx.tcx.hir().parent_iter(current_id) { + debug!(?parent); + if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent + && let Impl { of_trait: Some(of_trait), .. } = impl_ + && let Some(def_id) = of_trait.trait_def_id() + && let Some(name) = cx.tcx.get_diagnostic_name(def_id) + && matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic) + { + is_inside_appropriate_impl = true; + break; } } - - // Calls to methods with an `impl Into<{D,Subd}iagMessage>` parameter must be passed an arg - // with type `{D,Subd}iagMessage` or `impl Into<{D,Subd}iagMessage>`. Otherwise, emit an - // `UNTRANSLATABLE_DIAGNOSTIC` lint. - for (param_i, param_i_p_name) in impl_into_diagnostic_message_params { - // Is the arg type `{Sub,D}iagMessage`or `impl Into<{Sub,D}iagMessage>`? - let arg_ty = call_tys[param_i]; - let is_translatable = is_diag_message(arg_ty) - || matches!(arg_ty.kind(), ty::Param(p) if p.name == param_i_p_name); - if !is_translatable { - cx.emit_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, UntranslatableDiag); - } + debug!(?is_inside_appropriate_impl); + if !is_inside_appropriate_impl { + cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl); } } } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 44117e5d7a5..91d4f95df80 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -936,7 +936,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { span: tool_ident.map(|ident| ident.span), tool_name: tool_name.unwrap(), lint_name: pprust::path_to_string(&meta_item.path), - is_nightly_build: sess.is_nightly_build().then_some(()), + is_nightly_build: sess.is_nightly_build(), }); continue; } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 4f3933d461b..a6e7d288f08 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -78,6 +78,7 @@ mod ptr_nulls; mod redundant_semicolon; mod reference_casting; mod shadowed_into_iter; +mod tail_expr_drop_order; mod traits; mod types; mod unit_bindings; @@ -115,6 +116,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use shadowed_into_iter::ShadowedIntoIter; pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; +use tail_expr_drop_order::TailExprDropOrder; use traits::*; use types::*; use unit_bindings::*; @@ -238,6 +240,7 @@ late_lint_methods!( AsyncFnInTrait: AsyncFnInTrait, NonLocalDefinitions: NonLocalDefinitions::default(), ImplTraitOvercaptures: ImplTraitOvercaptures, + TailExprDropOrder: TailExprDropOrder, ] ] ); @@ -569,7 +572,8 @@ fn register_builtins(store: &mut LintStore) { "byte_slice_in_packed_struct_with_derive", "converted into hard error, see issue #107457 \ <https://github.com/rust-lang/rust/issues/107457> for more information", - ) + ); + store.register_removed("writes_through_immutable_pointer", "converted into hard error"); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 03962d796f4..c12c5427997 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -257,7 +257,7 @@ pub struct BuiltinUnreachablePub<'a> { #[suggestion(code = "pub(crate)")] pub suggestion: (Span, Applicability), #[help] - pub help: Option<()>, + pub help: bool, } #[derive(LintDiagnostic)] @@ -572,7 +572,7 @@ pub struct Expectation { #[subdiagnostic] pub rationale: Option<ExpectationNote>, #[note] - pub note: Option<()>, + pub note: bool, } #[derive(Subdiagnostic)] @@ -756,7 +756,7 @@ pub enum InvalidReferenceCastingDiag<'tcx> { #[label] orig_cast: Option<Span>, #[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)] - ty_has_interior_mutability: Option<()>, + ty_has_interior_mutability: bool, }, #[diag(lint_invalid_reference_casting_assign_to_ref)] #[note(lint_invalid_reference_casting_note_book)] @@ -764,7 +764,7 @@ pub enum InvalidReferenceCastingDiag<'tcx> { #[label] orig_cast: Option<Span>, #[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)] - ty_has_interior_mutability: Option<()>, + ty_has_interior_mutability: bool, }, #[diag(lint_invalid_reference_casting_bigger_layout)] #[note(lint_layout)] diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 5e8c39c0023..45d97403d60 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -54,8 +54,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting { && let Some(ty_has_interior_mutability) = is_cast_from_ref_to_mut_ptr(cx, init, &mut peel_casts) { - let ty_has_interior_mutability = ty_has_interior_mutability.then_some(()); - cx.emit_span_lint( INVALID_REFERENCE_CASTING, expr.span, diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs new file mode 100644 index 00000000000..f9ecc8c9806 --- /dev/null +++ b/compiler/rustc_lint/src/tail_expr_drop_order.rs @@ -0,0 +1,306 @@ +use std::mem::swap; + +use rustc_ast::UnOp; +use rustc_hir::def::Res; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{self as hir, Block, Expr, ExprKind, LetStmt, Pat, PatKind, QPath, StmtKind}; +use rustc_macros::LintDiagnostic; +use rustc_middle::ty; +use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::edition::Edition; +use rustc_span::Span; + +use crate::{LateContext, LateLintPass}; + +declare_lint! { + /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, that of type + /// with a significant `Drop` implementation, such as locks. + /// In case there are also local variables of type with significant `Drop` implementation as well, + /// this lint warns you of a potential transposition in the drop order. + /// Your discretion on the new drop order introduced by Edition 2024 is required. + /// + /// ### Example + /// ```rust,edition2024 + /// #![feature(shorter_tail_lifetimes)] + /// #![warn(tail_expr_drop_order)] + /// struct Droppy(i32); + /// impl Droppy { + /// fn get(&self) -> i32 { + /// self.0 + /// } + /// } + /// impl Drop for Droppy { + /// fn drop(&mut self) { + /// // This is a custom destructor and it induces side-effects that is observable + /// // especially when the drop order at a tail expression changes. + /// println!("loud drop {}", self.0); + /// } + /// } + /// fn edition_2024() -> i32 { + /// let another_droppy = Droppy(0); + /// Droppy(1).get() + /// } + /// fn main() { + /// edition_2024(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In tail expression of blocks or function bodies, + /// values of type with significant `Drop` implementation has an ill-specified drop order + /// before Edition 2024 so that they are dropped only after dropping local variables. + /// Edition 2024 introduces a new rule with drop orders for them, + /// so that they are dropped first before dropping local variables. + /// + /// A significant `Drop::drop` destructor here refers to an explicit, arbitrary + /// implementation of the `Drop` trait on the type, with exceptions including `Vec`, + /// `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise + /// so long that the generic types have no significant destructor recursively. + /// In other words, a type has a significant drop destructor when it has a `Drop` implementation + /// or its destructor invokes a significant destructor on a type. + /// Since we cannot completely reason about the change by just inspecting the existence of + /// a significant destructor, this lint remains only a suggestion and is set to `allow` by default. + /// + /// This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy` + /// does in Edition 2024. + /// No fix will be proposed by this lint. + /// However, the most probable fix is to hoist `Droppy` into its own local variable binding. + /// ```rust + /// struct Droppy(i32); + /// impl Droppy { + /// fn get(&self) -> i32 { + /// self.0 + /// } + /// } + /// fn edition_2024() -> i32 { + /// let value = Droppy(0); + /// let another_droppy = Droppy(1); + /// value.get() + /// } + /// ``` + pub TAIL_EXPR_DROP_ORDER, + Allow, + "Detect and warn on significant change in drop order in tail expression location", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), + reference: "issue #123739 <https://github.com/rust-lang/rust/issues/123739>", + }; +} + +declare_lint_pass!(TailExprDropOrder => [TAIL_EXPR_DROP_ORDER]); + +impl TailExprDropOrder { + fn check_fn_or_closure<'tcx>( + cx: &LateContext<'tcx>, + fn_kind: hir::intravisit::FnKind<'tcx>, + body: &'tcx hir::Body<'tcx>, + def_id: rustc_span::def_id::LocalDefId, + ) { + let mut locals = vec![]; + if matches!(fn_kind, hir::intravisit::FnKind::Closure) { + for &capture in cx.tcx.closure_captures(def_id) { + if matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue) + && capture.place.ty().has_significant_drop(cx.tcx, cx.param_env) + { + locals.push(capture.var_ident.span); + } + } + } + for param in body.params { + if cx + .typeck_results() + .node_type(param.hir_id) + .has_significant_drop(cx.tcx, cx.param_env) + { + locals.push(param.span); + } + } + if let hir::ExprKind::Block(block, _) = body.value.kind { + LintVisitor { cx, locals }.check_block_inner(block); + } else { + LintTailExpr { cx, locals: &locals, is_root_tail_expr: true }.visit_expr(body.value); + } + } +} + +impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + fn_kind: hir::intravisit::FnKind<'tcx>, + _: &'tcx hir::FnDecl<'tcx>, + body: &'tcx hir::Body<'tcx>, + _: Span, + def_id: rustc_span::def_id::LocalDefId, + ) { + if cx.tcx.sess.at_least_rust_2024() && cx.tcx.features().shorter_tail_lifetimes { + Self::check_fn_or_closure(cx, fn_kind, body, def_id); + } + } +} + +struct LintVisitor<'tcx, 'a> { + cx: &'a LateContext<'tcx>, + // We only record locals that have significant drops + locals: Vec<Span>, +} + +struct LocalCollector<'tcx, 'a> { + cx: &'a LateContext<'tcx>, + locals: &'a mut Vec<Span>, +} + +impl<'tcx, 'a> Visitor<'tcx> for LocalCollector<'tcx, 'a> { + type Result = (); + fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { + if let PatKind::Binding(_binding_mode, id, ident, pat) = pat.kind { + let ty = self.cx.typeck_results().node_type(id); + if ty.has_significant_drop(self.cx.tcx, self.cx.param_env) { + self.locals.push(ident.span); + } + if let Some(pat) = pat { + self.visit_pat(pat); + } + } else { + intravisit::walk_pat(self, pat); + } + } +} + +impl<'tcx, 'a> Visitor<'tcx> for LintVisitor<'tcx, 'a> { + fn visit_block(&mut self, block: &'tcx Block<'tcx>) { + let mut locals = <_>::default(); + swap(&mut locals, &mut self.locals); + self.check_block_inner(block); + swap(&mut locals, &mut self.locals); + } + fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) { + LocalCollector { cx: self.cx, locals: &mut self.locals }.visit_local(local); + } +} + +impl<'tcx, 'a> LintVisitor<'tcx, 'a> { + fn check_block_inner(&mut self, block: &Block<'tcx>) { + if !block.span.at_least_rust_2024() { + // We only lint for Edition 2024 onwards + return; + } + let Some(tail_expr) = block.expr else { return }; + for stmt in block.stmts { + match stmt.kind { + StmtKind::Let(let_stmt) => self.visit_local(let_stmt), + StmtKind::Item(_) => {} + StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e), + } + } + if self.locals.is_empty() { + return; + } + LintTailExpr { cx: self.cx, locals: &self.locals, is_root_tail_expr: true } + .visit_expr(tail_expr); + } +} + +struct LintTailExpr<'tcx, 'a> { + cx: &'a LateContext<'tcx>, + is_root_tail_expr: bool, + locals: &'a [Span], +} + +impl<'tcx, 'a> LintTailExpr<'tcx, 'a> { + fn expr_eventually_point_into_local(mut expr: &Expr<'tcx>) -> bool { + loop { + match expr.kind { + ExprKind::Index(access, _, _) | ExprKind::Field(access, _) => expr = access, + ExprKind::AddrOf(_, _, referee) | ExprKind::Unary(UnOp::Deref, referee) => { + expr = referee + } + ExprKind::Path(_) + if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind + && let [local, ..] = path.segments + && let Res::Local(_) = local.res => + { + return true; + } + _ => return false, + } + } + } + + fn expr_generates_nonlocal_droppy_value(&self, expr: &Expr<'tcx>) -> bool { + if Self::expr_eventually_point_into_local(expr) { + return false; + } + self.cx.typeck_results().expr_ty(expr).has_significant_drop(self.cx.tcx, self.cx.param_env) + } +} + +impl<'tcx, 'a> Visitor<'tcx> for LintTailExpr<'tcx, 'a> { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + if self.is_root_tail_expr { + self.is_root_tail_expr = false; + } else if self.expr_generates_nonlocal_droppy_value(expr) { + self.cx.tcx.emit_node_span_lint( + TAIL_EXPR_DROP_ORDER, + expr.hir_id, + expr.span, + TailExprDropOrderLint { spans: self.locals.to_vec() }, + ); + return; + } + match expr.kind { + ExprKind::Match(scrutinee, _, _) => self.visit_expr(scrutinee), + + ExprKind::ConstBlock(_) + | ExprKind::Array(_) + | ExprKind::Break(_, _) + | ExprKind::Continue(_) + | ExprKind::Ret(_) + | ExprKind::Become(_) + | ExprKind::Yield(_, _) + | ExprKind::InlineAsm(_) + | ExprKind::If(_, _, _) + | ExprKind::Loop(_, _, _, _) + | ExprKind::Closure(_) + | ExprKind::DropTemps(_) + | ExprKind::OffsetOf(_, _) + | ExprKind::Assign(_, _, _) + | ExprKind::AssignOp(_, _, _) + | ExprKind::Lit(_) + | ExprKind::Err(_) => {} + + ExprKind::MethodCall(_, _, _, _) + | ExprKind::Call(_, _) + | ExprKind::Type(_, _) + | ExprKind::Tup(_) + | ExprKind::Binary(_, _, _) + | ExprKind::Unary(_, _) + | ExprKind::Path(_) + | ExprKind::Let(_) + | ExprKind::Cast(_, _) + | ExprKind::Field(_, _) + | ExprKind::Index(_, _, _) + | ExprKind::AddrOf(_, _, _) + | ExprKind::Struct(_, _, _) + | ExprKind::Repeat(_, _) => intravisit::walk_expr(self, expr), + + ExprKind::Block(_, _) => { + // We do not lint further because the drop order stays the same inside the block + } + } + } + fn visit_block(&mut self, block: &'tcx Block<'tcx>) { + LintVisitor { cx: self.cx, locals: <_>::default() }.check_block_inner(block); + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_tail_expr_drop_order)] +struct TailExprDropOrderLint { + #[label] + pub spans: Vec<Span>, +} diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index cb7a07116ce..f1da14bb1f3 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -985,6 +985,14 @@ struct ImproperCTypesVisitor<'a, 'tcx> { mode: CItemKind, } +/// Accumulator for recursive ffi type checking +struct CTypesVisitorState<'tcx> { + cache: FxHashSet<Ty<'tcx>>, + /// The original type being checked, before we recursed + /// to any other types it contains. + base_ty: Ty<'tcx>, +} + enum FfiResult<'tcx> { FfiSafe, FfiPhantom(Ty<'tcx>), @@ -1213,7 +1221,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Checks if the given field's type is "ffi-safe". fn check_field_type_for_ffi( &self, - cache: &mut FxHashSet<Ty<'tcx>>, + acc: &mut CTypesVisitorState<'tcx>, field: &ty::FieldDef, args: GenericArgsRef<'tcx>, ) -> FfiResult<'tcx> { @@ -1223,13 +1231,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { .tcx .try_normalize_erasing_regions(self.cx.param_env, field_ty) .unwrap_or(field_ty); - self.check_type_for_ffi(cache, field_ty) + self.check_type_for_ffi(acc, field_ty) } /// Checks if the given `VariantDef`'s field types are "ffi-safe". fn check_variant_for_ffi( &self, - cache: &mut FxHashSet<Ty<'tcx>>, + acc: &mut CTypesVisitorState<'tcx>, ty: Ty<'tcx>, def: ty::AdtDef<'tcx>, variant: &ty::VariantDef, @@ -1239,7 +1247,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let transparent_with_all_zst_fields = if def.repr().transparent() { if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) { // Transparent newtypes have at most one non-ZST field which needs to be checked.. - match self.check_field_type_for_ffi(cache, field, args) { + match self.check_field_type_for_ffi(acc, field, args) { FfiUnsafe { ty, .. } if ty.is_unit() => (), r => return r, } @@ -1257,7 +1265,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe. let mut all_phantom = !variant.fields.is_empty(); for field in &variant.fields { - all_phantom &= match self.check_field_type_for_ffi(cache, field, args) { + all_phantom &= match self.check_field_type_for_ffi(acc, field, args) { FfiSafe => false, // `()` fields are FFI-safe! FfiUnsafe { ty, .. } if ty.is_unit() => false, @@ -1277,7 +1285,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Checks if the given type is "ffi-safe" (has a stable, well-defined /// representation which can be exported to C code). - fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult<'tcx> { + fn check_type_for_ffi( + &self, + acc: &mut CTypesVisitorState<'tcx>, + ty: Ty<'tcx>, + ) -> FfiResult<'tcx> { use FfiResult::*; let tcx = self.cx.tcx; @@ -1286,7 +1298,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // `struct S(*mut S);`. // FIXME: A recursion limit is necessary as well, for irregular // recursive types. - if !cache.insert(ty) { + if !acc.cache.insert(ty) { return FfiSafe; } @@ -1308,6 +1320,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } match def.adt_kind() { AdtKind::Struct | AdtKind::Union => { + if let Some(sym::cstring_type | sym::cstr_type) = + tcx.get_diagnostic_name(def.did()) + && !acc.base_ty.is_mutable_ptr() + { + return FfiUnsafe { + ty, + reason: fluent::lint_improper_ctypes_cstr_reason, + help: Some(fluent::lint_improper_ctypes_cstr_help), + }; + } + if !def.repr().c() && !def.repr().transparent() { return FfiUnsafe { ty, @@ -1354,7 +1377,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } - self.check_variant_for_ffi(cache, ty, def, def.non_enum_variant(), args) + self.check_variant_for_ffi(acc, ty, def, def.non_enum_variant(), args) } AdtKind::Enum => { if def.variants().is_empty() { @@ -1378,7 +1401,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if let Some(ty) = repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode) { - return self.check_type_for_ffi(cache, ty); + return self.check_type_for_ffi(acc, ty); } return FfiUnsafe { @@ -1399,7 +1422,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } - match self.check_variant_for_ffi(cache, ty, def, variant, args) { + match self.check_variant_for_ffi(acc, ty, def, variant, args) { FfiSafe => (), r => return r, } @@ -1469,9 +1492,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiSafe } - ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(cache, ty), + ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(acc, ty), - ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty), + ty::Array(inner_ty, _) => self.check_type_for_ffi(acc, inner_ty), ty::FnPtr(sig_tys, hdr) => { let sig = sig_tys.with(hdr); @@ -1485,7 +1508,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let sig = tcx.instantiate_bound_regions_with_erased(sig); for arg in sig.inputs() { - match self.check_type_for_ffi(cache, *arg) { + match self.check_type_for_ffi(acc, *arg) { FfiSafe => {} r => return r, } @@ -1496,7 +1519,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiSafe; } - self.check_type_for_ffi(cache, ret_ty) + self.check_type_for_ffi(acc, ret_ty) } ty::Foreign(..) => FfiSafe, @@ -1619,7 +1642,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return; } - match self.check_type_for_ffi(&mut FxHashSet::default(), ty) { + let mut acc = CTypesVisitorState { cache: FxHashSet::default(), base_ty: ty }; + match self.check_type_for_ffi(&mut acc, ty) { FfiResult::FfiSafe => {} FfiResult::FfiPhantom(ty) => { self.emit_ffi_unsafe_type_lint( diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 56d77c9d1d0..44c72e0c4fe 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -142,7 +142,6 @@ declare_lint_pass! { USELESS_DEPRECATED, WARNINGS, WASM_C_ABI, - WRITES_THROUGH_IMMUTABLE_POINTER, // tidy-alphabetical-end ] } @@ -251,7 +250,7 @@ declare_lint! { Deny, "conflicts between `#[repr(..)]` hints that were previously accepted and used in practice", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #68585 <https://github.com/rust-lang/rust/issues/68585>", }; } @@ -4697,40 +4696,6 @@ declare_lint! { } declare_lint! { - /// The `writes_through_immutable_pointer` lint detects writes through pointers derived from - /// shared references. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![feature(const_mut_refs)] - /// const WRITE_AFTER_CAST: () = unsafe { - /// let mut x = 0; - /// let ptr = &x as *const i32 as *mut i32; - /// *ptr = 0; - /// }; - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Shared references are immutable (when there is no `UnsafeCell` involved), - /// and writing through them or through pointers derived from them is Undefined Behavior. - /// The compiler recently learned to detect such Undefined Behavior during compile-time - /// evaluation, and in the future this will raise a hard error. - /// - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub WRITES_THROUGH_IMMUTABLE_POINTER, - Warn, - "shared references are immutable, and pointers derived from them must not be written to", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #X <https://github.com/rust-lang/rust/issues/X>", - }; -} - -declare_lint! { /// The `private_macro_use` lint detects private macros that are imported /// with `#[macro_use]`. /// diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index 83fda7ef07c..1f74aaf9965 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -10,5 +10,5 @@ libc = "0.2.73" [build-dependencies] # tidy-alphabetical-start -cc = "1.0.97" +cc = "=1.0.105" # FIXME(cc): pinned to keep support for VS2013 # tidy-alphabetical-end diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 283c4fbbb7c..9884ed15b8a 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1607,8 +1607,13 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, const auto &ExportList = Data->ExportLists.lookup(ModId); const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId); const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId); +#if LLVM_VERSION_GE(20, 0) + DenseSet<GlobalValue::GUID> CfiFunctionDefs; + DenseSet<GlobalValue::GUID> CfiFunctionDecls; +#else std::set<GlobalValue::GUID> CfiFunctionDefs; std::set<GlobalValue::GUID> CfiFunctionDecls; +#endif // Based on the 'InProcessThinBackend' constructor in LLVM for (auto &Name : Data->Index.cfiFunctionDefs()) @@ -1618,9 +1623,15 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, CfiFunctionDecls.insert( GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); +#if LLVM_VERSION_GE(20, 0) + Key = llvm::computeLTOCacheKey(conf, Data->Index, ModId, ImportList, + ExportList, ResolvedODR, DefinedGlobals, + CfiFunctionDefs, CfiFunctionDecls); +#else llvm::computeLTOCacheKey(Key, conf, Data->Index, ModId, ImportList, ExportList, ResolvedODR, DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls); +#endif LLVMRustStringWriteImpl(KeyOut, Key.c_str(), Key.size()); } diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 25ae7b2bc31..90228db378a 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -1002,11 +1002,7 @@ impl CrateError { if !locator.crate_rejections.via_filename.is_empty() { let mismatches = locator.crate_rejections.via_filename.iter(); for CrateMismatch { path, .. } in mismatches { - dcx.emit_err(errors::CrateLocationUnknownType { - span, - path: path, - crate_name, - }); + dcx.emit_err(errors::CrateLocationUnknownType { span, path, crate_name }); dcx.emit_err(errors::LibFilenameForm { span, dll_prefix: &locator.dll_prefix, @@ -1035,7 +1031,7 @@ impl CrateError { } dcx.emit_err(errors::NewerCrateVersion { span, - crate_name: crate_name, + crate_name, add_info, found_crates, }); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 8c0ea3eaea9..a13eac08c9f 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1487,7 +1487,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, sess)) } - fn get_foreign_modules(self, sess: &'a Session) -> impl Iterator<Item = ForeignModule> + '_ { + fn get_foreign_modules(self, sess: &'a Session) -> impl Iterator<Item = ForeignModule> + 'a { self.root.foreign_modules.decode((self, sess)) } diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 61348cdce23..5c2aa0005d4 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -160,7 +160,7 @@ pub struct TypeLengthLimit { pub span: Span, pub shrunk: String, #[note(middle_written_to_path)] - pub was_written: Option<()>, + pub was_written: bool, pub path: PathBuf, pub type_length: usize, } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 5bd7736a3f3..6886562d9b7 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -34,6 +34,7 @@ #![feature(allocator_api)] #![feature(array_windows)] #![feature(assert_matches)] +#![feature(box_as_ptr)] #![feature(box_patterns)] #![feature(closure_track_caller)] #![feature(const_option)] diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index a4f6d7afe4d..32e2f3b4b16 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{ItemLocalId, OwnerId}; use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable}; @@ -11,9 +11,9 @@ use crate::ty; #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] pub enum ResolvedArg { StaticLifetime, - EarlyBound(/* decl */ DefId), - LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ DefId), - Free(DefId, /* lifetime decl */ DefId), + EarlyBound(/* decl */ LocalDefId), + LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ LocalDefId), + Free(LocalDefId, /* lifetime decl */ LocalDefId), Error(ErrorGuaranteed), } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 665ab2797f2..3e101c0c635 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -62,13 +62,11 @@ impl AllocBytes for Box<[u8]> { } fn as_mut_ptr(&mut self) -> *mut u8 { - // Carefully avoiding any intermediate references. - ptr::addr_of_mut!(**self).cast() + Box::as_mut_ptr(self).cast() } fn as_ptr(&self) -> *const u8 { - // Carefully avoiding any intermediate references. - ptr::addr_of!(**self).cast() + Box::as_ptr(self).cast() } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 46c4d586f6a..5b2aac781eb 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1368,7 +1368,7 @@ rustc_index::newtype_index! { /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg /// [data-flow analyses]: /// https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis - /// [`CriticalCallEdges`]: ../../rustc_const_eval/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges + /// [`CriticalCallEdges`]: ../../rustc_mir_transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/ #[derive(HashStable)] #[encodable] diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 51b4154ddab..748ca047754 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -395,7 +395,7 @@ pub enum StatementKind<'tcx> { /// `PlaceMention(PLACE)`. /// /// When executed at runtime, this computes the given place, but then discards - /// it without doing a load. It is UB if the place is not pointing to live memory. + /// it without doing a load. `let _ = *ptr;` is fine even if the pointer is dangling. PlaceMention(Box<Place<'tcx>>), /// Encodes a user's type ascription. These need to be preserved diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index d54e2ca0a74..a3277fb96d2 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -353,7 +353,7 @@ pub enum ObligationCauseCode<'tcx> { ReturnValue(HirId), /// Opaque return type of this function - OpaqueReturnType(Option<(Ty<'tcx>, Span)>), + OpaqueReturnType(Option<(Ty<'tcx>, HirId)>), /// Block implicit return BlockTailExpression(HirId, hir::MatchSource), diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index e373292741b..362ff8e988d 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -240,7 +240,7 @@ impl<'tcx> Const<'tcx> { let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic"); - match Self::try_from_lit(tcx, ty, expr) { + match Self::try_from_lit_or_param(tcx, ty, expr) { Some(v) => v, None => ty::Const::new_unevaluated( tcx, @@ -281,7 +281,11 @@ impl<'tcx> Const<'tcx> { } #[instrument(skip(tcx), level = "debug")] - fn try_from_lit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>) -> Option<Self> { + fn try_from_lit_or_param( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + ) -> Option<Self> { // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments // currently have to be wrapped in curly brackets, so it's necessary to special-case. let expr = match &expr.kind { @@ -291,6 +295,22 @@ impl<'tcx> Const<'tcx> { _ => expr, }; + if let hir::ExprKind::Path( + qpath @ hir::QPath::Resolved( + _, + &hir::Path { res: Res::Def(DefKind::ConstParam, _), .. }, + ), + ) = expr.kind + { + if tcx.features().const_arg_path { + span_bug!( + expr.span, + "try_from_lit: received const param which shouldn't be possible" + ); + } + return Some(Const::from_param(tcx, qpath, expr.hir_id)); + }; + let lit_input = match expr.kind { hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind { @@ -318,14 +338,6 @@ impl<'tcx> Const<'tcx> { } } - if let hir::ExprKind::Path(hir::QPath::Resolved( - _, - &hir::Path { res: Res::Def(DefKind::ConstParam, _), .. }, - )) = expr.kind - { - span_bug!(expr.span, "try_from_lit: received const param which shouldn't be possible") - } - None } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9b39b849704..cad3515f068 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3035,13 +3035,13 @@ impl<'tcx> TyCtxt<'tcx> { match self.named_bound_var(lifetime.hir_id) { Some(resolve_bound_vars::ResolvedArg::EarlyBound(ebv)) => { - let new_parent = self.parent(ebv); + let new_parent = self.local_parent(ebv); // If we map to another opaque, then it should be a parent // of the opaque we mapped from. Continue mapping. if matches!(self.def_kind(new_parent), DefKind::OpaqueTy) { - debug_assert_eq!(self.parent(parent.to_def_id()), new_parent); - opaque_lifetime_param_def_id = ebv.expect_local(); + debug_assert_eq!(self.local_parent(parent), new_parent); + opaque_lifetime_param_def_id = ebv; continue; } @@ -3050,20 +3050,20 @@ impl<'tcx> TyCtxt<'tcx> { self, ty::EarlyParamRegion { index: generics - .param_def_id_to_index(self, ebv) + .param_def_id_to_index(self, ebv.to_def_id()) .expect("early-bound var should be present in fn generics"), - name: self.hir().name(self.local_def_id_to_hir_id(ebv.expect_local())), + name: self.item_name(ebv.to_def_id()), }, ); } Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => { - let new_parent = self.parent(lbv); + let new_parent = self.local_parent(lbv); return ty::Region::new_late_param( self, - new_parent, + new_parent.to_def_id(), ty::BoundRegionKind::BrNamed( - lbv, - self.hir().name(self.local_def_id_to_hir_id(lbv.expect_local())), + lbv.to_def_id(), + self.item_name(lbv.to_def_id()), ), ); } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 8cb8e9af11c..bbc696e0f08 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -269,7 +269,7 @@ impl<'tcx> Generics { } /// Returns the `GenericParamDef` associated with this `ParamConst`. - pub fn const_param(&'tcx self, param: ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef { + pub fn const_param(&'tcx self, param: ParamConst, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef { let param = self.param_at(param.index as usize, tcx); match param.kind { GenericParamDefKind::Const { .. } => param, diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 6f19739de45..ecb3943e788 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -581,9 +581,9 @@ impl<'tcx> Instance<'tcx> { let mut path = PathBuf::new(); let was_written = if let Some(path2) = written_to_path { path = path2; - Some(()) + true } else { - None + false }; tcx.dcx().emit_fatal(error::TypeLengthLimit { // We don't use `def_span(def_id)` so that diagnostics point diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 619981bf021..d0a9039441d 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1104,7 +1104,7 @@ where } fn is_never(this: TyAndLayout<'tcx>) -> bool { - this.ty.kind() == &ty::Never + matches!(this.ty.kind(), ty::Never) } fn is_tuple(this: TyAndLayout<'tcx>) -> bool { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 319fb7ef03b..f1ff90831b0 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3119,7 +3119,10 @@ define_print! { ty::ExistentialProjection<'tcx> { let name = cx.tcx().associated_item(self.def_id).name; - p!(write("{} = ", name), print(self.term)) + // The args don't contain the self ty (as it has been erased) but the corresp. + // generics do as the trait always has a self ty param. We need to offset. + let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..]; + p!(path_generic_args(|cx| write!(cx, "{name}"), args), " = ", print(self.term)) } ty::ProjectionPredicate<'tcx> { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 045c8ad39be..efbccca77c1 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -296,7 +296,7 @@ impl<'tcx> TyCtxt<'tcx> { ) -> (Ty<'tcx>, Ty<'tcx>) { let (mut a, mut b) = (source, target); loop { - match (&a.kind(), &b.kind()) { + match (a.kind(), b.kind()) { (&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args)) if a_def == b_def && a_def.is_struct() => { diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 7baf0256dd8..7a10e627ccd 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -327,14 +327,17 @@ mir_build_union_pattern = cannot use unions in constant patterns mir_build_unreachable_making_this_unreachable = collectively making this unreachable +mir_build_unreachable_making_this_unreachable_n_more = ...and {$covered_by_many_n_more_count} other patterns collectively make this unreachable + mir_build_unreachable_matches_same_values = matches some of the same values mir_build_unreachable_pattern = unreachable pattern - .label = unreachable pattern - .unreachable_matches_no_values = this pattern matches no values because `{$ty}` is uninhabited + .label = no value can reach this + .unreachable_matches_no_values = matches no values because `{$matches_no_values_ty}` is uninhabited + .unreachable_uninhabited_note = to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types .unreachable_covered_by_catchall = matches any value - .unreachable_covered_by_one = matches all the values already - .unreachable_covered_by_many = these patterns collectively make the last one unreachable + .unreachable_covered_by_one = matches all the relevant values + .unreachable_covered_by_many = multiple earlier patterns match some of the same values mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default mir_build_unsafe_not_inherited = items do not inherit unsafety from separate enclosing items diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 4430aab73a8..4f1166f9111 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -127,7 +127,7 @@ fn lit_to_mir_constant<'tcx>( Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) }; - let value = match (lit, &ty.kind()) { + let value = match (lit, ty.kind()) { (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { let s = s.as_str(); let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes()); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 8546a2539d7..693037d03e0 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -748,7 +748,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate(block, source_info, TerminatorKind::UnwindResume); } - /// Sets up the drops for explict tail calls. + /// Sets up the drops for explicit tail calls. /// /// Unlike other kinds of early exits, tail calls do not go through the drop tree. /// Instead, all scheduled drops are immediately added to the CFG. diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index e4e5844d2ef..b6cf7a40ecd 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -793,7 +793,7 @@ impl UnsafeOpKind { missing.iter().map(|feature| Cow::from(feature.to_string())).collect(), ), missing_target_features_count: missing.len(), - note: if build_enabled.is_empty() { None } else { Some(()) }, + note: !build_enabled.is_empty(), build_target_features: DiagArgValue::StrListSepByAnd( build_enabled .iter() @@ -958,7 +958,7 @@ impl UnsafeOpKind { missing.iter().map(|feature| Cow::from(feature.to_string())).collect(), ), missing_target_features_count: missing.len(), - note: if build_enabled.is_empty() { None } else { Some(()) }, + note: !build_enabled.is_empty(), build_target_features: DiagArgValue::StrListSepByAnd( build_enabled .iter() @@ -977,7 +977,7 @@ impl UnsafeOpKind { missing.iter().map(|feature| Cow::from(feature.to_string())).collect(), ), missing_target_features_count: missing.len(), - note: if build_enabled.is_empty() { None } else { Some(()) }, + note: !build_enabled.is_empty(), build_target_features: DiagArgValue::StrListSepByAnd( build_enabled .iter() diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 34577f102d1..7f9eefd1d52 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -161,7 +161,7 @@ pub(crate) struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { pub(crate) missing_target_features: DiagArgValue, pub(crate) missing_target_features_count: usize, #[note] - pub(crate) note: Option<()>, + pub(crate) note: bool, pub(crate) build_target_features: DiagArgValue, pub(crate) build_target_features_count: usize, #[subdiagnostic] @@ -413,7 +413,7 @@ pub(crate) struct CallToFunctionWithRequiresUnsafe { pub(crate) missing_target_features: DiagArgValue, pub(crate) missing_target_features_count: usize, #[note] - pub(crate) note: Option<()>, + pub(crate) note: bool, pub(crate) build_target_features: DiagArgValue, pub(crate) build_target_features_count: usize, #[subdiagnostic] @@ -431,7 +431,7 @@ pub(crate) struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { pub(crate) missing_target_features: DiagArgValue, pub(crate) missing_target_features_count: usize, #[note] - pub(crate) note: Option<()>, + pub(crate) note: bool, pub(crate) build_target_features: DiagArgValue, pub(crate) build_target_features_count: usize, #[subdiagnostic] @@ -493,7 +493,7 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> { } impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { - fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'_, G> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let mut diag = Diag::new(dcx, level, fluent::mir_build_non_exhaustive_patterns_type_not_empty); diag.span(self.scrut_span); @@ -586,20 +586,18 @@ pub(crate) struct NonConstPath { pub(crate) struct UnreachablePattern<'tcx> { #[label] pub(crate) span: Option<Span>, - #[subdiagnostic] - pub(crate) matches_no_values: Option<UnreachableMatchesNoValues<'tcx>>, + #[label(mir_build_unreachable_matches_no_values)] + pub(crate) matches_no_values: Option<Span>, + pub(crate) matches_no_values_ty: Ty<'tcx>, + #[note(mir_build_unreachable_uninhabited_note)] + pub(crate) uninhabited_note: Option<()>, #[label(mir_build_unreachable_covered_by_catchall)] pub(crate) covered_by_catchall: Option<Span>, #[label(mir_build_unreachable_covered_by_one)] pub(crate) covered_by_one: Option<Span>, #[note(mir_build_unreachable_covered_by_many)] pub(crate) covered_by_many: Option<MultiSpan>, -} - -#[derive(Subdiagnostic)] -#[note(mir_build_unreachable_matches_no_values)] -pub(crate) struct UnreachableMatchesNoValues<'tcx> { - pub(crate) ty: Ty<'tcx>, + pub(crate) covered_by_many_n_more_count: usize, } #[derive(Diagnostic)] @@ -623,7 +621,7 @@ pub(crate) struct LowerRangeBoundMustBeLessThanOrEqualToUpper { #[label] pub(crate) span: Span, #[note(mir_build_teach_note)] - pub(crate) teach: Option<()>, + pub(crate) teach: bool, } #[derive(Diagnostic)] @@ -865,7 +863,7 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { #[subdiagnostic] pub(crate) adt_defined_here: Option<AdtDefinedHere<'tcx>>, #[note(mir_build_privately_uninhabited)] - pub(crate) witness_1_is_privately_uninhabited: Option<()>, + pub(crate) witness_1_is_privately_uninhabited: bool, #[note(mir_build_pattern_ty)] pub(crate) _p: (), pub(crate) pattern_ty: Ty<'tcx>, diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 7b94867114d..b8877a64e47 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -29,7 +29,7 @@ pub(crate) fn lit_to_const<'tcx>( .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result))) }; - let valtree = match (lit, &ty.kind()) { + let valtree = match (lit, ty.kind()) { (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { let str_bytes = s.as_str().as_bytes(); ty::ValTree::from_raw_bytes(tcx, str_bytes) diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 2cbaed2cc62..89f98a40201 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -218,12 +218,7 @@ impl<'tcx> Cx<'tcx> { let lhs = self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind }); let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset }; - self.thir.exprs.push(Expr { - temp_lifetime, - ty: discr_ty, - span: span, - kind: bin, - }) + self.thir.exprs.push(Expr { temp_lifetime, ty: discr_ty, span, kind: bin }) } None => offset, }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index bc1acd51c69..4c066a68ef9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -718,7 +718,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { uncovered: Uncovered::new(pat.span, &cx, witnesses), inform, interpreted_as_const, - witness_1_is_privately_uninhabited: witness_1_is_privately_uninhabited.then_some(()), + witness_1_is_privately_uninhabited, _p: (), pattern_ty, let_suggestion, @@ -917,22 +917,28 @@ fn report_unreachable_pattern<'p, 'tcx>( pat: &DeconstructedPat<'p, 'tcx>, explanation: &RedundancyExplanation<'p, 'tcx>, ) { + static CAP_COVERED_BY_MANY: usize = 4; let pat_span = pat.data().span; let mut lint = UnreachablePattern { span: Some(pat_span), matches_no_values: None, + matches_no_values_ty: **pat.ty(), + uninhabited_note: None, covered_by_catchall: None, covered_by_one: None, covered_by_many: None, + covered_by_many_n_more_count: 0, }; match explanation.covered_by.as_slice() { [] => { // Empty pattern; we report the uninhabited type that caused the emptiness. lint.span = None; // Don't label the pattern itself + lint.uninhabited_note = Some(()); // Give a link about empty types + lint.matches_no_values = Some(pat_span); pat.walk(&mut |subpat| { let ty = **subpat.ty(); if cx.is_uninhabited(ty) { - lint.matches_no_values = Some(UnreachableMatchesNoValues { ty }); + lint.matches_no_values_ty = ty; false // No need to dig further. } else if matches!(subpat.ctor(), Constructor::Ref | Constructor::UnionField) { false // Don't explore further since they are not by-value. @@ -948,15 +954,27 @@ fn report_unreachable_pattern<'p, 'tcx>( lint.covered_by_one = Some(covering_pat.data().span); } covering_pats => { + let mut iter = covering_pats.iter(); let mut multispan = MultiSpan::from_span(pat_span); - for p in covering_pats { + for p in iter.by_ref().take(CAP_COVERED_BY_MANY) { multispan.push_span_label( p.data().span, fluent::mir_build_unreachable_matches_same_values, ); } - multispan - .push_span_label(pat_span, fluent::mir_build_unreachable_making_this_unreachable); + let remain = iter.count(); + if remain == 0 { + multispan.push_span_label( + pat_span, + fluent::mir_build_unreachable_making_this_unreachable, + ); + } else { + lint.covered_by_many_n_more_count = remain; + multispan.push_span_label( + pat_span, + fluent::mir_build_unreachable_making_this_unreachable_n_more, + ); + } lint.covered_by_many = Some(multispan); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 6f8d17b772a..53393046610 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -129,7 +129,7 @@ impl<'tcx> ConstToPat<'tcx> { let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty }; let e = self.tcx().dcx().emit_err(err); let kind = PatKind::Error(e); - return Box::new(Pat { span: self.span, ty: ty, kind }); + return Box::new(Pat { span: self.span, ty, kind }); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 615070034b9..d78e1f5da09 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -256,7 +256,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { RangeEnd::Included => { self.tcx.dcx().emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { span, - teach: self.tcx.sess.teach(E0030).then_some(()), + teach: self.tcx.sess.teach(E0030), }) } RangeEnd::Excluded => { diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 82528109be9..703339bf5bc 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -931,7 +931,7 @@ fn compute_storage_conflicts<'mir, 'tcx>( // Compute the storage conflicts for all eligible locals. let mut visitor = StorageConflictVisitor { body, - saved_locals: saved_locals, + saved_locals, local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()), eligible_storage_live: BitSet::new_empty(body.local_decls.len()), }; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 0fc4d6b9f4e..f207216d6f4 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -338,7 +338,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { tcx, local_decls: &body.local_decls, ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine), - param_env: param_env, + param_env, } } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 0ae635f9b73..ff4207fbefd 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -580,9 +580,9 @@ fn check_recursion_limit<'tcx>( let mut path = PathBuf::new(); let was_written = if let Some(written_to_path) = written_to_path { path = written_to_path; - Some(()) + true } else { - None + false }; tcx.dcx().emit_fatal(RecursionLimit { span, @@ -888,7 +888,9 @@ fn visit_instance_use<'tcx>( if tcx.should_codegen_locally(panic_instance) { output.push(create_fn_mono_item(tcx, panic_instance, source)); } - } else if tcx.has_attr(def_id, sym::rustc_intrinsic) { + } else if tcx.has_attr(def_id, sym::rustc_intrinsic) + && !tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden) + { // Codegen the fallback body of intrinsics with fallback bodies let instance = ty::Instance::new(def_id, instance.args); if tcx.should_codegen_locally(instance) { @@ -1033,9 +1035,9 @@ fn find_vtable_types_for_unsizing<'tcx>( } }; - match (&source_ty.kind(), &target_ty.kind()) { + match (source_ty.kind(), target_ty.kind()) { (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _)) - | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(*a, *b), + | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(a, b), (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => { ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) } diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 88286cb73a6..c97e07ee3ba 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -16,7 +16,7 @@ pub struct RecursionLimit { pub def_span: Span, pub def_path_str: String, #[note(monomorphize_written_to_path)] - pub was_written: Option<()>, + pub was_written: bool, pub path: PathBuf, } diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 0d4512be480..abaff7d9c19 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -913,7 +913,7 @@ pub(crate) struct InvalidLiteralSuffixOnTupleIndex { #[help(parse_tuple_exception_line_1)] #[help(parse_tuple_exception_line_2)] #[help(parse_tuple_exception_line_3)] - pub exception: Option<()>, + pub exception: bool, } #[derive(Diagnostic)] @@ -1299,7 +1299,7 @@ pub(crate) struct ComparisonOperatorsCannotBeChained { pub suggest_turbofish: Option<Span>, #[help(parse_sugg_turbofish_syntax)] #[help(parse_sugg_parentheses_for_function_args)] - pub help_turbofish: Option<()>, + pub help_turbofish: bool, #[subdiagnostic] pub chaining_sugg: Option<ComparisonOperatorsCannotBeChainedSugg>, } @@ -1578,7 +1578,7 @@ pub(crate) struct PathSingleColon { pub suggestion: Span, #[note(parse_type_ascription_removed)] - pub type_ascription: Option<()>, + pub type_ascription: bool, } #[derive(Diagnostic)] @@ -1589,7 +1589,7 @@ pub(crate) struct ColonAsSemi { pub span: Span, #[note(parse_type_ascription_removed)] - pub type_ascription: Option<()>, + pub type_ascription: bool, } #[derive(Diagnostic)] @@ -2462,7 +2462,7 @@ pub(crate) struct TrailingVertNotAllowed { pub start: Option<Span>, pub token: Token, #[note(parse_note_pattern_alternatives_use_single_vert)] - pub note_double_vert: Option<()>, + pub note_double_vert: bool, } #[derive(Diagnostic)] @@ -2894,7 +2894,7 @@ pub(crate) struct BadItemKind { pub descr: &'static str, pub ctx: &'static str, #[help] - pub help: Option<()>, + pub help: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 6391ff901cb..c65cf3f40f6 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -76,6 +76,7 @@ impl<'a> Parser<'a> { token::CommentKind::Line => OuterAttributeType::DocComment, token::CommentKind::Block => OuterAttributeType::DocBlockComment, }, + true, ) { err.note(fluent::parse_note); err.span_suggestion_verbose( @@ -139,7 +140,11 @@ impl<'a> Parser<'a> { // Emit error if inner attribute is encountered and forbidden. if style == ast::AttrStyle::Inner { - this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy); + this.error_on_forbidden_inner_attr( + attr_sp, + inner_parse_policy, + item.is_valid_for_outer_style(), + ); } Ok(attr::mk_attr_from_item(&self.psess.attr_id_generator, item, None, style, attr_sp)) @@ -151,6 +156,7 @@ impl<'a> Parser<'a> { err: &mut Diag<'_>, span: Span, attr_type: OuterAttributeType, + suggest_to_outer: bool, ) -> Option<Span> { let mut snapshot = self.create_snapshot_for_diagnostic(); let lo = span.lo() @@ -185,16 +191,18 @@ impl<'a> Parser<'a> { // FIXME(#100717) err.arg("item", item.kind.descr()); err.span_label(item.span, fluent::parse_label_does_not_annotate_this); - err.span_suggestion_verbose( - replacement_span, - fluent::parse_sugg_change_inner_to_outer, - match attr_type { - OuterAttributeType::Attribute => "", - OuterAttributeType::DocBlockComment => "*", - OuterAttributeType::DocComment => "/", - }, - rustc_errors::Applicability::MachineApplicable, - ); + if suggest_to_outer { + err.span_suggestion_verbose( + replacement_span, + fluent::parse_sugg_change_inner_to_outer, + match attr_type { + OuterAttributeType::Attribute => "", + OuterAttributeType::DocBlockComment => "*", + OuterAttributeType::DocComment => "/", + }, + rustc_errors::Applicability::MachineApplicable, + ); + } return None; } Err(item_err) => { @@ -205,7 +213,12 @@ impl<'a> Parser<'a> { Some(replacement_span) } - pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy) { + pub(super) fn error_on_forbidden_inner_attr( + &self, + attr_sp: Span, + policy: InnerAttrPolicy, + suggest_to_outer: bool, + ) { if let InnerAttrPolicy::Forbidden(reason) = policy { let mut diag = match reason.as_ref().copied() { Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => { @@ -239,6 +252,7 @@ impl<'a> Parser<'a> { &mut diag, attr_sp, OuterAttributeType::Attribute, + suggest_to_outer, ) .is_some() { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ef1387c50fa..fcdc10c0837 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1403,7 +1403,7 @@ impl<'a> Parser<'a> { let mut err = ComparisonOperatorsCannotBeChained { span: vec![op.span, self.prev_token.span], suggest_turbofish: None, - help_turbofish: None, + help_turbofish: false, chaining_sugg: None, }; @@ -1436,7 +1436,7 @@ impl<'a> Parser<'a> { { err.suggest_turbofish = Some(op.span.shrink_to_lo()); } else { - err.help_turbofish = Some(()); + err.help_turbofish = true; } let snapshot = self.create_snapshot_for_diagnostic(); @@ -1468,7 +1468,7 @@ impl<'a> Parser<'a> { { err.suggest_turbofish = Some(op.span.shrink_to_lo()); } else { - err.help_turbofish = Some(()); + err.help_turbofish = true; } // Consume the fn call arguments. match self.consume_fn_args() { @@ -1487,7 +1487,7 @@ impl<'a> Parser<'a> { { // All we know is that this is `foo < bar >` and *nothing* else. Try to // be helpful, but don't attempt to recover. - err.help_turbofish = Some(()); + err.help_turbofish = true; } // If it looks like a genuine attempt to chain operators (as opposed to a @@ -1895,7 +1895,7 @@ impl<'a> Parser<'a> { { self.dcx().emit_err(ColonAsSemi { span: self.token.span, - type_ascription: self.psess.unstable_features.is_nightly_build().then_some(()), + type_ascription: self.psess.unstable_features.is_nightly_build(), }); self.bump(); return true; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 422206ebbce..84684e808d9 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2162,13 +2162,13 @@ impl<'a> Parser<'a> { self.dcx().emit_warn(errors::InvalidLiteralSuffixOnTupleIndex { span, suffix, - exception: Some(()), + exception: true, }); } else { self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { span, suffix, - exception: None, + exception: false, }); } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 47820e93c23..14da6c331f1 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1248,8 +1248,8 @@ impl<'a> Parser<'a> { let span = self.psess.source_map().guess_head_span(span); let descr = kind.descr(); let help = match kind { - ItemKind::DelegationMac(deleg) if deleg.suffixes.is_none() => None, - _ => Some(()), + ItemKind::DelegationMac(deleg) if deleg.suffixes.is_none() => false, + _ => true, }; self.dcx().emit_err(errors::BadItemKind { span, descr, ctx, help }); None diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index eb9a957032f..cc68ae237ba 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -333,7 +333,7 @@ impl<'a> Parser<'a> { span: self.token.span, start: lo, token: self.token.clone(), - note_double_vert: matches!(self.token.kind, token::OrOr).then_some(()), + note_double_vert: matches!(self.token.kind, token::OrOr), }); self.bump(); true diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index b58f398efed..d8bf10e6021 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -261,11 +261,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(PathSingleColon { span: self.prev_token.span, suggestion: self.prev_token.span.shrink_to_hi(), - type_ascription: self - .psess - .unstable_features - .is_nightly_build() - .then_some(()), + type_ascription: self.psess.unstable_features.is_nightly_build(), }); } continue; @@ -334,11 +330,7 @@ impl<'a> Parser<'a> { err = self.dcx().create_err(PathSingleColon { span: self.token.span, suggestion: self.prev_token.span.shrink_to_hi(), - type_ascription: self - .psess - .unstable_features - .is_nightly_build() - .then_some(()), + type_ascription: self.psess.unstable_features.is_nightly_build(), }); } // Attempt to find places where a missing `>` might belong. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 69044192780..26ad39e06cd 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -459,11 +459,16 @@ impl<'a> Parser<'a> { pub fn parse_block(&mut self) -> PResult<'a, P<Block>> { let (attrs, block) = self.parse_inner_attrs_and_block()?; if let [.., last] = &*attrs { + let suggest_to_outer = match &last.kind { + ast::AttrKind::Normal(attr) => attr.item.is_valid_for_outer_style(), + _ => false, + }; self.error_on_forbidden_inner_attr( last.span, super::attr::InnerAttrPolicy::Forbidden(Some( InnerAttrForbiddenReason::InCodeBlock, )), + suggest_to_outer, ); } Ok(block) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a8e8270673a..52f0b1c1b04 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -851,7 +851,6 @@ impl<'a> Parser<'a> { // lifetimes and ident params (including SelfUpper). These are validated later // for order, duplication, and whether they actually reference params. let use_span = self.prev_token.span; - self.psess.gated_spans.gate(sym::precise_capturing, use_span); let (args, args_span) = self.parse_precise_capturing_args()?; GenericBound::Use(args, use_span.to(args_span)) } else { diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index dfc726efeb9..e7f208d5ad5 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -481,10 +481,6 @@ passes_must_not_suspend = `must_not_suspend` attribute should be applied to a struct, enum, union, or trait .label = is not a struct, enum, union, or trait -passes_must_use_async = - `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within - .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use` - passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target} @@ -657,6 +653,10 @@ passes_rustc_lint_opt_ty = `#[rustc_lint_opt_ty]` should be applied to a struct .label = not a struct +passes_rustc_pub_transparent = + attribute should be applied to `#[repr(transparent)]` types + .label = not a `#[repr(transparent)]` type + passes_rustc_safe_intrinsic = attribute should be applied to intrinsic functions .label = not an intrinsic function diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index e3c2999142f..d1dac9ca6da 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -245,6 +245,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_coroutine(attr, target); } [sym::linkage, ..] => self.check_linkage(attr, span, target), + [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent( attr.span, span, attrs), [ // ok sym::allow @@ -951,6 +952,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> { bare_fn_ty.decl.inputs.len() == 1 } else { false + } + || if let Some(&[hir::GenericArg::Type(ty)]) = i + .of_trait + .as_ref() + .and_then(|trait_ref| trait_ref.path.segments.last()) + .map(|last_segment| last_segment.args().args) + { + matches!(&ty.kind, hir::TyKind::Tup([_])) + } else { + false }; if !is_valid { self.dcx().emit_err(errors::DocFakeVariadicNotValid { span: meta.span() }); @@ -2381,6 +2392,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } + + fn check_rustc_pub_transparent(&self, attr_span: Span, span: Span, attrs: &[Attribute]) { + if !attrs + .iter() + .filter(|attr| attr.has_name(sym::repr)) + .filter_map(|attr| attr.meta_item_list()) + .flatten() + .any(|nmi| nmi.has_name(sym::transparent)) + { + self.dcx().emit_err(errors::RustcPubTransparent { span, attr_span }); + } + } } impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { @@ -2619,8 +2642,7 @@ fn check_duplicates( warning: matches!( duplicates, FutureWarnFollowing | FutureWarnPreceding - ) - .then_some(()), + ), }, ); } diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 659281c5e71..624ebb2f9f2 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -49,7 +49,7 @@ fn report_duplicate_item( orig_span, crate_name: tcx.crate_name(item_def_id.krate), orig_crate_name: tcx.crate_name(original_def_id.krate), - different_crates: (item_def_id.krate != original_def_id.krate).then_some(()), + different_crates: (item_def_id.krate != original_def_id.krate), name, }); } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index ee7d097e5d3..1202351bdcd 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -372,13 +372,6 @@ pub struct FfiConstInvalidTarget { } #[derive(LintDiagnostic)] -#[diag(passes_must_use_async)] -pub struct MustUseAsync { - #[label] - pub span: Span, -} - -#[derive(LintDiagnostic)] #[diag(passes_must_use_no_effect)] pub struct MustUseNoEffect { pub article: &'static str, @@ -623,6 +616,15 @@ pub struct RustcStdInternalSymbol { } #[derive(Diagnostic)] +#[diag(passes_rustc_pub_transparent)] +pub struct RustcPubTransparent { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(passes_link_ordinal)] pub struct LinkOrdinal { #[primary_span] @@ -752,7 +754,7 @@ pub struct UnusedDuplicate { #[note] pub other: Span, #[warning] - pub warning: Option<()>, + pub warning: bool, } #[derive(Diagnostic)] @@ -911,7 +913,7 @@ pub struct DuplicateDiagnosticItemInCrate { #[note(passes_diagnostic_item_first_defined)] pub orig_span: Option<Span>, #[note] - pub different_crates: Option<()>, + pub different_crates: bool, pub crate_name: Symbol, pub orig_crate_name: Symbol, pub name: Symbol, diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 18f97d6fb8f..f4a4c602f69 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -214,7 +214,7 @@ pub fn query_system<'tcx>( local_providers, extern_providers, encode_query_results: encode_all_query_results, - try_mark_green: try_mark_green, + try_mark_green, }, jobs: AtomicU64::new(1), } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index ff1c3431b7c..ab4a8be0fbf 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -547,7 +547,7 @@ impl<D: Deps> EncoderState<D> { /// Encodes a node that was promoted from the previous graph. It reads the information directly from /// the previous dep graph for performance reasons. /// - /// This differs from `encode_node` where you have to explictly provide the relevant `NodeInfo`. + /// This differs from `encode_node` where you have to explicitly provide the relevant `NodeInfo`. /// /// It expects all edges to already have a new dep node index assigned. #[inline] diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d57dabdd78d..fee42ba87c9 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -896,7 +896,8 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.potentially_unused_imports.push(import); let imported_binding = self.r.import(binding, import); if parent == self.r.graph_root { - if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) { + let ident = ident.normalize_to_macros_2_0(); + if let Some(entry) = self.r.extern_prelude.get(&ident) { if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() { self.r.dcx().emit_err( errors::MacroExpandedExternCrateCannotShadowExternArguments { @@ -913,14 +914,21 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let entry = self .r .extern_prelude - .entry(ident.normalize_to_macros_2_0()) + .entry(ident) .or_insert(ExternPreludeEntry { binding: None, introduced_by_item: true }); - // Binding from `extern crate` item in source code can replace - // a binding from `--extern` on command line here. - entry.binding = Some(imported_binding); if orig_name.is_some() { entry.introduced_by_item = true; } + // Binding from `extern crate` item in source code can replace + // a binding from `--extern` on command line here. + if !entry.is_import() { + entry.binding = Some(imported_binding) + } else if ident.name != kw::Underscore { + self.r.dcx().span_delayed_bug( + item.span, + format!("it had been define the external module '{ident}' multiple times"), + ); + } } self.r.define(parent, ident, TypeNS, imported_binding); } @@ -1150,7 +1158,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { for attr in attrs { if attr.has_name(sym::macro_escape) { - let inner_attribute = matches!(attr.style, ast::AttrStyle::Inner).then_some(()); + let inner_attribute = matches!(attr.style, ast::AttrStyle::Inner); self.r .dcx() .emit_warn(errors::MacroExternDeprecated { span: attr.span, inner_attribute }); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index ed23870dfdf..3595db78e93 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -314,13 +314,15 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { } fn visit_anon_const(&mut self, constant: &'a AnonConst) { - // HACK(min_generic_const_args): don't create defs for anon consts if we think they will - // later be turned into ConstArgKind::Path's. because this is before resolve is done, we - // may accidentally identify a construction of a unit struct as a param and not create a - // def. we'll then create a def later in ast lowering in this case. the parent of nested - // items will be messed up, but that's ok because there can't be any if we're just looking - // for bare idents. - if constant.value.is_potential_trivial_const_arg() { + if self.resolver.tcx.features().const_arg_path + && constant.value.is_potential_trivial_const_arg() + { + // HACK(min_generic_const_args): don't create defs for anon consts if we think they will + // later be turned into ConstArgKind::Path's. because this is before resolve is done, we + // may accidentally identify a construction of a unit struct as a param and not create a + // def. we'll then create a def later in ast lowering in this case. the parent of nested + // items will be messed up, but that's ok because there can't be any if we're just looking + // for bare idents. visit::walk_anon_const(self, constant) } else { let def = diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 942026ef012..bcbdf627b56 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1456,7 +1456,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let label_span = ident.span.shrink_to_hi(); let mut spans = MultiSpan::from_span(label_span); spans.push_span_label(label_span, "put a macro name here"); - err.subdiagnostic(MaybeMissingMacroRulesName { spans: spans }); + err.subdiagnostic(MaybeMissingMacroRulesName { spans }); return; } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index ad1841e3e89..662b772413b 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -850,7 +850,7 @@ pub(crate) struct MacroExternDeprecated { #[primary_span] pub(crate) span: Span, #[help] - pub inner_attribute: Option<()>, + pub inner_attribute: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 4a70fc0f308..40fdb01a72c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2677,14 +2677,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // We also can't shadow bindings from associated parent items. for ns in [ValueNS, TypeNS] { for parent_rib in self.ribs[ns].iter().rev() { - seen_bindings - .extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span))); - // Break at mod level, to account for nested items which are // allowed to shadow generic param names. if matches!(parent_rib.kind, RibKind::Module(..)) { break; } + + seen_bindings + .extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span))); } } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index e628c17aca3..2f43199796c 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -146,7 +146,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> { !is_zst }); if let Some(field) = field { - let ty0 = self.tcx.type_of(field.did).instantiate(self.tcx, args); + let ty0 = self.tcx.erase_regions(field.ty(self.tcx, args)); // Generalize any repr(transparent) user-defined type that is either a // pointer or reference, and either references itself or any other type that // contains or references itself, to avoid a reference cycle. @@ -316,7 +316,7 @@ pub fn transform_instance<'tcx>( .drop_trait() .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item")); let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { - def_id: def_id, + def_id, args: List::empty(), }); let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]); diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs index 0519722e4be..677b4c7a9c0 100644 --- a/compiler/rustc_smir/src/rustc_smir/alloc.rs +++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs @@ -132,7 +132,7 @@ pub(super) fn allocation_filter<'tcx>( )); } Allocation { - bytes: bytes, + bytes, provenance: ProvenanceMap { ptrs }, align: alloc.align.bytes(), mutability: alloc.mutability.stable(tables), diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 434df35a515..5e1b1b44bc2 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1415,6 +1415,14 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext // Overwrite the dummy data with our decoded SyntaxContextData HygieneData::with(|hygiene_data| { + if let Some(old) = hygiene_data.syntax_context_data.get(raw_id as usize) + && old.outer_expn == ctxt_data.outer_expn + && old.outer_transparency == ctxt_data.outer_transparency + && old.parent == ctxt_data.parent + { + ctxt_data = old.clone(); + } + let dummy = std::mem::replace( &mut hygiene_data.syntax_context_data[ctxt.as_u32() as usize], ctxt_data, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a2e94492f8c..2957105288b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -595,6 +595,7 @@ symbols! { conservative_impl_trait, console, const_allocate, + const_arg_path, const_async_blocks, const_closures, const_compare_raw_pointers, @@ -673,6 +674,7 @@ symbols! { crate_visibility_modifier, crt_dash_static: "crt-static", csky_target_feature, + cstr_type, cstring_type, ctlz, ctlz_nonzero, @@ -1672,6 +1674,7 @@ symbols! { rustc_private, rustc_proc_macro_decls, rustc_promotable, + rustc_pub_transparent, rustc_reallocator, rustc_regions, rustc_reservation_impl, diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 25e4d70945b..c1ddfcb2f90 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -642,7 +642,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { pub fn make_indirect(&mut self) { match self.mode { PassMode::Direct(_) | PassMode::Pair(_, _) => { - self.make_indirect_force(); + self.mode = Self::indirect_pass_mode(&self.layout); } PassMode::Indirect { attrs: _, meta_attrs: _, on_stack: false } => { // already indirect @@ -652,9 +652,19 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } } - /// Same as make_indirect, but doesn't check the current `PassMode`. - pub fn make_indirect_force(&mut self) { - self.mode = Self::indirect_pass_mode(&self.layout); + /// Same as `make_indirect`, but for arguments that are ignored. Only needed for ABIs that pass + /// ZSTs indirectly. + pub fn make_indirect_from_ignore(&mut self) { + match self.mode { + PassMode::Ignore => { + self.mode = Self::indirect_pass_mode(&self.layout); + } + PassMode::Indirect { attrs: _, meta_attrs: _, on_stack: false } => { + // already indirect + return; + } + _ => panic!("Tried to make {:?} indirect (expected `PassMode::Ignore`)", self.mode), + } } /// Pass this argument indirectly, by placing it at a fixed stack offset. diff --git a/compiler/rustc_target/src/abi/call/powerpc.rs b/compiler/rustc_target/src/abi/call/powerpc.rs index cb80d64c943..8f67f57cd2b 100644 --- a/compiler/rustc_target/src/abi/call/powerpc.rs +++ b/compiler/rustc_target/src/abi/call/powerpc.rs @@ -16,7 +16,7 @@ fn classify_arg<Ty>(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'_, Ty>) { && matches!(&*cx.target_spec().env, "gnu" | "musl" | "uclibc") && arg.layout.is_zst() { - arg.make_indirect_force(); + arg.make_indirect_from_ignore(); } return; } diff --git a/compiler/rustc_target/src/abi/call/s390x.rs b/compiler/rustc_target/src/abi/call/s390x.rs index 7dcbb3e4a9e..901ce139c7b 100644 --- a/compiler/rustc_target/src/abi/call/s390x.rs +++ b/compiler/rustc_target/src/abi/call/s390x.rs @@ -28,7 +28,7 @@ where && matches!(&*cx.target_spec().env, "gnu" | "musl" | "uclibc") && arg.layout.is_zst() { - arg.make_indirect_force(); + arg.make_indirect_from_ignore(); } return; } diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs index 3b2bf9b3187..311691d8efb 100644 --- a/compiler/rustc_target/src/abi/call/sparc64.rs +++ b/compiler/rustc_target/src/abi/call/sparc64.rs @@ -225,7 +225,7 @@ where && matches!(&*cx.target_spec().env, "gnu" | "musl" | "uclibc") && arg.layout.is_zst() { - arg.make_indirect_force(); + arg.make_indirect_from_ignore(); } return; } diff --git a/compiler/rustc_target/src/abi/call/x86_win64.rs b/compiler/rustc_target/src/abi/call/x86_win64.rs index 6ca01cf84ea..720707ef53f 100644 --- a/compiler/rustc_target/src/abi/call/x86_win64.rs +++ b/compiler/rustc_target/src/abi/call/x86_win64.rs @@ -43,7 +43,7 @@ pub fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) && cx.target_spec().env == "gnu" && arg.layout.is_zst() { - arg.make_indirect_force(); + arg.make_indirect_from_ignore(); } continue; } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index f6dd7898fb2..173671059ca 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -382,7 +382,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label, - was_written: None, + was_written: false, path: Default::default(), }), TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl { @@ -393,7 +393,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label, - was_written: None, + was_written: false, path: Default::default(), }), TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn { @@ -404,7 +404,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label, - was_written: None, + was_written: false, path: Default::default(), }), } @@ -586,7 +586,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, - was_written: path.as_ref().map(|_| ()), + was_written: path.is_some(), path: path.unwrap_or_default(), }), TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl { @@ -597,7 +597,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, - was_written: path.as_ref().map(|_| ()), + was_written: path.is_some(), path: path.unwrap_or_default(), }), TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn { @@ -608,7 +608,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer_subdiags, multi_suggestions, bad_label: None, - was_written: path.as_ref().map(|_| ()), + was_written: path.is_some(), path: path.unwrap_or_default(), }), } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs index 3f35391be13..cd61747917a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs @@ -101,7 +101,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { // region at the right depth with the same index (Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); - if id == def_id { + if id.to_def_id() == def_id { return ControlFlow::Break(arg); } } @@ -118,7 +118,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { debruijn_index ); debug!("LateBound id={:?} def_id={:?}", id, def_id); - if debruijn_index == self.current_index && id == def_id { + if debruijn_index == self.current_index && id.to_def_id() == def_id { return ControlFlow::Break(arg); } } @@ -192,7 +192,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { // the lifetime of the TyPath! (Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); - if id == def_id { + if id.to_def_id() == def_id { return ControlFlow::Break(()); } } @@ -201,7 +201,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", debruijn_index,); debug!("id={:?}", id); debug!("def_id={:?}", def_id); - if debruijn_index == self.current_index && id == def_id { + if debruijn_index == self.current_index && id.to_def_id() == def_id { return ControlFlow::Break(()); } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs index 9c772f42cca..f2a7da707b8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs @@ -11,7 +11,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { pub(super) fn try_report_placeholder_relation(&self) -> Option<Diag<'tcx>> { match &self.error { Some(RegionResolutionError::ConcreteFailure( - SubregionOrigin::RelateRegionParamBound(span), + SubregionOrigin::RelateRegionParamBound(span, _), Region(Interned( RePlaceholder(ty::Placeholder { bound: ty::BoundRegion { kind: sub_name, .. }, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs index 04e1be22a4d..600da730845 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs @@ -52,7 +52,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .add_to_diag(err); } } - infer::RelateRegionParamBound(span) => { + infer::RelateRegionParamBound(span, _) => { RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound } .add_to_diag(err); } @@ -199,7 +199,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { note, }) } - infer::RelateRegionParamBound(span) => { + infer::RelateRegionParamBound(span, _) => { let param_instantiated = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 3cee8ff5f4c..ada44b632d4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -17,8 +17,8 @@ use rustc_span::{BytePos, ErrorGuaranteed, Span, Symbol}; use rustc_type_ir::Upcast as _; use super::nice_region_error::find_anon_type; -use super::{nice_region_error, ObligationCauseAsDiagArg}; -use crate::error_reporting::infer::ObligationCauseExt as _; +use super::ObligationCauseAsDiagArg; +use crate::error_reporting::infer::ObligationCauseExt; use crate::error_reporting::TypeErrCtxt; use crate::errors::{ self, note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, @@ -257,7 +257,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .add_to_diag(err); } } - infer::RelateRegionParamBound(span) => { + infer::RelateRegionParamBound(span, _) => { RegionOriginNote::Plain { span, msg: fluent::trait_selection_relate_region_param_bound, @@ -410,7 +410,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { note, }) } - infer::RelateRegionParamBound(span) => { + infer::RelateRegionParamBound(span, ty) => { let param_instantiated = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, @@ -419,11 +419,31 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { note_and_explain::PrefixKind::LfParamInstantiatedWith, note_and_explain::SuffixKind::Empty, ); + let mut alt_span = None; + if let Some(ty) = ty + && sub.is_static() + && let ty::Dynamic(preds, _, ty::DynKind::Dyn) = ty.kind() + && let Some(def_id) = preds.principal_def_id() + { + for (clause, span) in + self.tcx.predicates_of(def_id).instantiate_identity(self.tcx) + { + if let ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) = + clause.kind().skip_binder() + && let ty::Param(param) = a.kind() + && param.name == kw::SelfUpper + && b.is_static() + { + // Point at explicit `'static` bound on the trait (`trait T: 'static`). + alt_span = Some(span); + } + } + } let param_must_outlive = note_and_explain::RegionExplanation::new( self.tcx, generic_param_scope, sub, - None, + alt_span, note_and_explain::PrefixKind::LfParamMustOutlive, note_and_explain::SuffixKind::Empty, ); @@ -1079,16 +1099,8 @@ fn msg_span_from_named_region<'tcx>( ) -> (String, Option<Span>) { match *region { ty::ReEarlyParam(br) => { - let scope = tcx - .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id) - .expect_local(); - let span = if let Some(param) = - tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) - { - param.span - } else { - tcx.def_span(scope) - }; + let param_def_id = tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id; + let span = tcx.def_span(param_def_id); let text = if br.has_name() { format!("the lifetime `{}` as defined here", br.name) } else { @@ -1104,16 +1116,8 @@ fn msg_span_from_named_region<'tcx>( ("the anonymous lifetime defined here".to_string(), Some(ty.span)) } else { match fr.bound_region { - ty::BoundRegionKind::BrNamed(_, name) => { - let span = if let Some(param) = tcx - .hir() - .get_generics(generic_param_scope) - .and_then(|generics| generics.get_named(name)) - { - param.span - } else { - tcx.def_span(generic_param_scope) - }; + ty::BoundRegionKind::BrNamed(param_def_id, name) => { + let span = tcx.def_span(param_def_id); let text = if name == kw::UnderscoreLifetime { "the anonymous lifetime as defined here".to_string() } else { @@ -1212,22 +1216,8 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>( hidden_region, "", ); - if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) { - if infcx.tcx.features().precise_capturing { - suggest_precise_capturing(tcx, opaque_ty_key.def_id, hidden_region, &mut err); - } else { - let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id); - nice_region_error::suggest_new_region_bound( - tcx, - &mut err, - fn_returns, - hidden_region.to_string(), - None, - format!("captures `{hidden_region}`"), - None, - Some(reg_info.def_id), - ) - } + if let Some(_) = tcx.is_suitable_region(generic_param_scope, hidden_region) { + suggest_precise_capturing(tcx, opaque_ty_key.def_id, hidden_region, &mut err); } } ty::RePlaceholder(_) => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 35f68a56d2d..ba656493d46 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -382,7 +382,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if !expected_inner.is_fn() || !found_inner.is_fn() { return; } - match (&expected_inner.kind(), &found_inner.kind()) { + match (expected_inner.kind(), found_inner.kind()) { (ty::FnPtr(sig_tys, hdr), ty::FnDef(did, args)) => { let sig = sig_tys.with(*hdr); let expected_sig = &(self.normalize_fn_sig)(sig); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d1cc630bc9a..9f0282319ec 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1693,7 +1693,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { StringPart::highlighted("multiple different versions".to_string()), StringPart::normal(" of crate `".to_string()), StringPart::highlighted(format!("{name}")), - StringPart::normal("` the your dependency graph".to_string()), + StringPart::normal("` in the dependency graph".to_string()), ], ); let candidates = if impl_candidates.is_empty() { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index a962be54c3d..3cb95294fb6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2727,6 +2727,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let tcx = self.tcx; let predicate = predicate.upcast(tcx); + let suggest_remove_deref = |err: &mut Diag<'_, G>, expr: &hir::Expr<'_>| { + if let Some(pred) = predicate.as_trait_clause() + && tcx.is_lang_item(pred.def_id(), LangItem::Sized) + && let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind + { + err.span_suggestion_verbose( + expr.span.until(inner.span), + "references are always `Sized`, even if they point to unsized data; consider \ + not dereferencing the expression", + String::new(), + Applicability::MaybeIncorrect, + ); + } + }; match *cause_code { ObligationCauseCode::ExprAssignable | ObligationCauseCode::MatchExpressionArm { .. } @@ -2773,6 +2787,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..) if !span.is_dummy() => { + if let ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, pos) = &cause_code { + if let Node::Expr(expr) = tcx.parent_hir_node(*hir_id) + && let hir::ExprKind::Call(_, args) = expr.kind + && let Some(expr) = args.get(*pos) + { + suggest_remove_deref(err, &expr); + } else if let Node::Expr(expr) = self.tcx.hir_node(*hir_id) + && let hir::ExprKind::MethodCall(_, _, args, _) = expr.kind + && let Some(expr) = args.get(*pos) + { + suggest_remove_deref(err, &expr); + } + } let item_name = tcx.def_path_str(item_def_id); let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id)); let mut multispan = MultiSpan::from(span); @@ -2970,6 +2997,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { )); err.downgrade_to_delayed_bug(); } + let mut local = true; match tcx.parent_hir_node(hir_id) { Node::LetStmt(hir::LetStmt { ty: Some(ty), .. }) => { err.span_suggestion_verbose( @@ -2978,7 +3006,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "&", Applicability::MachineApplicable, ); - err.note("all local variables must have a statically known size"); } Node::LetStmt(hir::LetStmt { init: Some(hir::Expr { kind: hir::ExprKind::Index(..), span, .. }), @@ -2993,7 +3020,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "&", Applicability::MachineApplicable, ); - err.note("all local variables must have a statically known size"); + } + Node::LetStmt(hir::LetStmt { init: Some(expr), .. }) => { + // When encountering an assignment of an unsized trait, like `let x = *"";`, + // we check if the RHS is a deref operation, to suggest removing it. + suggest_remove_deref(err, &expr); } Node::Param(param) => { err.span_suggestion_verbose( @@ -3003,10 +3034,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { "&", Applicability::MachineApplicable, ); + local = false; } - _ => { - err.note("all local variables must have a statically known size"); - } + _ => {} + } + if local { + err.note("all local variables must have a statically known size"); } if !tcx.features().unsized_locals { err.help("unsized locals are gated as an unstable feature"); @@ -3529,14 +3562,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } ObligationCauseCode::OpaqueReturnType(expr_info) => { - if let Some((expr_ty, expr_span)) = expr_info { + if let Some((expr_ty, hir_id)) = expr_info { let expr_ty = self.tcx.short_ty_string(expr_ty, &mut long_ty_file); + let expr = self.infcx.tcx.hir().expect_expr(hir_id); err.span_label( - expr_span, + expr.span, with_forced_trimmed_paths!(format!( "return type was inferred to be `{expr_ty}` here", )), ); + suggest_remove_deref(err, &expr); } } } @@ -4667,10 +4702,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let hir::ExprKind::Block(b, _) = body.value.kind && b.expr.is_none() { + // The span of '}' in the end of block. + let span = self.tcx.sess.source_map().end_point(b.span); sugg_spans.push(( - // The span will point to the closing curly brace `}` of the block. - b.span.shrink_to_hi().with_lo(b.span.hi() - BytePos(1)), - "\n Ok(())\n}".to_string(), + span.shrink_to_lo(), + format!( + "{}{}", + " Ok(())\n", + self.tcx.sess.source_map().indentation_before(span).unwrap_or_default(), + ), )); } err.multipart_suggestion_verbose( diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 78f1f7d9b9b..5384084f6d7 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -203,7 +203,7 @@ pub struct AnnotationRequired<'a> { #[subdiagnostic] pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, #[note(trait_selection_full_type_written)] - pub was_written: Option<()>, + pub was_written: bool, pub path: PathBuf, } @@ -224,7 +224,7 @@ pub struct AmbiguousImpl<'a> { #[subdiagnostic] pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, #[note(trait_selection_full_type_written)] - pub was_written: Option<()>, + pub was_written: bool, pub path: PathBuf, } @@ -245,7 +245,7 @@ pub struct AmbiguousReturn<'a> { #[subdiagnostic] pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, #[note(trait_selection_full_type_written)] - pub was_written: Option<()>, + pub was_written: bool, pub path: PathBuf, } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 29f78f9d5f0..38d338598a1 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -770,7 +770,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let reported = tcx.dcx().emit_err(UnableToConstructConstantValue { span: tcx.def_span(unevaluated.def), - unevaluated: unevaluated, + unevaluated, }); Err(ErrorHandled::Reported(reported.into(), tcx.def_span(unevaluated.def))) } diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 7c73f74e629..2c67e7d4847 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -179,7 +179,7 @@ pub(crate) mod rustc { }; use super::Tree; - use crate::layout::rustc::{Def, Ref}; + use crate::layout::rustc::{layout_of, Def, Ref}; #[derive(Debug, Copy, Clone)] pub(crate) enum Err { @@ -206,7 +206,7 @@ pub(crate) mod rustc { impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> { pub fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, Err> { use rustc_target::abi::HasDataLayout; - let layout = ty_layout(cx, ty); + let layout = layout_of(cx, ty)?; if let Err(e) = ty.error_reported() { return Err(Err::TypeError(e)); @@ -239,7 +239,7 @@ pub(crate) mod rustc { let FieldsShape::Array { stride, count } = &layout.fields else { return Err(Err::NotYetSupported); }; - let inner_layout = ty_layout(cx, *inner_ty); + let inner_layout = layout_of(cx, *inner_ty)?; assert_eq!(*stride, inner_layout.size); let elt = Tree::from_ty(*inner_ty, cx)?; Ok(std::iter::repeat(elt) @@ -254,7 +254,7 @@ pub(crate) mod rustc { }, ty::Ref(lifetime, ty, mutability) => { - let layout = ty_layout(cx, *ty); + let layout = layout_of(cx, *ty)?; let align = layout.align.abi.bytes_usize(); let size = layout.size.bytes_usize(); Ok(Tree::Ref(Ref { @@ -280,7 +280,7 @@ pub(crate) mod rustc { FieldsShape::Primitive => { assert_eq!(members.len(), 1); let inner_ty = members[0]; - let inner_layout = ty_layout(cx, inner_ty); + let inner_layout = layout_of(cx, inner_ty)?; Self::from_ty(inner_ty, cx) } FieldsShape::Arbitrary { offsets, .. } => { @@ -413,7 +413,7 @@ pub(crate) mod rustc { let padding = Self::padding(padding_needed.bytes_usize()); let field_ty = ty_field(cx, (ty, layout), field_idx); - let field_layout = ty_layout(cx, field_ty); + let field_layout = layout_of(cx, field_ty)?; let field_tree = Self::from_ty(field_ty, cx)?; struct_tree = struct_tree.then(padding).then(field_tree); @@ -471,7 +471,7 @@ pub(crate) mod rustc { |fields, (idx, field_def)| { let field_def = Def::Field(field_def); let field_ty = ty_field(cx, (ty, layout), idx); - let field_layout = ty_layout(cx, field_ty); + let field_layout = layout_of(cx, field_ty)?; let field = Self::from_ty(field_ty, cx)?; let trailing_padding_needed = layout.size - field_layout.size; let trailing_padding = Self::padding(trailing_padding_needed.bytes_usize()); @@ -484,10 +484,6 @@ pub(crate) mod rustc { } } - pub(crate) fn ty_layout<'tcx>(cx: LayoutCx<'tcx, TyCtxt<'tcx>>, ty: Ty<'tcx>) -> Layout<'tcx> { - crate::layout::rustc::layout_of(cx, ty).unwrap() - } - fn ty_field<'tcx>( cx: LayoutCx<'tcx, TyCtxt<'tcx>>, (ty, layout): (Ty<'tcx>, Layout<'tcx>), diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 1f3c4e3c817..2762b4e6384 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -44,18 +44,11 @@ mod rustc { let Self { src, dst, assume, context } = self; let layout_cx = LayoutCx { tcx: context, param_env: ParamEnv::reveal_all() }; - let layout_of = |ty| { - crate::layout::rustc::layout_of(layout_cx, ty) - .map_err(|_| Err::NotYetSupported) - .and_then(|_| Tree::from_ty(ty, layout_cx)) - }; // Convert `src` and `dst` from their rustc representations, to `Tree`-based - // representations. If these conversions fail, conclude that the transmutation is - // unacceptable; the layouts of both the source and destination types must be - // well-defined. - let src = layout_of(src); - let dst = layout_of(dst); + // representations. + let src = Tree::from_ty(src, layout_cx); + let dst = Tree::from_ty(dst, layout_cx); match (src, dst) { (Err(Err::TypeError(_)), _) | (_, Err(Err::TypeError(_))) => { diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs index 95373916a71..f8b59bdf326 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -4,7 +4,6 @@ use crate::layout; pub(crate) trait QueryContext { type Def: layout::Def; type Ref: layout::Ref; - type Scope: Copy; } #[cfg(test)] @@ -28,20 +27,17 @@ pub(crate) mod test { impl QueryContext for UltraMinimal { type Def = Def; type Ref = !; - type Scope = (); } } #[cfg(feature = "rustc")] mod rustc { - use rustc_middle::ty::{Ty, TyCtxt}; + use rustc_middle::ty::TyCtxt; use super::*; impl<'tcx> super::QueryContext for TyCtxt<'tcx> { type Def = layout::rustc::Def<'tcx>; type Ref = layout::rustc::Ref<'tcx>; - - type Scope = Ty<'tcx>; } } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 4ded935b801..ae5341ddec1 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -284,7 +284,7 @@ fn error( ) -> Result<!, ErrorGuaranteed> { let reported = tcx.dcx().emit_err(GenericConstantTooComplex { span: root_span, - maybe_supported: None, + maybe_supported: false, sub, }); @@ -298,7 +298,7 @@ fn maybe_supported_error( ) -> Result<!, ErrorGuaranteed> { let reported = tcx.dcx().emit_err(GenericConstantTooComplex { span: root_span, - maybe_supported: Some(()), + maybe_supported: true, sub, }); diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index bfbb45f0cb5..42ecaaeafa9 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -18,7 +18,7 @@ pub struct GenericConstantTooComplex { #[primary_span] pub span: Span, #[note(ty_utils_maybe_supported)] - pub maybe_supported: Option<()>, + pub maybe_supported: bool, #[subdiagnostic] pub sub: GenericConstantTooComplexSub, } diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index d274a934d52..9a3956596d2 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -366,7 +366,7 @@ fn adt_consider_insignificant_dtor<'tcx>( fn adt_drop_tys<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, -) -> Result<&ty::List<Ty<'tcx>>, AlwaysRequiresDrop> { +) -> Result<&'tcx ty::List<Ty<'tcx>>, AlwaysRequiresDrop> { // This is for the "adt_drop_tys" query, that considers all `Drop` impls, therefore all dtors are // significant. let adt_has_dtor = diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 2750838bbe9..98cc116bd00 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" bitflags = "2.4.1" derive-where = "1.2.7" indexmap = "2.0.0" +rustc-hash = "1.1.0" rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } @@ -31,3 +32,6 @@ nightly = [ "rustc_index/nightly", "rustc_ast_ir/nightly" ] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] } diff --git a/compiler/rustc_type_ir/src/data_structures.rs b/compiler/rustc_type_ir/src/data_structures.rs index 4ca97c0c86c..96036e53b0a 100644 --- a/compiler/rustc_type_ir/src/data_structures.rs +++ b/compiler/rustc_type_ir/src/data_structures.rs @@ -1,8 +1,13 @@ +use std::hash::BuildHasherDefault; + +use rustc_hash::FxHasher; +pub use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; + +pub type IndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>; +pub type IndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>; + #[cfg(feature = "nightly")] mod impl_ { - pub use rustc_data_structures::fx::{ - FxHashMap as HashMap, FxHashSet as HashSet, FxIndexMap as IndexMap, FxIndexSet as IndexSet, - }; pub use rustc_data_structures::sso::{SsoHashMap, SsoHashSet}; pub use rustc_data_structures::stack::ensure_sufficient_stack; pub use rustc_data_structures::sync::Lrc; @@ -10,11 +15,9 @@ mod impl_ { #[cfg(not(feature = "nightly"))] mod impl_ { - pub use std::collections::{HashMap, HashMap as SsoHashMap, HashSet, HashSet as SsoHashSet}; + pub use std::collections::{HashMap as SsoHashMap, HashSet as SsoHashSet}; pub use std::sync::Arc as Lrc; - pub use indexmap::{IndexMap, IndexSet}; - #[inline] pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R { f() diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index f30419c801f..433c444e701 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -237,7 +237,7 @@ pub fn supertrait_def_ids<I: Interner>( cx: I, trait_def_id: I::DefId, ) -> impl Iterator<Item = I::DefId> { - let mut set = HashSet::default(); + let mut set: HashSet<I::DefId> = HashSet::default(); let mut stack = vec![trait_def_id]; set.insert(trait_def_id); diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs index bfcea6a81d3..e8afaf1a480 100644 --- a/compiler/rustc_type_ir/src/outlives.rs +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -68,6 +68,9 @@ struct OutlivesCollector<'a, I: Interner> { } impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> { + #[cfg(not(feature = "nightly"))] + type Result = (); + fn visit_ty(&mut self, ty: I::Ty) -> Self::Result { if !self.visited.insert(ty) { return; diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index d47c9e725f3..418139c3aad 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -287,7 +287,7 @@ impl<X: Cx> NestedGoals<X> { } } - #[rustc_lint_query_instability] + #[cfg_attr(feature = "nightly", rustc_lint_query_instability)] #[allow(rustc::potential_query_instability)] fn iter(&self) -> impl Iterator<Item = (X::Input, UsageKind)> + '_ { self.nested_goals.iter().map(|(i, p)| (*i, *p)) diff --git a/config.example.toml b/config.example.toml index 1b7de662e84..f1dc32234cc 100644 --- a/config.example.toml +++ b/config.example.toml @@ -337,6 +337,7 @@ # "analysis", # "src", # "wasm-component-ld", +# "miri", "cargo-miri" # for dev/nightly channels #] # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation diff --git a/library/Cargo.lock b/library/Cargo.lock index 30f5076e1e2..aa22181a463 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -58,9 +58,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.118" +version = "0.1.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92afe7344b64cccf3662ca26d5d1c0828ab826f04206b97d856e3625e390e4b5" +checksum = "ce956e6dc07082ec481f0935a51e83b343f8ca51be560452c0ebf830d0bdf5a5" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index bdf16257c7c..a39a0a6ce0e 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "0.1.118", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.121", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 7de41259599..caaf37f0465 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -293,6 +293,7 @@ impl<T> Box<T> { /// /// ``` /// #![feature(new_uninit)] + /// #![feature(new_zeroed_alloc)] /// /// let zero = Box::<u32>::new_zeroed(); /// let zero = unsafe { zero.assume_init() }; @@ -303,7 +304,7 @@ impl<T> Box<T> { /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[inline] - #[unstable(feature = "new_uninit", issue = "63291")] + #[unstable(feature = "new_zeroed_alloc", issue = "129396")] #[must_use] pub fn new_zeroed() -> Box<mem::MaybeUninit<T>> { Self::new_zeroed_in(Global) @@ -684,6 +685,7 @@ impl<T> Box<[T]> { /// # Examples /// /// ``` + /// #![feature(new_zeroed_alloc)] /// #![feature(new_uninit)] /// /// let values = Box::<[u32]>::new_zeroed_slice(3); @@ -694,7 +696,7 @@ impl<T> Box<[T]> { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "new_uninit", issue = "63291")] + #[unstable(feature = "new_zeroed_alloc", issue = "129396")] #[must_use] pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> { unsafe { RawVec::with_capacity_zeroed(len).into_box(len) } @@ -955,6 +957,7 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> { /// # Examples /// /// ``` + /// #![feature(box_uninit_write)] /// #![feature(new_uninit)] /// /// let big_box = Box::<[usize; 1024]>::new_uninit(); @@ -972,7 +975,7 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> { /// assert_eq!(*x, i); /// } /// ``` - #[unstable(feature = "new_uninit", issue = "63291")] + #[unstable(feature = "box_uninit_write", issue = "129397")] #[inline] pub fn write(mut boxed: Self, value: T) -> Box<T, A> { unsafe { @@ -1254,6 +1257,95 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { unsafe { (Unique::from(&mut *ptr), alloc) } } + /// Returns a raw mutable pointer to the `Box`'s contents. + /// + /// The caller must ensure that the `Box` outlives the pointer this + /// function returns, or else it will end up dangling. + /// + /// This method guarantees that for the purpose of the aliasing model, this method + /// does not materialize a reference to the underlying memory, and thus the returned pointer + /// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`]. + /// Note that calling other methods that materialize references to the memory + /// may still invalidate this pointer. + /// See the example below for how this guarantee can be used. + /// + /// # Examples + /// + /// Due to the aliasing guarantee, the following code is legal: + /// + /// ```rust + /// #![feature(box_as_ptr)] + /// + /// unsafe { + /// let mut b = Box::new(0); + /// let ptr1 = Box::as_mut_ptr(&mut b); + /// ptr1.write(1); + /// let ptr2 = Box::as_mut_ptr(&mut b); + /// ptr2.write(2); + /// // Notably, the write to `ptr2` did *not* invalidate `ptr1`: + /// ptr1.write(3); + /// } + /// ``` + /// + /// [`as_mut_ptr`]: Self::as_mut_ptr + /// [`as_ptr`]: Self::as_ptr + #[unstable(feature = "box_as_ptr", issue = "129090")] + #[rustc_never_returns_null_ptr] + #[inline] + pub fn as_mut_ptr(b: &mut Self) -> *mut T { + // This is a primitive deref, not going through `DerefMut`, and therefore not materializing + // any references. + ptr::addr_of_mut!(**b) + } + + /// Returns a raw pointer to the `Box`'s contents. + /// + /// The caller must ensure that the `Box` outlives the pointer this + /// function returns, or else it will end up dangling. + /// + /// The caller must also ensure that the memory the pointer (non-transitively) points to + /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer + /// derived from it. If you need to mutate the contents of the `Box`, use [`as_mut_ptr`]. + /// + /// This method guarantees that for the purpose of the aliasing model, this method + /// does not materialize a reference to the underlying memory, and thus the returned pointer + /// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`]. + /// Note that calling other methods that materialize mutable references to the memory, + /// as well as writing to this memory, may still invalidate this pointer. + /// See the example below for how this guarantee can be used. + /// + /// # Examples + /// + /// Due to the aliasing guarantee, the following code is legal: + /// + /// ```rust + /// #![feature(box_as_ptr)] + /// + /// unsafe { + /// let mut v = Box::new(0); + /// let ptr1 = Box::as_ptr(&v); + /// let ptr2 = Box::as_mut_ptr(&mut v); + /// let _val = ptr2.read(); + /// // No write to this memory has happened yet, so `ptr1` is still valid. + /// let _val = ptr1.read(); + /// // However, once we do a write... + /// ptr2.write(1); + /// // ... `ptr1` is no longer valid. + /// // This would be UB: let _val = ptr1.read(); + /// } + /// ``` + /// + /// [`as_mut_ptr`]: Self::as_mut_ptr + /// [`as_ptr`]: Self::as_ptr + #[unstable(feature = "box_as_ptr", issue = "129090")] + #[rustc_never_returns_null_ptr] + #[inline] + pub fn as_ptr(b: &Self) -> *const T { + // This is a primitive deref, not going through `DerefMut`, and therefore not materializing + // any references. + ptr::addr_of!(**b) + } + /// Returns a reference to the underlying allocator. /// /// Note: this is an associated function, which means that you have diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3e44adf73f0..5e4b08df6cb 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -131,7 +131,6 @@ #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] -#![feature(iter_repeat_n)] #![feature(layout_for_ptr)] #![feature(local_waker)] #![feature(maybe_uninit_slice)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index bdee06154fa..f153aa6d3be 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -539,6 +539,7 @@ impl<T> Rc<T> { /// # Examples /// /// ``` + /// #![feature(new_zeroed_alloc)] /// #![feature(new_uninit)] /// /// use std::rc::Rc; @@ -551,7 +552,7 @@ impl<T> Rc<T> { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "new_uninit", issue = "63291")] + #[unstable(feature = "new_zeroed_alloc", issue = "129396")] #[must_use] pub fn new_zeroed() -> Rc<mem::MaybeUninit<T>> { unsafe { @@ -1000,6 +1001,7 @@ impl<T> Rc<[T]> { /// /// ``` /// #![feature(new_uninit)] + /// #![feature(new_zeroed_alloc)] /// /// use std::rc::Rc; /// @@ -1011,7 +1013,7 @@ impl<T> Rc<[T]> { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "new_uninit", issue = "63291")] + #[unstable(feature = "new_zeroed_alloc", issue = "129396")] #[must_use] pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> { unsafe { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 2c0d19b0ada..4a3522f1a64 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -542,6 +542,7 @@ impl<T> Arc<T> { /// # Examples /// /// ``` + /// #![feature(new_zeroed_alloc)] /// #![feature(new_uninit)] /// /// use std::sync::Arc; @@ -555,7 +556,7 @@ impl<T> Arc<T> { /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[inline] - #[unstable(feature = "new_uninit", issue = "63291")] + #[unstable(feature = "new_zeroed_alloc", issue = "129396")] #[must_use] pub fn new_zeroed() -> Arc<mem::MaybeUninit<T>> { unsafe { @@ -1134,6 +1135,7 @@ impl<T> Arc<[T]> { /// # Examples /// /// ``` + /// #![feature(new_zeroed_alloc)] /// #![feature(new_uninit)] /// /// use std::sync::Arc; @@ -1147,7 +1149,7 @@ impl<T> Arc<[T]> { /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[inline] - #[unstable(feature = "new_uninit", issue = "63291")] + #[unstable(feature = "new_zeroed_alloc", issue = "129396")] #[must_use] pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> { unsafe { @@ -1191,7 +1193,7 @@ impl<T, A: Allocator> Arc<[T], A> { /// assert_eq!(*values, [1, 2, 3]) /// ``` #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "new_uninit", issue = "63291")] + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn new_uninit_slice_in(len: usize, alloc: A) -> Arc<[mem::MaybeUninit<T>], A> { unsafe { Arc::from_ptr_in(Arc::allocate_for_slice_in(len, &alloc), alloc) } @@ -1220,7 +1222,7 @@ impl<T, A: Allocator> Arc<[T], A> { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "new_uninit", issue = "63291")] + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Arc<[mem::MaybeUninit<T>], A> { unsafe { diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b4e0bc5fcbe..cfd2e4a1512 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1334,7 +1334,7 @@ impl<T, A: Allocator> Vec<T, A> { self.buf.ptr() } - /// Returns an unsafe mutable pointer to the vector's buffer, or a dangling + /// Returns a raw mutable pointer to the vector's buffer, or a dangling /// raw pointer valid for zero sized reads if the vector didn't allocate. /// /// The caller must ensure that the vector outlives the pointer this @@ -1350,7 +1350,6 @@ impl<T, A: Allocator> Vec<T, A> { /// may still invalidate this pointer. /// See the second example below for how this guarantee can be used. /// - /// /// # Examples /// /// ``` diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs index faee64b2f67..bfc31a626fa 100644 --- a/library/alloc/tests/boxed.rs +++ b/library/alloc/tests/boxed.rs @@ -59,6 +59,7 @@ fn box_deref_lval() { assert_eq!(x.get(), 1000); } +#[allow(unused)] pub struct ConstAllocator; unsafe impl Allocator for ConstAllocator { diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 549a4bc6727..ad3f9d80878 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -6,7 +6,7 @@ use crate::error::Error; use crate::ptr::{Alignment, NonNull}; -use crate::{cmp, fmt, mem}; +use crate::{assert_unsafe_precondition, cmp, fmt, mem}; // While this function is used in one place and its implementation // could be inlined, the previous attempts to do so made rustc @@ -66,12 +66,20 @@ impl Layout { #[inline] #[rustc_allow_const_fn_unstable(ptr_alignment_type)] pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> { - if !align.is_power_of_two() { - return Err(LayoutError); + if Layout::is_size_align_valid(size, align) { + // SAFETY: Layout::is_size_align_valid checks the preconditions for this call. + unsafe { Ok(Layout { size, align: mem::transmute(align) }) } + } else { + Err(LayoutError) } + } - // SAFETY: just checked that align is a power of two. - Layout::from_size_alignment(size, unsafe { Alignment::new_unchecked(align) }) + const fn is_size_align_valid(size: usize, align: usize) -> bool { + let Some(align) = Alignment::new(align) else { return false }; + if size > Self::max_size_for_align(align) { + return false; + } + true } #[inline(always)] @@ -116,8 +124,17 @@ impl Layout { #[inline] #[rustc_allow_const_fn_unstable(ptr_alignment_type)] pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { + assert_unsafe_precondition!( + check_library_ub, + "Layout::from_size_align_unchecked requires that align is a power of 2 \ + and the rounded-up allocation size does not exceed isize::MAX", + ( + size: usize = size, + align: usize = align, + ) => Layout::is_size_align_valid(size, align) + ); // SAFETY: the caller is required to uphold the preconditions. - unsafe { Layout { size, align: Alignment::new_unchecked(align) } } + unsafe { Layout { size, align: mem::transmute(align) } } } /// The minimum size in bytes for a memory block of this layout. diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index 375358dddf5..ce09a0b444d 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -3,8 +3,8 @@ //! suggestions from rustc if you get anything slightly wrong in here, and overall //! helps with clarity as we're also referring to `char` intentionally in here. -use crate::fmt; use crate::mem::transmute; +use crate::{assert_unsafe_precondition, fmt}; /// One of the 128 Unicode characters from U+0000 through U+007F, /// often known as the [ASCII] subset. @@ -497,14 +497,18 @@ impl AsciiChar { /// Notably, it should not be expected to return hex digits, or any other /// reasonable extension of the decimal digits. /// - /// (This lose safety condition is intended to simplify soundness proofs + /// (This loose safety condition is intended to simplify soundness proofs /// when writing code using this method, since the implementation doesn't /// need something really specific, not to make those other arguments do /// something useful. It might be tightened before stabilization.) #[unstable(feature = "ascii_char", issue = "110998")] #[inline] pub const unsafe fn digit_unchecked(d: u8) -> Self { - debug_assert!(d < 10); + assert_unsafe_precondition!( + check_language_ub, + "`AsciiChar::digit_unchecked` input cannot exceed 9.", + (d: u8 = d) => d < 10 + ); // SAFETY: `'0'` through `'9'` are U+00030 through U+0039, // so because `d` must be 64 or less the addition can return at most diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index d860f3415d9..5dd9721d3fe 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -306,6 +306,7 @@ pub use once::OnceCell; /// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] +#[cfg_attr(not(bootstrap), rustc_pub_transparent)] pub struct Cell<T: ?Sized> { value: UnsafeCell<T>, } @@ -2055,6 +2056,7 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> { #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] +#[cfg_attr(not(bootstrap), rustc_pub_transparent)] pub struct UnsafeCell<T: ?Sized> { value: T, } @@ -2297,6 +2299,7 @@ impl<T> UnsafeCell<*mut T> { /// See [`UnsafeCell`] for details. #[unstable(feature = "sync_unsafe_cell", issue = "95439")] #[repr(transparent)] +#[cfg_attr(not(bootstrap), rustc_pub_transparent)] pub struct SyncUnsafeCell<T: ?Sized> { value: UnsafeCell<T>, } diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 097fa86c938..87df8a4e272 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -309,7 +309,8 @@ impl<T> OnceCell<T> { /// ``` #[inline] #[stable(feature = "once_cell", since = "1.70.0")] - pub fn into_inner(self) -> Option<T> { + #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + pub const fn into_inner(self) -> Option<T> { // Because `into_inner` takes `self` by value, the compiler statically verifies // that it is not currently borrowed. So it is safe to move out `Option<T>`. self.inner.into_inner() diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 22084dcff8f..7808d42ab5d 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -91,6 +91,7 @@ use crate::{fmt, intrinsics, ops, slice, str}; /// [str]: prim@str "str" #[derive(PartialEq, Eq, Hash)] #[stable(feature = "core_c_str", since = "1.64.0")] +#[rustc_diagnostic_item = "cstr_type"] #[rustc_has_incoherent_inherent_impls] #[lang = "CStr"] // `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index 467fa17a6f3..c7c462a4df1 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs @@ -78,7 +78,7 @@ impl fmt::Write for PadAdapter<'_, '_> { /// /// assert_eq!( /// format!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }), -/// "Foo { bar: 10, baz: \"Hello World\" }", +/// r#"Foo { bar: 10, baz: "Hello World" }"#, /// ); /// ``` #[must_use = "must eventually call `finish()` on Debug builders"] @@ -125,7 +125,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// /// assert_eq!( /// format!("{:?}", Bar { bar: 10, another: "Hello World".to_string() }), - /// "Bar { bar: 10, another: \"Hello World\", nonexistent_field: 1 }", + /// r#"Bar { bar: 10, another: "Hello World", nonexistent_field: 1 }"#, /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] @@ -237,7 +237,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// /// assert_eq!( /// format!("{:?}", Bar { bar: 10, baz: "Hello World".to_string() }), - /// "Bar { bar: 10, baz: \"Hello World\" }", + /// r#"Bar { bar: 10, baz: "Hello World" }"#, /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] @@ -280,7 +280,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// /// assert_eq!( /// format!("{:?}", Foo(10, "Hello World".to_string())), -/// "Foo(10, \"Hello World\")", +/// r#"Foo(10, "Hello World")"#, /// ); /// ``` #[must_use = "must eventually call `finish()` on Debug builders"] @@ -322,7 +322,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { /// /// assert_eq!( /// format!("{:?}", Foo(10, "Hello World".to_string())), - /// "Foo(10, \"Hello World\")", + /// r#"Foo(10, "Hello World")"#, /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] @@ -360,6 +360,51 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { self } + /// Marks the tuple struct as non-exhaustive, indicating to the reader that there are some + /// other fields that are not shown in the debug representation. + /// + /// # Examples + /// + /// ``` + /// #![feature(debug_more_non_exhaustive)] + /// + /// use std::fmt; + /// + /// struct Foo(i32, String); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_tuple("Foo") + /// .field(&self.0) + /// .finish_non_exhaustive() // Show that some other field(s) exist. + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(10, "secret!".to_owned())), + /// "Foo(10, ..)", + /// ); + /// ``` + #[unstable(feature = "debug_more_non_exhaustive", issue = "127942")] + pub fn finish_non_exhaustive(&mut self) -> fmt::Result { + self.result = self.result.and_then(|_| { + if self.fields > 0 { + if self.is_pretty() { + let mut slot = None; + let mut state = Default::default(); + let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state); + writer.write_str("..\n")?; + self.fmt.write_str(")") + } else { + self.fmt.write_str(", ..)") + } + } else { + self.fmt.write_str("(..)") + } + }); + self.result + } + /// Finishes output and returns any error encountered. /// /// # Examples @@ -381,7 +426,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { /// /// assert_eq!( /// format!("{:?}", Foo(10, "Hello World".to_string())), - /// "Foo(10, \"Hello World\")", + /// r#"Foo(10, "Hello World")"#, /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] @@ -555,6 +600,56 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { self } + /// Marks the set as non-exhaustive, indicating to the reader that there are some other + /// elements that are not shown in the debug representation. + /// + /// # Examples + /// + /// ``` + /// #![feature(debug_more_non_exhaustive)] + /// + /// use std::fmt; + /// + /// struct Foo(Vec<i32>); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// // Print at most two elements, abbreviate the rest + /// let mut f = fmt.debug_set(); + /// let mut f = f.entries(self.0.iter().take(2)); + /// if self.0.len() > 2 { + /// f.finish_non_exhaustive() + /// } else { + /// f.finish() + /// } + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(vec![1, 2, 3, 4])), + /// "{1, 2, ..}", + /// ); + /// ``` + #[unstable(feature = "debug_more_non_exhaustive", issue = "127942")] + pub fn finish_non_exhaustive(&mut self) -> fmt::Result { + self.inner.result = self.inner.result.and_then(|_| { + if self.inner.has_fields { + if self.inner.is_pretty() { + let mut slot = None; + let mut state = Default::default(); + let mut writer = PadAdapter::wrap(self.inner.fmt, &mut slot, &mut state); + writer.write_str("..\n")?; + self.inner.fmt.write_str("}") + } else { + self.inner.fmt.write_str(", ..}") + } + } else { + self.inner.fmt.write_str("..}") + } + }); + self.inner.result + } + /// Finishes output and returns any error encountered. /// /// # Examples @@ -699,6 +794,55 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { self } + /// Marks the list as non-exhaustive, indicating to the reader that there are some other + /// elements that are not shown in the debug representation. + /// + /// # Examples + /// + /// ``` + /// #![feature(debug_more_non_exhaustive)] + /// + /// use std::fmt; + /// + /// struct Foo(Vec<i32>); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// // Print at most two elements, abbreviate the rest + /// let mut f = fmt.debug_list(); + /// let mut f = f.entries(self.0.iter().take(2)); + /// if self.0.len() > 2 { + /// f.finish_non_exhaustive() + /// } else { + /// f.finish() + /// } + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(vec![1, 2, 3, 4])), + /// "[1, 2, ..]", + /// ); + /// ``` + #[unstable(feature = "debug_more_non_exhaustive", issue = "127942")] + pub fn finish_non_exhaustive(&mut self) -> fmt::Result { + self.inner.result.and_then(|_| { + if self.inner.has_fields { + if self.inner.is_pretty() { + let mut slot = None; + let mut state = Default::default(); + let mut writer = PadAdapter::wrap(self.inner.fmt, &mut slot, &mut state); + writer.write_str("..\n")?; + self.inner.fmt.write_str("]") + } else { + self.inner.fmt.write_str(", ..]") + } + } else { + self.inner.fmt.write_str("..]") + } + }) + } + /// Finishes output and returns any error encountered. /// /// # Examples @@ -750,7 +894,7 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { /// /// assert_eq!( /// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])), -/// "{\"A\": 10, \"B\": 11}", +/// r#"{"A": 10, "B": 11}"#, /// ); /// ``` #[must_use = "must eventually call `finish()` on Debug builders"] @@ -790,7 +934,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// /// assert_eq!( /// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])), - /// "{\"whole\": [(\"A\", 10), (\"B\", 11)]}", + /// r#"{"whole": [("A", 10), ("B", 11)]}"#, /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] @@ -826,7 +970,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// /// assert_eq!( /// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])), - /// "{\"whole\": [(\"A\", 10), (\"B\", 11)]}", + /// r#"{"whole": [("A", 10), ("B", 11)]}"#, /// ); /// ``` #[stable(feature = "debug_map_key_value", since = "1.42.0")] @@ -902,7 +1046,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// /// assert_eq!( /// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])), - /// "{\"whole\": [(\"A\", 10), (\"B\", 11)]}", + /// r#"{"whole": [("A", 10), ("B", 11)]}"#, /// ); /// ``` #[stable(feature = "debug_map_key_value", since = "1.42.0")] @@ -960,7 +1104,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// /// assert_eq!( /// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])), - /// "{\"A\": 10, \"B\": 11}", + /// r#"{"A": 10, "B": 11}"#, /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] @@ -976,6 +1120,62 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { self } + /// Marks the map as non-exhaustive, indicating to the reader that there are some other + /// entries that are not shown in the debug representation. + /// + /// # Examples + /// + /// ``` + /// #![feature(debug_more_non_exhaustive)] + /// + /// use std::fmt; + /// + /// struct Foo(Vec<(String, i32)>); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// // Print at most two elements, abbreviate the rest + /// let mut f = fmt.debug_map(); + /// let mut f = f.entries(self.0.iter().take(2).map(|&(ref k, ref v)| (k, v))); + /// if self.0.len() > 2 { + /// f.finish_non_exhaustive() + /// } else { + /// f.finish() + /// } + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(vec![ + /// ("A".to_string(), 10), + /// ("B".to_string(), 11), + /// ("C".to_string(), 12), + /// ])), + /// r#"{"A": 10, "B": 11, ..}"#, + /// ); + /// ``` + #[unstable(feature = "debug_more_non_exhaustive", issue = "127942")] + pub fn finish_non_exhaustive(&mut self) -> fmt::Result { + self.result = self.result.and_then(|_| { + assert!(!self.has_key, "attempted to finish a map with a partial entry"); + + if self.has_fields { + if self.is_pretty() { + let mut slot = None; + let mut state = Default::default(); + let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state); + writer.write_str("..\n")?; + self.fmt.write_str("}") + } else { + self.fmt.write_str(", ..}") + } + } else { + self.fmt.write_str("..}") + } + }); + self.result + } + /// Finishes output and returns any error encountered. /// /// # Panics @@ -1000,7 +1200,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// /// assert_eq!( /// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])), - /// "{\"A\": 10, \"B\": 11}", + /// r#"{"A": 10, "B": 11}"#, /// ); /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 1f2bf49d2b7..5dad9e1a75e 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -436,7 +436,7 @@ pub use self::sources::{once, Once}; pub use self::sources::{once_with, OnceWith}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{repeat, Repeat}; -#[unstable(feature = "iter_repeat_n", issue = "104434")] +#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] pub use self::sources::{repeat_n, RepeatN}; #[stable(feature = "iterator_repeat_with", since = "1.28.0")] pub use self::sources::{repeat_with, RepeatWith}; diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index 6a94051b7c7..55901e1e50b 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -24,7 +24,7 @@ pub use self::once::{once, Once}; pub use self::once_with::{once_with, OnceWith}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::repeat::{repeat, Repeat}; -#[unstable(feature = "iter_repeat_n", issue = "104434")] +#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] pub use self::repeat_n::{repeat_n, RepeatN}; #[stable(feature = "iterator_repeat_with", since = "1.28.0")] pub use self::repeat_with::{repeat_with, RepeatWith}; diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs index 4c4ae39f836..2e247a34075 100644 --- a/library/core/src/iter/sources/repeat_n.rs +++ b/library/core/src/iter/sources/repeat_n.rs @@ -18,7 +18,6 @@ use crate::num::NonZero; /// Basic usage: /// /// ``` -/// #![feature(iter_repeat_n)] /// use std::iter; /// /// // four of the number four: @@ -36,7 +35,6 @@ use crate::num::NonZero; /// For non-`Copy` types, /// /// ``` -/// #![feature(iter_repeat_n)] /// use std::iter; /// /// let v: Vec<i32> = Vec::with_capacity(123); @@ -58,7 +56,7 @@ use crate::num::NonZero; /// assert_eq!(None, it.next()); /// ``` #[inline] -#[unstable(feature = "iter_repeat_n", issue = "104434")] +#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> { let mut element = ManuallyDrop::new(element); @@ -77,7 +75,7 @@ pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> { /// This `struct` is created by the [`repeat_n()`] function. /// See its documentation for more. #[derive(Clone, Debug)] -#[unstable(feature = "iter_repeat_n", issue = "104434")] +#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] pub struct RepeatN<A> { count: usize, // Invariant: has been dropped iff count == 0. @@ -101,14 +99,14 @@ impl<A> RepeatN<A> { } } -#[unstable(feature = "iter_repeat_n", issue = "104434")] +#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] impl<A> Drop for RepeatN<A> { fn drop(&mut self) { self.take_element(); } } -#[unstable(feature = "iter_repeat_n", issue = "104434")] +#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] impl<A: Clone> Iterator for RepeatN<A> { type Item = A; @@ -156,14 +154,14 @@ impl<A: Clone> Iterator for RepeatN<A> { } } -#[unstable(feature = "iter_repeat_n", issue = "104434")] +#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] impl<A: Clone> ExactSizeIterator for RepeatN<A> { fn len(&self) -> usize { self.count } } -#[unstable(feature = "iter_repeat_n", issue = "104434")] +#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] impl<A: Clone> DoubleEndedIterator for RepeatN<A> { #[inline] fn next_back(&mut self) -> Option<A> { @@ -181,12 +179,12 @@ impl<A: Clone> DoubleEndedIterator for RepeatN<A> { } } -#[unstable(feature = "iter_repeat_n", issue = "104434")] +#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] impl<A: Clone> FusedIterator for RepeatN<A> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<A: Clone> TrustedLen for RepeatN<A> {} -#[unstable(feature = "trusted_len_next_unchecked", issue = "37572")] +#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")] impl<A: Clone> UncheckedIterator for RepeatN<A> { #[inline] unsafe fn next_unchecked(&mut self) -> Self::Item { diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index c97cd042ab4..5b7d95c2f65 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -104,7 +104,7 @@ macro_rules! float_sum_product { impl Sum for $a { fn sum<I: Iterator<Item=Self>>(iter: I) -> Self { iter.fold( - 0.0, + -0.0, #[rustc_inherit_overflow_checks] |a, b| a + b, ) @@ -126,7 +126,7 @@ macro_rules! float_sum_product { impl<'a> Sum<&'a $a> for $a { fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self { iter.fold( - 0.0, + -0.0, #[rustc_inherit_overflow_checks] |a, b| a + b, ) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e3640627c56..7f0efede240 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -110,7 +110,6 @@ #![cfg_attr(bootstrap, feature(offset_of_nested))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] -#![feature(char_indices_offset)] #![feature(const_align_of_val)] #![feature(const_align_of_val_raw)] #![feature(const_align_offset)] @@ -194,6 +193,7 @@ // Language features: // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(asm_const))] +#![cfg_attr(bootstrap, feature(const_fn_floating_point_arithmetic))] #![cfg_attr(bootstrap, feature(min_exhaustive_patterns))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] @@ -203,7 +203,6 @@ #![feature(cfg_sanitize)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_has_atomic_equal_alignment)] -#![feature(const_fn_floating_point_arithmetic)] #![feature(const_for)] #![feature(const_mut_refs)] #![feature(const_precise_live_drops)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 374fa086aec..5654f5aa4b8 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1097,7 +1097,6 @@ pub mod effects { pub trait TyCompat<T: ?Sized> {} impl<T: ?Sized> TyCompat<T> for T {} - impl<T: ?Sized> TyCompat<T> for Maybe {} impl<T: ?Sized> TyCompat<Maybe> for T {} #[lang = "EffectsIntersection"] diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 00c837041b6..be5cee2e852 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -47,6 +47,7 @@ use crate::ptr; #[lang = "manually_drop"] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] +#[cfg_attr(not(bootstrap), rustc_pub_transparent)] pub struct ManuallyDrop<T: ?Sized> { value: T, } diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index f920ab1792d..c308def2f57 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -237,6 +237,7 @@ use crate::{fmt, intrinsics, ptr, slice}; #[lang = "maybe_uninit"] #[derive(Copy)] #[repr(transparent)] +#[cfg_attr(not(bootstrap), rustc_pub_transparent)] pub union MaybeUninit<T> { uninit: (), value: ManuallyDrop<T>, diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 41bd34a2702..bb0cc1c60ba 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -261,7 +261,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let nan = f16::NAN; /// let f = 7.0_f16; @@ -293,7 +293,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let f = 7.0f16; /// let inf = f16::INFINITY; @@ -319,7 +319,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let f = 7.0f16; /// let inf: f16 = f16::INFINITY; @@ -347,7 +347,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let min = f16::MIN_POSITIVE; // 6.1035e-5 /// let max = f16::MAX; @@ -377,7 +377,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let min = f16::MIN_POSITIVE; // 6.1035e-5 /// let max = f16::MAX; @@ -409,7 +409,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// use std::num::FpCategory; /// @@ -867,7 +867,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let value = 4.6_f16; /// let rounded = unsafe { value.to_int_unchecked::<u16>() }; @@ -910,7 +910,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// # // FIXME(f16_f128): enable this once const casting works /// # // assert_ne!((1f16).to_bits(), 1f16 as u128); // to_bits() is not casting! @@ -958,7 +958,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let v = f16::from_bits(0x4a40); /// assert_eq!(v, 12.5); @@ -1071,7 +1071,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let value = f16::from_be_bytes([0x4a, 0x40]); /// assert_eq!(value, 12.5); @@ -1094,7 +1094,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let value = f16::from_le_bytes([0x40, 0x4a]); /// assert_eq!(value, 12.5); @@ -1124,7 +1124,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// let value = f16::from_ne_bytes(if cfg!(target_endian = "big") { /// [0x4a, 0x40] @@ -1257,7 +1257,7 @@ impl f16 { /// /// ``` /// #![feature(f16)] - /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885 + /// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { /// /// assert!((-3.0f16).clamp(-2.0, 1.0) == -2.0); /// assert!((0.0f16).clamp(-2.0, 1.0) == 0.0); diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 0569b8b7624..780e476f531 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1084,6 +1084,7 @@ use crate::{cmp, fmt}; #[lang = "pin"] #[fundamental] #[repr(transparent)] +#[cfg_attr(not(bootstrap), rustc_pub_transparent)] #[derive(Copy, Clone)] pub struct Pin<Ptr> { // FIXME(#93176): this field is made `#[unstable] #[doc(hidden)] pub` to: @@ -1291,8 +1292,8 @@ impl<Ptr: Deref> Pin<Ptr> { /// // Now, if `x` was the only reference, we have a mutable reference to /// // data that we pinned above, which we could use to move it as we have /// // seen in the previous example. We have violated the pinning API contract. - /// } - /// ``` + /// } + /// ``` /// /// ## Pinning of closure captures /// @@ -1370,33 +1371,6 @@ impl<Ptr: Deref> Pin<Ptr> { unsafe { Pin::new_unchecked(&*self.__pointer) } } - /// Unwraps this `Pin<Ptr>`, returning the underlying `Ptr`. - /// - /// # Safety - /// - /// This function is unsafe. You must guarantee that you will continue to - /// treat the pointer `Ptr` as pinned after you call this function, so that - /// the invariants on the `Pin` type can be upheld. If the code using the - /// resulting `Ptr` does not continue to maintain the pinning invariants that - /// is a violation of the API contract and may lead to undefined behavior in - /// later (safe) operations. - /// - /// Note that you must be able to guarantee that the data pointed to by `Ptr` - /// will be treated as pinned all the way until its `drop` handler is complete! - /// - /// *For more information, see the [`pin` module docs][self]* - /// - /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used - /// instead. - #[inline(always)] - #[rustc_const_unstable(feature = "const_pin", issue = "76654")] - #[stable(feature = "pin_into_inner", since = "1.39.0")] - pub const unsafe fn into_inner_unchecked(pin: Pin<Ptr>) -> Ptr { - pin.__pointer - } -} - -impl<Ptr: DerefMut> Pin<Ptr> { /// Gets a mutable reference to the pinned value this `Pin<Ptr>` points to. /// /// This is a generic method to go from `&mut Pin<Pointer<T>>` to `Pin<&mut T>`. @@ -1428,11 +1402,55 @@ impl<Ptr: DerefMut> Pin<Ptr> { /// ``` #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> { + pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> + where + Ptr: DerefMut, + { // SAFETY: see documentation on this function unsafe { Pin::new_unchecked(&mut *self.__pointer) } } + /// Gets `Pin<&mut T>` to the underlying pinned value from this nested `Pin`-pointer. + /// + /// This is a generic method to go from `Pin<&mut Pin<Pointer<T>>>` to `Pin<&mut T>`. It is + /// safe because the existence of a `Pin<Pointer<T>>` ensures that the pointee, `T`, cannot + /// move in the future, and this method does not enable the pointee to move. "Malicious" + /// implementations of `Ptr::DerefMut` are likewise ruled out by the contract of + /// `Pin::new_unchecked`. + #[unstable(feature = "pin_deref_mut", issue = "86918")] + #[must_use = "`self` will be dropped if the result is not used"] + #[inline(always)] + pub fn as_deref_mut(self: Pin<&mut Pin<Ptr>>) -> Pin<&mut Ptr::Target> + where + Ptr: DerefMut, + { + // SAFETY: What we're asserting here is that going from + // + // Pin<&mut Pin<Ptr>> + // + // to + // + // Pin<&mut Ptr::Target> + // + // is safe. + // + // We need to ensure that two things hold for that to be the case: + // + // 1) Once we give out a `Pin<&mut Ptr::Target>`, a `&mut Ptr::Target` will not be given out. + // 2) By giving out a `Pin<&mut Ptr::Target>`, we do not risk violating + // `Pin<&mut Pin<Ptr>>` + // + // The existence of `Pin<Ptr>` is sufficient to guarantee #1: since we already have a + // `Pin<Ptr>`, it must already uphold the pinning guarantees, which must mean that + // `Pin<&mut Ptr::Target>` does as well, since `Pin::as_mut` is safe. We do not have to rely + // on the fact that `Ptr` is _also_ pinned. + // + // For #2, we need to ensure that code given a `Pin<&mut Ptr::Target>` cannot cause the + // `Pin<Ptr>` to move? That is not possible, since `Pin<&mut Ptr::Target>` no longer retains + // any access to the `Ptr` itself, much less the `Pin<Ptr>`. + unsafe { self.get_unchecked_mut() }.as_mut() + } + /// Assigns a new value to the memory location pointed to by the `Pin<Ptr>`. /// /// This overwrites pinned data, but that is okay: the original pinned value's destructor gets @@ -1457,10 +1475,36 @@ impl<Ptr: DerefMut> Pin<Ptr> { #[inline(always)] pub fn set(&mut self, value: Ptr::Target) where + Ptr: DerefMut, Ptr::Target: Sized, { *(self.__pointer) = value; } + + /// Unwraps this `Pin<Ptr>`, returning the underlying `Ptr`. + /// + /// # Safety + /// + /// This function is unsafe. You must guarantee that you will continue to + /// treat the pointer `Ptr` as pinned after you call this function, so that + /// the invariants on the `Pin` type can be upheld. If the code using the + /// resulting `Ptr` does not continue to maintain the pinning invariants that + /// is a violation of the API contract and may lead to undefined behavior in + /// later (safe) operations. + /// + /// Note that you must be able to guarantee that the data pointed to by `Ptr` + /// will be treated as pinned all the way until its `drop` handler is complete! + /// + /// *For more information, see the [`pin` module docs][self]* + /// + /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used + /// instead. + #[inline(always)] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin_into_inner", since = "1.39.0")] + pub const unsafe fn into_inner_unchecked(pin: Pin<Ptr>) -> Ptr { + pin.__pointer + } } impl<'a, T: ?Sized> Pin<&'a T> { @@ -1613,46 +1657,6 @@ impl<T: ?Sized> Pin<&'static T> { } } -impl<'a, Ptr: DerefMut> Pin<&'a mut Pin<Ptr>> { - /// Gets `Pin<&mut T>` to the underlying pinned value from this nested `Pin`-pointer. - /// - /// This is a generic method to go from `Pin<&mut Pin<Pointer<T>>>` to `Pin<&mut T>`. It is - /// safe because the existence of a `Pin<Pointer<T>>` ensures that the pointee, `T`, cannot - /// move in the future, and this method does not enable the pointee to move. "Malicious" - /// implementations of `Ptr::DerefMut` are likewise ruled out by the contract of - /// `Pin::new_unchecked`. - #[unstable(feature = "pin_deref_mut", issue = "86918")] - #[must_use = "`self` will be dropped if the result is not used"] - #[inline(always)] - pub fn as_deref_mut(self) -> Pin<&'a mut Ptr::Target> { - // SAFETY: What we're asserting here is that going from - // - // Pin<&mut Pin<Ptr>> - // - // to - // - // Pin<&mut Ptr::Target> - // - // is safe. - // - // We need to ensure that two things hold for that to be the case: - // - // 1) Once we give out a `Pin<&mut Ptr::Target>`, a `&mut Ptr::Target` will not be given out. - // 2) By giving out a `Pin<&mut Ptr::Target>`, we do not risk violating - // `Pin<&mut Pin<Ptr>>` - // - // The existence of `Pin<Ptr>` is sufficient to guarantee #1: since we already have a - // `Pin<Ptr>`, it must already uphold the pinning guarantees, which must mean that - // `Pin<&mut Ptr::Target>` does as well, since `Pin::as_mut` is safe. We do not have to rely - // on the fact that `Ptr` is _also_ pinned. - // - // For #2, we need to ensure that code given a `Pin<&mut Ptr::Target>` cannot cause the - // `Pin<Ptr>` to move? That is not possible, since `Pin<&mut Ptr::Target>` no longer retains - // any access to the `Ptr` itself, much less the `Pin<Ptr>`. - unsafe { self.get_unchecked_mut() }.as_mut() - } -} - impl<T: ?Sized> Pin<&'static mut T> { /// Gets a pinning mutable reference from a static mutable reference. /// diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 68fce3960c7..19fe03d57cc 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -1,5 +1,4 @@ use crate::num::NonZero; -#[cfg(debug_assertions)] use crate::ub_checks::assert_unsafe_precondition; use crate::{cmp, fmt, hash, mem, num}; @@ -77,7 +76,6 @@ impl Alignment { #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] pub const unsafe fn new_unchecked(align: usize) -> Self { - #[cfg(debug_assertions)] assert_unsafe_precondition!( check_language_ub, "Alignment::new_unchecked requires a power of two", diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 3fe5212cea7..65e473d99b3 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2130,6 +2130,33 @@ pub fn addr_eq<T: ?Sized, U: ?Sized>(p: *const T, q: *const U) -> bool { (p as *const ()) == (q as *const ()) } +/// Compares the *addresses* of the two function pointers for equality. +/// +/// Function pointers comparisons can have surprising results since +/// they are never guaranteed to be unique and could vary between different +/// code generation units. Furthermore, different functions could have the +/// same address after being merged together. +/// +/// This is the same as `f == g` but using this function makes clear +/// that you are aware of these potentially surprising semantics. +/// +/// # Examples +/// +/// ``` +/// #![feature(ptr_fn_addr_eq)] +/// use std::ptr; +/// +/// fn a() { println!("a"); } +/// fn b() { println!("b"); } +/// assert!(!ptr::fn_addr_eq(a as fn(), b as fn())); +/// ``` +#[unstable(feature = "ptr_fn_addr_eq", issue = "129322")] +#[inline(always)] +#[must_use = "function pointer comparison produces a value"] +pub fn fn_addr_eq<T: FnPtr, U: FnPtr>(f: T, g: U) -> bool { + f.addr() == g.addr() +} + /// Hash a raw pointer. /// /// This can be used to hash a `&T` reference (which coerces to `*const T` implicitly) diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 7f278296b7b..73b11f803d9 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1481,7 +1481,6 @@ impl<T, E> Result<T, E> { #[track_caller] #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")] pub unsafe fn unwrap_unchecked(self) -> T { - debug_assert!(self.is_ok()); match self { Ok(t) => t, // SAFETY: the safety contract must be upheld by the caller. @@ -1513,7 +1512,6 @@ impl<T, E> Result<T, E> { #[track_caller] #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")] pub unsafe fn unwrap_err_unchecked(self) -> E { - debug_assert!(self.is_err()); match self { // SAFETY: the safety contract must be upheld by the caller. Ok(_) => unsafe { hint::unreachable_unchecked() }, diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 06f796f9f3a..681ec79c0b7 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -241,24 +241,35 @@ impl<'a> CharIndices<'a> { /// Returns the byte position of the next character, or the length /// of the underlying string if there are no more characters. /// + /// This means that, when the iterator has not been fully consumed, + /// the returned value will match the index that will be returned + /// by the next call to [`next()`](Self::next). + /// /// # Examples /// /// ``` - /// #![feature(char_indices_offset)] /// let mut chars = "a楽".char_indices(); /// + /// // `next()` has not been called yet, so `offset()` returns the byte + /// // index of the first character of the string, which is always 0. /// assert_eq!(chars.offset(), 0); + /// // As expected, the first call to `next()` also returns 0 as index. /// assert_eq!(chars.next(), Some((0, 'a'))); /// + /// // `next()` has been called once, so `offset()` returns the byte index + /// // of the second character ... /// assert_eq!(chars.offset(), 1); + /// // ... which matches the index returned by the next call to `next()`. /// assert_eq!(chars.next(), Some((1, '楽'))); /// + /// // Once the iterator has been consumed, `offset()` returns the length + /// // in bytes of the string. /// assert_eq!(chars.offset(), 4); /// assert_eq!(chars.next(), None); /// ``` #[inline] #[must_use] - #[unstable(feature = "char_indices_offset", issue = "83871")] + #[stable(feature = "char_indices_offset", since = "CURRENT_RUSTC_VERSION")] pub fn offset(&self) -> usize { self.front_offset } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 56517348dc7..cf9f1bfc0eb 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2818,5 +2818,5 @@ impl_fn_for_zst! { } // This is required to make `impl From<&str> for Box<dyn Error>` and `impl<E> From<E> for Box<dyn Error>` not overlap. -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "error_in_core_neg_impl", since = "1.65.0")] impl !crate::error::Error for &str {} diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 65d4d5cf2ce..9ec92e28450 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -122,23 +122,29 @@ macro_rules! tuple_impls { } } - #[stable(feature = "array_tuple_conv", since = "1.71.0")] - impl<T> From<[T; ${count($T)}]> for ($(${ignore($T)} T,)+) { - #[inline] - #[allow(non_snake_case)] - fn from(array: [T; ${count($T)}]) -> Self { - let [$($T,)+] = array; - ($($T,)+) + maybe_tuple_doc! { + $($T)+ @ + #[stable(feature = "array_tuple_conv", since = "1.71.0")] + impl<T> From<[T; ${count($T)}]> for ($(${ignore($T)} T,)+) { + #[inline] + #[allow(non_snake_case)] + fn from(array: [T; ${count($T)}]) -> Self { + let [$($T,)+] = array; + ($($T,)+) + } } } - #[stable(feature = "array_tuple_conv", since = "1.71.0")] - impl<T> From<($(${ignore($T)} T,)+)> for [T; ${count($T)}] { - #[inline] - #[allow(non_snake_case)] - fn from(tuple: ($(${ignore($T)} T,)+)) -> Self { - let ($($T,)+) = tuple; - [$($T,)+] + maybe_tuple_doc! { + $($T)+ @ + #[stable(feature = "array_tuple_conv", since = "1.71.0")] + impl<T> From<($(${ignore($T)} T,)+)> for [T; ${count($T)}] { + #[inline] + #[allow(non_snake_case)] + fn from(tuple: ($(${ignore($T)} T,)+)) -> Self { + let ($($T,)+) = tuple; + [$($T,)+] + } } } } @@ -148,7 +154,7 @@ macro_rules! tuple_impls { // Otherwise, it hides the docs entirely. macro_rules! maybe_tuple_doc { ($a:ident @ #[$meta:meta] $item:item) => { - #[doc(fake_variadic)] + #[cfg_attr(not(bootstrap), doc(fake_variadic))] #[doc = "This trait is implemented for tuples up to twelve items long."] #[$meta] $item diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index b65b48c162d..c1a8c34539e 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -10,7 +10,7 @@ use crate::intrinsics::{self, const_eval_select}; /// macro for language UB are always ignored. /// /// This macro should be called as -/// `assert_unsafe_precondition!(check_{library,lang}_ub, "message", (ident: type = expr, ident: type = expr) => check_expr)` +/// `assert_unsafe_precondition!(check_{library,language}_ub, "message", (ident: type = expr, ident: type = expr) => check_expr)` /// where each `expr` will be evaluated and passed in as function argument `ident: type`. Then all /// those arguments are passed to a function with the body `check_expr`. /// Pick `check_language_ub` when this is guarding a violation of language UB, i.e., immediate UB diff --git a/library/core/tests/fmt/builders.rs b/library/core/tests/fmt/builders.rs index 2bdc334b7c0..ba4801f5912 100644 --- a/library/core/tests/fmt/builders.rs +++ b/library/core/tests/fmt/builders.rs @@ -79,23 +79,23 @@ mod debug_struct { } assert_eq!( - "Bar { foo: Foo { bar: true, baz: 10/20 }, hello: \"world\" }", + r#"Bar { foo: Foo { bar: true, baz: 10/20 }, hello: "world" }"#, format!("{Bar:?}") ); assert_eq!( - "Bar { + r#"Bar { foo: Foo { bar: true, baz: 10/20, }, - hello: \"world\", -}", + hello: "world", +}"#, format!("{Bar:#?}") ); } #[test] - fn test_only_non_exhaustive() { + fn test_empty_non_exhaustive() { struct Foo; impl fmt::Debug for Foo { @@ -157,19 +157,19 @@ mod debug_struct { } assert_eq!( - "Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: \"world\", .. }", + r#"Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: "world", .. }"#, format!("{Bar:?}") ); assert_eq!( - "Bar { + r#"Bar { foo: Foo { bar: true, baz: 10/20, .. }, - hello: \"world\", + hello: "world", .. -}", +}"#, format!("{Bar:#?}") ); } @@ -249,15 +249,89 @@ mod debug_tuple { } } - assert_eq!("Bar(Foo(true, 10/20), \"world\")", format!("{Bar:?}")); + assert_eq!(r#"Bar(Foo(true, 10/20), "world")"#, format!("{Bar:?}")); assert_eq!( - "Bar( + r#"Bar( Foo( true, 10/20, ), - \"world\", + "world", +)"#, + format!("{Bar:#?}") + ); + } + + #[test] + fn test_empty_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Foo").finish_non_exhaustive() + } + } + + assert_eq!("Foo(..)", format!("{Foo:?}")); + assert_eq!("Foo(..)", format!("{Foo:#?}")); + } + + #[test] + fn test_multiple_and_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Foo") + .field(&true) + .field(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + assert_eq!("Foo(true, 10/20, ..)", format!("{Foo:?}")); + assert_eq!( + "Foo( + true, + 10/20, + .. )", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_nested_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Foo") + .field(&true) + .field(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_tuple("Bar").field(&Foo).field(&"world").finish_non_exhaustive() + } + } + + assert_eq!(r#"Bar(Foo(true, 10/20, ..), "world", ..)"#, format!("{Bar:?}")); + assert_eq!( + r#"Bar( + Foo( + true, + 10/20, + .. + ), + "world", + .. +)"#, format!("{Bar:#?}") ); } @@ -301,11 +375,11 @@ mod debug_map { assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}")); assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}")); - assert_eq!("{\"bar\": true}", format!("{Entry:?}")); + assert_eq!(r#"{"bar": true}"#, format!("{Entry:?}")); assert_eq!( - "{ - \"bar\": true, -}", + r#"{ + "bar": true, +}"#, format!("{Entry:#?}") ); } @@ -339,12 +413,12 @@ mod debug_map { assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}")); assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}")); - assert_eq!("{\"bar\": true, 10: 10/20}", format!("{Entry:?}")); + assert_eq!(r#"{"bar": true, 10: 10/20}"#, format!("{Entry:?}")); assert_eq!( - "{ - \"bar\": true, + r#"{ + "bar": true, 10: 10/20, -}", +}"#, format!("{Entry:#?}") ); } @@ -371,21 +445,20 @@ mod debug_map { } assert_eq!( - "{\"foo\": {\"bar\": true, 10: 10/20}, \ - {\"bar\": true, 10: 10/20}: \"world\"}", + r#"{"foo": {"bar": true, 10: 10/20}, {"bar": true, 10: 10/20}: "world"}"#, format!("{Bar:?}") ); assert_eq!( - "{ - \"foo\": { - \"bar\": true, + r#"{ + "foo": { + "bar": true, 10: 10/20, }, { - \"bar\": true, + "bar": true, 10: 10/20, - }: \"world\", -}", + }: "world", +}"#, format!("{Bar:#?}") ); } @@ -471,6 +544,103 @@ mod debug_map { let _ = format!("{Foo:?}"); } + + #[test] + fn test_empty_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map().finish_non_exhaustive() + } + } + + assert_eq!("{..}", format!("{Foo:?}")); + assert_eq!("{..}", format!("{Foo:#?}")); + } + + #[test] + fn test_multiple_and_non_exhaustive() { + struct Entry; + + impl fmt::Debug for Entry { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map() + .entry(&"bar", &true) + .entry(&10, &format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + struct KeyValue; + + impl fmt::Debug for KeyValue { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map() + .key(&"bar") + .value(&true) + .key(&10) + .value(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}")); + assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}")); + + assert_eq!(r#"{"bar": true, 10: 10/20, ..}"#, format!("{Entry:?}")); + assert_eq!( + r#"{ + "bar": true, + 10: 10/20, + .. +}"#, + format!("{Entry:#?}") + ); + } + + #[test] + fn test_nested_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map() + .entry(&"bar", &true) + .entry(&10, &format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_map().entry(&"foo", &Foo).entry(&Foo, &"world").finish_non_exhaustive() + } + } + + assert_eq!( + r#"{"foo": {"bar": true, 10: 10/20, ..}, {"bar": true, 10: 10/20, ..}: "world", ..}"#, + format!("{Bar:?}") + ); + assert_eq!( + r#"{ + "foo": { + "bar": true, + 10: 10/20, + .. + }, + { + "bar": true, + 10: 10/20, + .. + }: "world", + .. +}"#, + format!("{Bar:#?}") + ); + } } mod debug_set { @@ -547,15 +717,89 @@ mod debug_set { } } - assert_eq!("{{true, 10/20}, \"world\"}", format!("{Bar:?}")); + assert_eq!(r#"{{true, 10/20}, "world"}"#, format!("{Bar:?}")); assert_eq!( - "{ + r#"{ { true, 10/20, }, - \"world\", + "world", +}"#, + format!("{Bar:#?}") + ); + } + + #[test] + fn test_empty_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set().finish_non_exhaustive() + } + } + + assert_eq!("{..}", format!("{Foo:?}")); + assert_eq!("{..}", format!("{Foo:#?}")); + } + + #[test] + fn test_multiple_and_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set() + .entry(&true) + .entry(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + assert_eq!("{true, 10/20, ..}", format!("{Foo:?}")); + assert_eq!( + "{ + true, + 10/20, + .. }", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_nested_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set() + .entry(&true) + .entry(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_set().entry(&Foo).entry(&"world").finish_non_exhaustive() + } + } + + assert_eq!(r#"{{true, 10/20, ..}, "world", ..}"#, format!("{Bar:?}")); + assert_eq!( + r#"{ + { + true, + 10/20, + .. + }, + "world", + .. +}"#, format!("{Bar:#?}") ); } @@ -635,15 +879,89 @@ mod debug_list { } } - assert_eq!("[[true, 10/20], \"world\"]", format!("{Bar:?}")); + assert_eq!(r#"[[true, 10/20], "world"]"#, format!("{Bar:?}")); assert_eq!( - "[ + r#"[ [ true, 10/20, ], - \"world\", + "world", +]"#, + format!("{Bar:#?}") + ); + } + + #[test] + fn test_empty_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list().finish_non_exhaustive() + } + } + + assert_eq!("[..]", format!("{Foo:?}")); + assert_eq!("[..]", format!("{Foo:#?}")); + } + + #[test] + fn test_multiple_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list() + .entry(&true) + .entry(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + assert_eq!("[true, 10/20, ..]", format!("{Foo:?}")); + assert_eq!( + "[ + true, + 10/20, + .. ]", + format!("{Foo:#?}") + ); + } + + #[test] + fn test_nested_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list() + .entry(&true) + .entry(&format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_list().entry(&Foo).entry(&"world").finish_non_exhaustive() + } + } + + assert_eq!(r#"[[true, 10/20, ..], "world", ..]"#, format!("{Bar:?}")); + assert_eq!( + r#"[ + [ + true, + 10/20, + .. + ], + "world", + .. +]"#, format!("{Bar:#?}") ); } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 8872b4cbfd5..073429c7628 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -43,6 +43,7 @@ #![feature(core_io_borrowed_buf)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] +#![feature(debug_more_non_exhaustive)] #![feature(dec2flt)] #![feature(duration_constants)] #![feature(duration_constructors)] @@ -73,7 +74,6 @@ #![feature(iter_next_chunk)] #![feature(iter_order_by)] #![feature(iter_partition_in_place)] -#![feature(iter_repeat_n)] #![feature(iterator_try_collect)] #![feature(iterator_try_reduce)] #![feature(layout_for_ptr)] diff --git a/library/core/tests/num/float_iter_sum_identity.rs b/library/core/tests/num/float_iter_sum_identity.rs new file mode 100644 index 00000000000..6d3224522a8 --- /dev/null +++ b/library/core/tests/num/float_iter_sum_identity.rs @@ -0,0 +1,27 @@ +#[test] +fn f32_ref() { + let x: f32 = -0.0; + let still_x: f32 = [x].iter().sum(); + assert_eq!(1. / x, 1. / still_x) +} + +#[test] +fn f32_own() { + let x: f32 = -0.0; + let still_x: f32 = [x].into_iter().sum(); + assert_eq!(1. / x, 1. / still_x) +} + +#[test] +fn f64_ref() { + let x: f64 = -0.0; + let still_x: f64 = [x].iter().sum(); + assert_eq!(1. / x, 1. / still_x) +} + +#[test] +fn f64_own() { + let x: f64 = -0.0; + let still_x: f64 = [x].into_iter().sum(); + assert_eq!(1. / x, 1. / still_x) +} diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index 9d2912c4b22..53ff5ab1ced 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -30,6 +30,7 @@ mod int_log; mod ops; mod wrapping; +mod float_iter_sum_identity; mod ieee754; mod nan; diff --git a/library/profiler_builtins/build.rs b/library/profiler_builtins/build.rs index 9d1c1ba305b..c1e0e5c1c89 100644 --- a/library/profiler_builtins/build.rs +++ b/library/profiler_builtins/build.rs @@ -3,7 +3,7 @@ //! See the build.rs for libcompiler_builtins crate for details. use std::env; -use std::path::Path; +use std::path::PathBuf; fn main() { println!("cargo:rerun-if-env-changed=LLVM_PROFILER_RT_LIB"); @@ -79,17 +79,25 @@ fn main() { cfg.define("COMPILER_RT_HAS_ATOMICS", Some("1")); } - // Note that this should exist if we're going to run (otherwise we just - // don't build profiler builtins at all). - let root = Path::new("../../src/llvm-project/compiler-rt"); + // Get the LLVM `compiler-rt` directory from bootstrap. + println!("cargo:rerun-if-env-changed=RUST_COMPILER_RT_FOR_PROFILER"); + let root = PathBuf::from(env::var("RUST_COMPILER_RT_FOR_PROFILER").unwrap_or_else(|_| { + let path = "../../src/llvm-project/compiler-rt"; + println!("RUST_COMPILER_RT_FOR_PROFILER was not set; falling back to {path:?}"); + path.to_owned() + })); let src_root = root.join("lib").join("profile"); + assert!(src_root.exists(), "profiler runtime source directory not found: {src_root:?}"); + let mut n_sources_found = 0u32; for src in profile_sources { let path = src_root.join(src); if path.exists() { cfg.file(path); + n_sources_found += 1; } } + assert!(n_sources_found > 0, "couldn't find any profiler runtime source files in {src_root:?}"); cfg.include(root.join("include")); cfg.warnings(false); diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 7f23681ee45..334c75df231 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "0.1.118" } +compiler_builtins = { version = "0.1.121" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = [ diff --git a/library/std/build.rs b/library/std/build.rs index 35a5977b6eb..fecdf2c3e1f 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -103,9 +103,9 @@ fn main() { ("arm64ec", _) => false, // MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> ("x86_64", "windows") => false, - // x86 has ABI bugs that show up with optimizations. This should be partially fixed with - // the compiler-builtins update. <https://github.com/rust-lang/rust/issues/123885> - ("x86" | "x86_64", _) => false, + // Apple has a special ABI for `f16` that we do not yet support + // FIXME(builtins): fixed by <https://github.com/rust-lang/compiler-builtins/pull/675> + ("x86" | "x86_64", _) if target_vendor == "apple" => false, // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee` ("powerpc" | "powerpc64", _) => false, // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee` @@ -140,17 +140,17 @@ fn main() { _ => false, }; - // These are currently empty, but will fill up as some platforms move from completely - // unreliable to reliable basics but unreliable math. + // Configure platforms that have reliable basics but may have unreliable math. // LLVM is currenlty adding missing routines, <https://github.com/llvm/llvm-project/issues/93566> let has_reliable_f16_math = has_reliable_f16 && match (target_arch.as_str(), target_os.as_str()) { // FIXME: Disabled on Miri as the intrinsics are not implemented yet. _ if is_miri => false, - // Currently nothing special. Hooray! - // This will change as platforms gain better better support for standard ops but math - // lags behind. + // x86 has a crash for `powi`: <https://github.com/llvm/llvm-project/issues/105747> + ("x86" | "x86_64", _) => false, + // Assume that working `f16` means working `f16` math for most platforms, since + // operations just go through `f32`. _ => true, }; diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index c5edb03bb08..6a0d9f47960 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2491,6 +2491,8 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { /// /// Consider ignoring the error if validating the removal is not required for your use case. /// +/// [`io::ErrorKind::NotFound`] is only returned if no removal occurs. +/// /// [`fs::remove_file`]: remove_file /// [`fs::remove_dir`]: remove_dir /// diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 2530a376387..f65e9bc8d8b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -363,6 +363,7 @@ #![feature(get_mut_unchecked)] #![feature(map_try_insert)] #![feature(new_uninit)] +#![feature(new_zeroed_alloc)] #![feature(slice_concat_trait)] #![feature(thin_box)] #![feature(try_reserve_kind)] diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs index a58ca543d67..9ec3e387e2b 100644 --- a/library/std/src/os/wasi/fs.rs +++ b/library/std/src/os/wasi/fs.rs @@ -2,7 +2,6 @@ //! //! [`std::fs`]: crate::fs -#![deny(unsafe_op_in_unsafe_fn)] #![unstable(feature = "wasi_ext", issue = "71213")] // Used for `File::read` on intra-doc links diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs index e36b93e60ea..33b50c9e53b 100644 --- a/library/std/src/os/wasi/mod.rs +++ b/library/std/src/os/wasi/mod.rs @@ -30,7 +30,7 @@ #![cfg_attr(not(target_env = "p2"), stable(feature = "rust1", since = "1.0.0"))] #![cfg_attr(target_env = "p2", unstable(feature = "wasip2", issue = "none"))] -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] #![doc(cfg(target_os = "wasi"))] pub mod ffi; diff --git a/library/std/src/os/wasip2/mod.rs b/library/std/src/os/wasip2/mod.rs index 1d44dd72814..809a288f20d 100644 --- a/library/std/src/os/wasip2/mod.rs +++ b/library/std/src/os/wasip2/mod.rs @@ -2,4 +2,5 @@ //! //! This module is currently empty, but will be filled over time as wasi-libc support for WASI Preview 2 is stabilized. +#![forbid(unsafe_op_in_unsafe_fn)] #![stable(feature = "raw_ext", since = "1.1.0")] diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index e818b448270..190eed94555 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -275,7 +275,7 @@ fn default_hook(info: &PanicHookInfo<'_>) { if cfg!(miri) { let _ = writeln!( err, - "note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` \ + "note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` \ for the environment variable to have an effect" ); } diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs index 8179ec8821a..591be66fcb4 100644 --- a/library/std/src/sys/pal/solid/fs.rs +++ b/library/std/src/sys/pal/solid/fs.rs @@ -10,6 +10,7 @@ use crate::sync::Arc; use crate::sys::time::SystemTime; use crate::sys::unsupported; pub use crate::sys_common::fs::exists; +use crate::sys_common::ignore_notfound; /// A file descriptor. #[derive(Clone, Copy)] @@ -527,15 +528,23 @@ pub fn rmdir(p: &Path) -> io::Result<()> { pub fn remove_dir_all(path: &Path) -> io::Result<()> { for child in readdir(path)? { - let child = child?; - let child_type = child.file_type()?; - if child_type.is_dir() { - remove_dir_all(&child.path())?; - } else { - unlink(&child.path())?; + let result: io::Result<()> = try { + let child = child?; + let child_type = child.file_type()?; + if child_type.is_dir() { + remove_dir_all(&child.path())?; + } else { + unlink(&child.path())?; + } + }; + // ignore internal NotFound errors + if let Err(err) = result + && err.kind() != io::ErrorKind::NotFound + { + return result; } } - rmdir(path) + ignore_notfound(rmdir(path)) } pub fn readlink(p: &Path) -> io::Result<PathBuf> { diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index be13e1ae9b3..fc9d7e98883 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -2002,6 +2002,7 @@ mod remove_dir_impl { use crate::path::{Path, PathBuf}; use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::{cvt, cvt_r}; + use crate::sys_common::ignore_notfound; pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> io::Result<OwnedFd> { let fd = cvt_r(|| unsafe { @@ -2055,6 +2056,16 @@ mod remove_dir_impl { } } + fn is_enoent(result: &io::Result<()>) -> bool { + if let Err(err) = result + && matches!(err.raw_os_error(), Some(libc::ENOENT)) + { + true + } else { + false + } + } + fn remove_dir_all_recursive(parent_fd: Option<RawFd>, path: &CStr) -> io::Result<()> { // try opening as directory let fd = match openat_nofollow_dironly(parent_fd, &path) { @@ -2078,27 +2089,35 @@ mod remove_dir_impl { for child in dir { let child = child?; let child_name = child.name_cstr(); - match is_dir(&child) { - Some(true) => { - remove_dir_all_recursive(Some(fd), child_name)?; - } - Some(false) => { - cvt(unsafe { unlinkat(fd, child_name.as_ptr(), 0) })?; - } - None => { - // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed - // if the process has the appropriate privileges. This however can causing orphaned - // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing - // into it first instead of trying to unlink() it. - remove_dir_all_recursive(Some(fd), child_name)?; + // we need an inner try block, because if one of these + // directories has already been deleted, then we need to + // continue the loop, not return ok. + let result: io::Result<()> = try { + match is_dir(&child) { + Some(true) => { + remove_dir_all_recursive(Some(fd), child_name)?; + } + Some(false) => { + cvt(unsafe { unlinkat(fd, child_name.as_ptr(), 0) })?; + } + None => { + // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed + // if the process has the appropriate privileges. This however can causing orphaned + // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing + // into it first instead of trying to unlink() it. + remove_dir_all_recursive(Some(fd), child_name)?; + } } + }; + if result.is_err() && !is_enoent(&result) { + return result; } } // unlink the directory after removing its contents - cvt(unsafe { + ignore_notfound(cvt(unsafe { unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), path.as_ptr(), libc::AT_REMOVEDIR) - })?; + }))?; Ok(()) } diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index b62129f4cdd..10df3306f92 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -116,7 +116,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { if pfd.revents & libc::POLLNVAL == 0 { continue; } - if open64(c"/dev/null".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + if open64(c"/dev/null".as_ptr(), libc::O_RDWR, 0) == -1 { // If the stream is closed but we failed to reopen it, abort the // process. Otherwise we wouldn't preserve the safety of // operations on the corresponding Rust object Stdin, Stdout, or @@ -147,7 +147,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { use crate::sys::os::errno; for fd in 0..3 { if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { - if open64(c"/dev/null".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + if open64(c"/dev/null".as_ptr(), libc::O_RDWR, 0) == -1 { // If the stream is closed but we failed to reopen it, abort the // process. Otherwise we wouldn't preserve the safety of // operations on the corresponding Rust object Stdin, Stdout, or diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 0fa610eebb4..c9dcc5ad97a 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -267,14 +267,32 @@ impl Thread { #[cfg(target_os = "espidf")] pub fn sleep(dur: Duration) { - let mut micros = dur.as_micros(); - unsafe { - while micros > 0 { - let st = if micros > u32::MAX as u128 { u32::MAX } else { micros as u32 }; + // ESP-IDF does not have `nanosleep`, so we use `usleep` instead. + // As per the documentation of `usleep`, it is expected to support + // sleep times as big as at least up to 1 second. + // + // ESP-IDF does support almost up to `u32::MAX`, but due to a potential integer overflow in its + // `usleep` implementation + // (https://github.com/espressif/esp-idf/blob/d7ca8b94c852052e3bc33292287ef4dd62c9eeb1/components/newlib/time.c#L210), + // we limit the sleep time to the maximum one that would not cause the underlying `usleep` implementation to overflow + // (`portTICK_PERIOD_MS` can be anything between 1 to 1000, and is 10 by default). + const MAX_MICROS: u32 = u32::MAX - 1_000_000 - 1; + + // Add any nanoseconds smaller than a microsecond as an extra microsecond + // so as to comply with the `std::thread::sleep` contract which mandates + // implementations to sleep for _at least_ the provided `dur`. + // We can't overflow `micros` as it is a `u128`, while `Duration` is a pair of + // (`u64` secs, `u32` nanos), where the nanos are strictly smaller than 1 second + // (i.e. < 1_000_000_000) + let mut micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 }; + + while micros > 0 { + let st = if micros > MAX_MICROS as u128 { MAX_MICROS } else { micros as u32 }; + unsafe { libc::usleep(st); - - micros -= st as u128; } + + micros -= st as u128; } } diff --git a/library/std/src/sys/pal/wasi/args.rs b/library/std/src/sys/pal/wasi/args.rs index 6b6d1b8ff4e..52cfa202af8 100644 --- a/library/std/src/sys/pal/wasi/args.rs +++ b/library/std/src/sys/pal/wasi/args.rs @@ -1,4 +1,4 @@ -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] use crate::ffi::{CStr, OsStr, OsString}; use crate::os::wasi::ffi::OsStrExt; diff --git a/library/std/src/sys/pal/wasi/env.rs b/library/std/src/sys/pal/wasi/env.rs index 730e356d7fe..8d444982673 100644 --- a/library/std/src/sys/pal/wasi/env.rs +++ b/library/std/src/sys/pal/wasi/env.rs @@ -1,3 +1,5 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + pub mod os { pub const FAMILY: &str = ""; pub const OS: &str = ""; diff --git a/library/std/src/sys/pal/wasi/fd.rs b/library/std/src/sys/pal/wasi/fd.rs index 8966e4b80ad..19b60157e2e 100644 --- a/library/std/src/sys/pal/wasi/fd.rs +++ b/library/std/src/sys/pal/wasi/fd.rs @@ -1,4 +1,4 @@ -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] #![allow(dead_code)] use super::err2io; diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 11900886f0b..88b1e543ec7 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -1,4 +1,4 @@ -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] use super::fd::WasiFd; use crate::ffi::{CStr, OsStr, OsString}; @@ -13,7 +13,7 @@ use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::time::SystemTime; use crate::sys::unsupported; pub use crate::sys_common::fs::exists; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::sys_common::{ignore_notfound, AsInner, FromInner, IntoInner}; use crate::{fmt, iter, ptr}; pub struct File { @@ -794,14 +794,22 @@ fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> { io::const_io_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found") })?; - if entry.file_type()?.is_dir() { - remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?; - } else { - entry.inner.dir.fd.unlink_file(path)?; + let result: io::Result<()> = try { + if entry.file_type()?.is_dir() { + remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?; + } else { + entry.inner.dir.fd.unlink_file(path)?; + } + }; + // ignore internal NotFound errors + if let Err(err) = &result + && err.kind() != io::ErrorKind::NotFound + { + return result; } } // Once all this directory's contents are deleted it should be safe to // delete the directory tiself. - parent.remove_directory(osstr2str(path.as_ref())?) + ignore_notfound(parent.remove_directory(osstr2str(path.as_ref())?)) } diff --git a/library/std/src/sys/pal/wasi/helpers.rs b/library/std/src/sys/pal/wasi/helpers.rs index 4b770ee23bc..d047bf2fce8 100644 --- a/library/std/src/sys/pal/wasi/helpers.rs +++ b/library/std/src/sys/pal/wasi/helpers.rs @@ -1,3 +1,5 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + use crate::{io as std_io, mem}; #[inline] diff --git a/library/std/src/sys/pal/wasi/io.rs b/library/std/src/sys/pal/wasi/io.rs index 2cd45df88fa..b7c2f03daa0 100644 --- a/library/std/src/sys/pal/wasi/io.rs +++ b/library/std/src/sys/pal/wasi/io.rs @@ -1,4 +1,4 @@ -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] use crate::marker::PhantomData; use crate::os::fd::{AsFd, AsRawFd}; diff --git a/library/std/src/sys/pal/wasi/net.rs b/library/std/src/sys/pal/wasi/net.rs index b4cf94c8781..a6486799828 100644 --- a/library/std/src/sys/pal/wasi/net.rs +++ b/library/std/src/sys/pal/wasi/net.rs @@ -1,4 +1,4 @@ -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] use super::err2io; use super::fd::WasiFd; diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasi/os.rs index f5b17d9df94..f7701360f5a 100644 --- a/library/std/src/sys/pal/wasi/os.rs +++ b/library/std/src/sys/pal/wasi/os.rs @@ -1,4 +1,4 @@ -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] use core::slice::memchr; diff --git a/library/std/src/sys/pal/wasi/stdio.rs b/library/std/src/sys/pal/wasi/stdio.rs index 4cc0e4ed5a4..ca49f871e19 100644 --- a/library/std/src/sys/pal/wasi/stdio.rs +++ b/library/std/src/sys/pal/wasi/stdio.rs @@ -1,4 +1,4 @@ -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] use super::fd::WasiFd; use crate::io::{self, IoSlice, IoSliceMut}; diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs index c37acd8dfee..31c9cbd4699 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasi/thread.rs @@ -1,3 +1,5 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + use crate::ffi::CStr; use crate::num::NonZero; use crate::sys::unsupported; @@ -73,13 +75,13 @@ impl Thread { if #[cfg(target_feature = "atomics")] { pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { let p = Box::into_raw(Box::new(p)); - let mut native: libc::pthread_t = mem::zeroed(); - let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(libc::pthread_attr_init(&mut attr), 0); + let mut native: libc::pthread_t = unsafe { mem::zeroed() }; + let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() }; + assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0); let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE); - match libc::pthread_attr_setstacksize(&mut attr, stack_size) { + match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } { 0 => {} n => { assert_eq!(n, libc::EINVAL); @@ -90,20 +92,20 @@ impl Thread { let page_size = os::page_size(); let stack_size = (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); + assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0); } }; - let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); + let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) }; // Note: if the thread creation fails and this assert fails, then p will // be leaked. However, an alternative design could cause double-free // which is clearly worse. - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + assert_eq!(unsafe {libc::pthread_attr_destroy(&mut attr) }, 0); return if ret != 0 { // The thread failed to start and as a result p was not consumed. Therefore, it is // safe to reconstruct the box so that it gets deallocated. - drop(Box::from_raw(p)); + unsafe { drop(Box::from_raw(p)); } Err(io::Error::from_raw_os_error(ret)) } else { Ok(Thread { id: native }) diff --git a/library/std/src/sys/pal/wasi/time.rs b/library/std/src/sys/pal/wasi/time.rs index 016b06efbdc..0d8d0b59ac1 100644 --- a/library/std/src/sys/pal/wasi/time.rs +++ b/library/std/src/sys/pal/wasi/time.rs @@ -1,4 +1,4 @@ -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] use crate::time::Duration; diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index d99d4931de4..2134152ea93 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -14,7 +14,7 @@ use crate::sys::handle::Handle; use crate::sys::path::maybe_verbatim; use crate::sys::time::SystemTime; use crate::sys::{c, cvt, Align8}; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::sys_common::{ignore_notfound, AsInner, FromInner, IntoInner}; use crate::{fmt, ptr, slice, thread}; pub struct File { @@ -1160,7 +1160,7 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { return Err(io::Error::from_raw_os_error(c::ERROR_DIRECTORY as _)); } - match remove_dir_all_iterative(&file, File::posix_delete) { + match ignore_notfound(remove_dir_all_iterative(&file, File::posix_delete)) { Err(e) => { if let Some(code) = e.raw_os_error() { match code as u32 { diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys_common/fs.rs index acb6713cf1b..a25a7244660 100644 --- a/library/std/src/sys_common/fs.rs +++ b/library/std/src/sys_common/fs.rs @@ -3,6 +3,7 @@ use crate::fs; use crate::io::{self, Error, ErrorKind}; use crate::path::Path; +use crate::sys_common::ignore_notfound; pub(crate) const NOT_FILE_ERROR: Error = io::const_io_error!( ErrorKind::InvalidInput, @@ -32,14 +33,22 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { for child in fs::read_dir(path)? { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - fs::remove_file(&child.path())?; + let result: io::Result<()> = try { + let child = child?; + if child.file_type()?.is_dir() { + remove_dir_all_recursive(&child.path())?; + } else { + fs::remove_file(&child.path())?; + } + }; + // ignore internal NotFound errors to prevent race conditions + if let Err(err) = &result + && err.kind() != io::ErrorKind::NotFound + { + return result; } } - fs::remove_dir(path) + ignore_notfound(fs::remove_dir(path)) } pub fn exists(path: &Path) -> io::Result<bool> { diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 60ee405ecaa..1c884f107be 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -80,3 +80,11 @@ pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 { // r < denom, so (denom*numer) is the upper bound of (r*numer) q * numer + r * numer / denom } + +pub fn ignore_notfound<T>(result: crate::io::Result<T>) -> crate::io::Result<()> { + match result { + Err(err) if err.kind() == crate::io::ErrorKind::NotFound => Ok(()), + Ok(_) => Ok(()), + Err(err) => Err(err), + } +} diff --git a/library/stdarch b/library/stdarch -Subproject 47b929ddc521a78b0f699ba8d5c274d28593448 +Subproject d9466edb4c53cece8686ee6e17b028436ddf415 diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 4e8e0fd2532..71f69e03a9f 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -79,6 +79,11 @@ def get(base, url, path, checksums, verbose=False): eprint("removing", temp_path) os.unlink(temp_path) +def curl_version(): + m = re.match(bytes("^curl ([0-9]+)\\.([0-9]+)", "utf8"), require(["curl", "-V"])) + if m is None: + return (0, 0) + return (int(m[1]), int(m[2])) def download(path, url, probably_big, verbose): for _ in range(4): @@ -107,11 +112,15 @@ def _download(path, url, probably_big, verbose, exception): # If curl is not present on Win32, we should not sys.exit # but raise `CalledProcessError` or `OSError` instead require(["curl", "--version"], exception=platform_is_win32()) - run(["curl", option, + extra_flags = [] + if curl_version() > (7, 70): + extra_flags = [ "--retry-all-errors" ] + run(["curl", option] + extra_flags + [ "-L", # Follow redirect. "-y", "30", "-Y", "10", # timeout if speed is < 10 bytes/sec for > 30 seconds "--connect-timeout", "30", # timeout if cannot connect within 30 seconds "-o", path, + "--continue-at", "-", "--retry", "3", "-SRf", url], verbose=verbose, exception=True, # Will raise RuntimeError on failure @@ -533,9 +542,13 @@ class RustBuild(object): bin_root = self.bin_root() key = self.stage0_compiler.date - if self.rustc().startswith(bin_root) and \ - (not os.path.exists(self.rustc()) or - self.program_out_of_date(self.rustc_stamp(), key)): + is_outdated = self.program_out_of_date(self.rustc_stamp(), key) + need_rustc = self.rustc().startswith(bin_root) and (not os.path.exists(self.rustc()) \ + or is_outdated) + need_cargo = self.cargo().startswith(bin_root) and (not os.path.exists(self.cargo()) \ + or is_outdated) + + if need_rustc or need_cargo: if os.path.exists(bin_root): # HACK: On Windows, we can't delete rust-analyzer-proc-macro-server while it's # running. Kill it. @@ -556,7 +569,6 @@ class RustBuild(object): run_powershell([script]) shutil.rmtree(bin_root) - key = self.stage0_compiler.date cache_dst = (self.get_toml('bootstrap-cache-path', 'build') or os.path.join(self.build_dir, "cache")) @@ -568,11 +580,16 @@ class RustBuild(object): toolchain_suffix = "{}-{}{}".format(rustc_channel, self.build, tarball_suffix) - tarballs_to_download = [ - ("rust-std-{}".format(toolchain_suffix), "rust-std-{}".format(self.build)), - ("rustc-{}".format(toolchain_suffix), "rustc"), - ("cargo-{}".format(toolchain_suffix), "cargo"), - ] + tarballs_to_download = [] + + if need_rustc: + tarballs_to_download.append( + ("rust-std-{}".format(toolchain_suffix), "rust-std-{}".format(self.build)) + ) + tarballs_to_download.append(("rustc-{}".format(toolchain_suffix), "rustc")) + + if need_cargo: + tarballs_to_download.append(("cargo-{}".format(toolchain_suffix), "cargo")) tarballs_download_info = [ DownloadInfo( diff --git a/src/bootstrap/src/bin/rustdoc.rs b/src/bootstrap/src/bin/rustdoc.rs index ba6b0c2dbda..a338b9c8080 100644 --- a/src/bootstrap/src/bin/rustdoc.rs +++ b/src/bootstrap/src/bin/rustdoc.rs @@ -59,8 +59,6 @@ fn main() { if stage == "0" { cmd.arg("--cfg=bootstrap"); } - cmd.arg("-Zunstable-options"); - cmd.arg("--check-cfg=cfg(bootstrap)"); maybe_dump(format!("stage{stage}-rustdoc"), &cmd); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 4353cfadd8d..edf18e2ebf3 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -199,16 +199,6 @@ impl Step for Std { builder.require_submodule("library/stdarch", None); - // Profiler information requires LLVM's compiler-rt - if builder.config.profiler { - builder.require_submodule( - "src/llvm-project", - Some( - "The `build.profiler` config option requires `compiler-rt` sources from LLVM.", - ), - ); - } - let mut target_deps = builder.ensure(StartupObjects { compiler, target }); let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); @@ -466,6 +456,29 @@ pub fn std_crates_for_run_make(run: &RunConfig<'_>) -> Vec<String> { } } +/// Tries to find LLVM's `compiler-rt` source directory, for building `library/profiler_builtins`. +/// +/// Normally it lives in the `src/llvm-project` submodule, but if we will be using a +/// downloaded copy of CI LLVM, then we try to use the `compiler-rt` sources from +/// there instead, which lets us avoid checking out the LLVM submodule. +fn compiler_rt_for_profiler(builder: &Builder<'_>) -> PathBuf { + // Try to use `compiler-rt` sources from downloaded CI LLVM, if possible. + if builder.config.llvm_from_ci { + // CI LLVM might not have been downloaded yet, so try to download it now. + builder.config.maybe_download_ci_llvm(); + let ci_llvm_compiler_rt = builder.config.ci_llvm_root().join("compiler-rt"); + if ci_llvm_compiler_rt.exists() { + return ci_llvm_compiler_rt; + } + } + + // Otherwise, fall back to requiring the LLVM submodule. + builder.require_submodule("src/llvm-project", { + Some("The `build.profiler` config option requires `compiler-rt` sources from LLVM.") + }); + builder.src.join("src/llvm-project/compiler-rt") +} + /// Configure cargo to compile the standard library, adding appropriate env vars /// and such. pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, cargo: &mut Cargo) { @@ -473,8 +486,15 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car cargo.env("MACOSX_DEPLOYMENT_TARGET", target); } + // Paths needed by `library/profiler_builtins/build.rs`. if let Some(path) = builder.config.profiler_path(target) { cargo.env("LLVM_PROFILER_RT_LIB", path); + } else if builder.config.profiler_enabled(target) { + let compiler_rt = compiler_rt_for_profiler(builder); + // Currently this is separate from the env var used by `compiler_builtins` + // (below) so that adding support for CI LLVM here doesn't risk breaking + // the compiler builtins. But they could be unified if desired. + cargo.env("RUST_COMPILER_RT_FOR_PROFILER", compiler_rt); } // Determine if we're going to compile in optimized C intrinsics to @@ -507,8 +527,8 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car ); let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt"); assert!(compiler_builtins_root.exists()); - // Note that `libprofiler_builtins/build.rs` also computes this so if - // you're changing something here please also change that. + // The path to `compiler-rt` is also used by `profiler_builtins` (above), + // so if you're changing something here please also change that as appropriate. cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); " compiler-builtins-c" } else { diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 8d20b956213..4957de2e1b7 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -269,34 +269,45 @@ fn make_win_dist( let target_libs = find_files(&target_libs, &lib_path); // Copy runtime dlls next to rustc.exe - let dist_bin_dir = rust_root.join("bin/"); - fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed"); - for src in rustc_dlls { - builder.copy_link_to_folder(&src, &dist_bin_dir); + let rust_bin_dir = rust_root.join("bin/"); + fs::create_dir_all(&rust_bin_dir).expect("creating rust_bin_dir failed"); + for src in &rustc_dlls { + builder.copy_link_to_folder(src, &rust_bin_dir); + } + + if builder.config.lld_enabled { + // rust-lld.exe also needs runtime dlls + let rust_target_bin_dir = rust_root.join("lib/rustlib").join(target).join("bin"); + fs::create_dir_all(&rust_target_bin_dir).expect("creating rust_target_bin_dir failed"); + for src in &rustc_dlls { + builder.copy_link_to_folder(src, &rust_target_bin_dir); + } } //Copy platform tools to platform-specific bin directory - let target_bin_dir = - plat_root.join("lib").join("rustlib").join(target).join("bin").join("self-contained"); - fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed"); + let plat_target_bin_self_contained_dir = + plat_root.join("lib/rustlib").join(target).join("bin/self-contained"); + fs::create_dir_all(&plat_target_bin_self_contained_dir) + .expect("creating plat_target_bin_self_contained_dir failed"); for src in target_tools { - builder.copy_link_to_folder(&src, &target_bin_dir); + builder.copy_link_to_folder(&src, &plat_target_bin_self_contained_dir); } // Warn windows-gnu users that the bundled GCC cannot compile C files builder.create( - &target_bin_dir.join("GCC-WARNING.txt"), + &plat_target_bin_self_contained_dir.join("GCC-WARNING.txt"), "gcc.exe contained in this folder cannot be used for compiling C files - it is only \ used as a linker. In order to be able to compile projects containing C code use \ the GCC provided by MinGW or Cygwin.", ); //Copy platform libs to platform-specific lib directory - let target_lib_dir = - plat_root.join("lib").join("rustlib").join(target).join("lib").join("self-contained"); - fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed"); + let plat_target_lib_self_contained_dir = + plat_root.join("lib/rustlib").join(target).join("lib/self-contained"); + fs::create_dir_all(&plat_target_lib_self_contained_dir) + .expect("creating plat_target_lib_self_contained_dir failed"); for src in target_libs { - builder.copy_link_to_folder(&src, &target_lib_dir); + builder.copy_link_to_folder(&src, &plat_target_lib_self_contained_dir); } } diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 301633559fe..ffb617c642b 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -303,10 +303,11 @@ fn invoke_rustdoc( .arg(&out) .arg(&path) .arg("--markdown-css") - .arg("../rust.css"); + .arg("../rust.css") + .arg("-Zunstable-options"); if !builder.config.docs_minification { - cmd.arg("-Z").arg("unstable-options").arg("--disable-minification"); + cmd.arg("--disable-minification"); } cmd.run(builder); @@ -376,8 +377,6 @@ impl Step for Standalone { } let mut cmd = builder.rustdoc_cmd(compiler); - // Needed for --index-page flag - cmd.arg("-Z").arg("unstable-options"); cmd.arg("--html-after-content") .arg(&footer) @@ -386,6 +385,7 @@ impl Step for Standalone { .arg("--html-in-header") .arg(&favicon) .arg("--markdown-no-toc") + .arg("-Zunstable-options") .arg("--index-page") .arg(builder.src.join("src/doc/index.md")) .arg("--markdown-playground-url") @@ -478,9 +478,6 @@ impl Step for Releases { mem::drop(tmpfile); let mut cmd = builder.rustdoc_cmd(compiler); - // Needed for --index-page flag - cmd.arg("-Z").arg("unstable-options"); - cmd.arg("--html-after-content") .arg(&footer) .arg("--html-before-content") @@ -490,6 +487,7 @@ impl Step for Releases { .arg("--markdown-no-toc") .arg("--markdown-css") .arg("rust.css") + .arg("-Zunstable-options") .arg("--index-page") .arg(builder.src.join("src/doc/index.md")) .arg("--markdown-playground-url") @@ -636,6 +634,8 @@ impl Step for Std { if !builder.config.docs_minification { extra_args.push("--disable-minification"); } + // For `--index-page` and `--output-format=json`. + extra_args.push("-Zunstable-options"); doc_std(builder, self.format, stage, target, &out, &extra_args, &crates); @@ -715,8 +715,6 @@ fn doc_std( .arg("--target-dir") .arg(&*target_dir.to_string_lossy()) .arg("-Zskip-rustdoc-fingerprint") - .rustdocflag("-Z") - .rustdocflag("unstable-options") .rustdocflag("--resource-suffix") .rustdocflag(&builder.version); for arg in extra_args { @@ -822,7 +820,6 @@ impl Step for Rustc { // Since we always pass --document-private-items, there's no need to warn about linking to private items. cargo.rustdocflag("-Arustdoc::private-intra-doc-links"); cargo.rustdocflag("--enable-index-page"); - cargo.rustdocflag("-Zunstable-options"); cargo.rustdocflag("-Znormalize-docs"); cargo.rustdocflag("--show-type-layout"); // FIXME: `--generate-link-to-definition` tries to resolve cfged out code @@ -830,7 +827,6 @@ impl Step for Rustc { // cargo.rustdocflag("--generate-link-to-definition"); compile::rustc_cargo(builder, &mut cargo, target, &compiler); - cargo.arg("-Zunstable-options"); cargo.arg("-Zskip-rustdoc-fingerprint"); // Only include compiler crates, no dependencies of those, such as `libc`. @@ -986,7 +982,6 @@ macro_rules! tool_doc { cargo.rustdocflag("-Arustdoc::private-intra-doc-links"); cargo.rustdocflag("--enable-index-page"); cargo.rustdocflag("--show-type-layout"); - cargo.rustdocflag("-Zunstable-options"); // FIXME: `--generate-link-to-definition` tries to resolve cfged out code // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222 // cargo.rustdocflag("--generate-link-to-definition"); diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index c5a1ab78801..e1eea31b3bb 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -110,7 +110,7 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L // Initialize the llvm submodule if not initialized already. // If submodules are disabled, this does nothing. - builder.update_submodule("src/llvm-project"); + builder.config.update_submodule("src/llvm-project"); let root = "src/llvm-project/llvm"; let out_dir = builder.llvm_out(target); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index ff8ca2ad74a..3a1eb43b801 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1096,7 +1096,7 @@ tool_extended!((self, builder), CargoClippy, "src/tools/clippy", "cargo-clippy", stable=true; Clippy, "src/tools/clippy", "clippy-driver", stable=true, add_bins_to_sysroot = ["clippy-driver", "cargo-clippy"]; Miri, "src/tools/miri", "miri", stable=false, add_bins_to_sysroot = ["miri"]; - CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri", stable=true, add_bins_to_sysroot = ["cargo-miri"]; + CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri", stable=false, add_bins_to_sysroot = ["cargo-miri"]; Rls, "src/tools/rls", "rls", stable=true; Rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, add_bins_to_sysroot = ["rustfmt", "cargo-fmt"]; ); diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index a848163b272..ff0d1f3a725 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1612,7 +1612,6 @@ impl<'a> Builder<'a> { rustflags.arg("-Csymbol-mangling-version=v0"); } else { rustflags.arg("-Csymbol-mangling-version=legacy"); - rustflags.arg("-Zunstable-options"); } // Enable compile-time checking of `cfg` names, values and Cargo `features`. @@ -1860,16 +1859,7 @@ impl<'a> Builder<'a> { }, ); - let split_debuginfo = self.config.split_debuginfo(target); - let split_debuginfo_is_stable = target.contains("linux") - || target.contains("apple") - || (target.is_msvc() && split_debuginfo == SplitDebuginfo::Packed) - || (target.is_windows() && split_debuginfo == SplitDebuginfo::Off); - - if !split_debuginfo_is_stable { - rustflags.arg("-Zunstable-options"); - } - match split_debuginfo { + match self.config.split_debuginfo(target) { SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"), SplitDebuginfo::Unpacked => rustflags.arg("-Csplit-debuginfo=unpacked"), SplitDebuginfo::Off => rustflags.arg("-Csplit-debuginfo=off"), @@ -2046,7 +2036,6 @@ impl<'a> Builder<'a> { } if mode == Mode::Rustc { - rustflags.arg("-Zunstable-options"); rustflags.arg("-Wrustc::internal"); // FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all // of the individual lints are satisfied. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index bdd9fd755aa..ce23b7735f8 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -14,7 +14,7 @@ use std::sync::OnceLock; use std::{cmp, env, fs}; use build_helper::exit; -use build_helper::git::GitConfig; +use build_helper::git::{output_result, GitConfig}; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -2509,6 +2509,123 @@ impl Config { } } + /// Given a path to the directory of a submodule, update it. + /// + /// `relative_path` should be relative to the root of the git repository, not an absolute path. + /// + /// This *does not* update the submodule if `config.toml` explicitly says + /// not to, or if we're not in a git repository (like a plain source + /// tarball). Typically [`crate::Build::require_submodule`] should be + /// used instead to provide a nice error to the user if the submodule is + /// missing. + pub(crate) fn update_submodule(&self, relative_path: &str) { + if !self.submodules() { + return; + } + + let absolute_path = self.src.join(relative_path); + + // NOTE: The check for the empty directory is here because when running x.py the first time, + // the submodule won't be checked out. Check it out now so we can build it. + if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository() + && !helpers::dir_is_empty(&absolute_path) + { + return; + } + + // Submodule updating actually happens during in the dry run mode. We need to make sure that + // all the git commands below are actually executed, because some follow-up code + // in bootstrap might depend on the submodules being checked out. Furthermore, not all + // the command executions below work with an empty output (produced during dry run). + // Therefore, all commands below are marked with `run_always()`, so that they also run in + // dry run mode. + let submodule_git = || { + let mut cmd = helpers::git(Some(&absolute_path)); + cmd.run_always(); + cmd + }; + + // Determine commit checked out in submodule. + let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"]).as_command_mut()); + let checked_out_hash = checked_out_hash.trim_end(); + // Determine commit that the submodule *should* have. + let recorded = output( + helpers::git(Some(&self.src)) + .run_always() + .args(["ls-tree", "HEAD"]) + .arg(relative_path) + .as_command_mut(), + ); + + let actual_hash = recorded + .split_whitespace() + .nth(2) + .unwrap_or_else(|| panic!("unexpected output `{}`", recorded)); + + if actual_hash == checked_out_hash { + // already checked out + return; + } + + println!("Updating submodule {relative_path}"); + self.check_run( + helpers::git(Some(&self.src)) + .run_always() + .args(["submodule", "-q", "sync"]) + .arg(relative_path), + ); + + // Try passing `--progress` to start, then run git again without if that fails. + let update = |progress: bool| { + // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository, + // even though that has no relation to the upstream for the submodule. + let current_branch = output_result( + helpers::git(Some(&self.src)) + .allow_failure() + .run_always() + .args(["symbolic-ref", "--short", "HEAD"]) + .as_command_mut(), + ) + .map(|b| b.trim().to_owned()); + + let mut git = helpers::git(Some(&self.src)).allow_failure(); + git.run_always(); + if let Ok(branch) = current_branch { + // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name. + // This syntax isn't accepted by `branch.{branch}`. Strip it. + let branch = branch.strip_prefix("heads/").unwrap_or(&branch); + git.arg("-c").arg(format!("branch.{branch}.remote=origin")); + } + git.args(["submodule", "update", "--init", "--recursive", "--depth=1"]); + if progress { + git.arg("--progress"); + } + git.arg(relative_path); + git + }; + if !self.check_run(&mut update(true)) { + self.check_run(&mut update(false)); + } + + // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). + // diff-index reports the modifications through the exit status + let has_local_modifications = !self.check_run(submodule_git().allow_failure().args([ + "diff-index", + "--quiet", + "HEAD", + ])); + if has_local_modifications { + self.check_run(submodule_git().args(["stash", "push"])); + } + + self.check_run(submodule_git().args(["reset", "-q", "--hard"])); + self.check_run(submodule_git().args(["clean", "-qdfx"])); + + if has_local_modifications { + self.check_run(submodule_git().args(["stash", "pop"])); + } + } + #[cfg(feature = "bootstrap-self-test")] pub fn check_stage0_version(&self, _program_path: &Path, _component_name: &'static str) {} @@ -2613,19 +2730,23 @@ impl Config { asserts: bool, ) -> bool { let if_unchanged = || { - // Git is needed to track modifications here, but tarball source is not available. - // If not modified here or built through tarball source, we maintain consistency - // with '"if available"'. - if !self.rust_info.is_from_tarball() - && self - .last_modified_commit(&["src/llvm-project"], "download-ci-llvm", true) - .is_none() - { - // there are some untracked changes in the given paths. - false - } else { - llvm::is_ci_llvm_available(self, asserts) + if self.rust_info.is_from_tarball() { + // Git is needed for running "if-unchanged" logic. + println!( + "WARNING: 'if-unchanged' has no effect on tarball sources; ignoring `download-ci-llvm`." + ); + return false; } + + self.update_submodule("src/llvm-project"); + + // Check for untracked changes in `src/llvm-project`. + let has_changes = self + .last_modified_commit(&["src/llvm-project"], "download-ci-llvm", true) + .is_none(); + + // Return false if there are untracked changes, otherwise check if CI LLVM is available. + if has_changes { false } else { llvm::is_ci_llvm_available(self, asserts) } }; match download_ci_llvm { diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index dd0309733ae..1e3f8da5258 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -22,6 +22,24 @@ fn try_run(config: &Config, cmd: &mut Command) -> Result<(), ()> { config.try_run(cmd) } +fn extract_curl_version(out: &[u8]) -> semver::Version { + let out = String::from_utf8_lossy(out); + // The output should look like this: "curl <major>.<minor>.<patch> ..." + out.lines() + .next() + .and_then(|line| line.split(" ").nth(1)) + .and_then(|version| semver::Version::parse(version).ok()) + .unwrap_or(semver::Version::new(1, 0, 0)) +} + +fn curl_version() -> semver::Version { + let mut curl = Command::new("curl"); + curl.arg("-V"); + let Ok(out) = curl.output() else { return semver::Version::new(1, 0, 0) }; + let out = out.stdout; + extract_curl_version(&out) +} + /// Generic helpers that are useful anywhere in bootstrap. impl Config { pub fn is_verbose(&self) -> bool { @@ -56,7 +74,7 @@ impl Config { /// Returns false if do not execute at all, otherwise returns its /// `status.success()`. pub(crate) fn check_run(&self, cmd: &mut BootstrapCommand) -> bool { - if self.dry_run() { + if self.dry_run() && !cmd.run_always { return true; } self.verbose(|| println!("running: {cmd:?}")); @@ -220,6 +238,8 @@ impl Config { "30", // timeout if cannot connect within 30 seconds "-o", tempfile.to_str().unwrap(), + "--continue-at", + "-", "--retry", "3", "-SRf", @@ -230,6 +250,10 @@ impl Config { } else { curl.arg("--progress-bar"); } + // --retry-all-errors was added in 7.71.0, don't use it if curl is old. + if curl_version() >= semver::Version::new(7, 71, 0) { + curl.arg("--retry-all-errors"); + } curl.arg(url); if !self.check_run(&mut curl) { if self.build.contains("windows-msvc") { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 784519a20a2..268392c5fb1 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -473,117 +473,6 @@ impl Build { build } - /// Given a path to the directory of a submodule, update it. - /// - /// `relative_path` should be relative to the root of the git repository, not an absolute path. - /// - /// This *does not* update the submodule if `config.toml` explicitly says - /// not to, or if we're not in a git repository (like a plain source - /// tarball). Typically [`Build::require_submodule`] should be - /// used instead to provide a nice error to the user if the submodule is - /// missing. - fn update_submodule(&self, relative_path: &str) { - if !self.config.submodules() { - return; - } - - let absolute_path = self.config.src.join(relative_path); - - // NOTE: The check for the empty directory is here because when running x.py the first time, - // the submodule won't be checked out. Check it out now so we can build it. - if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository() - && !dir_is_empty(&absolute_path) - { - return; - } - - // Submodule updating actually happens during in the dry run mode. We need to make sure that - // all the git commands below are actually executed, because some follow-up code - // in bootstrap might depend on the submodules being checked out. Furthermore, not all - // the command executions below work with an empty output (produced during dry run). - // Therefore, all commands below are marked with `run_always()`, so that they also run in - // dry run mode. - let submodule_git = || { - let mut cmd = helpers::git(Some(&absolute_path)); - cmd.run_always(); - cmd - }; - - // Determine commit checked out in submodule. - let checked_out_hash = - submodule_git().args(["rev-parse", "HEAD"]).run_capture_stdout(self).stdout(); - let checked_out_hash = checked_out_hash.trim_end(); - // Determine commit that the submodule *should* have. - let recorded = helpers::git(Some(&self.src)) - .run_always() - .args(["ls-tree", "HEAD"]) - .arg(relative_path) - .run_capture_stdout(self) - .stdout(); - let actual_hash = recorded - .split_whitespace() - .nth(2) - .unwrap_or_else(|| panic!("unexpected output `{}`", recorded)); - - if actual_hash == checked_out_hash { - // already checked out - return; - } - - println!("Updating submodule {relative_path}"); - helpers::git(Some(&self.src)) - .run_always() - .args(["submodule", "-q", "sync"]) - .arg(relative_path) - .run(self); - - // Try passing `--progress` to start, then run git again without if that fails. - let update = |progress: bool| { - // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository, - // even though that has no relation to the upstream for the submodule. - let current_branch = helpers::git(Some(&self.src)) - .allow_failure() - .run_always() - .args(["symbolic-ref", "--short", "HEAD"]) - .run_capture_stdout(self) - .stdout_if_ok() - .map(|s| s.trim().to_owned()); - - let mut git = helpers::git(Some(&self.src)).allow_failure(); - git.run_always(); - if let Some(branch) = current_branch { - // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name. - // This syntax isn't accepted by `branch.{branch}`. Strip it. - let branch = branch.strip_prefix("heads/").unwrap_or(&branch); - git.arg("-c").arg(format!("branch.{branch}.remote=origin")); - } - git.args(["submodule", "update", "--init", "--recursive", "--depth=1"]); - if progress { - git.arg("--progress"); - } - git.arg(relative_path); - git - }; - if !update(true).run(self) { - update(false).run(self); - } - - // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). - // diff-index reports the modifications through the exit status - let has_local_modifications = - !submodule_git().allow_failure().args(["diff-index", "--quiet", "HEAD"]).run(self); - if has_local_modifications { - submodule_git().args(["stash", "push"]).run(self); - } - - submodule_git().args(["reset", "-q", "--hard"]).run(self); - submodule_git().args(["clean", "-qdfx"]).run(self); - - if has_local_modifications { - submodule_git().args(["stash", "pop"]).run(self); - } - } - /// Updates a submodule, and exits with a failure if submodule management /// is disabled and the submodule does not exist. /// @@ -598,7 +487,7 @@ impl Build { if cfg!(test) && !self.config.submodules() { return; } - self.update_submodule(submodule); + self.config.update_submodule(submodule); let absolute_path = self.config.src.join(submodule); if dir_is_empty(&absolute_path) { let maybe_enable = if !self.config.submodules() @@ -646,7 +535,7 @@ impl Build { let path = Path::new(submodule); // Don't update the submodule unless it's already been cloned. if GitInfo::new(false, path).is_managed_git_subrepository() { - self.update_submodule(submodule); + self.config.update_submodule(submodule); } } } @@ -659,7 +548,7 @@ impl Build { } if GitInfo::new(false, Path::new(submodule)).is_managed_git_subrepository() { - self.update_submodule(submodule); + self.config.update_submodule(submodule); } } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index c629f04c00e..51a25104e4c 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -230,4 +230,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "./x test --rustc-args was renamed to --compiletest-rustc-args as it only applies there. ./x miri --rustc-args was also removed.", }, + ChangeInfo { + change_id: 129295, + severity: ChangeSeverity::Info, + summary: "The `build.profiler` option now tries to use source code from `download-ci-llvm` if possible, instead of checking out the `src/llvm-project` submodule.", + }, ]; diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index d690aac27fa..389abb2fdd3 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,7 +2,7 @@ set -euo pipefail -LINUX_VERSION=v6.11-rc1 +LINUX_VERSION=4c7864e81d8bbd51036dacf92fb0a400e13aaeee # Build rustc, rustdoc and cargo ../x.py build --stage 1 library rustdoc @@ -28,7 +28,7 @@ rm -rf linux || true # Download Linux at a specific commit mkdir -p linux git -C linux init -git -C linux remote add origin https://github.com/torvalds/linux.git +git -C linux remote add origin https://github.com/Rust-for-Linux/linux.git git -C linux fetch --depth 1 origin ${LINUX_VERSION} git -C linux checkout FETCH_HEAD diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index cb0b2e63452..4e34e2667cf 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -81,6 +81,7 @@ - [wasm32-wasip1](platform-support/wasm32-wasip1.md) - [wasm32-wasip1-threads](platform-support/wasm32-wasip1-threads.md) - [wasm32-wasip2](platform-support/wasm32-wasip2.md) + - [wasm32-unknown-unknown](platform-support/wasm32-unknown-unknown.md) - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md) - [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md) - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 667758a1203..dd478e9df37 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -192,7 +192,7 @@ target | std | notes [`thumbv8m.main-none-eabi`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline [`thumbv8m.main-none-eabihf`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline, hardfloat `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten -`wasm32-unknown-unknown` | ✓ | WebAssembly +[`wasm32-unknown-unknown`](platform-support/wasm32-unknown-unknown.md) | ✓ | WebAssembly `wasm32-wasi` | ✓ | WebAssembly with WASI (undergoing a [rename to `wasm32-wasip1`][wasi-rename]) [`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASI [`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md new file mode 100644 index 00000000000..12b7817c382 --- /dev/null +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md @@ -0,0 +1,197 @@ +# `wasm32-unknown-unknown` + +**Tier: 2** + +The `wasm32-unknown-unknown` target is a WebAssembly compilation target which +does not import any functions from the host for the standard library. This is +the "minimal" WebAssembly in the sense of making the fewest assumptions about +the host environment. This target is often used when compiling to the web or +JavaScript environments as there is no standard for what functions can be +imported on the web. This target can also be useful for creating minimal or +bare-bones WebAssembly binaries. + +The `wasm32-unknown-unknown` target has support for the Rust standard library +but many parts of the standard library do not work and return errors. For +example `println!` does nothing, `std::fs` always return errors, and +`std::thread::spawn` will panic. There is no means by which this can be +overridden. For a WebAssembly target that more fully supports the standard +library see the [`wasm32-wasip1`](./wasm32-wasip1.md) or +[`wasm32-wasip2`](./wasm32-wasip2.md) targets. + +The `wasm32-unknown-unknown` target has full support for the `core` and `alloc` +crates. It additionally supports the `HashMap` type in the `std` crate, although +hash maps are not randomized like they are on other platforms. + +One existing user of this target (please feel free to edit and expand this list +too) is the [`wasm-bindgen` project](https://github.com/rustwasm/wasm-bindgen) +which facilitates Rust code interoperating with JavaScript code. Note, though, +that not all uses of `wasm32-unknown-unknown` are using JavaScript and the web. + +## Target maintainers + +When this target was added to the compiler, platform-specific documentation here +was not maintained at that time. This means that the list below is not +exhaustive, and there are more interested parties in this target. That being +said, those interested in maintaining this target are: + +- Alex Crichton, https://github.com/alexcrichton + +## Requirements + +This target is cross-compiled. The target includes support for `std` itself, +but as mentioned above many pieces of functionality that require an operating +system do not work and will return errors. + +This target currently has no equivalent in C/C++. There is no C/C++ toolchain +for this target. While interop is theoretically possible it's recommended to +instead use one of: + +* `wasm32-unknown-emscripten` - for web-based use cases the Emscripten + toolchain is typically chosen for running C/C++. +* [`wasm32-wasip1`](./wasm32-wasip1.md) - the wasi-sdk toolchain is used to + compile C/C++ on this target and can interop with Rust code. WASI works on + the web so far as there's no blocker, but an implementation of WASI APIs + must be either chosen or reimplemented. + +This target has no build requirements beyond what's in-tree in the Rust +repository. Linking binaries requires LLD to be enabled for the `wasm-ld` +driver. This target uses the `dlmalloc` crate as the default global allocator. + +## Building the target + +Building this target can be done by: + +* Configure the `wasm32-unknown-unknown` target to get built. +* Configure LLD to be built. +* Ensure the `WebAssembly` target backend is not disabled in LLVM. + +These are all controlled through `config.toml` options. It should be possible +to build this target on any platform. + +## Building Rust programs + +Rust programs can be compiled by adding this target via rustup: + +```sh +$ rustup target add wasm32-unknown-unknown +``` + +and then compiling with the target: + +```sh +$ rustc foo.rs --target wasm32-unknown-unknown +$ file foo.wasm +``` + +## Cross-compilation + +This target can be cross-compiled from any host. + +## Testing + +This target is not tested in CI for the rust-lang/rust repository. Many tests +must be disabled to run on this target and failures are non-obvious because +`println!` doesn't work in the standard library. It's recommended to test the +`wasm32-wasip1` target instead for WebAssembly compatibility. + +## Conditionally compiling code + +It's recommended to conditionally compile code for this target with: + +```text +#[cfg(all(target_family = "wasm", target_os = "unknown"))] +``` + +Note that there is no way to tell via `#[cfg]` whether code will be running on +the web or not. + +## Enabled WebAssembly features + +WebAssembly is an evolving standard which adds new features such as new +instructions over time. This target's default set of supported WebAssembly +features will additionally change over time. The `wasm32-unknown-unknown` target +inherits the default settings of LLVM which typically matches the default +settings of Emscripten as well. + +Changes to WebAssembly go through a [proposals process][proposals] but reaching +the final stage (stage 5) does not automatically mean that the feature will be +enabled in LLVM and Rust by default. At this time the general guidance is that +features must be present in most engines for a "good chunk of time" before +they're enabled in LLVM by default. There is currently no exact number of +months or engines that are required to enable features by default. + +[proposals]: https://github.com/WebAssembly/proposals + +As of the time of this writing the proposals that are enabled by default (the +`generic` CPU in LLVM terminology) are: + +* `multivalue` +* `mutable-globals` +* `reference-types` +* `sign-ext` + +If you're compiling WebAssembly code for an engine that does not support a +feature in LLVM's default feature set then the feature must be disabled at +compile time. Note, though, that enabled features may be used in the standard +library or precompiled libraries shipped via rustup. This means that not only +does your own code need to be compiled with the correct set of flags but the +Rust standard library additionally must be recompiled. + +Compiling all code for the initial release of WebAssembly looks like: + +```sh +$ export RUSTFLAGS=-Ctarget-cpu=mvp +$ cargo +nightly build -Zbuild-std=panic_abort,std --target wasm32-unknown-unknown +``` + +Here the `mvp` "cpu" is a placeholder in LLVM for disabling all supported +features by default. Cargo's `-Zbuild-std` feature, a Nightly Rust feature, is +then used to recompile the standard library in addition to your own code. This +will produce a binary that uses only the original WebAssembly features by +default and no proposals since its inception. + +To enable individual features it can be done with `-Ctarget-feature=+foo`. +Available features for Rust code itself are documented in the [reference] and +can also be found through: + +```sh +$ rustc -Ctarget-feature=help --target wasm32-unknown-unknown +``` + +You'll need to consult your WebAssembly engine's documentation to learn more +about the supported WebAssembly features the engine has. + +[reference]: https://doc.rust-lang.org/reference/attributes/codegen.html#wasm32-or-wasm64 + +Note that it is still possible for Rust crates and libraries to enable +WebAssembly features on a per-function level. This means that the build +command above may not be sufficient to disable all WebAssembly features. If the +final binary still has SIMD instructions, for example, the function in question +will need to be found and the crate in question will likely contain something +like: + +```rust,ignore (not-always-compiled-to-wasm) +#[target_feature(enable = "simd128")] +fn foo() { + // ... +} +``` + +In this situation there is no compiler flag to disable emission of SIMD +instructions and the crate must instead be modified to not include this function +at compile time either by default or through a Cargo feature. For crate authors +it's recommended to avoid `#[target_feature(enable = "...")]` except where +necessary and instead use: + +```rust,ignore (not-always-compiled-to-wasm) +#[cfg(target_feature = "simd128")] +fn foo() { + // ... +} +``` + +That is to say instead of enabling target features it's recommended to +conditionally compile code instead. This is notably different to the way native +platforms such as x86\_64 work, and this is due to the fact that WebAssembly +binaries must only contain code the engine understands. Native binaries work so +long as the CPU doesn't execute unknown code dynamically at runtime. diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md index c3eda26ca8e..994c0f4bbb3 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md @@ -162,3 +162,17 @@ It's recommended to conditionally compile code for this target with: Prior to Rust 1.80 the `target_env = "p1"` key was not set. Currently the `target_feature = "atomics"` is Nightly-only. Note that the precise `#[cfg]` necessary to detect this target may change as the target becomes more stable. + +## Enabled WebAssembly features + +The default set of WebAssembly features enabled for compilation includes two +more features in addition to that which +[`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md) enables: + +* `bulk-memory` +* `atomics` + +For more information about features see the documentation for +[`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md), but note that the +`mvp` CPU in LLVM does not support this target as it's required that +`bulk-memory`, `atomics`, and `mutable-globals` are all enabled. diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1.md b/src/doc/rustc/src/platform-support/wasm32-wasip1.md index fb70bbdc2b4..0e4def6768d 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip1.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip1.md @@ -132,3 +132,9 @@ It's recommended to conditionally compile code for this target with: Note that the `target_env = "p1"` condition first appeared in Rust 1.80. Prior to Rust 1.80 the `target_env` condition was not set. + +## Enabled WebAssembly features + +The default set of WebAssembly features enabled for compilation is currently the +same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the +documentation there for more information. diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip2.md b/src/doc/rustc/src/platform-support/wasm32-wasip2.md index 1e53fbc178e..bb2348b201e 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip2.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip2.md @@ -61,3 +61,9 @@ It's recommended to conditionally compile code for this target with: ```text #[cfg(all(target_os = "wasi", target_env = "p2"))] ``` + +## Enabled WebAssembly features + +The default set of WebAssembly features enabled for compilation is currently the +same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the +documentation there for more information. diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index b3fccbf6456..34332de80b3 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -12,7 +12,7 @@ rinja = { version = "0.3", default-features = false, features = ["config"] } base64 = "0.21.7" itertools = "0.12" indexmap = "2" -minifier = "0.3.0" +minifier = "0.3.1" pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index db81b4c4282..5260e363dd6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -272,7 +272,7 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> | rbv::ResolvedArg::LateBound(_, _, did) | rbv::ResolvedArg::Free(_, did), ) = cx.tcx.named_bound_var(lifetime.hir_id) - && let Some(lt) = cx.args.get(&did).and_then(|arg| arg.as_lt()) + && let Some(lt) = cx.args.get(&did.to_def_id()).and_then(|arg| arg.as_lt()) { return lt.clone(); } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ff5c16f2b3e..63d71a73cdf 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -12,7 +12,7 @@ use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel, StableS use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_hir::{BodyId, Mutability}; use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety; @@ -89,6 +89,11 @@ impl ItemId { } #[inline] + pub(crate) fn as_local_def_id(self) -> Option<LocalDefId> { + self.as_def_id().and_then(|id| id.as_local()) + } + + #[inline] pub(crate) fn krate(self) -> CrateNum { match self { ItemId::Auto { for_: id, .. } diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index abd66f15dc0..5c0898f28fc 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -136,7 +136,7 @@ impl<'a, 'tcx> HirCollector<'a, 'tcx> { self.enable_per_target_ignores, Some(&crate::html::markdown::ExtraInfo::new( self.tcx, - def_id.to_def_id(), + def_id, span_of_fragments(&attrs.doc_strings).unwrap_or(sp), )), ); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 6357cfee141..5cbf8c5e19f 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1288,56 +1288,90 @@ impl clean::Impl { if self.is_negative_trait_impl() { write!(f, "!")?; } - ty.print(cx).fmt(f)?; + if self.kind.is_fake_variadic() + && let generics = ty.generics() + && let &[inner_type] = generics.as_ref().map_or(&[][..], |v| &v[..]) + { + let last = ty.last(); + if f.alternate() { + write!(f, "{}<", last)?; + self.print_type(inner_type, f, use_absolute, cx)?; + write!(f, ">")?; + } else { + write!(f, "{}<", anchor(ty.def_id(), last, cx).to_string())?; + self.print_type(inner_type, f, use_absolute, cx)?; + write!(f, ">")?; + } + } else { + ty.print(cx).fmt(f)?; + } write!(f, " for ")?; } - if let clean::Type::Tuple(types) = &self.for_ - && let [clean::Type::Generic(name)] = &types[..] - && (self.kind.is_fake_variadic() || self.kind.is_auto()) - { - // Hardcoded anchor library/core/src/primitive_docs.rs - // Link should match `# Trait implementations` - primitive_link_fragment( - f, - PrimitiveType::Tuple, - format_args!("({name}₁, {name}₂, …, {name}ₙ)"), - "#trait-implementations-1", - cx, - )?; - } else if let clean::BareFunction(bare_fn) = &self.for_ - && let [clean::Argument { type_: clean::Type::Generic(name), .. }] = - &bare_fn.decl.inputs.values[..] - && (self.kind.is_fake_variadic() || self.kind.is_auto()) - { - // Hardcoded anchor library/core/src/primitive_docs.rs - // Link should match `# Trait implementations` - - print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?; - bare_fn.safety.print_with_space().fmt(f)?; - print_abi_with_space(bare_fn.abi).fmt(f)?; - let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" }; - primitive_link_fragment( - f, - PrimitiveType::Tuple, - format_args!("fn({name}₁, {name}₂, …, {name}ₙ{ellipsis})"), - "#trait-implementations-1", - cx, - )?; - // Write output. - if !bare_fn.decl.output.is_unit() { - write!(f, " -> ")?; - fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?; - } - } else if let Some(ty) = self.kind.as_blanket_ty() { + if let Some(ty) = self.kind.as_blanket_ty() { fmt_type(ty, f, use_absolute, cx)?; } else { - fmt_type(&self.for_, f, use_absolute, cx)?; + self.print_type(&self.for_, f, use_absolute, cx)?; } print_where_clause(&self.generics, cx, 0, Ending::Newline).fmt(f) }) } + fn print_type<'a, 'tcx: 'a>( + &self, + type_: &clean::Type, + f: &mut fmt::Formatter<'_>, + use_absolute: bool, + cx: &'a Context<'tcx>, + ) -> Result<(), fmt::Error> { + if let clean::Type::Tuple(types) = type_ + && let [clean::Type::Generic(name)] = &types[..] + && (self.kind.is_fake_variadic() || self.kind.is_auto()) + { + // Hardcoded anchor library/core/src/primitive_docs.rs + // Link should match `# Trait implementations` + primitive_link_fragment( + f, + PrimitiveType::Tuple, + format_args!("({name}₁, {name}₂, …, {name}ₙ)"), + "#trait-implementations-1", + cx, + )?; + } else if let clean::Type::Array(ty, len) = type_ + && let clean::Type::Generic(name) = &**ty + && &len[..] == "1" + && (self.kind.is_fake_variadic() || self.kind.is_auto()) + { + primitive_link(f, PrimitiveType::Array, format_args!("[{name}; N]"), cx)?; + } else if let clean::BareFunction(bare_fn) = &type_ + && let [clean::Argument { type_: clean::Type::Generic(name), .. }] = + &bare_fn.decl.inputs.values[..] + && (self.kind.is_fake_variadic() || self.kind.is_auto()) + { + // Hardcoded anchor library/core/src/primitive_docs.rs + // Link should match `# Trait implementations` + + print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?; + bare_fn.safety.print_with_space().fmt(f)?; + print_abi_with_space(bare_fn.abi).fmt(f)?; + let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" }; + primitive_link_fragment( + f, + PrimitiveType::Tuple, + format_args!("fn({name}₁, {name}₂, …, {name}ₙ{ellipsis})"), + "#trait-implementations-1", + cx, + )?; + // Write output. + if !bare_fn.decl.output.is_unit() { + write!(f, " -> ")?; + fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?; + } + } else { + fmt_type(&type_, f, use_absolute, cx)?; + } + Ok(()) + } } impl clean::Arguments { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 7bfe5d87d39..364d4e077b1 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -40,7 +40,7 @@ use pulldown_cmark::{ }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Diag, DiagMessage}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::TyCtxt; pub(crate) use rustc_resolve::rustdoc::main_body_opts; use rustc_resolve::rustdoc::may_be_doc_link; @@ -818,27 +818,25 @@ pub(crate) fn find_codes<T: doctest::DocTestVisitor>( } pub(crate) struct ExtraInfo<'tcx> { - def_id: DefId, + def_id: LocalDefId, sp: Span, tcx: TyCtxt<'tcx>, } impl<'tcx> ExtraInfo<'tcx> { - pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: DefId, sp: Span) -> ExtraInfo<'tcx> { + pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, sp: Span) -> ExtraInfo<'tcx> { ExtraInfo { def_id, sp, tcx } } fn error_invalid_codeblock_attr(&self, msg: impl Into<DiagMessage>) { - if let Some(def_id) = self.def_id.as_local() { - self.tcx.node_span_lint( - crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, - self.tcx.local_def_id_to_hir_id(def_id), - self.sp, - |lint| { - lint.primary_message(msg); - }, - ); - } + self.tcx.node_span_lint( + crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, + self.tcx.local_def_id_to_hir_id(self.def_id), + self.sp, + |lint| { + lint.primary_message(msg); + }, + ); } fn error_invalid_codeblock_attr_with_help( @@ -846,17 +844,15 @@ impl<'tcx> ExtraInfo<'tcx> { msg: impl Into<DiagMessage>, f: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), ) { - if let Some(def_id) = self.def_id.as_local() { - self.tcx.node_span_lint( - crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, - self.tcx.local_def_id_to_hir_id(def_id), - self.sp, - |lint| { - lint.primary_message(msg); - f(lint); - }, - ); - } + self.tcx.node_span_lint( + crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, + self.tcx.local_def_id_to_hir_id(self.def_id), + self.sp, + |lint| { + lint.primary_message(msg); + f(lint); + }, + ); } } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 0334eacc161..0ed8921b1e8 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -14,7 +14,6 @@ use rustc_span::edition::Edition; use rustc_span::{sym, FileName, Symbol}; use super::print_item::{full_path, item_path, print_item}; -use super::search_index::build_index; use super::sidebar::{print_sidebar, sidebar_module_like, Sidebar}; use super::write_shared::write_shared; use super::{collect_spans_and_sources, scrape_examples_help, AllTypes, LinkFromSrc, StylePath}; @@ -573,13 +572,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { } if !no_emit_shared { - // Build our search index - let index = build_index(&krate, &mut Rc::get_mut(&mut cx.shared).unwrap().cache, tcx); - - // Write shared runs within a flock; disable thread dispatching of IO temporarily. - Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true); - write_shared(&mut cx, &krate, index, &md_opts)?; - Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false); + write_shared(&mut cx, &krate, &md_opts, tcx)?; } Ok((cx, krate)) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 7ce637d3ab4..c1b2ee7d8ae 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -29,8 +29,10 @@ pub(crate) mod search_index; mod tests; mod context; +mod ordered_json; mod print_item; pub(crate) mod sidebar; +mod sorted_template; mod span_map; mod type_layout; mod write_shared; diff --git a/src/librustdoc/html/render/ordered_json.rs b/src/librustdoc/html/render/ordered_json.rs new file mode 100644 index 00000000000..7abe40eef3b --- /dev/null +++ b/src/librustdoc/html/render/ordered_json.rs @@ -0,0 +1,83 @@ +use std::borrow::Borrow; +use std::fmt; + +use itertools::Itertools as _; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +/// Prerendered json. +/// +/// Both the Display and serde_json::to_string implementations write the serialized json +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +#[serde(from = "Value")] +#[serde(into = "Value")] +pub(crate) struct OrderedJson(String); + +impl OrderedJson { + /// If you pass in an array, it will not be sorted. + pub(crate) fn serialize<T: Serialize>(item: T) -> Result<Self, serde_json::Error> { + Ok(Self(serde_json::to_string(&item)?)) + } + + /// Serializes and sorts + pub(crate) fn array_sorted<T: Borrow<Self>, I: IntoIterator<Item = T>>(items: I) -> Self { + let items = items + .into_iter() + .sorted_unstable_by(|a, b| a.borrow().cmp(&b.borrow())) + .format_with(",", |item, f| f(item.borrow())); + Self(format!("[{}]", items)) + } + + pub(crate) fn array_unsorted<T: Borrow<Self>, I: IntoIterator<Item = T>>(items: I) -> Self { + let items = items.into_iter().format_with(",", |item, f| f(item.borrow())); + Self(format!("[{items}]")) + } +} + +impl fmt::Display for OrderedJson { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl From<Value> for OrderedJson { + fn from(value: Value) -> Self { + let serialized = + serde_json::to_string(&value).expect("Serializing a Value to String should never fail"); + Self(serialized) + } +} + +impl From<OrderedJson> for Value { + fn from(json: OrderedJson) -> Self { + serde_json::from_str(&json.0).expect("OrderedJson should always store valid JSON") + } +} + +/// For use in JSON.parse('{...}'). +/// +/// Assumes we are going to be wrapped in single quoted strings. +/// +/// JSON.parse loads faster than raw JS source, +/// so this is used for large objects. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub(crate) struct EscapedJson(OrderedJson); + +impl From<OrderedJson> for EscapedJson { + fn from(json: OrderedJson) -> Self { + Self(json) + } +} + +impl fmt::Display for EscapedJson { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // All these `replace` calls are because we have to go through JS string + // for JSON content. + // We need to escape double quotes for the JSON + let json = self.0.0.replace('\\', r"\\").replace('\'', r"\'").replace("\\\"", "\\\\\""); + json.fmt(f) + } +} + +#[cfg(test)] +mod tests; diff --git a/src/librustdoc/html/render/ordered_json/tests.rs b/src/librustdoc/html/render/ordered_json/tests.rs new file mode 100644 index 00000000000..e0fe6446b9a --- /dev/null +++ b/src/librustdoc/html/render/ordered_json/tests.rs @@ -0,0 +1,121 @@ +use super::super::ordered_json::*; + +fn check(json: OrderedJson, serialized: &str) { + assert_eq!(json.to_string(), serialized); + assert_eq!(serde_json::to_string(&json).unwrap(), serialized); + + let json = json.to_string(); + let json: OrderedJson = serde_json::from_str(&json).unwrap(); + + assert_eq!(json.to_string(), serialized); + assert_eq!(serde_json::to_string(&json).unwrap(), serialized); + + let json = serde_json::to_string(&json).unwrap(); + let json: OrderedJson = serde_json::from_str(&json).unwrap(); + + assert_eq!(json.to_string(), serialized); + assert_eq!(serde_json::to_string(&json).unwrap(), serialized); +} + +// Make sure there is no extra level of string, plus number of escapes. +#[test] +fn escape_json_number() { + let json = OrderedJson::serialize(3).unwrap(); + let json = EscapedJson::from(json); + assert_eq!(format!("{json}"), "3"); +} + +#[test] +fn escape_json_single_quote() { + let json = OrderedJson::serialize("he's").unwrap(); + let json = EscapedJson::from(json); + assert_eq!(format!("{json}"), r#""he\'s""#); +} + +#[test] +fn escape_json_array() { + let json = OrderedJson::serialize([1, 2, 3]).unwrap(); + let json = EscapedJson::from(json); + assert_eq!(format!("{json}"), r#"[1,2,3]"#); +} + +#[test] +fn escape_json_string() { + let json = OrderedJson::serialize(r#"he"llo"#).unwrap(); + let json = EscapedJson::from(json); + assert_eq!(format!("{json}"), r#""he\\\"llo""#); +} + +#[test] +fn escape_json_string_escaped() { + let json = OrderedJson::serialize(r#"he\"llo"#).unwrap(); + let json = EscapedJson::from(json); + assert_eq!(format!("{json}"), r#""he\\\\\\\"llo""#); +} + +#[test] +fn escape_json_string_escaped_escaped() { + let json = OrderedJson::serialize(r#"he\\"llo"#).unwrap(); + let json = EscapedJson::from(json); + assert_eq!(format!("{json}"), r#""he\\\\\\\\\\\"llo""#); +} + +// Testing round trip + making sure there is no extra level of string +#[test] +fn number() { + let json = OrderedJson::serialize(3).unwrap(); + let serialized = "3"; + check(json, serialized); +} + +#[test] +fn boolean() { + let json = OrderedJson::serialize(true).unwrap(); + let serialized = "true"; + check(json, serialized); +} + +#[test] +fn string() { + let json = OrderedJson::serialize("he\"llo").unwrap(); + let serialized = r#""he\"llo""#; + check(json, serialized); +} + +#[test] +fn serialize_array() { + let json = OrderedJson::serialize([3, 1, 2]).unwrap(); + let serialized = "[3,1,2]"; + check(json, serialized); +} + +#[test] +fn sorted_array() { + let items = ["c", "a", "b"]; + let serialized = r#"["a","b","c"]"#; + let items: Vec<OrderedJson> = + items.into_iter().map(OrderedJson::serialize).collect::<Result<Vec<_>, _>>().unwrap(); + let json = OrderedJson::array_sorted(items); + check(json, serialized); +} + +#[test] +fn nested_array() { + let a = OrderedJson::serialize(3).unwrap(); + let b = OrderedJson::serialize(2).unwrap(); + let c = OrderedJson::serialize(1).unwrap(); + let d = OrderedJson::serialize([1, 3, 2]).unwrap(); + let json = OrderedJson::array_sorted([a, b, c, d]); + let serialized = r#"[1,2,3,[1,3,2]]"#; + check(json, serialized); +} + +#[test] +fn array_unsorted() { + let items = ["c", "a", "b"]; + let serialized = r#"["c","a","b"]"#; + let items: Vec<OrderedJson> = + items.into_iter().map(OrderedJson::serialize).collect::<Result<Vec<_>, _>>().unwrap(); + let json = OrderedJson::array_unsorted(items); + check(json, serialized); +} diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 8a2f31f7413..d7682bd1c19 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -18,6 +18,7 @@ use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; use crate::html::format::join_with_double_colon; use crate::html::markdown::short_markdown_summary; +use crate::html::render::ordered_json::OrderedJson; use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId}; /// The serialized search description sharded version @@ -46,7 +47,7 @@ use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, Re /// [2]: https://en.wikipedia.org/wiki/Sliding_window_protocol#Basic_concept /// [3]: https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/description-tcp-features pub(crate) struct SerializedSearchIndex { - pub(crate) index: String, + pub(crate) index: OrderedJson, pub(crate) desc: Vec<(usize, String)>, } @@ -578,12 +579,14 @@ pub(crate) fn build_index<'tcx>( let mut names = Vec::with_capacity(self.items.len()); let mut types = String::with_capacity(self.items.len()); let mut full_paths = Vec::with_capacity(self.items.len()); - let mut parents = Vec::with_capacity(self.items.len()); + let mut parents = String::with_capacity(self.items.len()); + let mut parents_backref_queue = VecDeque::new(); let mut functions = String::with_capacity(self.items.len()); let mut deprecated = Vec::with_capacity(self.items.len()); - let mut backref_queue = VecDeque::new(); + let mut type_backref_queue = VecDeque::new(); + let mut last_name = None; for (index, item) in self.items.iter().enumerate() { let n = item.ty as u8; let c = char::try_from(n + b'A').expect("item types must fit in ASCII"); @@ -596,17 +599,39 @@ pub(crate) fn build_index<'tcx>( "`{}` is missing idx", item.name ); - // 0 is a sentinel, everything else is one-indexed - parents.push(item.parent_idx.map(|x| x + 1).unwrap_or(0)); + assert!( + parents_backref_queue.len() <= 16, + "the string encoding only supports 16 slots of lookback" + ); + let parent: i32 = item.parent_idx.map(|x| x + 1).unwrap_or(0).try_into().unwrap(); + if let Some(idx) = parents_backref_queue.iter().position(|p: &i32| *p == parent) { + parents.push( + char::try_from('0' as u32 + u32::try_from(idx).unwrap()) + .expect("last possible value is '?'"), + ); + } else if parent == 0 { + write_vlqhex_to_string(parent, &mut parents); + } else { + parents_backref_queue.push_front(parent); + write_vlqhex_to_string(parent, &mut parents); + if parents_backref_queue.len() > 16 { + parents_backref_queue.pop_back(); + } + } - names.push(item.name.as_str()); + if Some(item.name.as_str()) == last_name { + names.push(""); + } else { + names.push(item.name.as_str()); + last_name = Some(item.name.as_str()); + } if !item.path.is_empty() { full_paths.push((index, &item.path)); } match &item.search_type { - Some(ty) => ty.write_to_string(&mut functions, &mut backref_queue), + Some(ty) => ty.write_to_string(&mut functions, &mut type_backref_queue), None => functions.push('`'), } @@ -683,24 +708,19 @@ pub(crate) fn build_index<'tcx>( // The index, which is actually used to search, is JSON // It uses `JSON.parse(..)` to actually load, since JSON // parses faster than the full JavaScript syntax. - let index = format!( - r#"["{}",{}]"#, - krate.name(tcx), - serde_json::to_string(&CrateData { - items: crate_items, - paths: crate_paths, - aliases: &aliases, - associated_item_disambiguators: &associated_item_disambiguators, - desc_index, - empty_desc, - }) - .expect("failed serde conversion") - // All these `replace` calls are because we have to go through JS string for JSON content. - .replace('\\', r"\\") - .replace('\'', r"\'") - // We need to escape double quotes for the JSON. - .replace("\\\"", "\\\\\"") - ); + let crate_name = krate.name(tcx); + let data = CrateData { + items: crate_items, + paths: crate_paths, + aliases: &aliases, + associated_item_disambiguators: &associated_item_disambiguators, + desc_index, + empty_desc, + }; + let index = OrderedJson::array_unsorted([ + OrderedJson::serialize(crate_name.as_str()).unwrap(), + OrderedJson::serialize(data).unwrap(), + ]); SerializedSearchIndex { index, desc } } diff --git a/src/librustdoc/html/render/sorted_template.rs b/src/librustdoc/html/render/sorted_template.rs new file mode 100644 index 00000000000..28f7766d7c7 --- /dev/null +++ b/src/librustdoc/html/render/sorted_template.rs @@ -0,0 +1,159 @@ +use std::collections::BTreeSet; +use std::fmt::{self, Write as _}; +use std::marker::PhantomData; +use std::str::FromStr; + +use itertools::{Itertools as _, Position}; +use serde::{Deserialize, Serialize}; + +/// Append-only templates for sorted, deduplicated lists of items. +/// +/// Last line of the rendered output is a comment encoding the next insertion point. +#[derive(Debug, Clone)] +pub(crate) struct SortedTemplate<F> { + format: PhantomData<F>, + before: String, + after: String, + fragments: BTreeSet<String>, +} + +/// Written to last line of file to specify the location of each fragment +#[derive(Serialize, Deserialize, Debug, Clone)] +struct Offset { + /// Index of the first byte in the template + start: usize, + /// The length of each fragment in the encoded template, including the separator + fragment_lengths: Vec<usize>, +} + +impl<F> SortedTemplate<F> { + /// Generate this template from arbitary text. + /// Will insert wherever the substring `delimiter` can be found. + /// Errors if it does not appear exactly once. + pub(crate) fn from_template(template: &str, delimiter: &str) -> Result<Self, Error> { + let mut split = template.split(delimiter); + let before = split.next().ok_or(Error("delimiter should appear at least once"))?; + let after = split.next().ok_or(Error("delimiter should appear at least once"))?; + // not `split_once` because we want to check for too many occurrences + if split.next().is_some() { + return Err(Error("delimiter should appear at most once")); + } + Ok(Self::from_before_after(before, after)) + } + + /// Template will insert fragments between `before` and `after` + pub(crate) fn from_before_after<S: ToString, T: ToString>(before: S, after: T) -> Self { + let before = before.to_string(); + let after = after.to_string(); + Self { format: PhantomData, before, after, fragments: Default::default() } + } +} + +impl<F> SortedTemplate<F> { + /// Adds this text to the template + pub(crate) fn append(&mut self, insert: String) { + self.fragments.insert(insert); + } +} + +impl<F: FileFormat> fmt::Display for SortedTemplate<F> { + fn fmt(&self, mut f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut fragment_lengths = Vec::default(); + write!(f, "{}", self.before)?; + for (p, fragment) in self.fragments.iter().with_position() { + let mut f = DeltaWriter { inner: &mut f, delta: 0 }; + let sep = if matches!(p, Position::First | Position::Only) { "" } else { F::SEPARATOR }; + write!(f, "{}{}", sep, fragment)?; + fragment_lengths.push(f.delta); + } + let offset = Offset { start: self.before.len(), fragment_lengths }; + let offset = serde_json::to_string(&offset).unwrap(); + write!(f, "{}\n{}{}{}", self.after, F::COMMENT_START, offset, F::COMMENT_END) + } +} + +impl<F: FileFormat> FromStr for SortedTemplate<F> { + type Err = Error; + fn from_str(s: &str) -> Result<Self, Self::Err> { + let (s, offset) = s + .rsplit_once("\n") + .ok_or(Error("invalid format: should have a newline on the last line"))?; + let offset = offset + .strip_prefix(F::COMMENT_START) + .ok_or(Error("last line expected to start with a comment"))?; + let offset = offset + .strip_suffix(F::COMMENT_END) + .ok_or(Error("last line expected to end with a comment"))?; + let offset: Offset = serde_json::from_str(&offset).map_err(|_| { + Error("could not find insertion location descriptor object on last line") + })?; + let (before, mut s) = + s.split_at_checked(offset.start).ok_or(Error("invalid start: out of bounds"))?; + let mut fragments = BTreeSet::default(); + for (p, &index) in offset.fragment_lengths.iter().with_position() { + let (fragment, rest) = + s.split_at_checked(index).ok_or(Error("invalid fragment length: out of bounds"))?; + s = rest; + let sep = if matches!(p, Position::First | Position::Only) { "" } else { F::SEPARATOR }; + let fragment = fragment + .strip_prefix(sep) + .ok_or(Error("invalid fragment length: expected to find separator here"))?; + fragments.insert(fragment.to_string()); + } + Ok(Self { + format: PhantomData, + before: before.to_string(), + after: s.to_string(), + fragments, + }) + } +} + +pub(crate) trait FileFormat { + const COMMENT_START: &'static str; + const COMMENT_END: &'static str; + const SEPARATOR: &'static str; +} + +#[derive(Debug, Clone)] +pub(crate) struct Html; + +impl FileFormat for Html { + const COMMENT_START: &'static str = "<!--"; + const COMMENT_END: &'static str = "-->"; + const SEPARATOR: &'static str = ""; +} + +#[derive(Debug, Clone)] +pub(crate) struct Js; + +impl FileFormat for Js { + const COMMENT_START: &'static str = "//"; + const COMMENT_END: &'static str = ""; + const SEPARATOR: &'static str = ","; +} + +#[derive(Debug, Clone)] +pub(crate) struct Error(&'static str); + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "invalid template: {}", self.0) + } +} + +struct DeltaWriter<W> { + inner: W, + delta: usize, +} + +impl<W: fmt::Write> fmt::Write for DeltaWriter<W> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.inner.write_str(s)?; + self.delta += s.len(); + Ok(()) + } +} + +#[cfg(test)] +mod tests; diff --git a/src/librustdoc/html/render/sorted_template/tests.rs b/src/librustdoc/html/render/sorted_template/tests.rs new file mode 100644 index 00000000000..db057463005 --- /dev/null +++ b/src/librustdoc/html/render/sorted_template/tests.rs @@ -0,0 +1,149 @@ +use std::str::FromStr; + +use super::super::sorted_template::*; + +fn is_comment_js(s: &str) -> bool { + s.starts_with("//") +} + +fn is_comment_html(s: &str) -> bool { + // not correct but good enough for these tests + s.starts_with("<!--") && s.ends_with("-->") +} + +#[test] +fn html_from_empty() { + let inserts = ["<p>hello</p>", "<p>kind</p>", "<p>hello</p>", "<p>world</p>"]; + let mut template = SortedTemplate::<Html>::from_before_after("", ""); + for insert in inserts { + template.append(insert.to_string()); + } + let template = format!("{template}"); + let (template, end) = template.rsplit_once("\n").unwrap(); + assert_eq!(template, "<p>hello</p><p>kind</p><p>world</p>"); + assert!(is_comment_html(end)); + assert!(!end.contains("\n")); +} + +#[test] +fn html_page() { + let inserts = ["<p>hello</p>", "<p>kind</p>", "<p>world</p>"]; + let before = "<html><head></head><body>"; + let after = "</body>"; + let mut template = SortedTemplate::<Html>::from_before_after(before, after); + for insert in inserts { + template.append(insert.to_string()); + } + let template = format!("{template}"); + let (template, end) = template.rsplit_once("\n").unwrap(); + assert_eq!(template, format!("{before}{}{after}", inserts.join(""))); + assert!(is_comment_html(end)); + assert!(!end.contains("\n")); +} + +#[test] +fn js_from_empty() { + let inserts = ["1", "2", "2", "2", "3", "1"]; + let mut template = SortedTemplate::<Js>::from_before_after("", ""); + for insert in inserts { + template.append(insert.to_string()); + } + let template = format!("{template}"); + let (template, end) = template.rsplit_once("\n").unwrap(); + assert_eq!(template, "1,2,3"); + assert!(is_comment_js(end)); + assert!(!end.contains("\n")); +} + +#[test] +fn js_empty_array() { + let template = SortedTemplate::<Js>::from_before_after("[", "]"); + let template = format!("{template}"); + let (template, end) = template.rsplit_once("\n").unwrap(); + assert_eq!(template, format!("[]")); + assert!(is_comment_js(end)); + assert!(!end.contains("\n")); +} + +#[test] +fn js_number_array() { + let inserts = ["1", "2", "3"]; + let mut template = SortedTemplate::<Js>::from_before_after("[", "]"); + for insert in inserts { + template.append(insert.to_string()); + } + let template = format!("{template}"); + let (template, end) = template.rsplit_once("\n").unwrap(); + assert_eq!(template, format!("[1,2,3]")); + assert!(is_comment_js(end)); + assert!(!end.contains("\n")); +} + +#[test] +fn magic_js_number_array() { + let inserts = ["1", "1"]; + let mut template = SortedTemplate::<Js>::from_template("[#]", "#").unwrap(); + for insert in inserts { + template.append(insert.to_string()); + } + let template = format!("{template}"); + let (template, end) = template.rsplit_once("\n").unwrap(); + assert_eq!(template, format!("[1]")); + assert!(is_comment_js(end)); + assert!(!end.contains("\n")); +} + +#[test] +fn round_trip_js() { + let inserts = ["1", "2", "3"]; + let mut template = SortedTemplate::<Js>::from_before_after("[", "]"); + for insert in inserts { + template.append(insert.to_string()); + } + let template1 = format!("{template}"); + let mut template = SortedTemplate::<Js>::from_str(&template1).unwrap(); + assert_eq!(template1, format!("{template}")); + template.append("4".to_string()); + let template = format!("{template}"); + let (template, end) = template.rsplit_once("\n").unwrap(); + assert_eq!(template, "[1,2,3,4]"); + assert!(is_comment_js(end)); +} + +#[test] +fn round_trip_html() { + let inserts = ["<p>hello</p>", "<p>kind</p>", "<p>world</p>", "<p>kind</p>"]; + let before = "<html><head></head><body>"; + let after = "</body>"; + let mut template = SortedTemplate::<Html>::from_before_after(before, after); + template.append(inserts[0].to_string()); + template.append(inserts[1].to_string()); + let template = format!("{template}"); + let mut template = SortedTemplate::<Html>::from_str(&template).unwrap(); + template.append(inserts[2].to_string()); + let template = format!("{template}"); + let (template, end) = template.rsplit_once("\n").unwrap(); + assert_eq!(template, format!("{before}<p>hello</p><p>kind</p><p>world</p>{after}")); + assert!(is_comment_html(end)); +} + +#[test] +fn blank_js() { + let inserts = ["1", "2", "3"]; + let template = SortedTemplate::<Js>::from_before_after("", ""); + let template = format!("{template}"); + let (t, _) = template.rsplit_once("\n").unwrap(); + assert_eq!(t, ""); + let mut template = SortedTemplate::<Js>::from_str(&template).unwrap(); + for insert in inserts { + template.append(insert.to_string()); + } + let template1 = format!("{template}"); + let mut template = SortedTemplate::<Js>::from_str(&template1).unwrap(); + assert_eq!(template1, format!("{template}")); + template.append("4".to_string()); + let template = format!("{template}"); + let (template, end) = template.rsplit_once("\n").unwrap(); + assert_eq!(template, "1,2,3,4"); + assert!(is_comment_js(end)); +} diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 8fd56eae37f..a18b7a252a4 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -1,19 +1,41 @@ +//! Rustdoc writes aut two kinds of shared files: +//! - Static files, which are embedded in the rustdoc binary and are written with a +//! filename that includes a hash of their contents. These will always have a new +//! URL if the contents change, so they are safe to cache with the +//! `Cache-Control: immutable` directive. They are written under the static.files/ +//! directory and are written when --emit-type is empty (default) or contains +//! "toolchain-specific". If using the --static-root-path flag, it should point +//! to a URL path prefix where each of these filenames can be fetched. +//! - Invocation specific files. These are generated based on the crate(s) being +//! documented. Their filenames need to be predictable without knowing their +//! contents, so they do not include a hash in their filename and are not safe to +//! cache with `Cache-Control: immutable`. They include the contents of the +//! --resource-suffix flag and are emitted when --emit-type is empty (default) +//! or contains "invocation-specific". + use std::cell::RefCell; -use std::fs::{self, File}; -use std::io::prelude::*; -use std::io::{self, BufReader}; -use std::path::{Component, Path}; +use std::ffi::OsString; +use std::fs::File; +use std::io::{self, BufWriter, Write as _}; +use std::iter::once; +use std::marker::PhantomData; +use std::path::{Component, Path, PathBuf}; use std::rc::{Rc, Weak}; +use std::str::FromStr; +use std::{fmt, fs}; use indexmap::IndexMap; use itertools::Itertools; +use regex::Regex; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; +use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::Symbol; +use serde::de::DeserializeOwned; use serde::ser::SerializeSeq; -use serde::{Serialize, Serializer}; +use serde::{Deserialize, Serialize, Serializer}; use super::{collect_paths_for_type, ensure_trailing_slash, Context, RenderMode}; use crate::clean::{Crate, Item, ItemId, ItemKind}; @@ -24,53 +46,83 @@ use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::formats::Impl; use crate::html::format::Buffer; -use crate::html::render::search_index::SerializedSearchIndex; +use crate::html::layout; +use crate::html::render::ordered_json::{EscapedJson, OrderedJson}; +use crate::html::render::search_index::{build_index, SerializedSearchIndex}; +use crate::html::render::sorted_template::{self, FileFormat, SortedTemplate}; use crate::html::render::{AssocItemLink, ImplRenderingParameters}; -use crate::html::{layout, static_files}; +use crate::html::static_files::{self, suffix_path}; use crate::visit::DocVisitor; use crate::{try_err, try_none}; -/// Rustdoc writes out two kinds of shared files: -/// - Static files, which are embedded in the rustdoc binary and are written with a -/// filename that includes a hash of their contents. These will always have a new -/// URL if the contents change, so they are safe to cache with the -/// `Cache-Control: immutable` directive. They are written under the static.files/ -/// directory and are written when --emit-type is empty (default) or contains -/// "toolchain-specific". If using the --static-root-path flag, it should point -/// to a URL path prefix where each of these filenames can be fetched. -/// - Invocation specific files. These are generated based on the crate(s) being -/// documented. Their filenames need to be predictable without knowing their -/// contents, so they do not include a hash in their filename and are not safe to -/// cache with `Cache-Control: immutable`. They include the contents of the -/// --resource-suffix flag and are emitted when --emit-type is empty (default) -/// or contains "invocation-specific". -pub(super) fn write_shared( +/// Write cross-crate information files, static files, invocation-specific files, etc. to disk +pub(crate) fn write_shared( cx: &mut Context<'_>, krate: &Crate, - search_index: SerializedSearchIndex, - options: &RenderOptions, + opt: &RenderOptions, + tcx: TyCtxt<'_>, ) -> Result<(), Error> { - // Write out the shared files. Note that these are shared among all rustdoc - // docs placed in the output directory, so this needs to be a synchronized - // operation with respect to all other rustdocs running around. + // NOTE(EtomicBomb): I don't think we need sync here because no read-after-write? + Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true); let lock_file = cx.dst.join(".lock"); + // Write shared runs within a flock; disable thread dispatching of IO temporarily. let _lock = try_err!(flock::Lock::new(&lock_file, true, true, true), &lock_file); - // InvocationSpecific resources should always be dynamic. - let write_invocation_specific = |p: &str, make_content: &dyn Fn() -> Result<Vec<u8>, Error>| { - let content = make_content()?; - if options.emit.is_empty() || options.emit.contains(&EmitType::InvocationSpecific) { - let output_filename = static_files::suffix_path(p, &cx.shared.resource_suffix); - cx.shared.fs.write(cx.dst.join(output_filename), content) - } else { - Ok(()) - } + let SerializedSearchIndex { index, desc } = + build_index(&krate, &mut Rc::get_mut(&mut cx.shared).unwrap().cache, tcx); + write_search_desc(cx, &krate, &desc)?; // does not need to be merged; written unconditionally + + let crate_name = krate.name(cx.tcx()); + let crate_name = crate_name.as_str(); // rand + let crate_name_json = OrderedJson::serialize(crate_name).unwrap(); // "rand" + let external_crates = hack_get_external_crate_names(&cx.dst)?; + let info = CrateInfo { + src_files_js: SourcesPart::get(cx, &crate_name_json)?, + search_index_js: SearchIndexPart::get(index, &cx.shared.resource_suffix)?, + all_crates: AllCratesPart::get(crate_name_json.clone())?, + crates_index: CratesIndexPart::get(&crate_name, &external_crates)?, + trait_impl: TraitAliasPart::get(cx, &crate_name_json)?, + type_impl: TypeAliasPart::get(cx, krate, &crate_name_json)?, }; - cx.shared - .fs - .create_dir_all(cx.dst.join("static.files")) - .map_err(|e| PathError::new(e, "static.files"))?; + let crates = vec![info]; // we have info from just one crate. rest will found in out dir + + write_static_files(cx, &opt)?; + let dst = &cx.dst; + if opt.emit.is_empty() || opt.emit.contains(&EmitType::InvocationSpecific) { + if cx.include_sources { + write_rendered_cci::<SourcesPart, _>(SourcesPart::blank, dst, &crates)?; + } + write_rendered_cci::<SearchIndexPart, _>(SearchIndexPart::blank, dst, &crates)?; + write_rendered_cci::<AllCratesPart, _>(AllCratesPart::blank, dst, &crates)?; + } + write_rendered_cci::<TraitAliasPart, _>(TraitAliasPart::blank, dst, &crates)?; + write_rendered_cci::<TypeAliasPart, _>(TypeAliasPart::blank, dst, &crates)?; + match &opt.index_page { + Some(index_page) if opt.enable_index_page => { + let mut md_opts = opt.clone(); + md_opts.output = cx.dst.clone(); + md_opts.external_html = cx.shared.layout.external_html.clone(); + try_err!( + crate::markdown::render(&index_page, md_opts, cx.shared.edition()), + &index_page + ); + } + None if opt.enable_index_page => { + write_rendered_cci::<CratesIndexPart, _>(|| CratesIndexPart::blank(cx), dst, &crates)?; + } + _ => {} // they don't want an index page + } + + Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false); + Ok(()) +} + +/// Writes the static files, the style files, and the css extensions +fn write_static_files(cx: &mut Context<'_>, options: &RenderOptions) -> Result<(), Error> { + let static_dir = cx.dst.join("static.files"); + + cx.shared.fs.create_dir_all(&static_dir).map_err(|e| PathError::new(e, "static.files"))?; // Handle added third-party themes for entry in &cx.shared.style_files { @@ -97,680 +149,786 @@ pub(super) fn write_shared( } if options.emit.is_empty() || options.emit.contains(&EmitType::Toolchain) { - let static_dir = cx.dst.join(Path::new("static.files")); static_files::for_each(|f: &static_files::StaticFile| { let filename = static_dir.join(f.output_filename()); cx.shared.fs.write(filename, f.minified()) })?; } - /// Read a file and return all lines that match the `"{crate}":{data},` format, - /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`. - /// - /// This forms the payload of files that look like this: - /// - /// ```javascript - /// var data = { - /// "{crate1}":{data}, - /// "{crate2}":{data} - /// }; - /// use_data(data); - /// ``` - /// - /// The file needs to be formatted so that *only crate data lines start with `"`*. - fn collect(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> { - let mut ret = Vec::new(); - let mut krates = Vec::new(); - - if path.exists() { - let prefix = format!("\"{krate}\""); - for line in BufReader::new(File::open(path)?).lines() { - let line = line?; - if !line.starts_with('"') { - continue; - } - if line.starts_with(&prefix) { - continue; - } - if line.ends_with(',') { - ret.push(line[..line.len() - 1].to_string()); - } else { - // No comma (it's the case for the last added crate line) - ret.push(line.to_string()); - } - krates.push( - line.split('"') - .find(|s| !s.is_empty()) - .map(|s| s.to_owned()) - .unwrap_or_else(String::new), - ); - } - } - Ok((ret, krates)) - } - - /// Read a file and return all lines that match the <code>"{crate}":{data},\ </code> format, - /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`. - /// - /// This forms the payload of files that look like this: - /// - /// ```javascript - /// var data = JSON.parse('{\ - /// "{crate1}":{data},\ - /// "{crate2}":{data}\ - /// }'); - /// use_data(data); - /// ``` - /// - /// The file needs to be formatted so that *only crate data lines start with `"`*. - fn collect_json(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> { - let mut ret = Vec::new(); - let mut krates = Vec::new(); - - if path.exists() { - let prefix = format!("[\"{krate}\""); - for line in BufReader::new(File::open(path)?).lines() { - let line = line?; - if !line.starts_with("[\"") { - continue; - } - if line.starts_with(&prefix) { - continue; - } - if line.ends_with("],\\") { - ret.push(line[..line.len() - 2].to_string()); - } else { - // Ends with "\\" (it's the case for the last added crate line) - ret.push(line[..line.len() - 1].to_string()); - } - krates.push( - line[1..] // We skip the `[` parent at the beginning of the line. - .split('"') - .find(|s| !s.is_empty()) - .map(|s| s.to_owned()) - .unwrap_or_else(String::new), - ); - } - } - Ok((ret, krates)) + Ok(()) +} + +/// Write the search description shards to disk +fn write_search_desc( + cx: &mut Context<'_>, + krate: &Crate, + search_desc: &[(usize, String)], +) -> Result<(), Error> { + let crate_name = krate.name(cx.tcx()).to_string(); + let encoded_crate_name = OrderedJson::serialize(&crate_name).unwrap(); + let path = PathBuf::from_iter([&cx.dst, Path::new("search.desc"), Path::new(&crate_name)]); + if path.exists() { + try_err!(fs::remove_dir_all(&path), &path); + } + for (i, (_, part)) in search_desc.iter().enumerate() { + let filename = static_files::suffix_path( + &format!("{crate_name}-desc-{i}-.js"), + &cx.shared.resource_suffix, + ); + let path = path.join(filename); + let part = OrderedJson::serialize(&part).unwrap(); + let part = format!("searchState.loadedDescShard({encoded_crate_name}, {i}, {part})"); + create_parents(&path)?; + try_err!(fs::write(&path, part), &path); } + Ok(()) +} - use std::ffi::OsString; +/// Contains pre-rendered contents to insert into the CCI template +#[derive(Serialize, Deserialize, Clone, Debug)] +struct CrateInfo { + src_files_js: PartsAndLocations<SourcesPart>, + search_index_js: PartsAndLocations<SearchIndexPart>, + all_crates: PartsAndLocations<AllCratesPart>, + crates_index: PartsAndLocations<CratesIndexPart>, + trait_impl: PartsAndLocations<TraitAliasPart>, + type_impl: PartsAndLocations<TypeAliasPart>, +} + +/// Paths (relative to the doc root) and their pre-merge contents +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(transparent)] +struct PartsAndLocations<P> { + parts: Vec<(PathBuf, P)>, +} - #[derive(Debug, Default)] - struct Hierarchy { - parent: Weak<Self>, - elem: OsString, - children: RefCell<FxHashMap<OsString, Rc<Self>>>, - elems: RefCell<FxHashSet<OsString>>, +impl<P> Default for PartsAndLocations<P> { + fn default() -> Self { + Self { parts: Vec::default() } } +} - impl Hierarchy { - fn with_parent(elem: OsString, parent: &Rc<Self>) -> Self { - Self { elem, parent: Rc::downgrade(parent), ..Self::default() } - } +impl<T, U> PartsAndLocations<Part<T, U>> { + fn push(&mut self, path: PathBuf, item: U) { + self.parts.push((path, Part { _artifact: PhantomData, item })); + } - fn to_json_string(&self) -> String { - let borrow = self.children.borrow(); - let mut subs: Vec<_> = borrow.values().collect(); - subs.sort_unstable_by(|a, b| a.elem.cmp(&b.elem)); - let mut files = self - .elems - .borrow() - .iter() - .map(|s| format!("\"{}\"", s.to_str().expect("invalid osstring conversion"))) - .collect::<Vec<_>>(); - files.sort_unstable(); - let subs = subs.iter().map(|s| s.to_json_string()).collect::<Vec<_>>().join(","); - let dirs = if subs.is_empty() && files.is_empty() { - String::new() - } else { - format!(",[{subs}]") - }; - let files = files.join(","); - let files = if files.is_empty() { String::new() } else { format!(",[{files}]") }; - format!( - "[\"{name}\"{dirs}{files}]", - name = self.elem.to_str().expect("invalid osstring conversion"), - dirs = dirs, - files = files - ) - } + /// Singleton part, one file + fn with(path: PathBuf, part: U) -> Self { + let mut ret = Self::default(); + ret.push(path, part); + ret + } +} - fn add_path(self: &Rc<Self>, path: &Path) { - let mut h = Rc::clone(&self); - let mut elems = path - .components() - .filter_map(|s| match s { - Component::Normal(s) => Some(s.to_owned()), - Component::ParentDir => Some(OsString::from("..")), - _ => None, - }) - .peekable(); - loop { - let cur_elem = elems.next().expect("empty file path"); - if cur_elem == ".." { - if let Some(parent) = h.parent.upgrade() { - h = parent; - } - continue; - } - if elems.peek().is_none() { - h.elems.borrow_mut().insert(cur_elem); - break; - } else { - let entry = Rc::clone( - h.children - .borrow_mut() - .entry(cur_elem.clone()) - .or_insert_with(|| Rc::new(Self::with_parent(cur_elem, &h))), - ); - h = entry; - } - } +/// A piece of one of the shared artifacts for documentation (search index, sources, alias list, etc.) +/// +/// Merged at a user specified time and written to the `doc/` directory +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(transparent)] +struct Part<T, U> { + #[serde(skip)] + _artifact: PhantomData<T>, + item: U, +} + +impl<T, U: fmt::Display> fmt::Display for Part<T, U> { + /// Writes serialized JSON + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.item) + } +} + +/// Wrapper trait for `Part<T, U>` +trait CciPart: Sized + fmt::Display + DeserializeOwned + 'static { + /// Identifies the file format of the cross-crate information + type FileFormat: sorted_template::FileFormat; + fn from_crate_info(crate_info: &CrateInfo) -> &PartsAndLocations<Self>; +} + +#[derive(Serialize, Deserialize, Clone, Default, Debug)] +struct SearchIndex; +type SearchIndexPart = Part<SearchIndex, EscapedJson>; +impl CciPart for SearchIndexPart { + type FileFormat = sorted_template::Js; + fn from_crate_info(crate_info: &CrateInfo) -> &PartsAndLocations<Self> { + &crate_info.search_index_js + } +} + +impl SearchIndexPart { + fn blank() -> SortedTemplate<<Self as CciPart>::FileFormat> { + SortedTemplate::from_before_after( + r"var searchIndex = new Map(JSON.parse('[", + r"]')); +if (typeof exports !== 'undefined') exports.searchIndex = searchIndex; +else if (window.initSearch) window.initSearch(searchIndex);", + ) + } + + fn get( + search_index: OrderedJson, + resource_suffix: &str, + ) -> Result<PartsAndLocations<Self>, Error> { + let path = suffix_path("search-index.js", resource_suffix); + let search_index = EscapedJson::from(search_index); + Ok(PartsAndLocations::with(path, search_index)) + } +} + +#[derive(Serialize, Deserialize, Clone, Default, Debug)] +struct AllCrates; +type AllCratesPart = Part<AllCrates, OrderedJson>; +impl CciPart for AllCratesPart { + type FileFormat = sorted_template::Js; + fn from_crate_info(crate_info: &CrateInfo) -> &PartsAndLocations<Self> { + &crate_info.all_crates + } +} + +impl AllCratesPart { + fn blank() -> SortedTemplate<<Self as CciPart>::FileFormat> { + SortedTemplate::from_before_after("window.ALL_CRATES = [", "];") + } + + fn get(crate_name_json: OrderedJson) -> Result<PartsAndLocations<Self>, Error> { + // external hack_get_external_crate_names not needed here, because + // there's no way that we write the search index but not crates.js + let path = PathBuf::from("crates.js"); + Ok(PartsAndLocations::with(path, crate_name_json)) + } +} + +/// Reads `crates.js`, which seems like the best +/// place to obtain the list of externally documented crates if the index +/// page was disabled when documenting the deps. +/// +/// This is to match the current behavior of rustdoc, which allows you to get all crates +/// on the index page, even if --enable-index-page is only passed to the last crate. +fn hack_get_external_crate_names(doc_root: &Path) -> Result<Vec<String>, Error> { + let path = doc_root.join("crates.js"); + let Ok(content) = fs::read_to_string(&path) else { + // they didn't emit invocation specific, so we just say there were no crates + return Ok(Vec::default()); + }; + // this is only run once so it's fine not to cache it + // !dot_matches_new_line: all crates on same line. greedy: match last bracket + let regex = Regex::new(r"\[.*\]").unwrap(); + let Some(content) = regex.find(&content) else { + return Err(Error::new("could not find crates list in crates.js", path)); + }; + let content: Vec<String> = try_err!(serde_json::from_str(content.as_str()), &path); + Ok(content) +} + +#[derive(Serialize, Deserialize, Clone, Default, Debug)] +struct CratesIndex; +type CratesIndexPart = Part<CratesIndex, String>; +impl CciPart for CratesIndexPart { + type FileFormat = sorted_template::Html; + fn from_crate_info(crate_info: &CrateInfo) -> &PartsAndLocations<Self> { + &crate_info.crates_index + } +} + +impl CratesIndexPart { + fn blank(cx: &Context<'_>) -> SortedTemplate<<Self as CciPart>::FileFormat> { + let page = layout::Page { + title: "Index of crates", + css_class: "mod sys", + root_path: "./", + static_root_path: cx.shared.static_root_path.as_deref(), + description: "List of crates", + resource_suffix: &cx.shared.resource_suffix, + rust_logo: true, + }; + let layout = &cx.shared.layout; + let style_files = &cx.shared.style_files; + const DELIMITER: &str = "\u{FFFC}"; // users are being naughty if they have this + let content = + format!("<h1>List of all crates</h1><ul class=\"all-items\">{DELIMITER}</ul>"); + let template = layout::render(layout, &page, "", content, &style_files); + match SortedTemplate::from_template(&template, DELIMITER) { + Ok(template) => template, + Err(e) => panic!( + "Object Replacement Character (U+FFFC) should not appear in the --index-page: {e}" + ), } } - if cx.include_sources { - let hierarchy = Rc::new(Hierarchy::default()); - for source in cx - .shared - .local_sources - .iter() - .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root).ok()) - { - hierarchy.add_path(source); + /// Might return parts that are duplicate with ones in prexisting index.html + fn get(crate_name: &str, external_crates: &[String]) -> Result<PartsAndLocations<Self>, Error> { + let mut ret = PartsAndLocations::default(); + let path = PathBuf::from("index.html"); + for crate_name in external_crates.iter().map(|s| s.as_str()).chain(once(crate_name)) { + let part = format!( + "<li><a href=\"{trailing_slash}index.html\">{crate_name}</a></li>", + trailing_slash = ensure_trailing_slash(crate_name), + ); + ret.push(path.clone(), part); } - let hierarchy = Rc::try_unwrap(hierarchy).unwrap(); - let dst = cx.dst.join(&format!("src-files{}.js", cx.shared.resource_suffix)); - let make_sources = || { - let (mut all_sources, _krates) = - try_err!(collect_json(&dst, krate.name(cx.tcx()).as_str()), &dst); - all_sources.push(format!( - r#"["{}",{}]"#, - &krate.name(cx.tcx()), - hierarchy - .to_json_string() - // All these `replace` calls are because we have to go through JS string for JSON content. - .replace('\\', r"\\") - .replace('\'', r"\'") - // We need to escape double quotes for the JSON. - .replace("\\\"", "\\\\\"") - )); - all_sources.sort(); - // This needs to be `var`, not `const`. - // This variable needs declared in the current global scope so that if - // src-script.js loads first, it can pick it up. - let mut v = String::from("var srcIndex = new Map(JSON.parse('[\\\n"); - v.push_str(&all_sources.join(",\\\n")); - v.push_str("\\\n]'));\ncreateSrcSidebar();\n"); - Ok(v.into_bytes()) - }; - write_invocation_specific("src-files.js", &make_sources)?; + Ok(ret) } +} - // Update the search index and crate list. - let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix)); - let (mut all_indexes, mut krates) = - try_err!(collect_json(&dst, krate.name(cx.tcx()).as_str()), &dst); - all_indexes.push(search_index.index); - krates.push(krate.name(cx.tcx()).to_string()); - krates.sort(); +#[derive(Serialize, Deserialize, Clone, Default, Debug)] +struct Sources; +type SourcesPart = Part<Sources, EscapedJson>; +impl CciPart for SourcesPart { + type FileFormat = sorted_template::Js; + fn from_crate_info(crate_info: &CrateInfo) -> &PartsAndLocations<Self> { + &crate_info.src_files_js + } +} - // Sort the indexes by crate so the file will be generated identically even - // with rustdoc running in parallel. - all_indexes.sort(); - write_invocation_specific("search-index.js", &|| { +impl SourcesPart { + fn blank() -> SortedTemplate<<Self as CciPart>::FileFormat> { // This needs to be `var`, not `const`. // This variable needs declared in the current global scope so that if - // search.js loads first, it can pick it up. - let mut v = String::from("var searchIndex = new Map(JSON.parse('[\\\n"); - v.push_str(&all_indexes.join(",\\\n")); - v.push_str( - r#"\ -]')); -if (typeof exports !== 'undefined') exports.searchIndex = searchIndex; -else if (window.initSearch) window.initSearch(searchIndex); -"#, - ); - Ok(v.into_bytes()) - })?; - - let search_desc_dir = cx.dst.join(format!("search.desc/{krate}", krate = krate.name(cx.tcx()))); - if Path::new(&search_desc_dir).exists() { - try_err!(std::fs::remove_dir_all(&search_desc_dir), &search_desc_dir); - } - try_err!(std::fs::create_dir_all(&search_desc_dir), &search_desc_dir); - let kratename = krate.name(cx.tcx()).to_string(); - for (i, (_, data)) in search_index.desc.into_iter().enumerate() { - let output_filename = static_files::suffix_path( - &format!("{kratename}-desc-{i}-.js"), - &cx.shared.resource_suffix, - ); - let path = search_desc_dir.join(output_filename); - try_err!( - std::fs::write( - &path, - &format!( - r##"searchState.loadedDescShard({kratename}, {i}, {data})"##, - kratename = serde_json::to_string(&kratename).unwrap(), - data = serde_json::to_string(&data).unwrap(), - ) - .into_bytes() - ), - &path - ); + // src-script.js loads first, it can pick it up. + SortedTemplate::from_before_after( + r"var srcIndex = new Map(JSON.parse('[", + r"]')); +createSrcSidebar();", + ) } - write_invocation_specific("crates.js", &|| { - let krates = krates.iter().map(|k| format!("\"{k}\"")).join(","); - Ok(format!("window.ALL_CRATES = [{krates}];").into_bytes()) - })?; + fn get(cx: &Context<'_>, crate_name: &OrderedJson) -> Result<PartsAndLocations<Self>, Error> { + let hierarchy = Rc::new(Hierarchy::default()); + cx.shared + .local_sources + .iter() + .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root).ok()) + .for_each(|source| hierarchy.add_path(source)); + let path = suffix_path("src-files.js", &cx.shared.resource_suffix); + let hierarchy = hierarchy.to_json_string(); + let part = OrderedJson::array_unsorted([crate_name, &hierarchy]); + let part = EscapedJson::from(part); + Ok(PartsAndLocations::with(path, part)) + } +} - if options.enable_index_page { - if let Some(index_page) = options.index_page.clone() { - let mut md_opts = options.clone(); - md_opts.output = cx.dst.clone(); - md_opts.external_html = (*cx.shared).layout.external_html.clone(); +/// Source files directory tree +#[derive(Debug, Default)] +struct Hierarchy { + parent: Weak<Self>, + elem: OsString, + children: RefCell<FxHashMap<OsString, Rc<Self>>>, + elems: RefCell<FxHashSet<OsString>>, +} - crate::markdown::render(&index_page, md_opts, cx.shared.edition()) - .map_err(|e| Error::new(e, &index_page))?; - } else { - let shared = Rc::clone(&cx.shared); - let dst = cx.dst.join("index.html"); - let page = layout::Page { - title: "Index of crates", - css_class: "mod sys", - root_path: "./", - static_root_path: shared.static_root_path.as_deref(), - description: "List of crates", - resource_suffix: &shared.resource_suffix, - rust_logo: true, - }; +impl Hierarchy { + fn with_parent(elem: OsString, parent: &Rc<Self>) -> Self { + Self { elem, parent: Rc::downgrade(parent), ..Self::default() } + } - let content = format!( - "<h1>List of all crates</h1><ul class=\"all-items\">{}</ul>", - krates.iter().format_with("", |k, f| { - f(&format_args!( - "<li><a href=\"{trailing_slash}index.html\">{k}</a></li>", - trailing_slash = ensure_trailing_slash(k), - )) - }) - ); - let v = layout::render(&shared.layout, &page, "", content, &shared.style_files); - shared.fs.write(dst, v)?; + fn to_json_string(&self) -> OrderedJson { + let subs = self.children.borrow(); + let files = self.elems.borrow(); + let name = OrderedJson::serialize(self.elem.to_str().expect("invalid osstring conversion")) + .unwrap(); + let mut out = Vec::from([name]); + if !subs.is_empty() || !files.is_empty() { + let subs = subs.iter().map(|(_, s)| s.to_json_string()); + out.push(OrderedJson::array_sorted(subs)); + } + if !files.is_empty() { + let files = files + .iter() + .map(|s| OrderedJson::serialize(s.to_str().expect("invalid osstring")).unwrap()); + out.push(OrderedJson::array_sorted(files)); } + OrderedJson::array_unsorted(out) } - let cloned_shared = Rc::clone(&cx.shared); - let cache = &cloned_shared.cache; - - // Collect the list of aliased types and their aliases. - // <https://github.com/search?q=repo%3Arust-lang%2Frust+[RUSTDOCIMPL]+type.impl&type=code> - // - // The clean AST has type aliases that point at their types, but - // this visitor works to reverse that: `aliased_types` is a map - // from target to the aliases that reference it, and each one - // will generate one file. - struct TypeImplCollector<'cx, 'cache> { - // Map from DefId-of-aliased-type to its data. - aliased_types: IndexMap<DefId, AliasedType<'cache>>, - visited_aliases: FxHashSet<DefId>, - cache: &'cache Cache, - cx: &'cache mut Context<'cx>, - } - // Data for an aliased type. - // - // In the final file, the format will be roughly: - // - // ```json - // // type.impl/CRATE/TYPENAME.js - // JSONP( - // "CRATE": [ - // ["IMPL1 HTML", "ALIAS1", "ALIAS2", ...], - // ["IMPL2 HTML", "ALIAS3", "ALIAS4", ...], - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ struct AliasedType - // ... - // ] - // ) - // ``` - struct AliasedType<'cache> { - // This is used to generate the actual filename of this aliased type. - target_fqp: &'cache [Symbol], - target_type: ItemType, - // This is the data stored inside the file. - // ItemId is used to deduplicate impls. - impl_: IndexMap<ItemId, AliasedTypeImpl<'cache>>, - } - // The `impl_` contains data that's used to figure out if an alias will work, - // and to generate the HTML at the end. - // - // The `type_aliases` list is built up with each type alias that matches. - struct AliasedTypeImpl<'cache> { - impl_: &'cache Impl, - type_aliases: Vec<(&'cache [Symbol], Item)>, - } - impl<'cx, 'cache> DocVisitor for TypeImplCollector<'cx, 'cache> { - fn visit_item(&mut self, it: &Item) { - self.visit_item_recur(it); - let cache = self.cache; - let ItemKind::TypeAliasItem(ref t) = *it.kind else { return }; - let Some(self_did) = it.item_id.as_def_id() else { return }; - if !self.visited_aliases.insert(self_did) { - return; - } - let Some(target_did) = t.type_.def_id(cache) else { return }; - let get_extern = { || cache.external_paths.get(&target_did) }; - let Some(&(ref target_fqp, target_type)) = - cache.paths.get(&target_did).or_else(get_extern) - else { - return; - }; - let aliased_type = self.aliased_types.entry(target_did).or_insert_with(|| { - let impl_ = cache - .impls - .get(&target_did) - .map(|v| &v[..]) - .unwrap_or_default() - .iter() - .map(|impl_| { - ( - impl_.impl_item.item_id, - AliasedTypeImpl { impl_, type_aliases: Vec::new() }, - ) - }) - .collect(); - AliasedType { target_fqp: &target_fqp[..], target_type, impl_ } - }); - let get_local = { || cache.paths.get(&self_did).map(|(p, _)| p) }; - let Some(self_fqp) = cache.exact_paths.get(&self_did).or_else(get_local) else { - return; - }; - let aliased_ty = self.cx.tcx().type_of(self_did).skip_binder(); - // Exclude impls that are directly on this type. They're already in the HTML. - // Some inlining scenarios can cause there to be two versions of the same - // impl: one on the type alias and one on the underlying target type. - let mut seen_impls: FxHashSet<ItemId> = cache - .impls - .get(&self_did) - .map(|s| &s[..]) - .unwrap_or_default() - .iter() - .map(|i| i.impl_item.item_id) - .collect(); - for (impl_item_id, aliased_type_impl) in &mut aliased_type.impl_ { - // Only include this impl if it actually unifies with this alias. - // Synthetic impls are not included; those are also included in the HTML. - // - // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this - // to use type unification. - // Be aware of `tests/rustdoc/type-alias/deeply-nested-112515.rs` which might regress. - let Some(impl_did) = impl_item_id.as_def_id() else { continue }; - let for_ty = self.cx.tcx().type_of(impl_did).skip_binder(); - let reject_cx = DeepRejectCtxt::new(self.cx.tcx(), TreatParams::AsCandidateKey); - if !reject_cx.types_may_unify(aliased_ty, for_ty) { - continue; - } - // Avoid duplicates - if !seen_impls.insert(*impl_item_id) { - continue; + fn add_path(self: &Rc<Self>, path: &Path) { + let mut h = Rc::clone(&self); + let mut elems = path + .components() + .filter_map(|s| match s { + Component::Normal(s) => Some(s.to_owned()), + Component::ParentDir => Some(OsString::from("..")), + _ => None, + }) + .peekable(); + loop { + let cur_elem = elems.next().expect("empty file path"); + if cur_elem == ".." { + if let Some(parent) = h.parent.upgrade() { + h = parent; } - // This impl was not found in the set of rejected impls - aliased_type_impl.type_aliases.push((&self_fqp[..], it.clone())); + continue; } - } - } - let mut type_impl_collector = TypeImplCollector { - aliased_types: IndexMap::default(), - visited_aliases: FxHashSet::default(), - cache, - cx, - }; - DocVisitor::visit_crate(&mut type_impl_collector, &krate); - // Final serialized form of the alias impl - struct AliasSerializableImpl { - text: String, - trait_: Option<String>, - aliases: Vec<String>, - } - impl Serialize for AliasSerializableImpl { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - let mut seq = serializer.serialize_seq(None)?; - seq.serialize_element(&self.text)?; - if let Some(trait_) = &self.trait_ { - seq.serialize_element(trait_)?; + if elems.peek().is_none() { + h.elems.borrow_mut().insert(cur_elem); + break; } else { - seq.serialize_element(&0)?; - } - for type_ in &self.aliases { - seq.serialize_element(type_)?; + let entry = Rc::clone( + h.children + .borrow_mut() + .entry(cur_elem.clone()) + .or_insert_with(|| Rc::new(Self::with_parent(cur_elem, &h))), + ); + h = entry; } - seq.end() } } - let cx = type_impl_collector.cx; - let dst = cx.dst.join("type.impl"); - let aliased_types = type_impl_collector.aliased_types; - for aliased_type in aliased_types.values() { - let impls = aliased_type - .impl_ - .values() - .flat_map(|AliasedTypeImpl { impl_, type_aliases }| { - let mut ret = Vec::new(); - let trait_ = impl_ - .inner_impl() - .trait_ - .as_ref() - .map(|trait_| format!("{:#}", trait_.print(cx))); - // render_impl will filter out "impossible-to-call" methods - // to make that functionality work here, it needs to be called with - // each type alias, and if it gives a different result, split the impl - for &(type_alias_fqp, ref type_alias_item) in type_aliases { - let mut buf = Buffer::html(); - cx.id_map = Default::default(); - cx.deref_id_map = Default::default(); - let target_did = impl_ +} + +#[derive(Serialize, Deserialize, Clone, Default, Debug)] +struct TypeAlias; +type TypeAliasPart = Part<TypeAlias, OrderedJson>; +impl CciPart for TypeAliasPart { + type FileFormat = sorted_template::Js; + fn from_crate_info(crate_info: &CrateInfo) -> &PartsAndLocations<Self> { + &crate_info.type_impl + } +} + +impl TypeAliasPart { + fn blank() -> SortedTemplate<<Self as CciPart>::FileFormat> { + SortedTemplate::from_before_after( + r"(function() { + var type_impls = Object.fromEntries([", + r"]); + if (window.register_type_impls) { + window.register_type_impls(type_impls); + } else { + window.pending_type_impls = type_impls; + } +})()", + ) + } + + fn get( + cx: &mut Context<'_>, + krate: &Crate, + crate_name_json: &OrderedJson, + ) -> Result<PartsAndLocations<Self>, Error> { + let cache = &Rc::clone(&cx.shared).cache; + let mut path_parts = PartsAndLocations::default(); + + let mut type_impl_collector = TypeImplCollector { + aliased_types: IndexMap::default(), + visited_aliases: FxHashSet::default(), + cache, + cx, + }; + DocVisitor::visit_crate(&mut type_impl_collector, &krate); + let cx = type_impl_collector.cx; + let aliased_types = type_impl_collector.aliased_types; + for aliased_type in aliased_types.values() { + let impls = aliased_type + .impl_ + .values() + .flat_map(|AliasedTypeImpl { impl_, type_aliases }| { + let mut ret = Vec::new(); + let trait_ = impl_ .inner_impl() .trait_ .as_ref() - .map(|trait_| trait_.def_id()) - .or_else(|| impl_.inner_impl().for_.def_id(cache)); - let provided_methods; - let assoc_link = if let Some(target_did) = target_did { - provided_methods = impl_.inner_impl().provided_trait_methods(cx.tcx()); - AssocItemLink::GotoSource(ItemId::DefId(target_did), &provided_methods) - } else { - AssocItemLink::Anchor(None) - }; - super::render_impl( - &mut buf, - cx, - *impl_, - &type_alias_item, - assoc_link, - RenderMode::Normal, - None, - &[], - ImplRenderingParameters { - show_def_docs: true, - show_default_items: true, - show_non_assoc_items: true, - toggle_open_by_default: true, - }, - ); - let text = buf.into_inner(); - let type_alias_fqp = (*type_alias_fqp).iter().join("::"); - if Some(&text) == ret.last().map(|s: &AliasSerializableImpl| &s.text) { - ret.last_mut() - .expect("already established that ret.last() is Some()") - .aliases - .push(type_alias_fqp); + .map(|trait_| format!("{:#}", trait_.print(cx))); + // render_impl will filter out "impossible-to-call" methods + // to make that functionality work here, it needs to be called with + // each type alias, and if it gives a different result, split the impl + for &(type_alias_fqp, ref type_alias_item) in type_aliases { + let mut buf = Buffer::html(); + cx.id_map = Default::default(); + cx.deref_id_map = Default::default(); + let target_did = impl_ + .inner_impl() + .trait_ + .as_ref() + .map(|trait_| trait_.def_id()) + .or_else(|| impl_.inner_impl().for_.def_id(cache)); + let provided_methods; + let assoc_link = if let Some(target_did) = target_did { + provided_methods = impl_.inner_impl().provided_trait_methods(cx.tcx()); + AssocItemLink::GotoSource(ItemId::DefId(target_did), &provided_methods) + } else { + AssocItemLink::Anchor(None) + }; + super::render_impl( + &mut buf, + cx, + *impl_, + &type_alias_item, + assoc_link, + RenderMode::Normal, + None, + &[], + ImplRenderingParameters { + show_def_docs: true, + show_default_items: true, + show_non_assoc_items: true, + toggle_open_by_default: true, + }, + ); + let text = buf.into_inner(); + let type_alias_fqp = (*type_alias_fqp).iter().join("::"); + if Some(&text) == ret.last().map(|s: &AliasSerializableImpl| &s.text) { + ret.last_mut() + .expect("already established that ret.last() is Some()") + .aliases + .push(type_alias_fqp); + } else { + ret.push(AliasSerializableImpl { + text, + trait_: trait_.clone(), + aliases: vec![type_alias_fqp], + }) + } + } + ret + }) + .collect::<Vec<_>>(); + + let mut path = PathBuf::from("type.impl"); + for component in &aliased_type.target_fqp[..aliased_type.target_fqp.len() - 1] { + path.push(component.as_str()); + } + let aliased_item_type = aliased_type.target_type; + path.push(&format!( + "{aliased_item_type}.{}.js", + aliased_type.target_fqp[aliased_type.target_fqp.len() - 1] + )); + + let part = OrderedJson::array_sorted( + impls.iter().map(OrderedJson::serialize).collect::<Result<Vec<_>, _>>().unwrap(), + ); + path_parts.push(path, OrderedJson::array_unsorted([crate_name_json, &part])); + } + Ok(path_parts) + } +} + +#[derive(Serialize, Deserialize, Clone, Default, Debug)] +struct TraitAlias; +type TraitAliasPart = Part<TraitAlias, OrderedJson>; +impl CciPart for TraitAliasPart { + type FileFormat = sorted_template::Js; + fn from_crate_info(crate_info: &CrateInfo) -> &PartsAndLocations<Self> { + &crate_info.trait_impl + } +} + +impl TraitAliasPart { + fn blank() -> SortedTemplate<<Self as CciPart>::FileFormat> { + SortedTemplate::from_before_after( + r"(function() { + var implementors = Object.fromEntries([", + r"]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})()", + ) + } + + fn get( + cx: &mut Context<'_>, + crate_name_json: &OrderedJson, + ) -> Result<PartsAndLocations<Self>, Error> { + let cache = &cx.shared.cache; + let mut path_parts = PartsAndLocations::default(); + // Update the list of all implementors for traits + // <https://github.com/search?q=repo%3Arust-lang%2Frust+[RUSTDOCIMPL]+trait.impl&type=code> + for (&did, imps) in &cache.implementors { + // Private modules can leak through to this phase of rustdoc, which + // could contain implementations for otherwise private types. In some + // rare cases we could find an implementation for an item which wasn't + // indexed, so we just skip this step in that case. + // + // FIXME: this is a vague explanation for why this can't be a `get`, in + // theory it should be... + let (remote_path, remote_item_type) = match cache.exact_paths.get(&did) { + Some(p) => match cache.paths.get(&did).or_else(|| cache.external_paths.get(&did)) { + Some((_, t)) => (p, t), + None => continue, + }, + None => match cache.external_paths.get(&did) { + Some((p, t)) => (p, t), + None => continue, + }, + }; + + let implementors = imps + .iter() + .filter_map(|imp| { + // If the trait and implementation are in the same crate, then + // there's no need to emit information about it (there's inlining + // going on). If they're in different crates then the crate defining + // the trait will be interested in our implementation. + // + // If the implementation is from another crate then that crate + // should add it. + if imp.impl_item.item_id.krate() == did.krate + || !imp.impl_item.item_id.is_local() + { + None } else { - ret.push(AliasSerializableImpl { - text, - trait_: trait_.clone(), - aliases: vec![type_alias_fqp], + Some(Implementor { + text: imp.inner_impl().print(false, cx).to_string(), + synthetic: imp.inner_impl().kind.is_auto(), + types: collect_paths_for_type(imp.inner_impl().for_.clone(), cache), }) } - } - ret - }) - .collect::<Vec<_>>(); + }) + .collect::<Vec<_>>(); - // FIXME: this fixes only rustdoc part of instability of trait impls - // for js files, see #120371 - // Manually collect to string and sort to make list not depend on order - let mut impls = impls - .iter() - .map(|i| serde_json::to_string(i).expect("failed serde conversion")) - .collect::<Vec<_>>(); - impls.sort(); + // Only create a js file if we have impls to add to it. If the trait is + // documented locally though we always create the file to avoid dead + // links. + if implementors.is_empty() && !cache.paths.contains_key(&did) { + continue; + } - let impls = format!(r#""{}":[{}]"#, krate.name(cx.tcx()), impls.join(",")); + let mut path = PathBuf::from("trait.impl"); + for component in &remote_path[..remote_path.len() - 1] { + path.push(component.as_str()); + } + path.push(&format!("{remote_item_type}.{}.js", remote_path[remote_path.len() - 1])); - let mut mydst = dst.clone(); - for part in &aliased_type.target_fqp[..aliased_type.target_fqp.len() - 1] { - mydst.push(part.to_string()); + let part = OrderedJson::array_sorted( + implementors + .iter() + .map(OrderedJson::serialize) + .collect::<Result<Vec<_>, _>>() + .unwrap(), + ); + path_parts.push(path, OrderedJson::array_unsorted([crate_name_json, &part])); } - cx.shared.ensure_dir(&mydst)?; - let aliased_item_type = aliased_type.target_type; - mydst.push(&format!( - "{aliased_item_type}.{}.js", - aliased_type.target_fqp[aliased_type.target_fqp.len() - 1] - )); - - let (mut all_impls, _) = try_err!(collect(&mydst, krate.name(cx.tcx()).as_str()), &mydst); - all_impls.push(impls); - // Sort the implementors by crate so the file will be generated - // identically even with rustdoc running in parallel. - all_impls.sort(); - - let mut v = String::from("(function() {var type_impls = {\n"); - v.push_str(&all_impls.join(",\n")); - v.push_str("\n};"); - v.push_str( - "if (window.register_type_impls) {\ - window.register_type_impls(type_impls);\ - } else {\ - window.pending_type_impls = type_impls;\ - }", - ); - v.push_str("})()"); - cx.shared.fs.write(mydst, v)?; - } - - // Update the list of all implementors for traits - // <https://github.com/search?q=repo%3Arust-lang%2Frust+[RUSTDOCIMPL]+trait.impl&type=code> - let dst = cx.dst.join("trait.impl"); - for (&did, imps) in &cache.implementors { - // Private modules can leak through to this phase of rustdoc, which - // could contain implementations for otherwise private types. In some - // rare cases we could find an implementation for an item which wasn't - // indexed, so we just skip this step in that case. - // - // FIXME: this is a vague explanation for why this can't be a `get`, in - // theory it should be... - let (remote_path, remote_item_type) = match cache.exact_paths.get(&did) { - Some(p) => match cache.paths.get(&did).or_else(|| cache.external_paths.get(&did)) { - Some((_, t)) => (p, t), - None => continue, - }, - None => match cache.external_paths.get(&did) { - Some((p, t)) => (p, t), - None => continue, - }, - }; + Ok(path_parts) + } +} - struct Implementor { - text: String, - synthetic: bool, - types: Vec<String>, +struct Implementor { + text: String, + synthetic: bool, + types: Vec<String>, +} + +impl Serialize for Implementor { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(None)?; + seq.serialize_element(&self.text)?; + if self.synthetic { + seq.serialize_element(&1)?; + seq.serialize_element(&self.types)?; } + seq.end() + } +} - impl Serialize for Implementor { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - let mut seq = serializer.serialize_seq(None)?; - seq.serialize_element(&self.text)?; - if self.synthetic { - seq.serialize_element(&1)?; - seq.serialize_element(&self.types)?; - } - seq.end() +/// Collect the list of aliased types and their aliases. +/// <https://github.com/search?q=repo%3Arust-lang%2Frust+[RUSTDOCIMPL]+type.impl&type=code> +/// +/// The clean AST has type aliases that point at their types, but +/// this visitor works to reverse that: `aliased_types` is a map +/// from target to the aliases that reference it, and each one +/// will generate one file. +struct TypeImplCollector<'cx, 'cache> { + /// Map from DefId-of-aliased-type to its data. + aliased_types: IndexMap<DefId, AliasedType<'cache>>, + visited_aliases: FxHashSet<DefId>, + cache: &'cache Cache, + cx: &'cache mut Context<'cx>, +} + +/// Data for an aliased type. +/// +/// In the final file, the format will be roughly: +/// +/// ```json +/// // type.impl/CRATE/TYPENAME.js +/// JSONP( +/// "CRATE": [ +/// ["IMPL1 HTML", "ALIAS1", "ALIAS2", ...], +/// ["IMPL2 HTML", "ALIAS3", "ALIAS4", ...], +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ struct AliasedType +/// ... +/// ] +/// ) +/// ``` +struct AliasedType<'cache> { + /// This is used to generate the actual filename of this aliased type. + target_fqp: &'cache [Symbol], + target_type: ItemType, + /// This is the data stored inside the file. + /// ItemId is used to deduplicate impls. + impl_: IndexMap<ItemId, AliasedTypeImpl<'cache>>, +} + +/// The `impl_` contains data that's used to figure out if an alias will work, +/// and to generate the HTML at the end. +/// +/// The `type_aliases` list is built up with each type alias that matches. +struct AliasedTypeImpl<'cache> { + impl_: &'cache Impl, + type_aliases: Vec<(&'cache [Symbol], Item)>, +} + +impl<'cx, 'cache> DocVisitor for TypeImplCollector<'cx, 'cache> { + fn visit_item(&mut self, it: &Item) { + self.visit_item_recur(it); + let cache = self.cache; + let ItemKind::TypeAliasItem(ref t) = *it.kind else { return }; + let Some(self_did) = it.item_id.as_def_id() else { return }; + if !self.visited_aliases.insert(self_did) { + return; + } + let Some(target_did) = t.type_.def_id(cache) else { return }; + let get_extern = { || cache.external_paths.get(&target_did) }; + let Some(&(ref target_fqp, target_type)) = cache.paths.get(&target_did).or_else(get_extern) + else { + return; + }; + let aliased_type = self.aliased_types.entry(target_did).or_insert_with(|| { + let impl_ = cache + .impls + .get(&target_did) + .map(|v| &v[..]) + .unwrap_or_default() + .iter() + .map(|impl_| { + (impl_.impl_item.item_id, AliasedTypeImpl { impl_, type_aliases: Vec::new() }) + }) + .collect(); + AliasedType { target_fqp: &target_fqp[..], target_type, impl_ } + }); + let get_local = { || cache.paths.get(&self_did).map(|(p, _)| p) }; + let Some(self_fqp) = cache.exact_paths.get(&self_did).or_else(get_local) else { + return; + }; + let aliased_ty = self.cx.tcx().type_of(self_did).skip_binder(); + // Exclude impls that are directly on this type. They're already in the HTML. + // Some inlining scenarios can cause there to be two versions of the same + // impl: one on the type alias and one on the underlying target type. + let mut seen_impls: FxHashSet<ItemId> = cache + .impls + .get(&self_did) + .map(|s| &s[..]) + .unwrap_or_default() + .iter() + .map(|i| i.impl_item.item_id) + .collect(); + for (impl_item_id, aliased_type_impl) in &mut aliased_type.impl_ { + // Only include this impl if it actually unifies with this alias. + // Synthetic impls are not included; those are also included in the HTML. + // + // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this + // to use type unification. + // Be aware of `tests/rustdoc/type-alias/deeply-nested-112515.rs` which might regress. + let Some(impl_did) = impl_item_id.as_def_id() else { continue }; + let for_ty = self.cx.tcx().type_of(impl_did).skip_binder(); + let reject_cx = DeepRejectCtxt::new(self.cx.tcx(), TreatParams::AsCandidateKey); + if !reject_cx.types_may_unify(aliased_ty, for_ty) { + continue; + } + // Avoid duplicates + if !seen_impls.insert(*impl_item_id) { + continue; } + // This impl was not found in the set of rejected impls + aliased_type_impl.type_aliases.push((&self_fqp[..], it.clone())); } + } +} - let implementors = imps - .iter() - .filter_map(|imp| { - // If the trait and implementation are in the same crate, then - // there's no need to emit information about it (there's inlining - // going on). If they're in different crates then the crate defining - // the trait will be interested in our implementation. - // - // If the implementation is from another crate then that crate - // should add it. - if imp.impl_item.item_id.krate() == did.krate || !imp.impl_item.item_id.is_local() { - None - } else { - Some(Implementor { - text: imp.inner_impl().print(false, cx).to_string(), - synthetic: imp.inner_impl().kind.is_auto(), - types: collect_paths_for_type(imp.inner_impl().for_.clone(), cache), - }) - } - }) - .collect::<Vec<_>>(); +/// Final serialized form of the alias impl +struct AliasSerializableImpl { + text: String, + trait_: Option<String>, + aliases: Vec<String>, +} - // Only create a js file if we have impls to add to it. If the trait is - // documented locally though we always create the file to avoid dead - // links. - if implementors.is_empty() && !cache.paths.contains_key(&did) { - continue; +impl Serialize for AliasSerializableImpl { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(None)?; + seq.serialize_element(&self.text)?; + if let Some(trait_) = &self.trait_ { + seq.serialize_element(trait_)?; + } else { + seq.serialize_element(&0)?; + } + for type_ in &self.aliases { + seq.serialize_element(type_)?; } + seq.end() + } +} - // FIXME: this fixes only rustdoc part of instability of trait impls - // for js files, see #120371 - // Manually collect to string and sort to make list not depend on order - let mut implementors = implementors - .iter() - .map(|i| serde_json::to_string(i).expect("failed serde conversion")) - .collect::<Vec<_>>(); - implementors.sort(); +fn get_path_parts<T: CciPart>( + dst: &Path, + crates_info: &[CrateInfo], +) -> FxHashMap<PathBuf, Vec<String>> { + let mut templates: FxHashMap<PathBuf, Vec<String>> = FxHashMap::default(); + crates_info + .iter() + .map(|crate_info| T::from_crate_info(crate_info).parts.iter()) + .flatten() + .for_each(|(path, part)| { + let path = dst.join(&path); + let part = part.to_string(); + templates.entry(path).or_default().push(part); + }); + templates +} - let implementors = format!(r#""{}":[{}]"#, krate.name(cx.tcx()), implementors.join(",")); +/// Create all parents +fn create_parents(path: &Path) -> Result<(), Error> { + let parent = path.parent().expect("should not have an empty path here"); + try_err!(fs::create_dir_all(parent), parent); + Ok(()) +} + +/// Returns a blank template unless we could find one to append to +fn read_template_or_blank<F, T: FileFormat>( + mut make_blank: F, + path: &Path, +) -> Result<SortedTemplate<T>, Error> +where + F: FnMut() -> SortedTemplate<T>, +{ + match fs::read_to_string(&path) { + Ok(template) => Ok(try_err!(SortedTemplate::from_str(&template), &path)), + Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(make_blank()), + Err(e) => Err(Error::new(e, &path)), + } +} - let mut mydst = dst.clone(); - for part in &remote_path[..remote_path.len() - 1] { - mydst.push(part.to_string()); +/// info from this crate and the --include-info-json'd crates +fn write_rendered_cci<T: CciPart, F>( + mut make_blank: F, + dst: &Path, + crates_info: &[CrateInfo], +) -> Result<(), Error> +where + F: FnMut() -> SortedTemplate<T::FileFormat>, +{ + // write the merged cci to disk + for (path, parts) in get_path_parts::<T>(dst, crates_info) { + create_parents(&path)?; + // read previous rendered cci from storage, append to them + let mut template = read_template_or_blank::<_, T::FileFormat>(&mut make_blank, &path)?; + for part in parts { + template.append(part); } - cx.shared.ensure_dir(&mydst)?; - mydst.push(&format!("{remote_item_type}.{}.js", remote_path[remote_path.len() - 1])); - - let (mut all_implementors, _) = - try_err!(collect(&mydst, krate.name(cx.tcx()).as_str()), &mydst); - all_implementors.push(implementors); - // Sort the implementors by crate so the file will be generated - // identically even with rustdoc running in parallel. - all_implementors.sort(); - - let mut v = String::from("(function() {var implementors = {\n"); - v.push_str(&all_implementors.join(",\n")); - v.push_str("\n};"); - v.push_str( - "if (window.register_implementors) {\ - window.register_implementors(implementors);\ - } else {\ - window.pending_implementors = implementors;\ - }", - ); - v.push_str("})()"); - cx.shared.fs.write(mydst, v)?; + let file = try_err!(File::create(&path), &path); + let mut file = BufWriter::new(file); + try_err!(write!(file, "{template}"), &path); + try_err!(file.flush(), &path); } Ok(()) } + +#[cfg(test)] +mod tests; diff --git a/src/librustdoc/html/render/write_shared/tests.rs b/src/librustdoc/html/render/write_shared/tests.rs new file mode 100644 index 00000000000..4d1874b7df5 --- /dev/null +++ b/src/librustdoc/html/render/write_shared/tests.rs @@ -0,0 +1,207 @@ +use crate::html::render::ordered_json::{EscapedJson, OrderedJson}; +use crate::html::render::sorted_template::{Html, SortedTemplate}; +use crate::html::render::write_shared::*; + +#[test] +fn hack_external_crate_names() { + let path = tempfile::TempDir::new().unwrap(); + let path = path.path(); + let crates = hack_get_external_crate_names(&path).unwrap(); + assert!(crates.is_empty()); + fs::write(path.join("crates.js"), r#"window.ALL_CRATES = ["a","b","c"];"#).unwrap(); + let crates = hack_get_external_crate_names(&path).unwrap(); + assert_eq!(crates, ["a".to_string(), "b".to_string(), "c".to_string()]); +} + +fn but_last_line(s: &str) -> &str { + let (before, _) = s.rsplit_once("\n").unwrap(); + before +} + +#[test] +fn sources_template() { + let mut template = SourcesPart::blank(); + assert_eq!( + but_last_line(&template.to_string()), + r"var srcIndex = new Map(JSON.parse('[]')); +createSrcSidebar();" + ); + template.append(EscapedJson::from(OrderedJson::serialize("u").unwrap()).to_string()); + assert_eq!( + but_last_line(&template.to_string()), + r#"var srcIndex = new Map(JSON.parse('["u"]')); +createSrcSidebar();"# + ); + template.append(EscapedJson::from(OrderedJson::serialize("v").unwrap()).to_string()); + assert_eq!( + but_last_line(&template.to_string()), + r#"var srcIndex = new Map(JSON.parse('["u","v"]')); +createSrcSidebar();"# + ); +} + +#[test] +fn sources_parts() { + let parts = + SearchIndexPart::get(OrderedJson::serialize(["foo", "bar"]).unwrap(), "suffix").unwrap(); + assert_eq!(&parts.parts[0].0, Path::new("search-indexsuffix.js")); + assert_eq!(&parts.parts[0].1.to_string(), r#"["foo","bar"]"#); +} + +#[test] +fn all_crates_template() { + let mut template = AllCratesPart::blank(); + assert_eq!(but_last_line(&template.to_string()), r"window.ALL_CRATES = [];"); + template.append(EscapedJson::from(OrderedJson::serialize("b").unwrap()).to_string()); + assert_eq!(but_last_line(&template.to_string()), r#"window.ALL_CRATES = ["b"];"#); + template.append(EscapedJson::from(OrderedJson::serialize("a").unwrap()).to_string()); + assert_eq!(but_last_line(&template.to_string()), r#"window.ALL_CRATES = ["a","b"];"#); +} + +#[test] +fn all_crates_parts() { + let parts = AllCratesPart::get(OrderedJson::serialize("crate").unwrap()).unwrap(); + assert_eq!(&parts.parts[0].0, Path::new("crates.js")); + assert_eq!(&parts.parts[0].1.to_string(), r#""crate""#); +} + +#[test] +fn search_index_template() { + let mut template = SearchIndexPart::blank(); + assert_eq!( + but_last_line(&template.to_string()), + r"var searchIndex = new Map(JSON.parse('[]')); +if (typeof exports !== 'undefined') exports.searchIndex = searchIndex; +else if (window.initSearch) window.initSearch(searchIndex);" + ); + template.append(EscapedJson::from(OrderedJson::serialize([1, 2]).unwrap()).to_string()); + assert_eq!( + but_last_line(&template.to_string()), + r"var searchIndex = new Map(JSON.parse('[[1,2]]')); +if (typeof exports !== 'undefined') exports.searchIndex = searchIndex; +else if (window.initSearch) window.initSearch(searchIndex);" + ); + template.append(EscapedJson::from(OrderedJson::serialize([4, 3]).unwrap()).to_string()); + assert_eq!( + but_last_line(&template.to_string()), + r"var searchIndex = new Map(JSON.parse('[[1,2],[4,3]]')); +if (typeof exports !== 'undefined') exports.searchIndex = searchIndex; +else if (window.initSearch) window.initSearch(searchIndex);" + ); +} + +#[test] +fn crates_index_part() { + let external_crates = ["bar".to_string(), "baz".to_string()]; + let mut parts = CratesIndexPart::get("foo", &external_crates).unwrap(); + parts.parts.sort_by(|a, b| a.1.to_string().cmp(&b.1.to_string())); + + assert_eq!(&parts.parts[0].0, Path::new("index.html")); + assert_eq!(&parts.parts[0].1.to_string(), r#"<li><a href="bar/index.html">bar</a></li>"#); + + assert_eq!(&parts.parts[1].0, Path::new("index.html")); + assert_eq!(&parts.parts[1].1.to_string(), r#"<li><a href="baz/index.html">baz</a></li>"#); + + assert_eq!(&parts.parts[2].0, Path::new("index.html")); + assert_eq!(&parts.parts[2].1.to_string(), r#"<li><a href="foo/index.html">foo</a></li>"#); +} + +#[test] +fn trait_alias_template() { + let mut template = TraitAliasPart::blank(); + assert_eq!( + but_last_line(&template.to_string()), + r#"(function() { + var implementors = Object.fromEntries([]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})()"#, + ); + template.append(OrderedJson::serialize(["a"]).unwrap().to_string()); + assert_eq!( + but_last_line(&template.to_string()), + r#"(function() { + var implementors = Object.fromEntries([["a"]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})()"#, + ); + template.append(OrderedJson::serialize(["b"]).unwrap().to_string()); + assert_eq!( + but_last_line(&template.to_string()), + r#"(function() { + var implementors = Object.fromEntries([["a"],["b"]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})()"#, + ); +} + +#[test] +fn type_alias_template() { + let mut template = TypeAliasPart::blank(); + assert_eq!( + but_last_line(&template.to_string()), + r#"(function() { + var type_impls = Object.fromEntries([]); + if (window.register_type_impls) { + window.register_type_impls(type_impls); + } else { + window.pending_type_impls = type_impls; + } +})()"#, + ); + template.append(OrderedJson::serialize(["a"]).unwrap().to_string()); + assert_eq!( + but_last_line(&template.to_string()), + r#"(function() { + var type_impls = Object.fromEntries([["a"]]); + if (window.register_type_impls) { + window.register_type_impls(type_impls); + } else { + window.pending_type_impls = type_impls; + } +})()"#, + ); + template.append(OrderedJson::serialize(["b"]).unwrap().to_string()); + assert_eq!( + but_last_line(&template.to_string()), + r#"(function() { + var type_impls = Object.fromEntries([["a"],["b"]]); + if (window.register_type_impls) { + window.register_type_impls(type_impls); + } else { + window.pending_type_impls = type_impls; + } +})()"#, + ); +} + +#[test] +fn read_template_test() { + let path = tempfile::TempDir::new().unwrap(); + let path = path.path().join("file.html"); + let make_blank = || SortedTemplate::<Html>::from_before_after("<div>", "</div>"); + + let template = read_template_or_blank(make_blank, &path).unwrap(); + assert_eq!(but_last_line(&template.to_string()), "<div></div>"); + fs::write(&path, template.to_string()).unwrap(); + let mut template = read_template_or_blank(make_blank, &path).unwrap(); + template.append("<img/>".to_string()); + fs::write(&path, template.to_string()).unwrap(); + let mut template = read_template_or_blank(make_blank, &path).unwrap(); + template.append("<br/>".to_string()); + fs::write(&path, template.to_string()).unwrap(); + let template = read_template_or_blank(make_blank, &path).unwrap(); + + assert_eq!(but_last_line(&template.to_string()), "<div><br/><img/></div>"); +} diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index eb5a5d935e2..28df8d3f011 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1547,10 +1547,23 @@ instead, we check that it's not a "finger" cursor. margin-left: 24px; } +@keyframes targetfadein { + from { + background-color: var(--main-background-color); + } + 10% { + background-color: var(--target-border-color); + } + to { + background-color: var(--target-background-color); + } +} + :target { padding-right: 3px; background-color: var(--target-background-color); border-right: 3px solid var(--target-border-color); + animation: 0.65s cubic-bezier(0, 0, 0.1, 1.0) 0.1s targetfadein; } .code-header a.tooltip { diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 3eb27ea087c..be0ec425946 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1393,6 +1393,7 @@ function initSearch(rawSearchIndex) { */ async function sortResults(results, isType, preferredCrate) { const userQuery = parsedQuery.userQuery; + const casedUserQuery = parsedQuery.original; const result_list = []; for (const result of results.values()) { result.item = searchIndex[result.id]; @@ -1403,6 +1404,13 @@ function initSearch(rawSearchIndex) { result_list.sort((aaa, bbb) => { let a, b; + // sort by exact case-sensitive match + a = (aaa.item.name !== casedUserQuery); + b = (bbb.item.name !== casedUserQuery); + if (a !== b) { + return a - b; + } + // sort by exact match with regard to the last word (mismatch goes later) a = (aaa.word !== userQuery); b = (bbb.word !== userQuery); @@ -3546,7 +3554,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\ // Used to de-duplicate inlined and re-exported stuff const itemReexports = new Map(crateCorpus.r); // an array of (Number) the parent path index + 1 to `paths`, or 0 if none - const itemParentIdxs = crateCorpus.i; + const itemParentIdxDecoder = new VlqHexDecoder(crateCorpus.i, noop => noop); // a map Number, string for impl disambiguators const implDisambiguator = new Map(crateCorpus.b); // an array of [(Number) item type, @@ -3593,6 +3601,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\ // faster analysis operations lastPath = ""; len = itemTypes.length; + let lastName = ""; + let lastWord = ""; for (let i = 0; i < len; ++i) { const bitIndex = i + 1; if (descIndex >= descShard.len && @@ -3608,10 +3618,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\ descIndex = 0; descShardList.push(descShard); } - let word = ""; - if (typeof itemNames[i] === "string") { - word = itemNames[i].toLowerCase(); - } + const name = itemNames[i] === "" ? lastName : itemNames[i]; + const word = itemNames[i] === "" ? lastWord : itemNames[i].toLowerCase(); const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath; const type = itemFunctionDecoder.next(); if (type !== null) { @@ -3633,15 +3641,16 @@ ${item.displayPath}<span class="${type}">${name}</span>\ } // This object should have exactly the same set of fields as the "crateRow" // object defined above. + const itemParentIdx = itemParentIdxDecoder.next(); const row = { crate, ty: itemTypes.charCodeAt(i) - 65, // 65 = "A" - name: itemNames[i], + name, path, descShard, descIndex, exactPath: itemReexports.has(i) ? itemPaths.get(itemReexports.get(i)) : path, - parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined, + parent: itemParentIdx > 0 ? paths[itemParentIdx - 1] : undefined, type, id, word, @@ -3655,6 +3664,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\ if (!searchIndexEmptyDesc.get(crate).contains(bitIndex)) { descIndex += 1; } + lastName = name; + lastWord = word; } if (aliases) { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5b96529fed7..ab03f620230 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -53,7 +53,7 @@ fn filter_assoc_items_by_name_and_namespace<'a>( assoc_items_of: DefId, ident: Ident, ns: Namespace, -) -> impl Iterator<Item = &ty::AssocItem> + 'a { +) -> impl Iterator<Item = &'a ty::AssocItem> + 'a { tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| { item.kind.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of) }) diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index ef05befdddc..977c0953336 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -16,9 +16,11 @@ use crate::core::DocContext; use crate::html::markdown::{self, RustCodeBlock}; pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) { - if let Some(dox) = &item.opt_doc_value() { + if let Some(def_id) = item.item_id.as_local_def_id() + && let Some(dox) = &item.opt_doc_value() + { let sp = item.attr_span(cx.tcx); - let extra = crate::html::markdown::ExtraInfo::new(cx.tcx, item.item_id.expect_def_id(), sp); + let extra = crate::html::markdown::ExtraInfo::new(cx.tcx, def_id, sp); for code_block in markdown::rust_code_blocks(dox, &extra) { check_rust_syntax(cx, item, dox, code_block); } diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index faf42b3aab1..23e298571d5 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -2,7 +2,7 @@ use std::mem; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; @@ -145,8 +145,9 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> { let old = mem::replace(&mut self.update_retained, false); let ret = self.set_is_in_hidden_item_and_fold(true, i); self.update_retained = old; - if ret.is_crate() { - // We don't strip the crate, even if it has `#[doc(hidden)]`. + if ret.item_id == clean::ItemId::DefId(CRATE_DEF_ID.into()) { + // We don't strip the current crate, even if it has `#[doc(hidden)]`. + debug!("strip_hidden: Not strippping local crate"); Some(ret) } else { Some(strip_item(ret)) diff --git a/src/llvm-project b/src/llvm-project -Subproject ccf4c38bdd73f1a37ec266c73bdaef80e39f8cf +Subproject 2b259b3c201f939f2ed8d2fb0a0e9b37dd2d132 diff --git a/src/tools/cargo b/src/tools/cargo -Subproject ba8b39413c74d08494f94a7542fe79aa636e166 +Subproject 8f40fc59fb0c8df91c97405785197f3c630304e diff --git a/src/tools/clippy/.cargo/config.toml b/src/tools/clippy/.cargo/config.toml index ce07290d1e1..d9c635df5dc 100644 --- a/src/tools/clippy/.cargo/config.toml +++ b/src/tools/clippy/.cargo/config.toml @@ -1,10 +1,10 @@ [alias] +bless = "test --config env.RUSTC_BLESS='1'" uitest = "test --test compile-test" -uibless = "test --test compile-test -- -- --bless" -bless = "test -- -- --bless" +uibless = "bless --test compile-test" dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- " -collect-metadata = "test --test dogfood --features internal -- collect_metadata" +collect-metadata = "test --test compile-test --config env.COLLECT_METADATA='1'" [build] # -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests diff --git a/src/tools/clippy/.github/deploy.sh b/src/tools/clippy/.github/deploy.sh index 5a59f94ec91..d937661c0f8 100644 --- a/src/tools/clippy/.github/deploy.sh +++ b/src/tools/clippy/.github/deploy.sh @@ -10,6 +10,7 @@ mkdir out/master/ cp util/gh-pages/index.html out/master cp util/gh-pages/script.js out/master cp util/gh-pages/lints.json out/master +cp util/gh-pages/style.css out/master if [[ -n $TAG_NAME ]]; then echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it" diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index 10e18e84c89..2aa13313fa5 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -136,11 +136,6 @@ jobs: - name: Test metadata collection run: cargo collect-metadata - - name: Test lint_configuration.md is up-to-date - run: | - echo "run \`cargo collect-metadata\` if this fails" - git update-index --refresh - integration_build: needs: changelog runs-on: ubuntu-latest diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index fddc2fd994e..9bc4ad9698d 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -5914,6 +5914,7 @@ Released 2018-09-13 [`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args [`to_string_trait_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_trait_impl [`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo +[`too_long_first_doc_paragraph`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_long_first_doc_paragraph [`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments [`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines [`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index 78409c7a09e..b48b881097f 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -30,8 +30,11 @@ color-print = "0.3.4" anstream = "0.6.0" [dev-dependencies] +cargo_metadata = "0.18.1" ui_test = "0.25" regex = "1.5.5" +serde = { version = "1.0.145", features = ["derive"] } +serde_json = "1.0.122" toml = "0.7.3" walkdir = "2.3" filetime = "0.2.9" @@ -41,7 +44,6 @@ itertools = "0.12" clippy_utils = { path = "clippy_utils" } if_chain = "1.0" quote = "1.0.25" -serde = { version = "1.0.145", features = ["derive"] } syn = { version = "2.0", features = ["full"] } futures = "0.3" parking_lot = "0.12" diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md index a71d94daca7..963e02e5c16 100644 --- a/src/tools/clippy/book/src/development/adding_lints.md +++ b/src/tools/clippy/book/src/development/adding_lints.md @@ -739,7 +739,7 @@ for some users. Adding a configuration is done in the following steps: 5. Update [Lint Configuration](../lint_configuration.md) - Run `cargo collect-metadata` to generate documentation changes for the book. + Run `cargo bless --test config-metadata` to generate documentation changes for the book. [`clippy_config::conf`]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_config/src/conf.rs [`clippy_lints` lib file]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index e3d550b1466..78348797588 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -1,5 +1,5 @@ <!-- -This file is generated by `cargo collect-metadata`. +This file is generated by `cargo bless --test config-metadata`. Please use that command to update the file and do not edit it by hand. --> @@ -199,7 +199,7 @@ Allowed names below the minimum allowed characters. The value `".."` can be used the list to indicate, that the configured values should be appended to the default configuration of Clippy. By default, any configuration will replace the default value. -**Default Value:** `["j", "z", "i", "y", "n", "x", "w"]` +**Default Value:** `["i", "j", "x", "y", "z", "w", "n"]` --- **Affected lints:** @@ -455,7 +455,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["TiB", "CoreGraphics", "CoffeeScript", "TeX", "Direct2D", "PiB", "DirectX", "NetBSD", "OAuth", "NaN", "OpenType", "WebGL2", "WebTransport", "JavaScript", "OpenSSL", "OpenSSH", "EiB", "PureScript", "OpenAL", "MiB", "WebAssembly", "MinGW", "CoreFoundation", "WebGPU", "ClojureScript", "CamelCase", "OpenDNS", "NaNs", "OpenMP", "GitLab", "KiB", "sRGB", "CoreText", "macOS", "TypeScript", "GiB", "OpenExr", "YCbCr", "OpenTelemetry", "OpenBSD", "FreeBSD", "GPLv2", "PostScript", "WebP", "LaTeX", "TensorFlow", "AccessKit", "TrueType", "OpenStreetMap", "OpenGL", "DevOps", "OCaml", "WebRTC", "WebGL", "BibLaTeX", "GitHub", "GraphQL", "iOS", "Direct3D", "BibTeX", "DirectWrite", "GPLv3", "IPv6", "WebSocket", "IPv4", "ECMAScript"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "AccessKit", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** @@ -949,5 +949,3 @@ Whether to also emit warnings for unsafe blocks with metavariable expansions in --- **Affected lints:** * [`macro_metavars_in_unsafe`](https://rust-lang.github.io/rust-clippy/master/index.html#macro_metavars_in_unsafe) - - diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml index d5b28e25323..5c4e0761dbc 100644 --- a/src/tools/clippy/clippy_config/Cargo.toml +++ b/src/tools/clippy/clippy_config/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" [dependencies] itertools = "0.12" -rustc-semver = "1.1" serde = { version = "1.0", features = ["derive"] } toml = "0.7.3" diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 4c2a8255d6b..a6f1b958bfb 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -1,7 +1,6 @@ use crate::msrvs::Msrv; use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename}; use crate::ClippyConfiguration; -use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_session::Session; use rustc_span::edit_distance::edit_distance; @@ -218,7 +217,7 @@ macro_rules! define_Conf { define_Conf! { /// Which crates to allow absolute paths from #[lints(absolute_paths)] - absolute_paths_allowed_crates: FxHashSet<String> = FxHashSet::default(), + absolute_paths_allowed_crates: Vec<String> = Vec::new(), /// The maximum number of segments a path can have before being linted, anything above this will /// be linted. #[lints(absolute_paths)] @@ -280,12 +279,12 @@ define_Conf! { allowed_dotfiles: Vec<String> = Vec::default(), /// A list of crate names to allow duplicates of #[lints(multiple_crate_versions)] - allowed_duplicate_crates: FxHashSet<String> = FxHashSet::default(), + allowed_duplicate_crates: Vec<String> = Vec::new(), /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of /// the list to indicate, that the configured values should be appended to the default /// configuration of Clippy. By default, any configuration will replace the default value. #[lints(min_ident_chars)] - allowed_idents_below_min_chars: FxHashSet<String> = + allowed_idents_below_min_chars: Vec<String> = DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect(), /// List of prefixes to allow when determining whether an item's name ends with the module's name. /// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`), @@ -323,7 +322,7 @@ define_Conf! { /// 2. Paths with any segment that containing the word 'prelude' /// are already allowed by default. #[lints(wildcard_imports)] - allowed_wildcard_imports: FxHashSet<String> = FxHashSet::default(), + allowed_wildcard_imports: Vec<String> = Vec::new(), /// Suppress checking of the passed type names in all types of operations. /// /// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead. @@ -355,7 +354,7 @@ define_Conf! { /// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]] /// ``` #[lints(arithmetic_side_effects)] - arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default(), + arithmetic_side_effects_allowed_binary: Vec<(String, String)> = <_>::default(), /// Suppress checking of the passed type names in unary operations like "negation" (`-`). /// /// #### Example @@ -431,7 +430,7 @@ define_Conf! { /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. #[lints(doc_markdown)] - doc_valid_idents: FxHashSet<String> = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect(), + doc_valid_idents: Vec<String> = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect(), /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. #[lints(non_send_fields_in_send_ty)] enable_raw_pointer_heuristic_for_send: bool = true, @@ -706,12 +705,12 @@ fn deserialize(file: &SourceFile) -> TryConf { DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS, ); // TODO: THIS SHOULD BE TESTED, this comment will be gone soon - if conf.conf.allowed_idents_below_min_chars.contains("..") { + if conf.conf.allowed_idents_below_min_chars.iter().any(|e| e == "..") { conf.conf .allowed_idents_below_min_chars .extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string)); } - if conf.conf.doc_valid_idents.contains("..") { + if conf.conf.doc_valid_idents.iter().any(|e| e == "..") { conf.conf .doc_valid_idents .extend(DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string)); @@ -890,14 +889,14 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec<usize>) { #[cfg(test)] mod tests { - use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use serde::de::IgnoredAny; + use std::collections::{HashMap, HashSet}; use std::fs; use walkdir::WalkDir; #[test] fn configs_are_tested() { - let mut names: FxHashSet<String> = crate::get_configuration_metadata() + let mut names: HashSet<String> = crate::get_configuration_metadata() .into_iter() .map(|meta| meta.name.replace('_', "-")) .collect(); @@ -910,7 +909,7 @@ mod tests { for entry in toml_files { let file = fs::read_to_string(entry.path()).unwrap(); #[allow(clippy::zero_sized_map_values)] - if let Ok(map) = toml::from_str::<FxHashMap<String, IgnoredAny>>(&file) { + if let Ok(map) = toml::from_str::<HashMap<String, IgnoredAny>>(&file) { for name in map.keys() { names.remove(name.as_str()); } diff --git a/src/tools/clippy/clippy_config/src/lib.rs b/src/tools/clippy/clippy_config/src/lib.rs index d2246f12029..ac838cc81d2 100644 --- a/src/tools/clippy/clippy_config/src/lib.rs +++ b/src/tools/clippy/clippy_config/src/lib.rs @@ -14,7 +14,7 @@ )] extern crate rustc_ast; -extern crate rustc_data_structures; +extern crate rustc_attr; #[allow(unused_extern_crates)] extern crate rustc_driver; extern crate rustc_errors; diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs index fc56ac51796..0e8215aa8e3 100644 --- a/src/tools/clippy/clippy_config/src/msrvs.rs +++ b/src/tools/clippy/clippy_config/src/msrvs.rs @@ -1,6 +1,6 @@ use rustc_ast::Attribute; -use rustc_semver::RustcVersion; -use rustc_session::Session; +use rustc_attr::parse_version; +use rustc_session::{RustcVersion, Session}; use rustc_span::{sym, Symbol}; use serde::Deserialize; use std::fmt; @@ -10,7 +10,7 @@ macro_rules! msrv_aliases { $($name:ident),* $(,)? })*) => { $($( - pub const $name: RustcVersion = RustcVersion::new($major, $minor, $patch); + pub const $name: RustcVersion = RustcVersion { major: $major, minor :$minor, patch: $patch }; )*)* }; } @@ -18,6 +18,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,81,0 { LINT_REASONS_STABILIZATION } + 1,80,0 { BOX_INTO_ITER} 1,77,0 { C_STR_LITERALS } 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } @@ -81,9 +82,9 @@ impl<'de> Deserialize<'de> for Msrv { D: serde::Deserializer<'de>, { let v = String::deserialize(deserializer)?; - RustcVersion::parse(&v) + parse_version(Symbol::intern(&v)) .map(|v| Msrv { stack: vec![v] }) - .map_err(|_| serde::de::Error::custom("not a valid Rust version")) + .ok_or_else(|| serde::de::Error::custom("not a valid Rust version")) } } @@ -95,7 +96,7 @@ impl Msrv { pub fn read_cargo(&mut self, sess: &Session) { let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION") .ok() - .and_then(|v| RustcVersion::parse(&v).ok()); + .and_then(|v| parse_version(Symbol::intern(&v))); match (self.current(), cargo_msrv) { (None, Some(cargo_msrv)) => self.stack = vec![cargo_msrv], @@ -115,7 +116,7 @@ impl Msrv { } pub fn meets(&self, required: RustcVersion) -> bool { - self.current().map_or(true, |version| version.meets(required)) + self.current().map_or(true, |msrv| msrv >= required) } fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option<RustcVersion> { @@ -131,7 +132,7 @@ impl Msrv { } if let Some(msrv) = msrv_attr.value_str() { - if let Ok(version) = RustcVersion::parse(msrv.as_str()) { + if let Some(version) = parse_version(msrv) { return Some(version); } diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index 755b04b0b23..fc15913354c 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -1,3 +1,4 @@ +#![feature(rustc_private)] // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 15578d69c3a..8dbda1c634c 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -604,7 +604,7 @@ fn gen_declared_lints<'a>( details.sort_unstable(); let mut output = GENERATED_FILE_COMMENT.to_string(); - output.push_str("pub(crate) static LINTS: &[&crate::LintInfo] = &[\n"); + output.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n"); for (is_public, module_name, lint_name) in details { if !is_public { diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 99ed93468a0..fbd4566da58 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -25,7 +25,6 @@ regex = { version = "1.5", optional = true } unicode-normalization = "0.1" unicode-script = { version = "0.5", default-features = false } semver = "1.0" -rustc-semver = "1.1" url = "2.2" [dev-dependencies] diff --git a/src/tools/clippy/clippy_lints/src/absolute_paths.rs b/src/tools/clippy/clippy_lints/src/absolute_paths.rs index c0a9d888e0b..c72b3f1318c 100644 --- a/src/tools/clippy/clippy_lints/src/absolute_paths.rs +++ b/src/tools/clippy/clippy_lints/src/absolute_paths.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::snippet_opt; +use clippy_utils::is_from_proc_macro; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; @@ -8,6 +8,7 @@ use rustc_hir::{HirId, ItemKind, Node, Path}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -24,6 +25,13 @@ declare_clippy_lint! { /// Note: One exception to this is code from macro expansion - this does not lint such cases, as /// using absolute paths is the proper way of referencing items in one. /// + /// ### Known issues + /// + /// There are currently a few cases which are not caught by this lint: + /// * Macro calls. e.g. `path::to::macro!()` + /// * Derive macros. e.g. `#[derive(path::to::macro)]` + /// * Attribute macros. e.g. `#[path::to::macro]` + /// /// ### Example /// ```no_run /// let x = std::f64::consts::PI; @@ -48,63 +56,66 @@ impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]); pub struct AbsolutePaths { pub absolute_paths_max_segments: u64, - pub absolute_paths_allowed_crates: &'static FxHashSet<String>, + pub absolute_paths_allowed_crates: FxHashSet<Symbol>, } impl AbsolutePaths { pub fn new(conf: &'static Conf) -> Self { Self { absolute_paths_max_segments: conf.absolute_paths_max_segments, - absolute_paths_allowed_crates: &conf.absolute_paths_allowed_crates, + absolute_paths_allowed_crates: conf + .absolute_paths_allowed_crates + .iter() + .map(|x| Symbol::intern(x)) + .collect(), } } } -impl LateLintPass<'_> for AbsolutePaths { +impl<'tcx> LateLintPass<'tcx> for AbsolutePaths { // We should only lint `QPath::Resolved`s, but since `Path` is only used in `Resolved` and `UsePath` // we don't need to use a visitor or anything as we can just check if the `Node` for `hir_id` isn't // a `Use` - #[expect(clippy::cast_possible_truncation)] - fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) { - let Self { - absolute_paths_max_segments, - absolute_paths_allowed_crates, - } = self; - - if !path.span.from_expansion() - && let node = cx.tcx.hir_node(hir_id) - && !matches!(node, Node::Item(item) if matches!(item.kind, ItemKind::Use(_, _))) - && let [first, rest @ ..] = path.segments - // Handle `::std` - && let (segment, len) = if first.ident.name == kw::PathRoot { - // Indexing is fine as `PathRoot` must be followed by another segment. `len() - 1` - // is fine here for the same reason - (&rest[0], path.segments.len() - 1) - } else { - (first, path.segments.len()) - } - && len > *absolute_paths_max_segments as usize - && let Some(segment_snippet) = snippet_opt(cx, segment.ident.span) - && segment_snippet == segment.ident.as_str() - { - let is_abs_external = - matches!(segment.res, Res::Def(DefKind::Mod, DefId { index, .. }) if index == CRATE_DEF_INDEX); - let is_abs_crate = segment.ident.name == kw::Crate; - - if is_abs_external && absolute_paths_allowed_crates.contains(segment.ident.name.as_str()) - || is_abs_crate && absolute_paths_allowed_crates.contains("crate") + fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, hir_id: HirId) { + let segments = match path.segments { + [] | [_] => return, + // Don't count enum variants and trait items as part of the length. + [rest @ .., _] + if let [.., s] = rest + && matches!(s.res, Res::Def(DefKind::Enum | DefKind::Trait | DefKind::TraitAlias, _)) => + { + rest + }, + path => path, + }; + if let [s1, s2, ..] = segments + && let has_root = s1.ident.name == kw::PathRoot + && let first = if has_root { s2 } else { s1 } + && let len = segments.len() - usize::from(has_root) + && len as u64 > self.absolute_paths_max_segments + && let crate_name = if let Res::Def(DefKind::Mod, DefId { index, .. }) = first.res + && index == CRATE_DEF_INDEX { + // `other_crate::foo` or `::other_crate::foo` + first.ident.name + } else if first.ident.name == kw::Crate || has_root { + // `::foo` or `crate::foo` + kw::Crate + } else { return; } - - if is_abs_external || is_abs_crate { - span_lint( - cx, - ABSOLUTE_PATHS, - path.span, - "consider bringing this path into scope with the `use` keyword", - ); - } + && !path.span.from_expansion() + && let node = cx.tcx.hir_node(hir_id) + && !matches!(node, Node::Item(item) if matches!(item.kind, ItemKind::Use(..))) + && !self.absolute_paths_allowed_crates.contains(&crate_name) + && !is_from_proc_macro(cx, path) + { + span_lint( + cx, + ABSOLUTE_PATHS, + path.span, + "consider bringing this path into scope with the `use` keyword", + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index 3b4cc113480..56f5e903dc3 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -4,8 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_semver::RustcVersion; -use rustc_session::impl_lint_pass; +use rustc_session::{impl_lint_pass, RustcVersion}; use rustc_span::symbol; use std::f64::consts as f64; diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index 6e336efbb90..55645d04eef 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -3,7 +3,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap}; use clippy_utils::sugg::Sugg; -use clippy_utils::{is_diag_trait_item, last_path_segment, local_is_initialized, path_to_local}; +use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local}; use rustc_errors::Applicability; use rustc_hir::{self as hir, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -118,6 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { } ) && !clone_source_borrows_from_dest(cx, lhs, rhs.span) + && !is_in_test(cx.tcx, e.hir_id) { span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/attrs/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/attrs/empty_line_after.rs index ca43e76ac57..7ff644b4c44 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/empty_line_after.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/empty_line_after.rs @@ -1,6 +1,6 @@ use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::{is_present_in_source, snippet_opt, without_block_comments}; +use clippy_utils::source::{is_present_in_source, without_block_comments, SpanRangeExt}; use rustc_ast::{AttrKind, AttrStyle}; use rustc_lint::EarlyContext; use rustc_span::Span; @@ -26,7 +26,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { item.span.parent(), ); - if let Some(snippet) = snippet_opt(cx, end_of_attr_to_next_attr_or_item) { + if let Some(snippet) = end_of_attr_to_next_attr_or_item.get_source_text(cx) { let lines = snippet.split('\n').collect::<Vec<_>>(); let lines = without_block_comments(lines); diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 8f430ae601a..3b14e9aee7f 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -1,5 +1,3 @@ -//! checks for attributes - mod allow_attributes; mod allow_attributes_without_reason; mod blanket_clippy_restriction_lints; @@ -310,8 +308,8 @@ declare_clippy_lint! { /// ```rust,ignore /// #[allow(unused_mut)] /// fn foo() -> usize { - /// let mut a = Vec::new(); - /// a.len() + /// let mut a = Vec::new(); + /// a.len() /// } /// ``` /// Use instead: diff --git a/src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs index 3fde7061585..877025cce4c 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/non_minimal_cfg.rs @@ -1,6 +1,6 @@ use super::{Attribute, NON_MINIMAL_CFG}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; @@ -29,8 +29,13 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { meta.span, "unneeded sub `cfg` when there is only one condition", |diag| { - if let Some(snippet) = snippet_opt(cx, list[0].span()) { - diag.span_suggestion(meta.span, "try", snippet, Applicability::MaybeIncorrect); + if let Some(snippet) = list[0].span().get_source_text(cx) { + diag.span_suggestion( + meta.span, + "try", + snippet.to_owned(), + Applicability::MaybeIncorrect, + ); } }, ); diff --git a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs index 486e7c6ec4f..478ba7a187b 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs @@ -1,6 +1,7 @@ use super::{Attribute, UNNECESSARY_CLIPPY_CFG}; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; +use itertools::Itertools; use rustc_ast::AttrStyle; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, Level}; @@ -31,7 +32,7 @@ pub(super) fn check( return; } if nb_items == clippy_lints.len() { - if let Some(snippet) = snippet_opt(cx, behind_cfg_attr.span) { + if let Some(snippet) = behind_cfg_attr.span.get_source_text(cx) { span_lint_and_sugg( cx, UNNECESSARY_CLIPPY_CFG, @@ -47,11 +48,7 @@ pub(super) fn check( ); } } else { - let snippet = clippy_lints - .iter() - .filter_map(|sp| snippet_opt(cx, *sp)) - .collect::<Vec<_>>() - .join(","); + let snippet = clippy_lints.iter().filter_map(|sp| sp.get_source_text(cx)).join(","); span_lint_and_note( cx, UNNECESSARY_CLIPPY_CFG, diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index f0868231d01..67ba605a59f 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -1,7 +1,7 @@ use super::utils::{extract_clippy_lint, is_lint_level, is_word}; use super::{Attribute, USELESS_ATTRIBUTE}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{first_line_of_span, snippet_opt}; +use clippy_utils::source::{first_line_of_span, SpanRangeExt}; use rustc_ast::NestedMetaItem; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; @@ -69,14 +69,14 @@ pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute]) } let line_span = first_line_of_span(cx, attr.span); - if let Some(mut sugg) = snippet_opt(cx, line_span) { - if sugg.contains("#[") { + if let Some(src) = line_span.get_source_text(cx) { + if src.contains("#[") { + #[expect(clippy::collapsible_span_lint_calls)] span_lint_and_then(cx, USELESS_ATTRIBUTE, line_span, "useless lint attribute", |diag| { - sugg = sugg.replacen("#[", "#![", 1); diag.span_suggestion( line_span, "if you just forgot a `!`, use", - sugg, + src.replacen("#[", "#![", 1), Applicability::MaybeIncorrect, ); }); diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index a2f48c18170..e933fdf1d6e 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::eq_expr_value; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -134,28 +134,30 @@ fn check_inverted_bool_in_condition( let suggestion = match (left.kind, right.kind) { (ExprKind::Unary(UnOp::Not, left_sub), ExprKind::Unary(UnOp::Not, right_sub)) => { - let Some(left) = snippet_opt(cx, left_sub.span) else { + let Some(left) = left_sub.span.get_source_text(cx) else { return; }; - let Some(right) = snippet_opt(cx, right_sub.span) else { + let Some(right) = right_sub.span.get_source_text(cx) else { return; }; let Some(op) = bin_op_eq_str(op) else { return }; format!("{left} {op} {right}") }, (ExprKind::Unary(UnOp::Not, left_sub), _) => { - let Some(left) = snippet_opt(cx, left_sub.span) else { + let Some(left) = left_sub.span.get_source_text(cx) else { return; }; - let Some(right) = snippet_opt(cx, right.span) else { + let Some(right) = right.span.get_source_text(cx) else { return; }; let Some(op) = inverted_bin_op_eq_str(op) else { return }; format!("{left} {op} {right}") }, (_, ExprKind::Unary(UnOp::Not, right_sub)) => { - let Some(left) = snippet_opt(cx, left.span) else { return }; - let Some(right) = snippet_opt(cx, right_sub.span) else { + let Some(left) = left.span.get_source_text(cx) else { + return; + }; + let Some(right) = right_sub.span.get_source_text(cx) else { return; }; let Some(op) = inverted_bin_op_eq_str(op) else { return }; @@ -313,8 +315,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { self.output.push_str(&str); } else { self.output.push('!'); - let snip = snippet_opt(self.cx, terminal.span)?; - self.output.push_str(&snip); + self.output.push_str(&terminal.span.get_source_text(self.cx)?); } }, True | False | Not(_) => { @@ -345,8 +346,12 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { } }, &Term(n) => { - let snip = snippet_opt(self.cx, self.terminals[n as usize].span.source_callsite())?; - self.output.push_str(&snip); + self.output.push_str( + &self.terminals[n as usize] + .span + .source_callsite() + .get_source_text(self.cx)?, + ); }, } Some(()) @@ -370,8 +375,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> { _ => None, } .and_then(|op| { - let lhs_snippet = snippet_opt(cx, lhs.span)?; - let rhs_snippet = snippet_opt(cx, rhs.span)?; + let lhs_snippet = lhs.span.get_source_text(cx)?; + let rhs_snippet = rhs.span.get_source_text(cx)?; if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) { if let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node) { @@ -399,7 +404,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> { let path: &str = path.ident.name.as_str(); a == path }) - .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", snippet_opt(cx, receiver.span)?))) + .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", receiver.span.get_source_text(cx)?))) }, _ => None, } diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs index bd123a725a7..cba8224b84c 100644 --- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs +++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs @@ -1,6 +1,6 @@ use crate::reference::DEREF_ADDROF; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed}; use rustc_errors::Applicability; @@ -73,6 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { } }) && !is_from_proc_macro(cx, e) + && let Some(deref_text) = deref_target.span.get_source_text(cx) { span_lint_and_then( cx, @@ -83,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { diag.span_suggestion( e.span, "if you would like to reborrow, try removing `&*`", - snippet_opt(cx, deref_target.span).unwrap(), + deref_text.as_str(), Applicability::MachineApplicable, ); @@ -98,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { diag.span_suggestion( e.span, "if you would like to deref, try using `&**`", - format!("&**{}", &snippet_opt(cx, deref_target.span).unwrap()), + format!("&**{deref_text}"), Applicability::MaybeIncorrect, ); }, diff --git a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs index 3af2d8c0256..fed0aa8b275 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs @@ -1,5 +1,3 @@ -//! lint on missing cargo common metadata - use cargo_metadata::Metadata; use clippy_utils::diagnostics::span_lint; use rustc_lint::LateContext; diff --git a/src/tools/clippy/clippy_lints/src/cargo/mod.rs b/src/tools/clippy/clippy_lints/src/cargo/mod.rs index 312ad4c2990..96a2b161464 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/mod.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/mod.rs @@ -205,7 +205,7 @@ declare_clippy_lint! { } pub struct Cargo { - allowed_duplicate_crates: &'static FxHashSet<String>, + allowed_duplicate_crates: FxHashSet<String>, ignore_publish: bool, } @@ -221,7 +221,7 @@ impl_lint_pass!(Cargo => [ impl Cargo { pub fn new(conf: &'static Conf) -> Self { Self { - allowed_duplicate_crates: &conf.allowed_duplicate_crates, + allowed_duplicate_crates: conf.allowed_duplicate_crates.iter().cloned().collect(), ignore_publish: conf.cargo_ignore_publish, } } @@ -263,7 +263,7 @@ impl LateLintPass<'_> for Cargo { { match MetadataCommand::new().exec() { Ok(metadata) => { - multiple_crate_versions::check(cx, &metadata, self.allowed_duplicate_crates); + multiple_crate_versions::check(cx, &metadata, &self.allowed_duplicate_crates); }, Err(e) => { for lint in WITH_DEPS_LINTS { diff --git a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs index 2769463c8a5..44cd1f7192f 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs @@ -1,5 +1,3 @@ -//! lint on multiple versions of a crate being used - use cargo_metadata::{DependencyKind, Metadata, Node, Package, PackageId}; use clippy_utils::diagnostics::span_lint; use itertools::Itertools; diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs index f05fd3fcde5..15ecba20a0b 100644 --- a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity() && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next() && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind() - && let Some(recv) = snippet_opt(cx, receiver.span) + && let Some(recv) = receiver.span.get_source_text(cx) { // `as_mut_ptr` might not exist let applicability = Applicability::MaybeIncorrect; diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs index bd3acc06f4b..346aed7e9f1 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_const_context; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; @@ -34,7 +34,7 @@ pub(super) fn check( diag.help("an `as` cast can become silently lossy if the types change in the future"); let mut applicability = Applicability::MachineApplicable; let from_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "<from>", &mut applicability); - let Some(ty) = snippet_opt(cx, hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt())) else { + let Some(ty) = hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt()).get_source_text(cx) else { return; }; match cast_to_hir.kind { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index 102fe25fc67..5708aae3f3e 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -4,7 +4,7 @@ use clippy_utils::expr_or_init; use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; -use rustc_errors::{Applicability, Diag, SuggestionStyle}; +use rustc_errors::{Applicability, Diag}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -190,12 +190,10 @@ fn offer_suggestion( format!("{cast_to_snip}::try_from({})", Sugg::hir(cx, cast_expr, "..")) }; - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( expr.span, "... or use `try_from` and handle the error accordingly", suggestion, Applicability::Unspecified, - // always show the suggestion in a separate line - SuggestionStyle::ShowAlways, ); } diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs index 5dc6df1e907..b22e8f4ee89 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_any.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; @@ -24,12 +24,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, expr.span, format!("casting function pointer `{from_snippet}` to `{cast_to}`"), |diag| { - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( expr.span, "did you mean to invoke the function?", format!("{from_snippet}() as {cast_to}"), applicability, - SuggestionStyle::ShowAlways, ); }, ); diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index fb0b0cba6a6..566adc83d69 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{snippet_opt, SpanRangeExt}; use clippy_utils::visitors::{for_each_expr_without_closures, Visitable}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; @@ -104,7 +104,7 @@ pub(super) fn check<'tcx>( let literal_str = &cast_str; if let LitKind::Int(n, _) = lit.node - && let Some(src) = snippet_opt(cx, cast_expr.span) + && let Some(src) = cast_expr.span.get_source_text(cx) && cast_to.is_floating_point() && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) && let from_nbits = 128 - n.get().leading_zeros() @@ -131,7 +131,7 @@ pub(super) fn check<'tcx>( | LitKind::Float(_, LitFloatType::Suffixed(_)) if cast_from.kind() == cast_to.kind() => { - if let Some(src) = snippet_opt(cx, cast_expr.span) { + if let Some(src) = cast_expr.span.get_source_text(cx) { if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) { lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); return true; @@ -253,7 +253,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx let res = cx.qpath_res(&qpath, expr.hir_id); // Function call if let Res::Def(DefKind::Fn, def_id) = res { - let Some(snippet) = snippet_opt(cx, cx.tcx.def_span(def_id)) else { + let Some(snippet) = cx.tcx.def_span(def_id).get_source_text(cx) else { return ControlFlow::Continue(()); }; // This is the worst part of this entire function. This is the only way I know of to diff --git a/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs index 3c1c7d2dc3a..c5c4a28646d 100644 --- a/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/zero_ptr.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{is_in_const_context, is_integer_literal, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, Ty, TyKind}; @@ -20,7 +20,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_> let sugg = if let TyKind::Infer = mut_ty.ty.kind { format!("{std_or_core}::{sugg_fn}()") - } else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) { + } else if let Some(mut_ty_snip) = mut_ty.ty.span.get_source_text(cx) { format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()") } else { return; diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs index b54f392bf2f..d820c1e0720 100644 --- a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs +++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs @@ -5,7 +5,7 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#{cfg(not(test))]`) + /// Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#[cfg(not(test))]`) /// /// ### Why is this bad? /// This may give the false impression that a codebase has 100% coverage, yet actually has untested code. diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index 1711565fca8..dd7c34d1e46 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -1,5 +1,3 @@ -//! lint on manually implemented checked conversions that could be transformed into `try_from` - use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 5fa0522e4e5..0099eefbc8d 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -1,5 +1,3 @@ -//! calculate cognitive complexity and warn about overly complex functions - use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{IntoSpan, SpanRangeExt}; diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index f311c052ad6..e73bfc6ebf7 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -1,17 +1,3 @@ -//! Checks for if expressions that contain only an if expression. -//! -//! For example, the lint would catch: -//! -//! ```rust,ignore -//! if x { -//! if y { -//! println!("Hello world"); -//! } -//! } -//! ``` -//! -//! This lint is **warn** by default - use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_block, snippet_block_with_applicability}; use clippy_utils::sugg::Sugg; diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs index eebda3ff76f..c6847411c75 100644 --- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs +++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; +use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; use clippy_utils::visitors::{for_each_expr, Visitable}; use clippy_utils::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; @@ -7,7 +7,6 @@ use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; -use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -44,24 +43,11 @@ declare_clippy_lint! { } declare_lint_pass!(CollectionIsNeverRead => [COLLECTION_IS_NEVER_READ]); -// Add `String` here when it is added to diagnostic items -static COLLECTIONS: [Symbol; 9] = [ - sym::BTreeMap, - sym::BTreeSet, - sym::BinaryHeap, - sym::HashMap, - sym::HashSet, - sym::LinkedList, - sym::Option, - sym::Vec, - sym::VecDeque, -]; - impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { // Look for local variables whose type is a container. Search surrounding block for read access. if let PatKind::Binding(_, local_id, _, _) = local.pat.kind - && match_acceptable_type(cx, local, &COLLECTIONS) + && match_acceptable_type(cx, local) && let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id) && has_no_read_access(cx, local_id, enclosing_block) { @@ -70,11 +56,22 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { } } -fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[Symbol]) -> bool { +fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool { let ty = cx.typeck_results().pat_ty(local.pat); - collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym)) - // String type is a lang item but not a diagnostic item for now so we need a separate check - || is_type_lang_item(cx, ty, LangItem::String) + matches!( + get_type_diagnostic_name(cx, ty), + Some( + sym::BTreeMap + | sym::BTreeSet + | sym::BinaryHeap + | sym::HashMap + | sym::HashSet + | sym::LinkedList + | sym::Option + | sym::Vec + | sym::VecDeque + ) + ) || is_type_lang_item(cx, ty, LangItem::String) } fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirId, block: T) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs index b49a977dbea..24570d8f440 100644 --- a/src/tools/clippy/clippy_lints/src/create_dir.rs +++ b/src/tools/clippy/clippy_lints/src/create_dir.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -46,7 +46,7 @@ impl LateLintPass<'_> for CreateDir { "calling `std::fs::create_dir` where there may be a better way", |diag| { let mut app = Applicability::MaybeIncorrect; - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( expr.span, "consider calling `std::fs::create_dir_all` instead", format!( @@ -54,7 +54,6 @@ impl LateLintPass<'_> for CreateDir { snippet_with_applicability(cx, arg.span, "..", &mut app) ), app, - SuggestionStyle::ShowAlways, ); }, ); diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 3fb083dd833..60e51713173 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -2,7 +2,7 @@ // Use that command to update this file and do not edit by hand. // Manual edits will be overwritten. -pub(crate) static LINTS: &[&crate::LintInfo] = &[ +pub static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION_INFO, #[cfg(feature = "internal")] @@ -22,8 +22,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ #[cfg(feature = "internal")] crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO, #[cfg(feature = "internal")] - crate::utils::internal_lints::metadata_collector::METADATA_COLLECTOR_INFO, - #[cfg(feature = "internal")] crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO, @@ -146,6 +144,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::doc::NEEDLESS_DOCTEST_MAIN_INFO, crate::doc::SUSPICIOUS_DOC_COMMENTS_INFO, crate::doc::TEST_ATTR_IN_DOCTEST_INFO, + crate::doc::TOO_LONG_FIRST_DOC_PARAGRAPH_INFO, crate::doc::UNNECESSARY_SAFETY_DOC_INFO, crate::double_parens::DOUBLE_PARENS_INFO, crate::drop_forget_ref::DROP_NON_DROP_INFO, diff --git a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs index bd1cc46e185..771bcac2441 100644 --- a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs +++ b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use itertools::Itertools; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_span::{BytePos, Span}; use std::ops::Range; @@ -59,12 +59,11 @@ pub(super) fn check( && (doc_comment == "///" || doc_comment == "//!") { // suggest filling in a blank line - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( line_break_span.shrink_to_lo(), "if this should be its own paragraph, add a blank doc comment line", format!("\n{doc_comment}"), Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, ); if ccount > 0 || blockquote_level > 0 { diag.help("if this not intended to be a quote at all, escape it with `\\>`"); @@ -79,12 +78,11 @@ pub(super) fn check( if ccount == 0 && blockquote_level == 0 { // simpler suggestion style for indentation let indent = list_indentation - lcount; - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( span.shrink_to_hi(), "indent this line", std::iter::repeat(" ").take(indent).join(""), Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, ); diag.help("if this is supposed to be its own paragraph, add a blank line"); return; @@ -107,12 +105,11 @@ pub(super) fn check( suggested.push_str(text); } } - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( span, "add markers to start of line", suggested, Applicability::MachineApplicable, - SuggestionStyle::ShowAlways, ); diag.help("if this not intended to be a quote at all, escape it with `\\>`"); }); diff --git a/src/tools/clippy/clippy_lints/src/doc/markdown.rs b/src/tools/clippy/clippy_lints/src/doc/markdown.rs index 41c0bcd55ad..8cdaba88e50 100644 --- a/src/tools/clippy/clippy_lints/src/doc/markdown.rs +++ b/src/tools/clippy/clippy_lints/src/doc/markdown.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_lint::LateContext; use rustc_span::{BytePos, Pos, Span}; use url::Url; @@ -92,6 +92,10 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b && matches!(prefix.chars().last(), Some('S' | 'X')) { prefix + } else if let Some(prefix) = s.strip_suffix("ified") + && prefix.chars().all(|c| c.is_ascii_uppercase()) + { + prefix } else { s.strip_suffix('s').unwrap_or(s) }; @@ -133,24 +137,15 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b } if has_underscore(word) || word.contains("::") || is_camel_case(word) || word.ends_with("()") { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_then( cx, DOC_MARKDOWN, span, "item in documentation is missing backticks", |diag| { + let mut applicability = Applicability::MachineApplicable; let snippet = snippet_with_applicability(cx, span, "..", &mut applicability); - diag.span_suggestion_with_style( - span, - "try", - format!("`{snippet}`"), - applicability, - // always show the suggestion in a separate line, since the - // inline presentation adds another pair of backticks - SuggestionStyle::ShowAlways, - ); + diag.span_suggestion_verbose(span, "try", format!("`{snippet}`"), applicability); }, ); } diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index d7b3a7c74f3..790579b21c9 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -1,4 +1,6 @@ mod lazy_continuation; +mod too_long_first_doc_paragraph; + use clippy_config::Conf; use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; @@ -309,7 +311,7 @@ declare_clippy_lint! { /// ### Known problems /// Inner doc comments can only appear before items, so there are certain cases where the suggestion /// made by this lint is not valid code. For example: - /// ```rs + /// ```rust /// fn foo() {} /// ///! /// fn bar() {} @@ -422,15 +424,47 @@ declare_clippy_lint! { "require every line of a paragraph to be indented and marked" } +declare_clippy_lint! { + /// ### What it does + /// Checks if the first line in the documentation of items listed in module page is too long. + /// + /// ### Why is this bad? + /// Documentation will show the first paragraph of the doscstring in the summary page of a + /// module, so having a nice, short summary in the first paragraph is part of writing good docs. + /// + /// ### Example + /// ```no_run + /// /// A very short summary. + /// /// A much longer explanation that goes into a lot more detail about + /// /// how the thing works, possibly with doclinks and so one, + /// /// and probably spanning a many rows. + /// struct Foo {} + /// ``` + /// Use instead: + /// ```no_run + /// /// A very short summary. + /// /// + /// /// A much longer explanation that goes into a lot more detail about + /// /// how the thing works, possibly with doclinks and so one, + /// /// and probably spanning a many rows. + /// struct Foo {} + /// ``` + #[clippy::version = "1.81.0"] + pub TOO_LONG_FIRST_DOC_PARAGRAPH, + style, + "ensure that the first line of a documentation paragraph isn't too long" +} + +#[derive(Clone)] pub struct Documentation { - valid_idents: &'static FxHashSet<String>, + valid_idents: FxHashSet<String>, check_private_items: bool, } impl Documentation { pub fn new(conf: &'static Conf) -> Self { Self { - valid_idents: &conf.doc_valid_idents, + valid_idents: conf.doc_valid_idents.iter().cloned().collect(), check_private_items: conf.check_private_items, } } @@ -448,48 +482,60 @@ impl_lint_pass!(Documentation => [ SUSPICIOUS_DOC_COMMENTS, EMPTY_DOCS, DOC_LAZY_CONTINUATION, + TOO_LONG_FIRST_DOC_PARAGRAPH, ]); impl<'tcx> LateLintPass<'tcx> for Documentation { fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { - let Some(headers) = check_attrs(cx, self.valid_idents, attrs) else { + let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return; }; match cx.tcx.hir_node(cx.last_node_with_lint_attrs) { - Node::Item(item) => match item.kind { - ItemKind::Fn(sig, _, body_id) => { - if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { - let body = cx.tcx.hir().body(body_id); - - let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); - missing_headers::check( + Node::Item(item) => { + too_long_first_doc_paragraph::check( + cx, + item, + attrs, + headers.first_paragraph_len, + self.check_private_items, + ); + match item.kind { + ItemKind::Fn(sig, _, body_id) => { + if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) + || in_external_macro(cx.tcx.sess, item.span)) + { + let body = cx.tcx.hir().body(body_id); + + let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value); + missing_headers::check( + cx, + item.owner_id, + sig, + headers, + Some(body_id), + panic_info, + self.check_private_items, + ); + } + }, + ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) { + (false, Safety::Unsafe) => span_lint( cx, - item.owner_id, - sig, - headers, - Some(body_id), - panic_info, - self.check_private_items, - ); - } - }, - ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) { - (false, Safety::Unsafe) => span_lint( - cx, - MISSING_SAFETY_DOC, - cx.tcx.def_span(item.owner_id), - "docs for unsafe trait missing `# Safety` section", - ), - (true, Safety::Safe) => span_lint( - cx, - UNNECESSARY_SAFETY_DOC, - cx.tcx.def_span(item.owner_id), - "docs for safe trait have unnecessary `# Safety` section", - ), + MISSING_SAFETY_DOC, + cx.tcx.def_span(item.owner_id), + "docs for unsafe trait missing `# Safety` section", + ), + (true, Safety::Safe) => span_lint( + cx, + UNNECESSARY_SAFETY_DOC, + cx.tcx.def_span(item.owner_id), + "docs for safe trait have unnecessary `# Safety` section", + ), + _ => (), + }, _ => (), - }, - _ => (), + } }, Node::TraitItem(trait_item) => { if let TraitItemKind::Fn(sig, ..) = trait_item.kind @@ -547,6 +593,7 @@ struct DocHeaders { safety: bool, errors: bool, panics: bool, + first_paragraph_len: usize, } /// Does some pre-processing on raw, desugared `#[doc]` attributes such as parsing them and @@ -653,6 +700,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize let mut paragraph_range = 0..0; let mut code_level = 0; let mut blockquote_level = 0; + let mut is_first_paragraph = true; let mut containers = Vec::new(); @@ -720,6 +768,10 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize } ticks_unbalanced = false; paragraph_range = range; + if is_first_paragraph { + headers.first_paragraph_len = doc[paragraph_range.clone()].chars().count(); + is_first_paragraph = false; + } }, End(TagEnd::Heading(_) | TagEnd::Paragraph | TagEnd::Item) => { if let End(TagEnd::Heading(_)) = event { diff --git a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs new file mode 100644 index 00000000000..7bb3bb12f2c --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs @@ -0,0 +1,91 @@ +use rustc_ast::ast::Attribute; +use rustc_errors::Applicability; +use rustc_hir::{Item, ItemKind}; +use rustc_lint::LateContext; + +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; +use clippy_utils::source::snippet_opt; + +use super::TOO_LONG_FIRST_DOC_PARAGRAPH; + +pub(super) fn check( + cx: &LateContext<'_>, + item: &Item<'_>, + attrs: &[Attribute], + mut first_paragraph_len: usize, + check_private_items: bool, +) { + if !check_private_items && !cx.effective_visibilities.is_exported(item.owner_id.def_id) { + return; + } + if first_paragraph_len <= 200 + || !matches!( + item.kind, + // This is the list of items which can be documented AND are displayed on the module + // page. So associated items or impl blocks are not part of this list. + ItemKind::Static(..) + | ItemKind::Const(..) + | ItemKind::Fn(..) + | ItemKind::Macro(..) + | ItemKind::Mod(..) + | ItemKind::TyAlias(..) + | ItemKind::Enum(..) + | ItemKind::Struct(..) + | ItemKind::Union(..) + | ItemKind::Trait(..) + | ItemKind::TraitAlias(..) + ) + { + return; + } + + let mut spans = Vec::new(); + let mut should_suggest_empty_doc = false; + + for attr in attrs { + if let Some(doc) = attr.doc_str() { + spans.push(attr.span); + let doc = doc.as_str(); + let doc = doc.trim(); + if spans.len() == 1 { + // We make this suggestion only if the first doc line ends with a punctuation + // because it might just need to add an empty line with `///`. + should_suggest_empty_doc = doc.ends_with('.') || doc.ends_with('!') || doc.ends_with('?'); + } + let len = doc.chars().count(); + if len >= first_paragraph_len { + break; + } + first_paragraph_len -= len; + } + } + + let &[first_span, .., last_span] = spans.as_slice() else { + return; + }; + if is_from_proc_macro(cx, item) { + return; + } + + span_lint_and_then( + cx, + TOO_LONG_FIRST_DOC_PARAGRAPH, + first_span.with_hi(last_span.lo()), + "first doc comment paragraph is too long", + |diag| { + if should_suggest_empty_doc + && let Some(second_span) = spans.get(1) + && let new_span = first_span.with_hi(second_span.lo()).with_lo(first_span.hi()) + && let Some(snippet) = snippet_opt(cx, new_span) + { + diag.span_suggestion( + new_span, + "add an empty line", + format!("{snippet}///\n"), + Applicability::MachineApplicable, + ); + } + }, + ); +} diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs index 02f9c2c3648..5315f55ba38 100644 --- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs +++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs @@ -1,5 +1,3 @@ -//! Lint on if expressions with an else if, but without a final else branch. - use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs index 1869faab1d3..f4c55738cb8 100644 --- a/src/tools/clippy/clippy_lints/src/empty_enum.rs +++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs @@ -1,5 +1,3 @@ -//! lint when there is an enum with no variants - use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index e54cd248ead..4755cefe784 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -1,6 +1,3 @@ -//! lint on C-like enums that are `repr(isize/usize)` and have values that -//! don't fit into an `i32` - use clippy_utils::consts::{mir_to_const, Constant}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index a7e831fdc42..cabc6592258 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::higher::VecArgs; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::type_diagnostic_name; +use clippy_utils::ty::get_type_diagnostic_name; use clippy_utils::usage::{local_used_after_expr, local_used_in}; use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, path_to_local, path_to_local_id}; use rustc_errors::Applicability; @@ -139,7 +139,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc { let callee_ty_raw = typeck.expr_ty(callee); let callee_ty = callee_ty_raw.peel_refs(); - if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc)) + if matches!(get_type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc)) || !check_inputs(typeck, body.params, None, args) { return; diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs index f095c1add91..012ad8e1a22 100644 --- a/src/tools/clippy/clippy_lints/src/float_literal.rs +++ b/src/tools/clippy/clippy_lints/src/float_literal.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::numeric_literal; use rustc_ast::ast::{self, LitFloatType, LitKind}; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, FloatTy}; @@ -117,12 +117,11 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { if type_suffix.is_none() { float_str.push_str(".0"); } - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( expr.span, "consider changing the type or replacing it with", numeric_literal::format(&float_str, type_suffix, true), Applicability::MachineApplicable, - SuggestionStyle::ShowAlways, ); }, ); @@ -134,12 +133,11 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { expr.span, "float has excessive precision", |diag| { - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( expr.span, "consider changing the type or truncating it to", numeric_literal::format(&float_str, type_suffix, true), Applicability::MachineApplicable, - SuggestionStyle::ShowAlways, ); }, ); diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs index 0b248f784b7..4dedff69b9a 100644 --- a/src/tools/clippy/clippy_lints/src/format.rs +++ b/src/tools/clippy/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage}; -use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::source::{snippet_with_context, SpanRangeExt}; use clippy_utils::sugg::Sugg; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; @@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), ([], [_]) => { // Simulate macro expansion, converting {{ and }} to { and }. - let Some(snippet) = snippet_opt(cx, format_args.span) else { + let Some(snippet) = format_args.span.get_source_text(cx) else { return; }; let s_expand = snippet.replace("{{", "{").replace("}}", "}"); @@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { span_useless_format(cx, call_site, sugg, applicability); }, ([arg], [piece]) => { - if let Ok(value) = find_format_arg_expr(expr, arg) + if let Some(value) = find_format_arg_expr(expr, arg) && let FormatArgsPiece::Placeholder(placeholder) = piece && placeholder.format_trait == FormatTrait::Display && placeholder.format_options == FormatOptions::default() diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index a31d5cb6ec7..020c0c5440d 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -7,7 +7,7 @@ use clippy_utils::macros::{ find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall, }; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; use itertools::Itertools; use rustc_ast::{ @@ -224,13 +224,11 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { if let FormatArgsPiece::Placeholder(placeholder) = piece && let Ok(index) = placeholder.argument.index && let Some(arg) = self.format_args.arguments.all_args().get(index) + && let Some(arg_expr) = find_format_arg_expr(self.expr, arg) { - let arg_expr = find_format_arg_expr(self.expr, arg); - self.check_unused_format_specifier(placeholder, arg_expr); - if let Ok(arg_expr) = arg_expr - && placeholder.format_trait == FormatTrait::Display + if placeholder.format_trait == FormatTrait::Display && placeholder.format_options == FormatOptions::default() && !self.is_aliased(index) { @@ -242,28 +240,13 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { } } - fn check_unused_format_specifier( - &self, - placeholder: &FormatPlaceholder, - arg_expr: Result<&Expr<'_>, &rustc_ast::Expr>, - ) { - let ty_or_ast_expr = arg_expr.map(|expr| self.cx.typeck_results().expr_ty(expr).peel_refs()); - - let is_format_args = match ty_or_ast_expr { - Ok(ty) => is_type_lang_item(self.cx, ty, LangItem::FormatArguments), - Err(expr) => matches!(expr.peel_parens_and_refs().kind, rustc_ast::ExprKind::FormatArgs(_)), - }; - + fn check_unused_format_specifier(&self, placeholder: &FormatPlaceholder, arg: &Expr<'_>) { let options = &placeholder.format_options; - let arg_span = match arg_expr { - Ok(expr) => expr.span, - Err(expr) => expr.span, - }; - if let Some(placeholder_span) = placeholder.span - && is_format_args && *options != FormatOptions::default() + && let ty = self.cx.typeck_results().expr_ty(arg).peel_refs() + && is_type_lang_item(self.cx, ty, LangItem::FormatArguments) { span_lint_and_then( self.cx, @@ -274,7 +257,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { let mut suggest_format = |spec| { let message = format!("for the {spec} to apply consider using `format!()`"); - if let Some(mac_call) = matching_root_macro_call(self.cx, arg_span, sym::format_args_macro) { + if let Some(mac_call) = matching_root_macro_call(self.cx, arg.span, sym::format_args_macro) { diag.span_suggestion( self.cx.sess().source_map().span_until_char(mac_call.span, '!'), message, @@ -424,7 +407,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()) && implements_trait(cx, target, display_trait_id, &[]) && let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait() - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span.source_callsite()) + && let Some(receiver_snippet) = receiver.span.source_callsite().get_source_text(cx) { let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); if n_needed_derefs == 0 && !needs_ref { diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index e6f27cb82d1..7cd12ac7db8 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -196,7 +196,7 @@ impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> { && trait_name == self.format_trait_impl.name && let Ok(index) = placeholder.argument.index && let Some(arg) = format_args.arguments.all_args().get(index) - && let Ok(arg_expr) = find_format_arg_expr(self.expr, arg) + && let Some(arg_expr) = find_format_arg_expr(self.expr, arg) { self.check_format_arg_self(arg_expr); } diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index 1c1d8b57bc4..b84bf7c821c 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -3,7 +3,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; use clippy_utils::path_def_id; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_path, Visitor}; use rustc_hir::{ @@ -178,8 +178,8 @@ fn convert_to_from( return None; }; - let from = snippet_opt(cx, self_ty.span)?; - let into = snippet_opt(cx, target_ty.span)?; + let from = self_ty.span.get_source_text(cx)?; + let into = target_ty.span.get_source_text(cx)?; let mut suggestions = vec![ // impl Into<T> for U -> impl From<T> for U @@ -187,10 +187,10 @@ fn convert_to_from( (into_trait_seg.ident.span, String::from("From")), // impl Into<T> for U -> impl Into<U> for U // ~ ~ - (target_ty.span, from.clone()), + (target_ty.span, from.to_owned()), // impl Into<T> for U -> impl Into<T> for T // ~ ~ - (self_ty.span, into), + (self_ty.span, into.to_owned()), // fn into(self) -> T -> fn from(self) -> T // ~~~~ ~~~~ (impl_item.ident.span, String::from("from")), @@ -223,7 +223,7 @@ fn convert_to_from( } for span in finder.upper { - suggestions.push((span, from.clone())); + suggestions.push((span, from.to_owned())); } for span in finder.lower { suggestions.push((span, String::from("val"))); diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs index 6ab7bbc2dfc..e5fa67d6964 100644 --- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs +++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs @@ -22,8 +22,8 @@ declare_clippy_lint! { /// /// ### Known problems /// - /// This lint may suggest using (&<expression>).parse() instead of <expression>.parse() directly - /// in some cases, which is correct but adds unnecessary complexity to the code. + /// This lint may suggest using `(&<expression>).parse()` instead of `<expression>.parse()` + /// directly in some cases, which is correct but adds unnecessary complexity to the code. /// /// ### Example /// ```ignore diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs index cf85c74e688..05e341e06fd 100644 --- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, GenericParam, Generics, HirId, ImplItem, ImplItemKind, TraitItem, TraitItemKind}; @@ -18,20 +19,18 @@ fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_ |diag| { if let Some(gen_span) = generics.span_for_param_suggestion() { // If there's already a generic param with the same bound, do not lint **this** suggestion. - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( gen_span, "add a type parameter", format!(", {{ /* Generic name */ }}: {}", ¶m.name.ident().as_str()[5..]), - rustc_errors::Applicability::HasPlaceholders, - rustc_errors::SuggestionStyle::ShowAlways, + Applicability::HasPlaceholders, ); } else { - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( generics.span, "add a type parameter", format!("<{{ /* Generic name */ }}: {}>", ¶m.name.ident().as_str()[5..]), - rustc_errors::Applicability::HasPlaceholders, - rustc_errors::SuggestionStyle::ShowAlways, + Applicability::HasPlaceholders, ); } }, diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index b179d7b5249..93828121047 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -8,11 +8,11 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{sym, Span}; use clippy_utils::attrs::is_proc_macro; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_must_use_ty; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{return_ty, trait_ref_of_method}; @@ -129,9 +129,9 @@ fn check_needless_must_use( cx, DOUBLE_MUST_USE, fn_header_span, - "this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]`", + "this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]`", None, - "either add some descriptive text or remove the attribute", + "either add some descriptive message or remove the attribute", ); } } @@ -155,7 +155,7 @@ fn check_must_use_candidate<'tcx>( return; } span_lint_and_then(cx, MUST_USE_CANDIDATE, fn_span, msg, |diag| { - if let Some(snippet) = snippet_opt(cx, fn_span) { + if let Some(snippet) = fn_span.get_source_text(cx) { diag.span_suggestion( fn_span, "add the attribute", @@ -193,17 +193,13 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet) } } -static KNOWN_WRAPPER_TYS: &[Symbol] = &[sym::Rc, sym::Arc]; - fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) -> bool { match *ty.kind() { // primitive types are never mutable ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false, ty::Adt(adt, args) => { tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env) - || KNOWN_WRAPPER_TYS - .iter() - .any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did())) + || matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Rc | sym::Arc)) && args.types().any(|ty| is_mutable_ty(cx, ty, tys)) }, ty::Tuple(args) => args.iter().any(|ty| is_mutable_ty(cx, ty, tys)), diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs index 586ca58d60d..0f5ce340c44 100644 --- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs +++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs @@ -1,12 +1,11 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::source::SpanRangeExt; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_span::Span; -use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::snippet_opt; - use super::TOO_MANY_LINES; pub(super) fn check_fn( @@ -22,57 +21,57 @@ pub(super) fn check_fn( return; } - let Some(code_snippet) = snippet_opt(cx, body.value.span) else { - return; - }; let mut line_count: u64 = 0; - let mut in_comment = false; - let mut code_in_line; + let too_many = body.value.span.check_source_text(cx, |src| { + let mut in_comment = false; + let mut code_in_line; - let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..)) - && code_snippet.as_bytes().first().copied() == Some(b'{') - && code_snippet.as_bytes().last().copied() == Some(b'}') - { - // Removing the braces from the enclosing block - &code_snippet[1..code_snippet.len() - 1] - } else { - &code_snippet - } - .trim() // Remove leading and trailing blank lines - .lines(); + let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..)) + && src.as_bytes().first().copied() == Some(b'{') + && src.as_bytes().last().copied() == Some(b'}') + { + // Removing the braces from the enclosing block + &src[1..src.len() - 1] + } else { + src + } + .trim() // Remove leading and trailing blank lines + .lines(); - for mut line in function_lines { - code_in_line = false; - loop { - line = line.trim_start(); - if line.is_empty() { - break; - } - if in_comment { - if let Some(i) = line.find("*/") { - line = &line[i + 2..]; - in_comment = false; - continue; + for mut line in function_lines { + code_in_line = false; + loop { + line = line.trim_start(); + if line.is_empty() { + break; } - } else { - let multi_idx = line.find("/*").unwrap_or(line.len()); - let single_idx = line.find("//").unwrap_or(line.len()); - code_in_line |= multi_idx > 0 && single_idx > 0; - // Implies multi_idx is below line.len() - if multi_idx < single_idx { - line = &line[multi_idx + 2..]; - in_comment = true; - continue; + if in_comment { + if let Some(i) = line.find("*/") { + line = &line[i + 2..]; + in_comment = false; + continue; + } + } else { + let multi_idx = line.find("/*").unwrap_or(line.len()); + let single_idx = line.find("//").unwrap_or(line.len()); + code_in_line |= multi_idx > 0 && single_idx > 0; + // Implies multi_idx is below line.len() + if multi_idx < single_idx { + line = &line[multi_idx + 2..]; + in_comment = true; + continue; + } } + break; + } + if code_in_line { + line_count += 1; } - break; - } - if code_in_line { - line_count += 1; } - } + line_count > too_many_lines_threshold + }); - if line_count > too_many_lines_threshold { + if too_many { span_lint( cx, TOO_MANY_LINES, diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs index 0ebd8d0c237..120c5396a1c 100644 --- a/src/tools/clippy/clippy_lints/src/if_not_else.rs +++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs @@ -1,6 +1,3 @@ -//! lint on if branches that could be swapped so no `!` operation is necessary -//! on the condition - use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_else_clause; diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index b926e1e62ba..ba06567b957 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context, wal use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{get_async_fn_body, is_async_fn, is_from_proc_macro}; use core::ops::ControlFlow; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -54,13 +54,7 @@ fn lint_return(cx: &LateContext<'_>, emission_place: HirId, span: Span) { |diag| { let mut app = Applicability::MachineApplicable; let snip = snippet_with_applicability(cx, span, "..", &mut app); - diag.span_suggestion_with_style( - span, - "add `return` as shown", - format!("return {snip}"), - app, - SuggestionStyle::ShowAlways, - ); + diag.span_suggestion_verbose(span, "add `return` as shown", format!("return {snip}"), app); }, ); } @@ -75,12 +69,11 @@ fn lint_break(cx: &LateContext<'_>, emission_place: HirId, break_span: Span, exp |diag| { let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, expr_span, break_span.ctxt(), "..", &mut app).0; - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( break_span, "change `break` to `return` as shown", format!("return {snip}"), app, - SuggestionStyle::ShowAlways, ); }, ); diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index 0ef5b803a89..2ad045e1268 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -7,8 +7,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; -use rustc_semver::RustcVersion; -use rustc_session::impl_lint_pass; +use rustc_session::{impl_lint_pass, RustcVersion}; use rustc_span::def_id::DefId; use rustc_span::{ExpnKind, Span}; @@ -65,18 +64,18 @@ impl IncompatibleMsrv { StabilityLevel::Stable { since: StableSince::Version(version), .. - } => Some(RustcVersion::new( - version.major.into(), - version.minor.into(), - version.patch.into(), - )), + } => Some(version), _ => None, }) { version } else if let Some(parent_def_id) = tcx.opt_parent(def_id) { self.get_def_id_version(tcx, parent_def_id) } else { - RustcVersion::new(1, 0, 0) + RustcVersion { + major: 1, + minor: 0, + patch: 0, + } }; self.is_above_msrv.insert(def_id, version); version diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs index 5b0aadf35c6..d386bfca6ba 100644 --- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::fulfill_or_allowed; use clippy_utils::source::snippet; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; @@ -71,6 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { && let ty = cx.typeck_results().expr_ty(expr) && let Some(adt_def) = ty.ty_adt_def() && adt_def.is_struct() + && let Some(local_def_id) = adt_def.did().as_local() + && let ty_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id) && let Some(variant) = adt_def.variants().iter().next() { let mut def_order_map = FxHashMap::default(); @@ -103,15 +106,17 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { snippet(cx, qpath.span(), ".."), ); - span_lint_and_sugg( - cx, - INCONSISTENT_STRUCT_CONSTRUCTOR, - expr.span, - "struct constructor field order is inconsistent with struct definition field order", - "try", - sugg, - Applicability::MachineApplicable, - ); + if !fulfill_or_allowed(cx, INCONSISTENT_STRUCT_CONSTRUCTOR, Some(ty_hir_id)) { + span_lint_and_sugg( + cx, + INCONSISTENT_STRUCT_CONSTRUCTOR, + expr.span, + "struct constructor field order is inconsistent with struct definition field order", + "try", + sugg, + Applicability::MachineApplicable, + ); + } } } } diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index 3ac50b8f1fb..22e9674714f 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -1,5 +1,3 @@ -//! lint on indexing and slicing operations - use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index 676d50c4951..71c317552ee 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::higher; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::ty::{get_type_diagnostic_name, implements_trait}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -210,18 +210,6 @@ const COMPLETING_METHODS: [(&str, usize); 12] = [ ("product", 0), ]; -/// the paths of types that are known to be infinitely allocating -const INFINITE_COLLECTORS: &[Symbol] = &[ - sym::BinaryHeap, - sym::BTreeMap, - sym::BTreeSet, - sym::HashMap, - sym::HashSet, - sym::LinkedList, - sym::Vec, - sym::VecDeque, -]; - fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { ExprKind::MethodCall(method, receiver, args, _) => { @@ -248,10 +236,19 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { } } else if method.ident.name == sym!(collect) { let ty = cx.typeck_results().expr_ty(expr); - if INFINITE_COLLECTORS - .iter() - .any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item)) - { + if matches!( + get_type_diagnostic_name(cx, ty), + Some( + sym::BinaryHeap + | sym::BTreeMap + | sym::BTreeSet + | sym::HashMap + | sym::HashSet + | sym::LinkedList + | sym::Vec + | sym::VecDeque, + ) + ) { return is_infinite(cx, receiver); } } diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index 9eed7aa9243..d39f910f993 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -1,5 +1,3 @@ -//! lint on inherent implementations - use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_lint_allowed; use rustc_data_structures::fx::FxHashMap; diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index 5657c58bb0a..1b900f6be8e 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -1,5 +1,3 @@ -//! checks for `#[inline]` on trait methods without bodies - use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::DiagExt; use rustc_errors::Applicability; diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs index b8e0eef7c7e..fc575bff7e6 100644 --- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs +++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs @@ -1,7 +1,5 @@ -//! lint on blocks unnecessarily using >= with a + 1 or - 1 - use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; @@ -132,8 +130,8 @@ impl IntPlusOne { BinOpKind::Le => "<", _ => return None, }; - if let Some(snippet) = snippet_opt(cx, node.span) { - if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) { + if let Some(snippet) = node.span.get_source_text(cx) { + if let Some(other_side_snippet) = other_side.span.get_source_text(cx) { let rec = match side { Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")), Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")), diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index 4d44bae02b8..74bf82f58bd 100644 --- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -1,5 +1,3 @@ -//! lint on enum variants that are prefixed or suffixed by the same characters - use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir}; use clippy_utils::is_bool; diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs index a88d8e24fda..4f066113aea 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs @@ -1,5 +1,3 @@ -//! lint when items are used after statements - use clippy_utils::diagnostics::span_lint_hir; use rustc_hir::{Block, ItemKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs index 3614fb8cc96..8caa484bb99 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_hir::{HirId, Item, ItemKind, Mod}; @@ -93,11 +93,14 @@ impl LateLintPass<'_> for ItemsAfterTestModule { if let Some(prev) = mod_pos.checked_sub(1) && let prev = cx.tcx.hir().item(module.item_ids[prev]) && let items_span = last.span.with_lo(test_mod.span.hi()) - && let Some(items) = snippet_opt(cx, items_span) + && let Some(items) = items_span.get_source_text(cx) { diag.multipart_suggestion_with_style( "move the items to before the test module was defined", - vec![(prev.span.shrink_to_hi(), items), (items_span, String::new())], + vec![ + (prev.span.shrink_to_hi(), items.to_owned()), + (items_span, String::new()), + ], Applicability::MachineApplicable, SuggestionStyle::HideCodeAlways, ); diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs index 225d79aa71d..2f027c11707 100644 --- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs +++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs @@ -1,5 +1,3 @@ -//! lint when there is a large size difference between variants on an enum - use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; diff --git a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs index 4abf7edc9b4..d2bdf194ada 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs @@ -3,7 +3,7 @@ use std::{fmt, ops}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::fn_has_unsatisfiable_preds; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; @@ -186,7 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { // TODO: Is there a cleaner, robust way to ask this question? // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data", // and that doesn't get us the true name in scope rather than the span text either. - if let Some(name) = snippet_opt(cx, local_span) + if let Some(name) = local_span.get_source_text(cx) && is_ident(&name) { // If the local is an ordinary named variable, diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs index 752e1326e3e..ccab1e27d3b 100644 --- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs +++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs @@ -3,7 +3,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::{get_parent_expr, is_from_proc_macro}; use hir::def_id::DefId; -use rustc_errors::{Applicability, SuggestionStyle}; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{ExprKind, Item, ItemKind, QPath, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -143,12 +143,11 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { && !is_from_proc_macro(cx, expr) { span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( span, "use the associated constant instead", sugg, Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways, ); }); } diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 4c737371bd2..0bc7fc2dd9d 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::source::{snippet_with_context, SpanRangeExt}; use clippy_utils::sugg::{has_enclosing_paren, Sugg}; use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; use rustc_ast::ast::LitKind; @@ -216,7 +216,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { } fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span { - let Some(snippet) = snippet_opt(cx, span) else { + let Some(snippet) = span.get_source_text(cx) else { return span; }; if has_enclosing_paren(snippet) { diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index ce13a9afef5..2ac06b360be 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -66,8 +66,8 @@ extern crate declare_clippy_lint; #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))] mod utils; -mod declared_lints; -mod deprecated_lints; +pub mod declared_lints; +pub mod deprecated_lints; // begin lints modules, do not remove this comment, it’s used in `update_lints` mod absolute_paths; @@ -440,7 +440,7 @@ impl RegistrationGroups { } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub(crate) enum LintCategory { Cargo, Complexity, @@ -479,11 +479,39 @@ impl LintCategory { } } -pub(crate) struct LintInfo { +pub struct LintInfo { /// Double reference to maintain pointer equality - lint: &'static &'static Lint, + pub lint: &'static &'static Lint, category: LintCategory, - explanation: &'static str, + pub explanation: &'static str, + /// e.g. `clippy_lints/src/absolute_paths.rs#43` + pub location: &'static str, + pub version: Option<&'static str>, +} + +impl LintInfo { + /// Returns the lint name in lowercase without the `clippy::` prefix + #[allow(clippy::missing_panics_doc)] + pub fn name_lower(&self) -> String { + self.lint.name.strip_prefix("clippy::").unwrap().to_ascii_lowercase() + } + + /// Returns the name of the lint's category in lowercase (`style`, `pedantic`) + pub fn category_str(&self) -> &'static str { + match self.category { + Cargo => "cargo", + Complexity => "complexity", + Correctness => "correctness", + Nursery => "nursery", + Pedantic => "pedantic", + Perf => "perf", + Restriction => "restriction", + Style => "style", + Suspicious => "suspicious", + #[cfg(feature = "internal")] + Internal => "internal", + } + } } pub fn explain(name: &str) -> i32 { @@ -538,14 +566,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_removed(name, reason); } - #[cfg(feature = "internal")] - { - if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) { - store.register_late_pass(|_| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new())); - return; - } - } - let format_args_storage = FormatArgsStorage::default(); let format_args = format_args_storage.clone(); store.register_early_pass(move || { diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index 259e4d6c08f..81f2a03fb55 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -1,10 +1,7 @@ -//! Lints concerned with the grouping of digits with underscores in integral or -//! floating-point literal expressions. - use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::numeric_literal::{NumericLiteral, Radix}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; @@ -228,7 +225,7 @@ impl LiteralDigitGrouping { } fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) { - if let Some(src) = snippet_opt(cx, span) + if let Some(src) = span.get_source_text(cx) && let Ok(lit_kind) = LitKind::from_token_lit(lit) && let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) { @@ -442,7 +439,7 @@ impl DecimalLiteralRepresentation { // Lint integral literals. if let Ok(lit_kind) = LitKind::from_token_lit(lit) && let LitKind::Int(val, _) = lit_kind - && let Some(src) = snippet_opt(cx, span) + && let Some(src) = span.get_source_text(cx) && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) && num_lit.radix == Radix::Decimal && val >= u128::from(self.threshold) diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index eea5f2a94ea..b134af500f5 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs @@ -3,7 +3,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{ - implements_trait, implements_trait_with_env, is_copy, make_normalized_projection, + implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection, make_normalized_projection_with_regions, normalize_with_regions, }; use rustc_errors::Applicability; @@ -20,9 +20,10 @@ pub(super) fn check( msrv: &Msrv, enforce_iter_loop_reborrow: bool, ) { - let Some((adjust, ty)) = is_ref_iterable(cx, self_arg, call_expr, enforce_iter_loop_reborrow) else { + let Some((adjust, ty)) = is_ref_iterable(cx, self_arg, call_expr, enforce_iter_loop_reborrow, msrv) else { return; }; + if let ty::Array(_, count) = *ty.peel_refs().kind() { if !ty.is_ref() { if !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) { @@ -109,6 +110,7 @@ fn is_ref_iterable<'tcx>( self_arg: &Expr<'_>, call_expr: &Expr<'_>, enforce_iter_loop_reborrow: bool, + msrv: &Msrv, ) -> Option<(AdjustKind, Ty<'tcx>)> { let typeck = cx.typeck_results(); if let Some(trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) @@ -128,6 +130,12 @@ fn is_ref_iterable<'tcx>( let self_ty = typeck.expr_ty(self_arg); let self_is_copy = is_copy(cx, self_ty); + if !msrv.meets(msrvs::BOX_INTO_ITER) + && is_type_lang_item(cx, self_ty.peel_refs(), rustc_hir::LangItem::OwnedBox) + { + return None; + } + if adjustments.is_empty() && self_is_copy { // Exact type match, already checked earlier return Some((AdjustKind::None, self_ty)); diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs index fed58f7ff14..e215097142b 100644 --- a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -122,8 +122,23 @@ struct BodyVisitor<'a, 'tcx> { /// within a relevant macro. macro_unsafe_blocks: Vec<HirId>, /// When this is >0, it means that the node currently being visited is "within" a - /// macro definition. This is not necessary for correctness, it merely helps reduce the number - /// of spans we need to insert into the map, since only spans from macros are relevant. + /// macro definition. + /// This is used to detect if an expression represents a metavariable. + /// + /// For example, the following pre-expansion code that we want to lint + /// ```ignore + /// macro_rules! m { ($e:expr) => { unsafe { $e; } } } + /// m!(1); + /// ``` + /// would look like this post-expansion code: + /// ```ignore + /// unsafe { /* macro */ + /// 1 /* root */; /* macro */ + /// } + /// ``` + /// Visiting the block and the statement will increment the `expn_depth` so that it is >0, + /// and visiting the expression with a root context while `expn_depth > 0` tells us + /// that it must be a metavariable. expn_depth: u32, cx: &'a LateContext<'tcx>, lint: &'a mut ExprMetavarsInUnsafe, @@ -157,7 +172,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BodyVisitor<'a, 'tcx> { && (self.lint.warn_unsafe_macro_metavars_in_private_macros || is_public_macro(self.cx, macro_def_id)) { self.macro_unsafe_blocks.push(block.hir_id); + self.expn_depth += 1; walk_block(self, block); + self.expn_depth -= 1; self.macro_unsafe_blocks.pop(); } else if ctxt.is_root() && self.expn_depth > 0 { let unsafe_block = self.macro_unsafe_blocks.last().copied(); diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 25c7e5d38b3..61723aec590 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; +use clippy_utils::source::{position_before_rarrow, snippet_block, SpanRangeExt}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ @@ -68,8 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { header_span, "this function can be simplified using the `async fn` syntax", |diag| { - if let Some(vis_snip) = snippet_opt(cx, *vis_span) - && let Some(header_snip) = snippet_opt(cx, header_span) + if let Some(vis_snip) = vis_span.get_source_text(cx) + && let Some(header_snip) = header_span.get_source_text(cx) && let Some(ret_pos) = position_before_rarrow(&header_snip) && let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output) { @@ -190,6 +190,6 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, Some((sugg, String::new())) } else { let sugg = "return the output of the future directly"; - snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {snip}"))) + output.span.get_source_text(cx).map(|src| (sugg, format!(" -> {src}"))) } } diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs index 6bdc79129a9..9d3ddab60bb 100644 --- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs +++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{is_from_proc_macro, path_to_local}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Constness, Expr, ExprKind}; @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { // case somebody does that for some reason && (is_infinity(&const_1) && is_neg_infinity(&const_2) || is_neg_infinity(&const_1) && is_infinity(&const_2)) - && let Some(local_snippet) = snippet_opt(cx, first.span) + && let Some(local_snippet) = first.span.get_source_text(cx) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite, diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs index 1c568b1b74f..11716a539ab 100644 --- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs +++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::visitors::{is_local_used, local_used_once}; use clippy_utils::{is_trait_method, path_to_local_id}; use rustc_errors::Applicability; @@ -107,8 +107,8 @@ impl LateLintPass<'_> for ManualHashOne { finish_expr.span, "manual implementation of `BuildHasher::hash_one`", |diag| { - if let Some(build_hasher) = snippet_opt(cx, build_hasher.span) - && let Some(hashed_value) = snippet_opt(cx, hashed_value.span) + if let Some(build_hasher) = build_hasher.span.get_source_text(cx) + && let Some(hashed_value) = hashed_value.span.get_source_text(cx) { diag.multipart_suggestion( "try", diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 28cfe22835a..6b1d90483cc 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -2,7 +2,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::is_doc_hidden; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{self, VisibilityKind}; use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; @@ -124,7 +124,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { |diag| { if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)) && let header_span = cx.sess().source_map().span_until_char(item.span, delimiter) - && let Some(snippet) = snippet_opt(cx, header_span) + && let Some(snippet) = header_span.get_source_text(cx) { diag.span_suggestion( header_span, @@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { "this seems like a manual implementation of the non-exhaustive pattern", |diag| { let header_span = cx.sess().source_map().span_until_char(enum_span, '{'); - if let Some(snippet) = snippet_opt(cx, header_span) { + if let Some(snippet) = header_span.get_source_text(cx) { diag.span_suggestion( header_span, "add the attribute", diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs index 07d4abbf5cd..9afb2b5bc84 100644 --- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -143,8 +143,8 @@ impl LateLintPass<'_> for ManualRangePatterns { pat.span, "this OR pattern can be rewritten using a range", |diag| { - if let Some(min) = snippet_opt(cx, min.span) - && let Some(max) = snippet_opt(cx, max.span) + if let Some(min) = min.span.get_source_text(cx) + && let Some(max) = max.span.get_source_text(cx) { diag.span_suggestion( pat.span, diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index 09f6362b4dd..d4e53f8f74b 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -2,14 +2,13 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; +use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item}; use clippy_utils::{match_def_path, paths, SpanlessEq}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::ExprKind::Assign; use rustc_lint::{LateContext, LateLintPass}; -use rustc_semver::RustcVersion; use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_span::Span; @@ -21,16 +20,6 @@ const ACCEPTABLE_METHODS: [&[&str]; 5] = [ &paths::SLICE_INTO, &paths::VEC_DEQUE_ITER, ]; -const ACCEPTABLE_TYPES: [(rustc_span::Symbol, Option<RustcVersion>); 7] = [ - (sym::BinaryHeap, Some(msrvs::BINARY_HEAP_RETAIN)), - (sym::BTreeSet, Some(msrvs::BTREE_SET_RETAIN)), - (sym::BTreeMap, Some(msrvs::BTREE_MAP_RETAIN)), - (sym::HashSet, Some(msrvs::HASH_SET_RETAIN)), - (sym::HashMap, Some(msrvs::HASH_MAP_RETAIN)), - (sym::Vec, None), - (sym::VecDeque, None), -]; -const MAP_TYPES: [rustc_span::Symbol; 2] = [sym::BTreeMap, sym::HashMap]; declare_clippy_lint! { /// ### What it does @@ -265,16 +254,22 @@ fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> boo } fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); - ACCEPTABLE_TYPES.iter().any(|(ty, acceptable_msrv)| { - is_type_diagnostic_item(cx, expr_ty, *ty) - && acceptable_msrv.map_or(true, |acceptable_msrv| msrv.meets(acceptable_msrv)) - }) + let ty = cx.typeck_results().expr_ty(expr).peel_refs(); + let required = match get_type_diagnostic_name(cx, ty) { + Some(sym::BinaryHeap) => msrvs::BINARY_HEAP_RETAIN, + Some(sym::BTreeSet) => msrvs::BTREE_SET_RETAIN, + Some(sym::BTreeMap) => msrvs::BTREE_MAP_RETAIN, + Some(sym::HashSet) => msrvs::HASH_SET_RETAIN, + Some(sym::HashMap) => msrvs::HASH_MAP_RETAIN, + Some(sym::Vec | sym::VecDeque) => return true, + _ => return false, + }; + msrv.meets(required) } fn match_map_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs(); - MAP_TYPES.iter().any(|ty| is_type_diagnostic_item(cx, expr_ty, *ty)) + let ty = cx.typeck_results().expr_ty(expr).peel_refs(); + matches!(get_type_diagnostic_name(cx, ty), Some(sym::BTreeMap | sym::HashMap)) } fn make_span_lint_and_sugg(cx: &LateContext<'_>, span: Span, sugg: String) { diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs index 90cfdecc199..b666e77c09e 100644 --- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs @@ -96,7 +96,7 @@ fn check_arm<'tcx>( // collapsing patterns need an explicit field name in struct pattern matching // ex: Struct {x: Some(1)} let replace_msg = if is_innermost_parent_pat_struct { - format!(", prefixed by {}:", snippet(cx, binding_span, "their field name")) + format!(", prefixed by `{}`:", snippet(cx, binding_span, "their field name")) } else { String::new() }; diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs index 2d4c8daf5cb..d5d83df9347 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::ConstEvalCtxt; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg}; @@ -67,11 +67,11 @@ fn check_and_lint<'tcx>( && path_to_local_id(peel_blocks(then_expr), binding_hir_id) && cx.typeck_results().expr_adjustments(then_expr).is_empty() && let Some(ty_name) = find_type_name(cx, ty) - && let Some(or_body_snippet) = snippet_opt(cx, else_expr.span) + && let Some(or_body_snippet) = else_expr.span.get_source_text(cx) && let Some(indent) = indent_of(cx, expr.span) && ConstEvalCtxt::new(cx).eval_simple(else_expr).is_some() { - lint(cx, expr, let_expr, ty_name, or_body_snippet, indent); + lint(cx, expr, let_expr, ty_name, &or_body_snippet, indent); } } @@ -110,7 +110,7 @@ fn lint<'tcx>( expr: &Expr<'tcx>, scrutinee: &'tcx Expr<'_>, ty_name: &str, - or_body_snippet: String, + or_body_snippet: &str, indent: usize, ) { let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent)); diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 24dea03601c..b6930f7b9d1 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -22,7 +22,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; /// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty /// match arms. fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { - if let Some(ff) = span.get_source_text(cx) + if let Some(ff) = span.get_source_range(cx) && let Some(text) = ff.as_str() { text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*") diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index a5df863d800..740cce0a6c2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -49,10 +49,12 @@ pub(super) fn check<'tcx>( "case-sensitive file extension comparison", |diag| { diag.help("consider using a case-insensitive comparison instead"); - if let Some(mut recv_source) = snippet_opt(cx, recv.span) { - if !cx.typeck_results().expr_ty(recv).is_ref() { - recv_source = format!("&{recv_source}"); - } + if let Some(recv_source) = recv.span.get_source_text(cx) { + let recv_source = if cx.typeck_results().expr_ty(recv).is_ref() { + recv_source.to_owned() + } else { + format!("&{recv_source}") + }; let suggestion_source = reindent_multiline( format!( diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs index 2e43d19a699..4fbf661727d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs @@ -1,7 +1,7 @@ use super::FILTER_MAP_BOOL_THEN; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::BOOL_THEN; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_copy; use clippy_utils::{is_from_proc_macro, is_trait_method, match_def_path, peel_blocks}; use rustc_errors::Applicability; @@ -42,9 +42,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & .iter() .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) .count() - && let Some(param_snippet) = snippet_opt(cx, param.span) - && let Some(filter) = snippet_opt(cx, recv.span) - && let Some(map) = snippet_opt(cx, then_body.span) + && let Some(param_snippet) = param.span.get_source_text(cx) + && let Some(filter) = recv.span.get_source_text(cx) + && let Some(map) = then_body.span.get_source_text(cx) { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 917a8e33eb9..f4840785584 100644 --- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::{is_path_diagnostic_item, sugg}; use rustc_errors::Applicability; @@ -39,7 +39,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> } let call_site = expr.span.source_callsite(); - if let Some(snippet) = snippet_opt(cx, call_site) + if let Some(snippet) = call_site.get_source_text(cx) && let snippet_split = snippet.split("::").collect::<Vec<_>>() && let Some((_, elements)) = snippet_split.split_last() { diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs index c6285c87a26..9daad1a8a94 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs @@ -74,7 +74,7 @@ pub(super) fn check<'tcx>( "&" }; - diag.span_suggestion_with_style( + diag.span_suggestion_verbose( span, "using `[]` is clearer and more concise", format!( @@ -82,7 +82,6 @@ pub(super) fn check<'tcx>( snippet_with_applicability(cx, recv.span, "..", &mut applicability) ), applicability, - rustc_errors::SuggestionStyle::ShowAlways, ); }, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs index 22d896433f0..40b48ccca5d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs +++ b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs @@ -1,5 +1,3 @@ -//! Lint for `c.is_digit(10)` - use super::IS_DIGIT_ASCII_RADIX; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::consts::{ConstEvalCtxt, FullInt}; diff --git a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs index aa1ec60d434..2dad7fcf3c1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs +++ b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::expr_or_init; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_a join_arg.span, "argument to `Path::join` starts with a path separator", |diag| { - let arg_str = snippet_opt(cx, spanned.span).unwrap_or_else(|| "..".to_string()); + let arg_str = snippet(cx, spanned.span, ".."); let no_separator = if sym_str.starts_with('/') { arg_str.replacen('/', "", 1) diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs index b1af0083e65..b1a8e1e5e47 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::source::{indent_of, reindent_multiline, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id}; use rustc_errors::Applicability; @@ -23,11 +23,11 @@ pub(super) fn check<'tcx>( && let ExprKind::Call(err_path, [err_arg]) = or_expr.kind && is_res_lang_ctor(cx, path_res(cx, err_path), ResultErr) && is_ok_wrapping(cx, map_expr) - && let Some(recv_snippet) = snippet_opt(cx, recv.span) - && let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span) + && let Some(recv_snippet) = recv.span.get_source_text(cx) + && let Some(err_arg_snippet) = err_arg.span.get_source_text(cx) && let Some(indent) = indent_of(cx, expr.span) { - let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4)); + let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.as_str().into(), true, Some(indent + 4)); span_lint_and_sugg( cx, MANUAL_OK_OR, diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs index f93edded729..11fba35c16e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::{is_from_proc_macro, is_trait_method}; use rustc_errors::Applicability; @@ -31,13 +31,15 @@ pub(super) fn check<'tcx>( && let Res::Def(DefKind::Ctor(_, _), _) = cx.qpath_res(&qpath, path.hir_id) && let ExprKind::Closure(closure) = acc.kind && !is_from_proc_macro(cx, expr) - && let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| snippet_opt(cx, fn_arg_span)) + && let Some(args_snip) = closure + .fn_arg_span + .and_then(|fn_arg_span| fn_arg_span.get_source_text(cx)) { let init_snip = rest .is_empty() .then_some(first.span) - .and_then(|span| snippet_opt(cx, span)) - .unwrap_or("...".to_owned()); + .and_then(|span| span.get_source_text(cx)) + .map_or_else(|| "...".to_owned(), |src| src.to_owned()); span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 1d7b10fe8f0..d7126990edb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -2702,10 +2702,10 @@ declare_clippy_lint! { /// } /// }) /// } - /// ``` + /// ``` /// - /// After: - /// ```rust + /// After: + /// ```rust /// use std::{fmt, num::ParseIntError}; /// /// #[derive(Debug)] diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs index e3d78207715..332da722a37 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs @@ -7,7 +7,7 @@ use rustc_span::Span; use super::utils::get_last_chain_binding_hir_id; use super::NEEDLESS_CHARACTER_ITERATION; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{match_def_path, path_to_local_id, peel_blocks}; fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { @@ -35,7 +35,7 @@ fn handle_expr( && path_to_local_id(receiver, first_param) && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() && *char_arg_ty.kind() == ty::Char - && let Some(snippet) = snippet_opt(cx, before_chars) + && let Some(snippet) = before_chars.get_source_text(cx) { span_lint_and_sugg( cx, @@ -79,7 +79,7 @@ fn handle_expr( && let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id() && match_def_path(cx, fn_def_id, &["core", "char", "methods", "<impl char>", "is_ascii"]) && path_to_local_id(peels_expr_ref(arg), first_param) - && let Some(snippet) = snippet_opt(cx, before_chars) + && let Some(snippet) = before_chars.get_source_text(cx) { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 46b457daf70..f61923e5bf5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -2,7 +2,7 @@ use super::NEEDLESS_COLLECT; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection}; +use clippy_utils::ty::{get_type_diagnostic_name, make_normalized_projection, make_projection}; use clippy_utils::{ can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, path_to_local_id, CaptureKind, @@ -88,9 +88,10 @@ pub(super) fn check<'tcx>( Node::LetStmt(l) => { if let PatKind::Binding(BindingMode::NONE | BindingMode::MUT, id, _, None) = l.pat.kind && let ty = cx.typeck_results().expr_ty(collect_expr) - && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList] - .into_iter() - .any(|item| is_type_diagnostic_item(cx, ty, item)) + && matches!( + get_type_diagnostic_name(cx, ty), + Some(sym::Vec | sym::VecDeque | sym::BinaryHeap | sym::LinkedList) + ) && let iter_ty = cx.typeck_results().expr_ty(iter_expr) && let Some(block) = get_enclosing_block(cx, l.hir_id) && let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty)) diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs b/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs index eaae8613d44..9f714fdd47b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::path_res; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::local_used_after_expr; use rustc_errors::Applicability; @@ -32,7 +32,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name expr.span, "derefed type is same as origin", "try", - snippet_opt(cx, recv.span).unwrap(), + recv.span.get_source_text(cx).unwrap().to_owned(), Applicability::MachineApplicable, ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs index 5f6f027a3b5..cc0d432b799 100644 --- a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs @@ -1,6 +1,6 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local}; use itertools::Itertools; use rustc_ast::LitKind; @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>( _ => return, } && !is_from_proc_macro(cx, expr) - && let Some(scrutinee_snip) = snippet_opt(cx, scrutinee.span) + && let Some(scrutinee_snip) = scrutinee.span.get_source_text(cx) { // Normalize the char using `map` so `join` doesn't use `Display`, if we don't then // something like `r"\"` will become `'\'`, which is of course invalid diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs index f6184222d8e..64eb8411795 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; @@ -38,11 +38,11 @@ pub(super) fn check( return; }; let both_calls_span = get_call_span.with_hi(call_span.hi()); - if let Some(snippet) = snippet_opt(cx, both_calls_span) - && let Some(arg_snippet) = snippet_opt(cx, arg.span) + if let Some(snippet) = both_calls_span.get_source_text(cx) + && let Some(arg_snippet) = arg.span.get_source_text(cx) { let generics_snippet = if let Some(generics) = path.args - && let Some(generics_snippet) = snippet_opt(cx, generics.span_ext) + && let Some(generics_snippet) = generics.span_ext.get_source_text(cx) { format!("::{generics_snippet}") } else { @@ -63,7 +63,7 @@ pub(super) fn check( suggestion, Applicability::MaybeIncorrect, ); - } else if let Some(caller_snippet) = snippet_opt(cx, get_caller.span) { + } else if let Some(caller_snippet) = get_caller.span.get_source_text(cx) { let full_span = get_caller.span.with_hi(call_span.hi()); span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 70885e46e95..4d18bc7ac77 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -1,7 +1,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local}; @@ -40,7 +40,7 @@ pub fn check_for_loop_iter( && let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent) && let (clone_or_copy_needed, references_to_binding) = clone_or_copy_needed(cx, pat, body) && !clone_or_copy_needed - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { // Issue 12098 // https://github.com/rust-lang/rust-clippy/issues/12098 @@ -100,7 +100,7 @@ pub fn check_for_loop_iter( && implements_trait(cx, collection_ty, into_iterator_trait_id, &[]) && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item") && iter_item_ty == into_iter_item_ty - && let Some(collection_snippet) = snippet_opt(cx, collection.span) + && let Some(collection_snippet) = collection.span.get_source_text(cx) { collection_snippet } else { @@ -122,7 +122,7 @@ pub fn check_for_loop_iter( } else { Applicability::MachineApplicable }; - diag.span_suggestion(expr.span, "use", snippet, applicability); + diag.span_suggestion(expr.span, "use", snippet.to_owned(), applicability); if !references_to_binding.is_empty() { diag.multipart_suggestion( "remove any references to the binding", diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 4429f032605..b84594c0da1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -64,9 +64,9 @@ pub(super) fn check<'tcx>( // but prefer to avoid changing the signature of the function itself. if let hir::ExprKind::MethodCall(.., span) = expr.kind { span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| { - diag.span_suggestion( + diag.span_suggestion_verbose( span, - format!("use `{simplify_using}(..)` instead"), + format!("use `{simplify_using}` instead"), format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")), applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index fed2b128dcf..69c5bc57e29 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -2,7 +2,7 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_config::msrvs::{self, Msrv}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, SpanRangeExt}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{ @@ -133,7 +133,7 @@ fn check_addr_of_expr( && (*referent_ty != receiver_ty || (matches!(referent_ty.kind(), ty::Array(..)) && is_copy(cx, *referent_ty)) || is_cow_into_owned(cx, method_name, method_def_id)) - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { if receiver_ty == target_ty && n_target_refs >= n_receiver_refs { span_lint_and_sugg( @@ -167,7 +167,7 @@ fn check_addr_of_expr( parent.span, format!("unnecessary use of `{method_name}`"), "use", - receiver_snippet, + receiver_snippet.to_owned(), Applicability::MachineApplicable, ); } else { @@ -217,7 +217,7 @@ fn check_into_iter_call_arg( && let parent_ty = cx.typeck_results().expr_ty(parent) && implements_trait(cx, parent_ty, iterator_trait_id, &[]) && let Some(item_ty) = get_iterator_item_ty(cx, parent_ty) - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { return true; @@ -309,8 +309,8 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb if let Some(parent) = get_parent_expr(cx, expr) && let Some((fn_name, argument_expr)) = get_fn_name_and_arg(cx, parent) && fn_name.as_str() == "split" - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) - && let Some(arg_snippet) = snippet_opt(cx, argument_expr.span) + && let Some(receiver_snippet) = receiver.span.get_source_text(cx) + && let Some(arg_snippet) = argument_expr.span.get_source_text(cx) { // We may end-up here because of an expression like `x.to_string().split(…)` where the type of `x` // implements `AsRef<str>` but does not implement `Deref<Target = str>`. In this case, we have to @@ -405,7 +405,7 @@ fn check_other_call_arg<'tcx>( None } && can_change_type(cx, maybe_arg, receiver_ty) - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + && let Some(receiver_snippet) = receiver.span.get_source_text(cx) { span_lint_and_sugg( cx, @@ -695,7 +695,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx && let arg_ty = arg_ty.peel_refs() // For now we limit this lint to `String` and `Vec`. && (is_str_and_string(cx, arg_ty, original_arg_ty) || is_slice_and_vec(cx, arg_ty, original_arg_ty)) - && let Some(snippet) = snippet_opt(cx, caller.span) + && let Some(snippet) = caller.span.get_source_text(cx) { span_lint_and_sugg( cx, @@ -706,7 +706,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx if original_arg_ty.is_array() { format!("{snippet}.as_slice()") } else { - snippet + snippet.to_owned() }, Applicability::MaybeIncorrect, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs index 3004d9c4233..ee5177d1ffa 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, SpanRangeExt}; use clippy_utils::{expr_or_init, is_trait_method, pat_is_wild}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, FnDecl, PatKind, TyKind}; @@ -81,8 +81,14 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, let new_closure_param = match find_elem_explicit_type_span(closure.fn_decl) { // We have an explicit type. Get its snippet, that of the binding name, and do `binding: ty`. // Fallback to `..` if we fail getting either snippet. - Some(ty_span) => snippet_opt(cx, elem.span) - .and_then(|binding_name| snippet_opt(cx, ty_span).map(|ty_name| format!("{binding_name}: {ty_name}"))) + Some(ty_span) => elem + .span + .get_source_text(cx) + .and_then(|binding_name| { + ty_span + .get_source_text(cx) + .map(|ty_name| format!("{binding_name}: {ty_name}")) + }) .unwrap_or_else(|| "..".to_string()), // Otherwise, we have no explicit type. We can replace with the binding name of the element. None => snippet(cx, elem.span, "..").into_owned(), diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs index 53fa444e93c..c83e5198c27 100644 --- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs +++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs @@ -41,14 +41,14 @@ declare_clippy_lint! { impl_lint_pass!(MinIdentChars => [MIN_IDENT_CHARS]); pub struct MinIdentChars { - allowed_idents_below_min_chars: &'static FxHashSet<String>, + allowed_idents_below_min_chars: FxHashSet<String>, min_ident_chars_threshold: u64, } impl MinIdentChars { pub fn new(conf: &'static Conf) -> Self { Self { - allowed_idents_below_min_chars: &conf.allowed_idents_below_min_chars, + allowed_idents_below_min_chars: conf.allowed_idents_below_min_chars.iter().cloned().collect(), min_ident_chars_threshold: conf.min_ident_chars_threshold, } } diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs index 6db03adf44a..33ab94e00a5 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; +use itertools::Itertools; use rustc_ast::ast::{Pat, PatKind}; use rustc_lint::EarlyContext; @@ -45,19 +46,6 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { "you matched a field with a wildcard pattern, consider using `..` instead", ); } else { - let mut normal = vec![]; - - for field in pfields { - match field.pat.kind { - PatKind::Wild => {}, - _ => { - if let Some(n) = snippet_opt(cx, field.span) { - normal.push(n); - } - }, - } - } - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( cx, @@ -65,7 +53,16 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { field.span, "you matched a field with a wildcard pattern, consider using `..` instead", |diag| { - diag.help(format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", "))); + diag.help(format!( + "try with `{type_name} {{ {}, .. }}`", + pfields + .iter() + .filter_map(|f| match f.pat.kind { + PatKind::Wild => None, + _ => f.span.get_source_text(cx), + }) + .format(", "), + )); }, ); } diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs index cdf6645b3df..59f29d242ab 100644 --- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs +++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::def_path_def_ids; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefIdMap; @@ -73,7 +73,7 @@ impl LateLintPass<'_> for ImportRename { && let Some(name) = self.renames.get(&id) // Remove semicolon since it is not present for nested imports && let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';') - && let Some(snip) = snippet_opt(cx, span_without_semi) + && let Some(snip) = span_without_semi.get_source_text(cx) && let Some(import) = match snip.split_once(" as ") { None => Some(snip.as_str()), Some((import, rename)) => { diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs index 83af9979b9e..f52b3a6a5a1 100644 --- a/src/tools/clippy/clippy_lints/src/mut_key.rs +++ b/src/tools/clippy/clippy_lints/src/mut_key.rs @@ -125,14 +125,12 @@ impl<'tcx> MutableKeyType<'tcx> { // generics (because the compiler cannot ensure immutability for unknown types). fn check_ty_(&mut self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) { let ty = ty.peel_refs(); - if let ty::Adt(def, args) = ty.kind() { - let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet] - .iter() - .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did())); - if !is_keyed_type { - return; - } - + if let ty::Adt(def, args) = ty.kind() + && matches!( + cx.tcx.get_diagnostic_name(def.did()), + Some(sym::HashMap | sym::BTreeMap | sym::HashSet | sym::BTreeSet) + ) + { let subst_ty = args.type_at(0); if self.interior_mut.is_interior_mut_ty(cx, subst_ty) { span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type"); diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs index 853e476a006..38841496458 100644 --- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs +++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs @@ -1,7 +1,3 @@ -//! Checks for usage of mutex where an atomic value could be used -//! -//! This lint is **allow** by default - use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_type_diagnostic_item; use rustc_hir::Expr; diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index 9cb4fa41c73..df155a7a412 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -1,7 +1,3 @@ -//! Checks for needless boolean results of if-else expressions -//! -//! This lint is **warn** by default - use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs index b97cb4579ca..ce97370d4d9 100644 --- a/src/tools/clippy/clippy_lints/src/needless_continue.rs +++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs @@ -1,38 +1,3 @@ -//! Checks for continue statements in loops that are redundant. -//! -//! For example, the lint would catch -//! -//! ```rust -//! let mut a = 1; -//! let x = true; -//! -//! while a < 5 { -//! a = 6; -//! if x { -//! // ... -//! } else { -//! continue; -//! } -//! println!("Hello, world"); -//! } -//! ``` -//! -//! And suggest something like this: -//! -//! ```rust -//! let mut a = 1; -//! let x = true; -//! -//! while a < 5 { -//! a = 6; -//! if x { -//! // ... -//! println!("Hello, world"); -//! } -//! } -//! ``` -//! -//! This lint is **warn** by default. use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::{indent_of, snippet, snippet_block}; use rustc_ast::ast; diff --git a/src/tools/clippy/clippy_lints/src/needless_if.rs b/src/tools/clippy/clippy_lints/src/needless_if.rs index 1d6233d432a..8e14fbf2f80 100644 --- a/src/tools/clippy/clippy_lints/src/needless_if.rs +++ b/src/tools/clippy/clippy_lints/src/needless_if.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::If; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{snippet_opt, SpanRangeExt}; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -57,7 +57,7 @@ impl LateLintPass<'_> for NeedlessIf { src.bytes() .all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace()) }) - && let Some(cond_snippet) = snippet_opt(cx, cond.span) + && let Some(cond_snippet) = cond.span.get_source_text(cx) && !is_from_proc_macro(cx, expr) { span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index 4bfc30fa5cf..46cdb82130f 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::path_to_local; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{SourceText, SpanRangeExt}; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used}; use core::ops::ControlFlow; @@ -236,7 +236,7 @@ fn first_usage<'tcx>( }) } -fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option<String> { +fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option<SourceText> { let span = local.span.with_hi(match local.ty { // let <pat>: <ty>; // ~~~~~~~~~~~~~~~ @@ -246,7 +246,7 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> None => local.pat.span.hi(), }); - snippet_opt(cx, span) + span.get_source_text(cx) } fn check<'tcx>( @@ -275,7 +275,10 @@ fn check<'tcx>( |diag| { diag.multipart_suggestion( format!("move the declaration `{binding_name}` here"), - vec![(local_stmt.span, String::new()), (assign.lhs_span, let_snippet)], + vec![ + (local_stmt.span, String::new()), + (assign.lhs_span, let_snippet.to_owned()), + ], Applicability::MachineApplicable, ); }, diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index a0bbf6b14b2..addb4b1aee8 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_self; use clippy_utils::ptr::get_spans; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, SpanRangeExt}; use clippy_utils::ty::{ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; @@ -242,8 +242,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { for (span, suggestion) in clone_spans { diag.span_suggestion( span, - snippet_opt(cx, span) - .map_or("change the call to".into(), |x| format!("change `{x}` to")), + span.get_source_text(cx) + .map_or("change the call to".to_owned(), |src| format!("change `{src}` to")), suggestion, Applicability::Unspecified, ); @@ -267,8 +267,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { for (span, suggestion) in clone_spans { diag.span_suggestion( span, - snippet_opt(cx, span) - .map_or("change the call to".into(), |x| format!("change `{x}` to")), + span.get_source_text(cx) + .map_or("change the call to".to_owned(), |src| format!("change `{src}` to")), suggestion, Applicability::Unspecified, ); diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 8232e69db39..b181791699a 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::has_drop; use clippy_utils::{ in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks, @@ -268,34 +268,31 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { && reduced.iter().all(|e| e.span.ctxt() == ctxt) { if let ExprKind::Index(..) = &expr.kind { - if is_inside_always_const_context(cx.tcx, expr.hir_id) { - return; + if !is_inside_always_const_context(cx.tcx, expr.hir_id) + && let [arr, func] = &*reduced + && let Some(arr) = arr.span.get_source_text(cx) + && let Some(func) = func.span.get_source_text(cx) + { + span_lint_hir_and_then( + cx, + UNNECESSARY_OPERATION, + expr.hir_id, + stmt.span, + "unnecessary operation", + |diag| { + diag.span_suggestion( + stmt.span, + "statement can be written as", + format!("assert!({arr}.len() > {func});"), + Applicability::MaybeIncorrect, + ); + }, + ); } - let snippet = - if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) { - format!("assert!({arr}.len() > {func});") - } else { - return; - }; - span_lint_hir_and_then( - cx, - UNNECESSARY_OPERATION, - expr.hir_id, - stmt.span, - "unnecessary operation", - |diag| { - diag.span_suggestion( - stmt.span, - "statement can be written as", - snippet, - Applicability::MaybeIncorrect, - ); - }, - ); } else { let mut snippet = String::new(); for e in reduced { - if let Some(snip) = snippet_opt(cx, e.span) { + if let Some(snip) = e.span.get_source_text(cx) { snippet.push_str(&snip); snippet.push(';'); } else { diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 6915cd40615..25f547f1a43 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -1,7 +1,3 @@ -//! Checks for usage of const which the type is not `Freeze` (`Cell`-free). -//! -//! This lint is **warn** by default. - use std::ptr; use clippy_config::Conf; @@ -188,7 +184,7 @@ impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTE impl<'tcx> NonCopyConst<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self { Self { - interior_mut: InteriorMut::new(tcx, &conf.ignore_interior_mutability), + interior_mut: InteriorMut::without_pointers(tcx, &conf.ignore_interior_mutability), } } diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs index 2aaf1e6ff46..51ba29d7389 100644 --- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs +++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,7 +1,7 @@ use clippy_config::types::MacroMatcher; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{SourceText, SpanRangeExt}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; @@ -34,7 +34,7 @@ declare_clippy_lint! { } /// The (callsite span, (open brace, close brace), source snippet) -type MacroInfo = (Span, (char, char), String); +type MacroInfo = (Span, (char, char), SourceText); pub struct MacroBraces { macro_braces: FxHashMap<String, (char, char)>, @@ -94,7 +94,7 @@ fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBrace if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind && let name = mac_name.as_str() && let Some(&braces) = mac_braces.macro_braces.get(name) - && let Some(snip) = snippet_opt(cx, span_call_site) + && let Some(snip) = span_call_site.get_source_text(cx) // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 && snip.starts_with(&format!("{name}!")) diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index bc71a4790b9..8b9f899d82d 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -35,7 +35,7 @@ impl ArithmeticSideEffects { ("f64", FxHashSet::from_iter(["f64"])), ("std::string::String", FxHashSet::from_iter(["str"])), ]); - for [lhs, rhs] in &conf.arithmetic_side_effects_allowed_binary { + for (lhs, rhs) in &conf.arithmetic_side_effects_allowed_binary { allowed_binary.entry(lhs).or_default().insert(rhs); } for s in &conf.arithmetic_side_effects_allowed { diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs index 641d881d974..11c97b4ef00 100644 --- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method}; @@ -46,8 +46,8 @@ pub(super) fn check<'tcx>( expr.span, "manual implementation of an assign operation", |diag| { - if let (Some(snip_a), Some(snip_r)) = - (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) + if let Some(snip_a) = assignee.span.get_source_text(cx) + && let Some(snip_r) = rhs.span.get_source_text(cx) { diag.span_suggestion( expr.span, diff --git a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs index 311cbd050a1..8daedd1c901 100644 --- a/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/src/tools/clippy/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{eq_expr_value, sugg}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -42,7 +42,9 @@ fn lint_misrefactored_assign_op( expr.span, "variable appears on both sides of an assignment operation", |diag| { - if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) { + if let Some(snip_a) = assignee.span.get_source_text(cx) + && let Some(snip_r) = rhs_other.span.get_source_text(cx) + { let a = &sugg::Sugg::hir(cx, assignee, ".."); let r = &sugg::Sugg::hir(cx, rhs, ".."); let long = format!("{snip_a} = {}", sugg::make_binop(op, a, r)); diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index 9baecff801f..9e8a821c3f4 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -80,7 +80,7 @@ declare_clippy_lint! { /// ```no_run /// // `n` can be any number, including `i32::MAX`. /// fn foo(n: i32) -> i32 { - /// n + 1 + /// n + 1 /// } /// ``` /// diff --git a/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs b/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs index ab5fb178700..9d8e833ef6d 100644 --- a/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs +++ b/src/tools/clippy/clippy_lints/src/operators/needless_bitwise_bool.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -24,8 +24,8 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp e.span, "use of bitwise operator instead of lazy operator between booleans", |diag| { - if let Some(lhs_snip) = snippet_opt(cx, lhs.span) - && let Some(rhs_snip) = snippet_opt(cx, rhs.span) + if let Some(lhs_snip) = lhs.span.get_source_text(cx) + && let Some(rhs_snip) = rhs.span.get_source_text(cx) { let sugg = format!("{lhs_snip} {op_str} {rhs_snip}"); diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable); diff --git a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs index 607930561e0..861564d5456 100644 --- a/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs +++ b/src/tools/clippy/clippy_lints/src/operators/ptr_eq.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::std_or_core; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; @@ -22,8 +22,8 @@ pub(super) fn check<'tcx>( if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left) && let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right) - && let Some(left_snip) = snippet_opt(cx, left_var.span) - && let Some(right_snip) = snippet_opt(cx, right_var.span) + && let Some(left_snip) = left_var.span.get_source_text(cx) + && let Some(right_snip) = right_var.span.get_source_text(cx) { let Some(top_crate) = std_or_core(cx) else { return }; span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs index 18bfb588a11..d7fa48c1e38 100644 --- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::path_to_local_id; -use clippy_utils::source::{snippet, snippet_opt}; +use clippy_utils::source::{snippet, SpanRangeExt}; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; @@ -74,7 +74,7 @@ impl<'tcx> PathbufPushSearcher<'tcx> { && let Some(arg) = self.arg && let ExprKind::Lit(x) = arg.kind && let LitKind::Str(_, StrStyle::Cooked) = x.node - && let Some(s) = snippet_opt(cx, arg.span) + && let Some(s) = arg.span.get_source_text(cx) { Some(format!(" = PathBuf::from({s});")) } else { @@ -84,8 +84,8 @@ impl<'tcx> PathbufPushSearcher<'tcx> { fn gen_pathbuf_join(&self, cx: &LateContext<'_>) -> Option<String> { let arg = self.arg?; - let arg_str = snippet_opt(cx, arg.span)?; - let init_val = snippet_opt(cx, self.init_val.span)?; + let arg_str = arg.span.get_source_text(cx)?; + let init_val = self.init_val.span.get_source_text(cx)?; Some(format!(" = {init_val}.join({arg_str});")) } diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 02c05e0aaf9..125f694996c 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -1,7 +1,5 @@ -//! Checks for usage of `&Vec[_]` and `&String`. - use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::expr_sig; use clippy_utils::visitors::contains_unsafe_block; use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local}; @@ -243,7 +241,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { .chain(result.replacements.iter().map(|r| { ( r.expr_span, - format!("{}{}", snippet_opt(cx, r.self_span).unwrap(), r.replacement), + format!("{}{}", r.self_span.get_source_text(cx).unwrap(), r.replacement), ) })) .collect(), @@ -372,7 +370,7 @@ impl fmt::Display for DerefTyDisplay<'_, '_> { DerefTy::Path => f.write_str("Path"), DerefTy::Slice(hir_ty, ty) => { f.write_char('[')?; - match hir_ty.and_then(|s| snippet_opt(self.0, s)) { + match hir_ty.and_then(|s| s.get_source_text(self.0)) { Some(s) => f.write_str(&s)?, None => ty.fmt(f)?, } @@ -413,6 +411,7 @@ impl<'tcx> DerefTy<'tcx> { } } +#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, @@ -488,8 +487,6 @@ fn check_fn_args<'cx, 'tcx: 'cx>( return None; } - let ty_name = snippet_opt(cx, ty.span()).unwrap_or_else(|| args.type_at(1).to_string()); - span_lint_hir_and_then( cx, PTR_ARG, @@ -500,7 +497,10 @@ fn check_fn_args<'cx, 'tcx: 'cx>( diag.span_suggestion( hir_ty.span, "change this to", - format!("&{}{ty_name}", mutability.prefix_str()), + match ty.span().get_source_text(cx) { + Some(s) => format!("&{}{s}", mutability.prefix_str()), + None => format!("&{}{}", mutability.prefix_str(), args.type_at(1)), + }, Applicability::Unspecified, ); }, diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs index 7c82895d609..87a52cb2186 100644 --- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs +++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -120,8 +120,8 @@ fn build_suggestion( receiver_expr: &Expr<'_>, cast_lhs_expr: &Expr<'_>, ) -> Option<String> { - let receiver = snippet_opt(cx, receiver_expr.span)?; - let cast_lhs = snippet_opt(cx, cast_lhs_expr.span)?; + let receiver = receiver_expr.span.get_source_text(cx)?; + let cast_lhs = cast_lhs_expr.span.get_source_text(cx)?; Some(format!("{receiver}.{}({cast_lhs})", method.suggestion())) } diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index a1231c082e6..bfdc1cbeed7 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth}; use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths}; use rustc_errors::Applicability; @@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { .assert_crate_local() .lint_root; - if let Some(snip) = snippet_opt(cx, span) + if let Some(snip) = span.get_source_text(cx) && let Some(dot) = snip.rfind('.') { let sugg_span = span.with_lo(span.lo() + BytePos(u32::try_from(dot).unwrap())); diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs index 8f32cf5f2a1..2b4ef21fc48 100644 --- a/src/tools/clippy/clippy_lints/src/reference.rs +++ b/src/tools/clippy/clippy_lints/src/reference.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::source::{snippet_with_applicability, SpanRangeExt}; use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::BytePos; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -56,11 +56,11 @@ impl EarlyLintPass for DerefAddrOf { { let mut applicability = Applicability::MachineApplicable; let sugg = if e.span.from_expansion() { - if let Some(macro_source) = snippet_opt(cx, e.span) { + if let Some(macro_source) = e.span.get_source_text(cx) { // Remove leading whitespace from the given span // e.g: ` $visitor` turns into `$visitor` - let trim_leading_whitespaces = |span| { - snippet_opt(cx, span) + let trim_leading_whitespaces = |span: Span| { + span.get_source_text(cx) .and_then(|snip| { #[expect(clippy::cast_possible_truncation)] snip.find(|c: char| !c.is_whitespace()) diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index 95014b23043..f6ef02b7c23 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -2,7 +2,7 @@ use std::fmt::Display; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::{def_path_def_ids, path_def_id, paths}; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; @@ -122,7 +122,7 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescape }; if let Some((primary, auxiliary, kind)) = parts - && let Some(literal_snippet) = snippet_opt(cx, base) + && let Some(literal_snippet) = base.get_source_text(cx) && let Some(inner) = literal_snippet.get(offset as usize..) // Only convert to native rustc spans if the parsed regex matches the // source snippet exactly, to ensure the span offsets are correct diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 13016cdadb0..5ce091b7a7a 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::source::{snippet_opt, snippet_with_context}; +use clippy_utils::source::{snippet_with_context, SpanRangeExt}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::{for_each_expr, Descend}; use clippy_utils::{ @@ -250,20 +250,25 @@ impl<'tcx> LateLintPass<'tcx> for Return { |err| { err.span_label(local.span, "unnecessary `let` binding"); - if let Some(mut snippet) = snippet_opt(cx, initexpr.span) { - if binary_expr_needs_parentheses(initexpr) { - if !has_enclosing_paren(&snippet) { - snippet = format!("({snippet})"); + if let Some(src) = initexpr.span.get_source_text(cx) { + let sugg = if binary_expr_needs_parentheses(initexpr) { + if has_enclosing_paren(&src) { + src.to_owned() + } else { + format!("({src})") } } else if !cx.typeck_results().expr_adjustments(retexpr).is_empty() { - if !has_enclosing_paren(&snippet) { - snippet = format!("({snippet})"); + if has_enclosing_paren(&src) { + format!("{src} as _") + } else { + format!("({src}) as _") } - snippet.push_str(" as _"); - } + } else { + src.to_owned() + }; err.multipart_suggestion( "return the expression directly", - vec![(local.span, String::new()), (retexpr.span, snippet)], + vec![(local.span, String::new()), (retexpr.span, sugg)], Applicability::MachineApplicable, ); } else { @@ -394,7 +399,7 @@ fn check_final_expr<'tcx>( // Returns may be used to turn an expression into a statement in rustc's AST. // This allows the addition of attributes, like `#[allow]` (See: clippy#9361) - // `#[expect(clippy::needless_return)]` needs to be handled separatly to + // `#[expect(clippy::needless_return)]` needs to be handled separately to // actually fulfill the expectation (clippy::#12998) match cx.tcx.hir().attrs(expr.hir_id) { [] => {}, diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs index e0558429638..44e585953bf 100644 --- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs +++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_trait_def_id; use clippy_utils::higher::VecArgs; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use rustc_ast::{LitIntType, LitKind, UintTy}; use rustc_errors::Applicability; @@ -92,12 +92,12 @@ impl LateLintPass<'_> for SingleRangeInVecInit { if matches!(lang_item, LangItem::Range) && let ty = cx.typeck_results().expr_ty(start.expr) - && let Some(snippet) = snippet_opt(cx, span) + && let Some(snippet) = span.get_source_text(cx) // `is_from_proc_macro` will skip any `vec![]`. Let's not! && snippet.starts_with(suggested_type.starts_with()) && snippet.ends_with(suggested_type.ends_with()) - && let Some(start_snippet) = snippet_opt(cx, start.span) - && let Some(end_snippet) = snippet_opt(cx, end.span) + && let Some(start_snippet) = start.span.get_source_text(cx) + && let Some(end_snippet) = end.span.get_source_text(cx) { let should_emit_every_value = if let Some(step_def_id) = get_trait_def_id(cx.tcx, &["core", "iter", "Step"]) && implements_trait(cx, ty, step_def_id, &[]) diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs index 01f0e3cfadb..7750d8909d3 100644 --- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs +++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs @@ -1,6 +1,3 @@ -//! Lint on use of `size_of` or `size_of_val` of T in an expression -//! expecting a count of T - use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index 974e21df817..44283a49e84 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -9,7 +9,6 @@ use rustc_hir::def_id::DefId; use rustc_hir::{HirId, Path, PathSegment}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_semver::RustcVersion; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{sym, Span}; @@ -185,9 +184,7 @@ fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: &Msrv) -> bool { } = stability.level { let stable = match since { - StableSince::Version(v) => { - msrv.meets(RustcVersion::new(v.major.into(), v.minor.into(), v.patch.into())) - }, + StableSince::Version(v) => msrv.meets(v), StableSince::Current => msrv.current().is_none(), StableSince::Err => false, }; diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index cfc387886dc..6ca4ca000e9 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -190,7 +190,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { } }, ExprKind::Index(target, _idx, _) => { - let e_ty = cx.typeck_results().expr_ty(target).peel_refs(); + let e_ty = cx.typeck_results().expr_ty_adjusted(target).peel_refs(); if e_ty.is_str() || is_type_lang_item(cx, e_ty, LangItem::String) { span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 59b74122f30..2e87d36df31 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -1,7 +1,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; +use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt}; use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash}; use core::hash::{Hash, Hasher}; use itertools::Itertools; @@ -206,8 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { let fixed_trait_snippet = unique_traits .iter() - .filter_map(|b| snippet_opt(cx, b.span)) - .collect::<Vec<_>>() + .filter_map(|b| b.span.get_source_text(cx)) .join(" + "); span_lint_and_sugg( @@ -462,9 +461,8 @@ fn rollup_traits( let traits = comparable_bounds .iter() - .filter_map(|&(_, span)| snippet_opt(cx, span)) - .collect::<Vec<_>>(); - let traits = traits.join(" + "); + .filter_map(|&(_, span)| span.get_source_text(cx)) + .join(" + "); span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs index afc53e6f32d..978d49f09c3 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::source::{indent_of, reindent_multiline, SourceText, SpanRangeExt}; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; @@ -79,7 +79,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp && block.expr.is_none() && let Some(last_stmt) = block.stmts.iter().last() && let StmtKind::Semi(last_expr) = last_stmt.kind - && let Some(snip) = snippet_opt(cx, last_expr.span) + && let Some(snip) = last_expr.span.get_source_text(cx) { Some((last_stmt.span, snip)) } else { @@ -90,24 +90,24 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp db.span_suggestion( span, "remove the semicolon from the last statement in the block", - sugg, + sugg.as_str(), Applicability::MaybeIncorrect, ); or = "or "; applicability = Applicability::MaybeIncorrect; }); - let arg_snippets: Vec<String> = args_to_recover + let arg_snippets: Vec<_> = args_to_recover .iter() - .filter_map(|arg| snippet_opt(cx, arg.span)) + .filter_map(|arg| arg.span.get_source_text(cx)) .collect(); - let arg_snippets_without_empty_blocks: Vec<String> = args_to_recover + let arg_snippets_without_empty_blocks: Vec<_> = args_to_recover .iter() .filter(|arg| !is_empty_block(arg)) - .filter_map(|arg| snippet_opt(cx, arg.span)) + .filter_map(|arg| arg.span.get_source_text(cx)) .collect(); - if let Some(call_snippet) = snippet_opt(cx, expr.span) { + if let Some(call_snippet) = expr.span.get_source_text(cx) { let sugg = fmt_stmts_and_call( cx, expr, @@ -161,8 +161,8 @@ fn fmt_stmts_and_call( cx: &LateContext<'_>, call_expr: &Expr<'_>, call_snippet: &str, - args_snippets: &[impl AsRef<str>], - non_empty_block_args_snippets: &[impl AsRef<str>], + args_snippets: &[SourceText], + non_empty_block_args_snippets: &[SourceText], ) -> String { let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0); let call_snippet_with_replacements = args_snippets diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 448946bd66d..af7abd009d2 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -34,11 +34,18 @@ declare_clippy_lint! { /// ```rust,ignore /// use std::io; /// fn foo<W: io::Write>(w: &mut W) -> io::Result<()> { - /// // must be `w.write_all(b"foo")?;` /// w.write(b"foo")?; /// Ok(()) /// } /// ``` + /// Use instead: + /// ```rust,ignore + /// use std::io; + /// fn foo<W: io::Write>(w: &mut W) -> io::Result<()> { + /// w.write_all(b"foo")?; + /// Ok(()) + /// } + /// ``` #[clippy::version = "pre 1.29.0"] pub UNUSED_IO_AMOUNT, correctness, @@ -235,7 +242,7 @@ fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { /// If `expr` is an (e).await, return the inner expression "e" that's being /// waited on. Otherwise return None. -fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &hir::Expr<'a> { +fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { if let ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind { if let ExprKind::Call(func, [ref arg_0, ..]) = expr.kind { if matches!( diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index b70aa768b46..65f431d338b 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{position_before_rarrow, snippet_opt}; +use clippy_utils::source::{position_before_rarrow, SpanRangeExt}; use rustc_ast::visit::FnKind; use rustc_ast::{ast, ClosureBinder}; use rustc_errors::Applicability; @@ -128,15 +128,17 @@ fn is_unit_expr(expr: &ast::Expr) -> bool { fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { let (ret_span, appl) = - snippet_opt(cx, span.with_hi(ty.span.hi())).map_or((ty.span, Applicability::MaybeIncorrect), |fn_source| { - position_before_rarrow(&fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { - ( - #[expect(clippy::cast_possible_truncation)] - ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), - Applicability::MachineApplicable, - ) - }) - }); + span.with_hi(ty.span.hi()) + .get_source_text(cx) + .map_or((ty.span, Applicability::MaybeIncorrect), |src| { + position_before_rarrow(&src).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { + ( + #[expect(clippy::cast_possible_truncation)] + ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + Applicability::MachineApplicable, + ) + }) + }); span_lint_and_sugg( cx, UNUSED_UNIT, diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index c0d9bcdd259..0b4ea0752b6 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -89,15 +89,15 @@ enum UnwrappableKind { impl UnwrappableKind { fn success_variant_pattern(self) -> &'static str { match self { - UnwrappableKind::Option => "Some(..)", - UnwrappableKind::Result => "Ok(..)", + UnwrappableKind::Option => "Some(<item>)", + UnwrappableKind::Result => "Ok(<item>)", } } fn error_variant_pattern(self) -> &'static str { match self { UnwrappableKind::Option => "None", - UnwrappableKind::Result => "Err(..)", + UnwrappableKind::Result => "Err(<item>)", } } } diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 93785b45c27..5da48f4f7fb 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -229,7 +229,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { && let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity() && same_type_and_consts(ty, impl_ty) // Ensure the type we encounter and the one from the impl have the same lifetime parameters. It may be that - // the lifetime parameters of `ty` are ellided (`impl<'a> Foo<'a> { fn new() -> Self { Foo{..} } }`, in + // the lifetime parameters of `ty` are elided (`impl<'a> Foo<'a> { fn new() -> Self { Foo{..} } }`, in // which case we must still trigger the lint. && (has_no_lifetime(ty) || same_lifetimes(ty, impl_ty)) { diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 316c1f32d3a..0cce45290cf 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -1,6 +1,3 @@ -//! A group of attributes that can be attached to Rust code in order -//! to generate a clippy lint detecting said code automatically. - use clippy_utils::{get_attr, higher}; use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::LitIntType; diff --git a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs index 5acfd35fd6a..f50ce6c99de 100644 --- a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs @@ -1,5 +1,5 @@ use clippy_utils::macros::FormatArgsStorage; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use itertools::Itertools; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; @@ -75,38 +75,21 @@ fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool { // `format!("{} {} {c}", "one", "two", c = "three")` // ^^ ^^ ^^^^^^ - let between_spans = once(args.span) + !once(args.span) .chain(argument_span) .tuple_windows() - .map(|(start, end)| start.between(end)); - - for between_span in between_spans { - let mut seen_comma = false; - - let Some(snippet) = snippet_opt(cx, between_span) else { - return true; - }; - for token in tokenize(&snippet) { - match token.kind { - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {}, - TokenKind::Comma if !seen_comma => seen_comma = true, - // named arguments, `start_val, name = end_val` - // ^^^^^^^^^ between_span - TokenKind::Ident | TokenKind::Eq if seen_comma => {}, - // An unexpected token usually indicates that we crossed a macro boundary - // - // `println!(some_proc_macro!("input {}"), a)` - // ^^^ between_span - // `println!("{}", val!(x))` - // ^^^^^^^ between_span - _ => return true, - } - } - - if !seen_comma { - return true; - } - } - - false + .map(|(start, end)| start.between(end)) + .all(|sp| { + sp.check_source_text(cx, |src| { + // text should be either `, name` or `, name =` + let mut iter = tokenize(src).filter(|t| { + !matches!( + t.kind, + TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace + ) + }); + iter.next().is_some_and(|t| matches!(t.kind, TokenKind::Comma)) + && iter.all(|t| matches!(t.kind, TokenKind::Ident | TokenKind::Eq)) + }) + }) } diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index 1d294c2944b..f662c7651f6 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -3,7 +3,6 @@ pub mod collapsible_calls; pub mod interning_defined_symbol; pub mod invalid_paths; pub mod lint_without_lint_pass; -pub mod metadata_collector; pub mod msrv_attr_impl; pub mod outer_expn_data_pass; pub mod produce_ice; diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs index df342e48d63..20526113d69 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs @@ -9,7 +9,6 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_semver::RustcVersion; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::Symbol; @@ -92,7 +91,12 @@ pub struct LintWithoutLintPass { registered_lints: FxHashSet<Symbol>, } -impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE]); +impl_lint_pass!(LintWithoutLintPass => [ + DEFAULT_LINT, + LINT_WITHOUT_LINT_PASS, + INVALID_CLIPPY_VERSION_ATTRIBUTE, + MISSING_CLIPPY_VERSION_ATTRIBUTE, +]); impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { @@ -220,7 +224,7 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<' return; } - if RustcVersion::parse(value.as_str()).is_err() { + if rustc_attr::parse_version(value).is_none() { span_lint_and_help( cx, INVALID_CLIPPY_VERSION_ATTRIBUTE, diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs deleted file mode 100644 index 57f45aa3e48..00000000000 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ /dev/null @@ -1,1078 +0,0 @@ -//! This lint is used to collect metadata about clippy lints. This metadata is exported as a json -//! file and then used to generate the [clippy lint list](https://rust-lang.github.io/rust-clippy/master/index.html) -//! -//! This module and therefore the entire lint is guarded by a feature flag called `internal` -//! -//! The module transforms all lint names to ascii lowercase to ensure that we don't have mismatches -//! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such -//! a simple mistake) - -use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}; -use clippy_config::{get_configuration_metadata, ClippyConfiguration}; - -use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::{match_type, walk_ptrs_ty_depth}; -use clippy_utils::{last_path_segment, match_function_call, match_path, paths}; -use itertools::Itertools; -use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def::DefKind; -use rustc_hir::intravisit::Visitor; -use rustc_hir::{self as hir, intravisit, Closure, ExprKind, Item, ItemKind, Mutability, QPath}; -use rustc_lint::{unerased_lint_store, CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId}; -use rustc_middle::hir::nested_filter; -use rustc_session::impl_lint_pass; -use rustc_span::symbol::Ident; -use rustc_span::{sym, Loc, Span, Symbol}; -use serde::ser::SerializeStruct; -use serde::{Serialize, Serializer}; -use std::collections::{BTreeSet, BinaryHeap}; -use std::fmt::Write as _; -use std::fs::{self, File}; -use std::io::prelude::*; -use std::path::{Path, PathBuf}; -use std::process::Command; -use std::{env, fmt}; - -/// This is the json output file of the lint collector. -const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json"; -/// This is the markdown output file of the lint collector. -const MARKDOWN_OUTPUT_FILE: &str = "../book/src/lint_configuration.md"; -/// These groups will be ignored by the lint group matcher. This is useful for collections like -/// `clippy::all` -const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"]; -/// Lints within this group will be excluded from the collection. These groups -/// have to be defined without the `clippy::` prefix. -const EXCLUDED_LINT_GROUPS: [&str; 1] = ["internal"]; -/// Collected deprecated lint will be assigned to this group in the JSON output -const DEPRECATED_LINT_GROUP_STR: &str = "deprecated"; -/// This is the lint level for deprecated lints that will be displayed in the lint list -const DEPRECATED_LINT_LEVEL: &str = "none"; -/// This array holds Clippy's lint groups with their corresponding default lint level. The -/// lint level for deprecated lints is set in `DEPRECATED_LINT_LEVEL`. -const DEFAULT_LINT_LEVELS: &[(&str, &str)] = &[ - ("correctness", "deny"), - ("suspicious", "warn"), - ("restriction", "allow"), - ("style", "warn"), - ("pedantic", "allow"), - ("complexity", "warn"), - ("perf", "warn"), - ("cargo", "allow"), - ("nursery", "allow"), -]; -/// This prefix is in front of the lint groups in the lint store. The prefix will be trimmed -/// to only keep the actual lint group in the output. -const CLIPPY_LINT_GROUP_PREFIX: &str = "clippy::"; -const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [ - &["clippy_utils", "diagnostics", "span_lint"], - &["clippy_utils", "diagnostics", "span_lint_and_help"], - &["clippy_utils", "diagnostics", "span_lint_and_note"], - &["clippy_utils", "diagnostics", "span_lint_hir"], - &["clippy_utils", "diagnostics", "span_lint_and_sugg"], - &["clippy_utils", "diagnostics", "span_lint_and_then"], - &["clippy_utils", "diagnostics", "span_lint_hir_and_then"], -]; -const SUGGESTION_DIAG_METHODS: [(&str, bool); 9] = [ - ("span_suggestion", false), - ("span_suggestion_short", false), - ("span_suggestion_verbose", false), - ("span_suggestion_hidden", false), - ("tool_only_span_suggestion", false), - ("multipart_suggestion", true), - ("multipart_suggestions", true), - ("tool_only_multipart_suggestion", true), - ("span_suggestions", true), -]; - -/// The index of the applicability name of `paths::APPLICABILITY_VALUES` -const APPLICABILITY_NAME_INDEX: usize = 2; -/// This applicability will be set for unresolved applicability values. -const APPLICABILITY_UNRESOLVED_STR: &str = "Unresolved"; -/// The version that will be displayed if none has been defined -const VERSION_DEFAULT_STR: &str = "Unknown"; - -const CHANGELOG_PATH: &str = "../CHANGELOG.md"; - -declare_clippy_lint! { - /// ### What it does - /// Collects metadata about clippy lints for the website. - /// - /// This lint will be used to report problems of syntax parsing. You should hopefully never - /// see this but never say never I guess ^^ - /// - /// ### Why is this bad? - /// This is not a bad thing but definitely a hacky way to do it. See - /// issue [#4310](https://github.com/rust-lang/rust-clippy/issues/4310) for a discussion - /// about the implementation. - /// - /// ### Known problems - /// Hopefully none. It would be pretty uncool to have a problem here :) - /// - /// ### Example output - /// ```json,ignore - /// { - /// "id": "metadata_collector", - /// "id_span": { - /// "path": "clippy_lints/src/utils/internal_lints/metadata_collector.rs", - /// "line": 1 - /// }, - /// "group": "clippy::internal", - /// "docs": " ### What it does\nCollects metadata about clippy lints for the website. [...] " - /// } - /// ``` - #[clippy::version = "1.56.0"] - pub METADATA_COLLECTOR, - internal, - "A busy bee collection metadata about lints" -} - -impl_lint_pass!(MetadataCollector => [METADATA_COLLECTOR]); - -#[allow(clippy::module_name_repetitions)] -#[derive(Debug, Clone)] -pub struct MetadataCollector { - /// All collected lints - /// - /// We use a Heap here to have the lints added in alphabetic order in the export - lints: BinaryHeap<LintMetadata>, - applicability_info: FxHashMap<String, ApplicabilityInfo>, - config: Vec<ClippyConfiguration>, - clippy_project_root: PathBuf, -} - -impl MetadataCollector { - pub fn new() -> Self { - Self { - lints: BinaryHeap::<LintMetadata>::default(), - applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(), - config: get_configuration_metadata(), - clippy_project_root: env::current_dir() - .expect("failed to get current dir") - .ancestors() - .nth(1) - .expect("failed to get project root") - .to_path_buf(), - } - } - - fn get_lint_configs(&self, lint_name: &str) -> Option<String> { - self.config - .iter() - .filter(|config| config.lints.iter().any(|&lint| lint == lint_name)) - .map(ToString::to_string) - .reduce(|acc, x| acc + "\n\n" + &x) - .map(|configurations| { - format!( - r#" -### Configuration -This lint has the following configuration variables: - -{configurations} -"# - ) - }) - } - - fn configs_to_markdown(&self, map_fn: fn(&ClippyConfiguration) -> String) -> String { - self.config - .iter() - .filter(|config| config.deprecation_reason.is_none()) - .filter(|config| !config.lints.is_empty()) - .map(map_fn) - .join("\n") - } - - fn get_markdown_docs(&self) -> String { - format!( - r#"# Lint Configuration Options - -The following list shows each configuration option, along with a description, its default value, an example -and lints affected. - ---- - -{}"#, - self.configs_to_markdown(ClippyConfiguration::to_markdown_paragraph), - ) - } -} - -impl Drop for MetadataCollector { - /// You might ask: How hacky is this? - /// My answer: YES - fn drop(&mut self) { - // The metadata collector gets dropped twice, this makes sure that we only write - // when the list is full - if self.lints.is_empty() { - return; - } - - let mut applicability_info = std::mem::take(&mut self.applicability_info); - - // Add deprecated lints - self.lints.extend( - crate::deprecated_lints::DEPRECATED - .iter() - .zip(crate::deprecated_lints::DEPRECATED_VERSION) - .filter_map(|((lint, reason), version)| LintMetadata::new_deprecated(lint, reason, version)), - ); - // Mapping the final data - let mut lints = std::mem::take(&mut self.lints).into_sorted_vec(); - for x in &mut lints { - x.applicability = Some(applicability_info.remove(&x.id).unwrap_or_default()); - replace_produces(&x.id, &mut x.docs, &self.clippy_project_root); - } - - collect_renames(&mut lints); - - // Outputting json - fs::write(JSON_OUTPUT_FILE, serde_json::to_string_pretty(&lints).unwrap()).unwrap(); - - // Outputting markdown - let mut file = File::create(MARKDOWN_OUTPUT_FILE).unwrap(); - writeln!( - file, - "<!-- -This file is generated by `cargo collect-metadata`. -Please use that command to update the file and do not edit it by hand. ---> - -{}", - self.get_markdown_docs(), - ) - .unwrap(); - - // Write configuration links to CHANGELOG.md - let changelog = fs::read_to_string(CHANGELOG_PATH).unwrap(); - let mut changelog_file = File::create(CHANGELOG_PATH).unwrap(); - let position = changelog - .find("<!-- begin autogenerated links to configuration documentation -->") - .unwrap(); - writeln!( - changelog_file, - "{}<!-- begin autogenerated links to configuration documentation -->\n{}\n<!-- end autogenerated links to configuration documentation -->", - &changelog[..position], - self.configs_to_markdown(ClippyConfiguration::to_markdown_link) - ) - .unwrap(); - } -} - -#[derive(Debug, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)] -struct LintMetadata { - id: String, - id_span: Option<SerializableSpan>, - group: String, - level: String, - docs: String, - version: String, - /// This field is only used in the output and will only be - /// mapped shortly before the actual output. - applicability: Option<ApplicabilityInfo>, - /// All the past names of lints which have been renamed. - #[serde(skip_serializing_if = "BTreeSet::is_empty")] - former_ids: BTreeSet<String>, -} - -impl LintMetadata { - fn new( - id: String, - id_span: SerializableSpan, - group: String, - level: &'static str, - version: String, - docs: String, - ) -> Self { - Self { - id, - id_span: Some(id_span), - group, - level: level.to_string(), - version, - docs, - applicability: None, - former_ids: BTreeSet::new(), - } - } - - fn new_deprecated(name: &str, reason: &str, version: &str) -> Option<Self> { - // The reason starts with a lowercase letter and end without a period. - // This needs to be fixed for the website. - let mut reason = reason.to_owned(); - if let Some(reason) = reason.get_mut(0..1) { - reason.make_ascii_uppercase(); - } - name.strip_prefix("clippy::").map(|name| Self { - id: name.into(), - id_span: None, - group: DEPRECATED_LINT_GROUP_STR.into(), - level: DEPRECATED_LINT_LEVEL.into(), - version: version.into(), - docs: format!( - "### What it does\n\n\ - Nothing. This lint has been deprecated\n\n\ - ### Deprecation reason\n\n{reason}.\n", - ), - applicability: None, - former_ids: BTreeSet::new(), - }) - } -} - -fn replace_produces(lint_name: &str, docs: &mut String, clippy_project_root: &Path) { - let mut doc_lines = docs.lines().map(ToString::to_string).collect::<Vec<_>>(); - let mut lines = doc_lines.iter_mut(); - - 'outer: loop { - // Find the start of the example - - // ```rust - loop { - match lines.next() { - Some(line) if line.trim_start().starts_with("```rust") => { - if line.contains("ignore") || line.contains("no_run") { - // A {{produces}} marker may have been put on a ignored code block by mistake, - // just seek to the end of the code block and continue checking. - if lines.any(|line| line.trim_start().starts_with("```")) { - continue; - } - - panic!("lint `{lint_name}` has an unterminated code block") - } - - break; - }, - Some(line) if line.trim_start() == "{{produces}}" => { - panic!("lint `{lint_name}` has marker {{{{produces}}}} with an ignored or missing code block") - }, - Some(line) => { - let line = line.trim(); - // These are the two most common markers of the corrections section - if line.eq_ignore_ascii_case("Use instead:") || line.eq_ignore_ascii_case("Could be written as:") { - break 'outer; - } - }, - None => break 'outer, - } - } - - // Collect the example - let mut example = Vec::new(); - loop { - match lines.next() { - Some(line) if line.trim_start() == "```" => break, - Some(line) => example.push(line), - None => panic!("lint `{lint_name}` has an unterminated code block"), - } - } - - // Find the {{produces}} and attempt to generate the output - loop { - match lines.next() { - Some(line) if line.is_empty() => {}, - Some(line) if line.trim() == "{{produces}}" => { - let output = get_lint_output(lint_name, &example, clippy_project_root); - line.replace_range( - .., - &format!( - "<details>\ - <summary>Produces</summary>\n\ - \n\ - ```text\n\ - {output}\n\ - ```\n\ - </details>" - ), - ); - - break; - }, - // No {{produces}}, we can move on to the next example - Some(_) => break, - None => break 'outer, - } - } - } - - *docs = cleanup_docs(&doc_lines); -} - -fn get_lint_output(lint_name: &str, example: &[&mut String], clippy_project_root: &Path) -> String { - let dir = tempfile::tempdir().unwrap_or_else(|e| panic!("failed to create temp dir: {e}")); - let file = dir.path().join("lint_example.rs"); - - let mut source = String::new(); - let unhidden = example - .iter() - .map(|line| line.trim_start().strip_prefix("# ").unwrap_or(line)); - - // Get any attributes - let mut lines = unhidden.peekable(); - while let Some(line) = lines.peek() { - if line.starts_with("#!") { - source.push_str(line); - source.push('\n'); - lines.next(); - } else { - break; - } - } - - let needs_main = !example.iter().any(|line| line.contains("fn main")); - if needs_main { - source.push_str("fn main() {\n"); - } - - for line in lines { - source.push_str(line); - source.push('\n'); - } - - if needs_main { - source.push_str("}\n"); - } - - if let Err(e) = fs::write(&file, &source) { - panic!("failed to write to `{}`: {e}", file.as_path().to_string_lossy()); - } - - let prefixed_name = format!("{CLIPPY_LINT_GROUP_PREFIX}{lint_name}"); - - let mut cmd = Command::new(env::var("CARGO").unwrap_or("cargo".into())); - - cmd.current_dir(clippy_project_root) - .env("CARGO_INCREMENTAL", "0") - .env("CLIPPY_ARGS", "") - .env("CLIPPY_DISABLE_DOCS_LINKS", "1") - // We need to disable this to enable all lints - .env("ENABLE_METADATA_COLLECTION", "0") - .args(["run", "--bin", "clippy-driver"]) - .args(["--target-dir", "./clippy_lints/target"]) - .args(["--", "--error-format=json"]) - .args(["--edition", "2021"]) - .arg("-Cdebuginfo=0") - .args(["-A", "clippy::all"]) - .args(["-W", &prefixed_name]) - .args(["-L", "./target/debug"]) - .args(["-Z", "no-codegen"]); - - let output = cmd - .arg(file.as_path()) - .output() - .unwrap_or_else(|e| panic!("failed to run `{cmd:?}`: {e}")); - - let tmp_file_path = file.to_string_lossy(); - let stderr = std::str::from_utf8(&output.stderr).unwrap(); - let msgs = stderr - .lines() - .filter(|line| line.starts_with('{')) - .map(|line| serde_json::from_str(line).unwrap()) - .collect::<Vec<serde_json::Value>>(); - - let mut rendered = String::new(); - let iter = msgs - .iter() - .filter(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s == &prefixed_name)); - - for message in iter { - let rendered_part = message["rendered"].as_str().expect("rendered field should exist"); - rendered.push_str(rendered_part); - } - - if rendered.is_empty() { - let rendered: Vec<&str> = msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); - let non_json: Vec<&str> = stderr.lines().filter(|line| !line.starts_with('{')).collect(); - panic!( - "did not find lint `{lint_name}` in output of example, got:\n{}\n{}", - non_json.join("\n"), - rendered.join("\n") - ); - } - - // The reader doesn't need to see `/tmp/.tmpfiy2Qd/lint_example.rs` :) - rendered.trim_end().replace(&*tmp_file_path, "lint_example.rs") -} - -#[derive(Debug, Clone, Serialize, PartialEq, Eq, PartialOrd, Ord)] -struct SerializableSpan { - path: String, - line: usize, -} - -impl fmt::Display for SerializableSpan { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}:{}", self.path.rsplit('/').next().unwrap_or_default(), self.line) - } -} - -impl SerializableSpan { - fn from_item(cx: &LateContext<'_>, item: &Item<'_>) -> Self { - Self::from_span(cx, item.ident.span) - } - - fn from_span(cx: &LateContext<'_>, span: Span) -> Self { - let loc: Loc = cx.sess().source_map().lookup_char_pos(span.lo()); - - Self { - path: format!("{}", loc.file.name.prefer_remapped_unconditionaly()), - line: loc.line, - } - } -} - -#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] -struct ApplicabilityInfo { - /// Indicates if any of the lint emissions uses multiple spans. This is related to - /// [rustfix#141](https://github.com/rust-lang/rustfix/issues/141) as such suggestions can - /// currently not be applied automatically. - is_multi_part_suggestion: bool, - applicability: Option<usize>, -} - -impl Serialize for ApplicabilityInfo { - fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> - where - S: Serializer, - { - let mut s = serializer.serialize_struct("ApplicabilityInfo", 2)?; - s.serialize_field("is_multi_part_suggestion", &self.is_multi_part_suggestion)?; - if let Some(index) = self.applicability { - s.serialize_field( - "applicability", - &paths::APPLICABILITY_VALUES[index][APPLICABILITY_NAME_INDEX], - )?; - } else { - s.serialize_field("applicability", APPLICABILITY_UNRESOLVED_STR)?; - } - s.end() - } -} - -// ================================================================== -// Lint pass -// ================================================================== -impl<'hir> LateLintPass<'hir> for MetadataCollector { - /// Collecting lint declarations like: - /// ```rust, ignore - /// declare_clippy_lint! { - /// /// ### What it does - /// /// Something IDK. - /// pub SOME_LINT, - /// internal, - /// "Who am I?" - /// } - /// ``` - fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) { - if let ItemKind::Static(ty, Mutability::Not, _) = item.kind { - // Normal lint - if is_lint_ref_type(cx, ty) - // item validation - // disallow check - && let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase() - // metadata extraction - && let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item) - && let Some(mut raw_docs) = extract_attr_docs_or_lint(cx, item) - { - if let Some(configuration_section) = self.get_lint_configs(&lint_name) { - raw_docs.push_str(&configuration_section); - } - let version = get_lint_version(cx, item); - - self.lints.push(LintMetadata::new( - lint_name, - SerializableSpan::from_item(cx, item), - group, - level, - version, - raw_docs, - )); - } - } - } - - /// Collecting constant applicability from the actual lint emissions - /// - /// Example: - /// ```rust, ignore - /// span_lint_and_sugg( - /// cx, - /// SOME_LINT, - /// item.span, - /// "Le lint message", - /// "Here comes help:", - /// "#![allow(clippy::all)]", - /// Applicability::MachineApplicable, // <-- Extracts this constant value - /// ); - /// ``` - fn check_expr(&mut self, cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>) { - if let Some(args) = match_lint_emission(cx, expr) { - let emission_info = extract_emission_info(cx, args); - if emission_info.is_empty() { - // See: - // - src/misc.rs:734:9 - // - src/methods/mod.rs:3545:13 - // - src/methods/mod.rs:3496:13 - // We are basically unable to resolve the lint name itself. - return; - } - - for (lint_name, applicability, is_multi_part) in emission_info { - let app_info = self.applicability_info.entry(lint_name).or_default(); - app_info.applicability = applicability; - app_info.is_multi_part_suggestion = is_multi_part; - } - } - } -} - -// ================================================================== -// Lint definition extraction -// ================================================================== -fn sym_to_string(sym: Symbol) -> String { - sym.as_str().to_string() -} - -fn extract_attr_docs_or_lint(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> { - extract_attr_docs(cx, item).or_else(|| { - lint_collection_error_item(cx, item, "could not collect the lint documentation"); - None - }) -} - -/// This function collects all documentation that has been added to an item using -/// `#[doc = r""]` attributes. Several attributes are aggravated using line breaks -/// -/// ```ignore -/// #[doc = r"Hello world!"] -/// #[doc = r"=^.^="] -/// struct SomeItem {} -/// ``` -/// -/// Would result in `Hello world!\n=^.^=\n` -fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> { - let attrs = cx.tcx.hir().attrs(item.hir_id()); - let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str); - - if let Some(line) = lines.next() { - let raw_docs = lines.fold(String::from(line.as_str()) + "\n", |s, line| s + line.as_str() + "\n"); - return Some(raw_docs); - } - - None -} - -/// This function may modify the doc comment to ensure that the string can be displayed using a -/// markdown viewer in Clippy's lint list. The following modifications could be applied: -/// * Removal of leading space after a new line. (Important to display tables) -/// * Ensures that code blocks only contain language information -fn cleanup_docs(docs_collection: &Vec<String>) -> String { - let mut in_code_block = false; - let mut is_code_block_rust = false; - - let mut docs = String::new(); - for line in docs_collection { - // Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :) - if is_code_block_rust && line.trim_start().starts_with("# ") { - continue; - } - - // The line should be represented in the lint list, even if it's just an empty line - docs.push('\n'); - if let Some(info) = line.trim_start().strip_prefix("```") { - in_code_block = !in_code_block; - is_code_block_rust = false; - if in_code_block { - let lang = info - .trim() - .split(',') - // remove rustdoc directives - .find(|&s| !matches!(s, "" | "ignore" | "no_run" | "should_panic")) - // if no language is present, fill in "rust" - .unwrap_or("rust"); - let len_diff = line.len() - line.trim_start().len(); - if len_diff != 0 { - // We put back the indentation. - docs.push_str(&line[..len_diff]); - } - docs.push_str("```"); - docs.push_str(lang); - - is_code_block_rust = lang == "rust"; - continue; - } - } - // This removes the leading space that the macro translation introduces - if let Some(stripped_doc) = line.strip_prefix(' ') { - docs.push_str(stripped_doc); - } else if !line.is_empty() { - docs.push_str(line); - } - } - - docs -} - -fn get_lint_version(cx: &LateContext<'_>, item: &Item<'_>) -> String { - extract_clippy_version_value(cx, item).map_or_else( - || VERSION_DEFAULT_STR.to_string(), - |version| version.as_str().to_string(), - ) -} - -fn get_lint_group_and_level_or_lint( - cx: &LateContext<'_>, - lint_name: &str, - item: &Item<'_>, -) -> Option<(String, &'static str)> { - let result = unerased_lint_store(cx.tcx.sess).check_lint_name( - lint_name, - Some(sym::clippy), - &std::iter::once(Ident::with_dummy_span(sym::clippy)).collect(), - ); - if let CheckLintNameResult::Tool(lint_lst, None) = result { - if let Some(group) = get_lint_group(cx, lint_lst[0]) { - if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) { - return None; - } - - if let Some(level) = get_lint_level_from_group(&group) { - Some((group, level)) - } else { - lint_collection_error_item( - cx, - item, - &format!("Unable to determine lint level for found group `{group}`"), - ); - None - } - } else { - lint_collection_error_item(cx, item, "Unable to determine lint group"); - None - } - } else { - lint_collection_error_item(cx, item, "Unable to find lint in lint_store"); - None - } -} - -fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option<String> { - for (group_name, lints, _) in unerased_lint_store(cx.tcx.sess).get_lint_groups() { - if IGNORED_LINT_GROUPS.contains(&group_name) { - continue; - } - - if lints.iter().any(|group_lint| *group_lint == lint_id) { - let group = group_name.strip_prefix(CLIPPY_LINT_GROUP_PREFIX).unwrap_or(group_name); - return Some((*group).to_string()); - } - } - - None -} - -fn get_lint_level_from_group(lint_group: &str) -> Option<&'static str> { - DEFAULT_LINT_LEVELS - .iter() - .find_map(|(group_name, group_level)| (*group_name == lint_group).then_some(*group_level)) -} - -fn collect_renames(lints: &mut Vec<LintMetadata>) { - for lint in lints { - let mut collected = String::new(); - let mut names = vec![lint.id.clone()]; - - loop { - if let Some(lint_name) = names.pop() { - for (k, v) in crate::deprecated_lints::RENAMED { - if let Some(name) = v.strip_prefix(CLIPPY_LINT_GROUP_PREFIX) - && name == lint_name - && let Some(past_name) = k.strip_prefix(CLIPPY_LINT_GROUP_PREFIX) - { - lint.former_ids.insert(past_name.to_owned()); - writeln!(collected, "* `{past_name}`").unwrap(); - names.push(past_name.to_string()); - } - } - - continue; - } - - break; - } - - if !collected.is_empty() { - write!( - &mut lint.docs, - r#" -### Past names - -{collected} -"# - ) - .unwrap(); - } - } -} - -// ================================================================== -// Lint emission -// ================================================================== -fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &str) { - span_lint( - cx, - METADATA_COLLECTOR, - item.ident.span, - format!("metadata collection error for `{}`: {message}", item.ident.name), - ); -} - -// ================================================================== -// Applicability -// ================================================================== -/// This function checks if a given expression is equal to a simple lint emission function call. -/// It will return the function arguments if the emission matched any function. -fn match_lint_emission<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'_>) -> Option<&'hir [hir::Expr<'hir>]> { - LINT_EMISSION_FUNCTIONS - .iter() - .find_map(|emission_fn| match_function_call(cx, expr, emission_fn)) -} - -fn take_higher_applicability(a: Option<usize>, b: Option<usize>) -> Option<usize> { - a.map_or(b, |a| a.max(b.unwrap_or_default()).into()) -} - -fn extract_emission_info<'hir>( - cx: &LateContext<'hir>, - args: &'hir [hir::Expr<'hir>], -) -> Vec<(String, Option<usize>, bool)> { - let mut lints = Vec::new(); - let mut applicability = None; - let mut multi_part = false; - - for arg in args { - let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(arg)); - - if match_type(cx, arg_ty, &paths::LINT) { - // If we found the lint arg, extract the lint name - let mut resolved_lints = resolve_lints(cx, arg); - lints.append(&mut resolved_lints); - } else if match_type(cx, arg_ty, &paths::APPLICABILITY) { - applicability = resolve_applicability(cx, arg); - } else if arg_ty.is_closure() { - multi_part |= check_is_multi_part(cx, arg); - applicability = applicability.or_else(|| resolve_applicability(cx, arg)); - } - } - - lints - .into_iter() - .map(|lint_name| (lint_name, applicability, multi_part)) - .collect() -} - -/// Resolves the possible lints that this expression could reference -fn resolve_lints<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Vec<String> { - let mut resolver = LintResolver::new(cx); - resolver.visit_expr(expr); - resolver.lints -} - -/// This function tries to resolve the linked applicability to the given expression. -fn resolve_applicability<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<usize> { - let mut resolver = ApplicabilityResolver::new(cx); - resolver.visit_expr(expr); - resolver.complete() -} - -fn check_is_multi_part<'hir>(cx: &LateContext<'hir>, closure_expr: &'hir hir::Expr<'hir>) -> bool { - if let ExprKind::Closure(&Closure { body, .. }) = closure_expr.kind { - let mut scanner = IsMultiSpanScanner::new(cx); - intravisit::walk_body(&mut scanner, cx.tcx.hir().body(body)); - return scanner.is_multi_part(); - } else if let Some(local) = get_parent_local(cx, closure_expr) { - if let Some(local_init) = local.init { - return check_is_multi_part(cx, local_init); - } - } - - false -} - -struct LintResolver<'a, 'hir> { - cx: &'a LateContext<'hir>, - lints: Vec<String>, -} - -impl<'a, 'hir> LintResolver<'a, 'hir> { - fn new(cx: &'a LateContext<'hir>) -> Self { - Self { - cx, - lints: Vec::<String>::default(), - } - } -} - -impl<'a, 'hir> Visitor<'hir> for LintResolver<'a, 'hir> { - type NestedFilter = nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { - if let ExprKind::Path(qpath) = &expr.kind - && let QPath::Resolved(_, path) = qpath - && let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr)) - && match_type(self.cx, expr_ty, &paths::LINT) - { - if let hir::def::Res::Def(DefKind::Static { .. }, _) = path.res { - let lint_name = last_path_segment(qpath).ident.name; - self.lints.push(sym_to_string(lint_name).to_ascii_lowercase()); - } else if let Some(local) = get_parent_local(self.cx, expr) { - if let Some(local_init) = local.init { - intravisit::walk_expr(self, local_init); - } - } - } - - intravisit::walk_expr(self, expr); - } -} - -/// This visitor finds the highest applicability value in the visited expressions -struct ApplicabilityResolver<'a, 'hir> { - cx: &'a LateContext<'hir>, - /// This is the index of highest `Applicability` for `paths::APPLICABILITY_VALUES` - applicability_index: Option<usize>, -} - -impl<'a, 'hir> ApplicabilityResolver<'a, 'hir> { - fn new(cx: &'a LateContext<'hir>) -> Self { - Self { - cx, - applicability_index: None, - } - } - - fn add_new_index(&mut self, new_index: usize) { - self.applicability_index = take_higher_applicability(self.applicability_index, Some(new_index)); - } - - fn complete(self) -> Option<usize> { - self.applicability_index - } -} - -impl<'a, 'hir> Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { - type NestedFilter = nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } - - fn visit_path(&mut self, path: &hir::Path<'hir>, _id: hir::HirId) { - for (index, enum_value) in paths::APPLICABILITY_VALUES.iter().enumerate() { - if match_path(path, enum_value) { - self.add_new_index(index); - return; - } - } - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { - let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr)); - - if match_type(self.cx, expr_ty, &paths::APPLICABILITY) - && let Some(local) = get_parent_local(self.cx, expr) - && let Some(local_init) = local.init - { - intravisit::walk_expr(self, local_init); - }; - - intravisit::walk_expr(self, expr); - } -} - -/// This returns the parent local node if the expression is a reference one -fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::LetStmt<'hir>> { - if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind { - if let hir::def::Res::Local(local_hir) = path.res { - return get_parent_local_hir_id(cx, local_hir); - } - } - - None -} - -fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::LetStmt<'hir>> { - match cx.tcx.parent_hir_node(hir_id) { - hir::Node::LetStmt(local) => Some(local), - hir::Node::Pat(pattern) => get_parent_local_hir_id(cx, pattern.hir_id), - _ => None, - } -} - -/// This visitor finds the highest applicability value in the visited expressions -struct IsMultiSpanScanner<'a, 'hir> { - cx: &'a LateContext<'hir>, - suggestion_count: usize, -} - -impl<'a, 'hir> IsMultiSpanScanner<'a, 'hir> { - fn new(cx: &'a LateContext<'hir>) -> Self { - Self { - cx, - suggestion_count: 0, - } - } - - /// Add a new single expression suggestion to the counter - fn add_single_span_suggestion(&mut self) { - self.suggestion_count += 1; - } - - /// Signals that a suggestion with possible multiple spans was found - fn add_multi_part_suggestion(&mut self) { - self.suggestion_count += 2; - } - - /// Checks if the suggestions include multiple spans - fn is_multi_part(&self) -> bool { - self.suggestion_count > 1 - } -} - -impl<'a, 'hir> Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> { - type NestedFilter = nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { - // Early return if the lint is already multi span - if self.is_multi_part() { - return; - } - - if let ExprKind::MethodCall(path, recv, _, _arg_span) = &expr.kind { - let (self_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(recv)); - if match_type(self.cx, self_ty, &paths::DIAG) { - let called_method = path.ident.name.as_str().to_string(); - for (method_name, is_multi_part) in &SUGGESTION_DIAG_METHODS { - if *method_name == called_method { - if *is_multi_part { - self.add_multi_part_suggestion(); - } else { - self.add_single_span_suggestion(); - } - break; - } - } - } - } - - intravisit::walk_expr(self, expr); - } -} diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index 228db14d1b7..d3e49bff422 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -5,7 +5,7 @@ use clippy_config::msrvs::{self, Msrv}; use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method}; @@ -214,9 +214,11 @@ impl SuggestedType { } fn snippet(self, cx: &LateContext<'_>, args_span: Option<Span>, len_span: Option<Span>) -> String { - let maybe_args = args_span.and_then(|sp| snippet_opt(cx, sp)).unwrap_or_default(); + let maybe_args = args_span + .and_then(|sp| sp.get_source_text(cx)) + .map_or(String::new(), |x| x.to_owned()); let maybe_len = len_span - .and_then(|sp| snippet_opt(cx, sp).map(|s| format!("; {s}"))) + .and_then(|sp| sp.get_source_text(cx).map(|s| format!("; {s}"))) .unwrap_or_default(); match self { diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs index 63f3a5d7f83..7a85196ceca 100644 --- a/src/tools/clippy/clippy_lints/src/visibility.rs +++ b/src/tools/clippy/clippy_lints/src/visibility.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{Item, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; @@ -82,9 +82,7 @@ impl EarlyLintPass for Visibility { if !in_external_macro(cx.sess(), item.span) && let VisibilityKind::Restricted { path, shorthand, .. } = &item.vis.kind { - if **path == kw::SelfLower - && let Some(false) = is_from_proc_macro(cx, item.vis.span) - { + if **path == kw::SelfLower && !is_from_proc_macro(cx, item.vis.span) { span_lint_and_then( cx, NEEDLESS_PUB_SELF, @@ -104,7 +102,7 @@ impl EarlyLintPass for Visibility { if (**path == kw::Super || **path == kw::SelfLower || **path == kw::Crate) && !*shorthand && let [.., last] = &*path.segments - && let Some(false) = is_from_proc_macro(cx, item.vis.span) + && !is_from_proc_macro(cx, item.vis.span) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( @@ -125,7 +123,7 @@ impl EarlyLintPass for Visibility { if *shorthand && let [.., last] = &*path.segments - && let Some(false) = is_from_proc_macro(cx, item.vis.span) + && !is_from_proc_macro(cx, item.vis.span) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( @@ -147,6 +145,6 @@ impl EarlyLintPass for Visibility { } } -fn is_from_proc_macro(cx: &EarlyContext<'_>, span: Span) -> Option<bool> { - snippet_opt(cx, span).map(|s| !s.starts_with("pub")) +fn is_from_proc_macro(cx: &EarlyContext<'_>, span: Span) -> bool { + !span.check_source_text(cx, |src| src.starts_with("pub")) } diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index c4d64ee4609..7d9e58ad2f8 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -100,14 +100,14 @@ declare_clippy_lint! { pub struct WildcardImports { warn_on_all: bool, - allowed_segments: &'static FxHashSet<String>, + allowed_segments: FxHashSet<String>, } impl WildcardImports { pub fn new(conf: &'static Conf) -> Self { Self { warn_on_all: conf.warn_on_all_wildcard_imports, - allowed_segments: &conf.allowed_wildcard_imports, + allowed_segments: conf.allowed_wildcard_imports.iter().cloned().collect(), } } } @@ -181,7 +181,7 @@ impl WildcardImports { fn check_exceptions(&self, cx: &LateContext<'_>, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool { item.span.from_expansion() || is_prelude_import(segments) - || is_allowed_via_config(segments, self.allowed_segments) + || is_allowed_via_config(segments, &self.allowed_segments) || (is_super_only_import(segments) && is_in_test(cx.tcx, item.hir_id())) } } diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 54e7e92f0c4..ec5a5896fb2 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::is_in_test; use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall}; -use clippy_utils::source::{expand_past_previous_comma, snippet_opt}; +use clippy_utils::source::{expand_past_previous_comma, SpanRangeExt}; use rustc_ast::token::LitKind; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, @@ -397,7 +397,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma format!("using `{name}!()` with a format string that ends in a single newline"), |diag| { let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); - let Some(format_snippet) = snippet_opt(cx, format_string_span) else { + let Some(format_snippet) = format_string_span.get_source_text(cx) else { return; }; @@ -492,7 +492,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { && let Some(arg) = format_args.arguments.by_index(index) && let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind && !arg.expr.span.from_expansion() - && let Some(value_string) = snippet_opt(cx, arg.expr.span) + && let Some(value_string) = arg.expr.span.get_source_text(cx) { let (replacement, replace_raw) = match lit.kind { LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { @@ -515,7 +515,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { _ => continue, }; - let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { + let Some(format_string_snippet) = format_args.span.get_source_text(cx) else { continue; }; let format_string_is_raw = format_string_snippet.starts_with('r'); diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index 9fefd94d339..629ce9d04d4 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -8,7 +8,6 @@ publish = false clippy_config = { path = "../clippy_config" } arrayvec = { version = "0.7", default-features = false } itertools = "0.12" -rustc-semver = "1.1" # FIXME(f16_f128): remove when no longer needed for parsing rustc_apfloat = "0.2.0" diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index d2200bcf710..42c8b218d14 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -7,7 +7,7 @@ use rustc_session::Session; use rustc_span::{sym, Span}; use std::str::FromStr; -use crate::source::snippet_opt; +use crate::source::SpanRangeExt; use crate::tokenize_with_text; /// Deprecation status of attributes known by Clippy. @@ -179,25 +179,23 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool { /// Checks if the given span contains a `#[cfg(..)]` attribute pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { - let Some(snip) = snippet_opt(cx, s) else { - // Assume true. This would require either an invalid span, or one which crosses file boundaries. - return true; - }; - let mut iter = tokenize_with_text(&snip); + s.check_source_text(cx, |src| { + let mut iter = tokenize_with_text(src); - // Search for the token sequence [`#`, `[`, `cfg`] - while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { - let mut iter = iter.by_ref().skip_while(|(t, _)| { - matches!( - t, - TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } - ) - }); - if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) - && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) - { - return true; + // Search for the token sequence [`#`, `[`, `cfg`] + while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { + let mut iter = iter.by_ref().skip_while(|(t, _)| { + matches!( + t, + TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } + ) + }); + if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) + && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) + { + return true; + } } - } - false + false + }) } diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 7f2234b310b..2bd6837d973 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -123,16 +123,14 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { fn path_search_pat(path: &Path<'_>) -> (Pat, Pat) { let (head, tail) = match path.segments { - [head, .., tail] => (head, tail), - [p] => (p, p), [] => return (Pat::Str(""), Pat::Str("")), + [p] => (Pat::Sym(p.ident.name), p), + // QPath::Resolved can have a path that looks like `<Foo as Bar>::baz` where + // the path (`Bar::baz`) has it's span covering the whole QPath. + [.., tail] => (Pat::Str(""), tail), }; ( - if head.ident.name == kw::PathRoot { - Pat::Str("::") - } else { - Pat::Sym(head.ident.name) - }, + head, if tail.args.is_some() { Pat::Str(">") } else { diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index e907e4058e5..760d5bc95f7 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -687,7 +687,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) && let expr_lo = expr_span.lo() && expr_lo >= span.lo - && let Some(src) = (span.lo..expr_lo).get_source_text(&self.tcx) + && let Some(src) = (span.lo..expr_lo).get_source_range(&self.tcx) && let Some(src) = src.as_str() { use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index f325e4eaf15..f61ef9ac1b0 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1,6 +1,6 @@ use crate::consts::ConstEvalCtxt; use crate::macros::macro_backtrace; -use crate::source::{snippet_opt, walk_span_to_context, SpanRange, SpanRangeExt}; +use crate::source::{walk_span_to_context, SpanRange, SpanRangeExt}; use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; @@ -588,10 +588,9 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &' // block with an empty span. ([], None) if block.span.is_empty() => &ExprKind::Tup(&[]), // `{}` => `()` - ([], None) => match snippet_opt(cx, block.span) { - // Don't reduce if there are any tokens contained in the braces - Some(snip) - if tokenize(&snip) + ([], None) + if block.span.check_source_text(cx, |src| { + tokenize(src) .map(|t| t.kind) .filter(|t| { !matches!( @@ -599,11 +598,10 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &' TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace ) }) - .ne([TokenKind::OpenBrace, TokenKind::CloseBrace].iter().copied()) => - { - kind - }, - _ => &ExprKind::Tup(&[]), + .eq([TokenKind::OpenBrace, TokenKind::CloseBrace].iter().copied()) + }) => + { + &ExprKind::Tup(&[]) }, ([], Some(expr)) => match expr.kind { // `{ return .. }` => `return ..` @@ -1191,9 +1189,9 @@ fn eq_span_tokens( pred: impl Fn(TokenKind) -> bool, ) -> bool { fn f(cx: &LateContext<'_>, left: Range<BytePos>, right: Range<BytePos>, pred: impl Fn(TokenKind) -> bool) -> bool { - if let Some(lsrc) = left.get_source_text(cx) + if let Some(lsrc) = left.get_source_range(cx) && let Some(lsrc) = lsrc.as_str() - && let Some(rsrc) = right.get_source_text(cx) + && let Some(rsrc) = right.get_source_range(cx) && let Some(rsrc) = rsrc.as_str() { let pred = |t: &(_, _)| pred(t.0); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 28755ae0710..5db14872c36 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -149,6 +149,7 @@ macro_rules! extract_msrv_attr { /// If the given expression is a local binding, find the initializer expression. /// If that initializer expression is another local binding, find its initializer again. +/// /// This process repeats as long as possible (but usually no more than once). Initializer /// expressions with adjustments are ignored. If this is not desired, use [`find_binding_init`] /// instead. @@ -179,6 +180,7 @@ pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr } /// Finds the initializer expression for a local binding. Returns `None` if the binding is mutable. +/// /// By only considering immutable bindings, we guarantee that the returned expression represents the /// value of the binding wherever it is referenced. /// @@ -431,12 +433,12 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tc }) } -/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the +/// THIS METHOD IS DEPRECATED. Matches a `QPath` against a slice of segment string literals. +/// +/// This method is deprecated and will eventually be removed since it does not match against the /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from /// `QPath::Resolved.1.res.opt_def_id()`. /// -/// Matches a `QPath` against a slice of segment string literals. -/// /// There is also `match_path` if you are dealing with a `rustc_hir::Path` instead of a /// `rustc_hir::QPath`. /// @@ -485,12 +487,12 @@ pub fn is_path_diagnostic_item<'tcx>( path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id)) } -/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the +/// THIS METHOD IS DEPRECATED. Matches a `Path` against a slice of segment string literals. +/// +/// This method is deprecated and will eventually be removed since it does not match against the /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from /// `QPath::Resolved.1.res.opt_def_id()`. /// -/// Matches a `Path` against a slice of segment string literals. -/// /// There is also `match_qpath` if you are dealing with a `rustc_hir::QPath` instead of a /// `rustc_hir::Path`. /// @@ -905,6 +907,7 @@ pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> } /// Returns true if the expr is equal to `Default::default()` of it's type when evaluated. +/// /// It doesn't cover all cases, for example indirect function calls (some of std /// functions are supported) but it is the best we have. pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { @@ -1061,6 +1064,7 @@ impl std::ops::BitOrAssign for CaptureKind { } /// Given an expression referencing a local, determines how it would be captured in a closure. +/// /// Note as this will walk up to parent expressions until the capture can be determined it should /// only be used while making a closure somewhere a value is consumed. e.g. a block, match arm, or /// function argument (other than a receiver). @@ -2365,8 +2369,9 @@ pub fn fn_def_id_with_node_args<'tcx>( } /// Returns `Option<String>` where String is a textual representation of the type encapsulated in -/// the slice iff the given expression is a slice of primitives (as defined in the -/// `is_recursively_primitive_type` function) and `None` otherwise. +/// the slice iff the given expression is a slice of primitives. +/// +/// (As defined in the `is_recursively_primitive_type` function.) Returns `None` otherwise. pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> { let expr_type = cx.typeck_results().expr_ty_adjusted(expr); let expr_kind = expr_type.kind(); diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index 455239cc37f..1d7479bff82 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -150,10 +150,11 @@ pub fn first_node_macro_backtrace(cx: &LateContext<'_>, node: &impl HirNode) -> } /// If `node` is the "first node" in a macro expansion, returns `Some` with the `ExpnId` of the -/// macro call site (i.e. the parent of the macro expansion). This generally means that `node` -/// is the outermost node of an entire macro expansion, but there are some caveats noted below. -/// This is useful for finding macro calls while visiting the HIR without processing the macro call -/// at every node within its expansion. +/// macro call site (i.e. the parent of the macro expansion). +/// +/// This generally means that `node` is the outermost node of an entire macro expansion, but there +/// are some caveats noted below. This is useful for finding macro calls while visiting the HIR +/// without processing the macro call at every node within its expansion. /// /// If you already have immediate access to the parent node, it is simpler to /// just check the context of that span directly (e.g. `parent.span.from_expansion()`). @@ -426,12 +427,8 @@ impl FormatArgsStorage { } } -/// Attempt to find the [`rustc_hir::Expr`] that corresponds to the [`FormatArgument`]'s value, if -/// it cannot be found it will return the [`rustc_ast::Expr`]. -pub fn find_format_arg_expr<'hir, 'ast>( - start: &'hir Expr<'hir>, - target: &'ast FormatArgument, -) -> Result<&'hir Expr<'hir>, &'ast rustc_ast::Expr> { +/// Attempt to find the [`rustc_hir::Expr`] that corresponds to the [`FormatArgument`]'s value +pub fn find_format_arg_expr<'hir>(start: &'hir Expr<'hir>, target: &FormatArgument) -> Option<&'hir Expr<'hir>> { let SpanData { lo, hi, @@ -449,7 +446,6 @@ pub fn find_format_arg_expr<'hir, 'ast>( ControlFlow::Continue(()) } }) - .ok_or(&target.expr) } /// Span of the `:` and format specifiers diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 95fbf0b2ea2..d9befb3c157 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -18,7 +18,6 @@ use rustc_middle::mir::{ use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt}; -use rustc_semver::RustcVersion; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext}; @@ -391,11 +390,7 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { StableSince::Err => return false, }; - msrv.meets(RustcVersion::new( - u32::from(const_stab_rust_version.major), - u32::from(const_stab_rust_version.minor), - u32::from(const_stab_rust_version.patch), - )) + msrv.meets(const_stab_rust_version) } else { // Unstable const fn with the feature enabled. msrv.current().is_none() diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 96dd3c55d37..482e1e0147b 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -16,7 +16,7 @@ use rustc_span::{ }; use std::borrow::Cow; use std::fmt; -use std::ops::Range; +use std::ops::{Deref, Index, Range}; pub trait HasSession { fn sess(&self) -> &Session; @@ -94,10 +94,16 @@ impl IntoSpan for Range<BytePos> { } pub trait SpanRangeExt: SpanRange { + /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, + /// or the source text is not accessible. + fn get_source_text(self, cx: &impl HasSession) -> Option<SourceText> { + get_source_range(cx.sess().source_map(), self.into_range()).and_then(SourceText::new) + } + /// Gets the source file, and range in the file, of the given span. Returns `None` if the span /// extends through multiple files, or is malformed. - fn get_source_text(self, cx: &impl HasSession) -> Option<SourceFileRange> { - get_source_text(cx.sess().source_map(), self.into_range()) + fn get_source_range(self, cx: &impl HasSession) -> Option<SourceFileRange> { + get_source_range(cx.sess().source_map(), self.into_range()) } /// Calls the given function with the source text referenced and returns the value. Returns @@ -144,32 +150,70 @@ pub trait SpanRangeExt: SpanRange { fn trim_start(self, cx: &impl HasSession) -> Range<BytePos> { trim_start(cx.sess().source_map(), self.into_range()) } +} +impl<T: SpanRange> SpanRangeExt for T {} - /// Writes the referenced source text to the given writer. Will return `Err` if the source text - /// could not be retrieved. - fn write_source_text_to(self, cx: &impl HasSession, dst: &mut impl fmt::Write) -> fmt::Result { - write_source_text_to(cx.sess().source_map(), self.into_range(), dst) +/// Handle to a range of text in a source file. +pub struct SourceText(SourceFileRange); +impl SourceText { + /// Takes ownership of the source file handle if the source text is accessible. + pub fn new(text: SourceFileRange) -> Option<Self> { + if text.as_str().is_some() { + Some(Self(text)) + } else { + None + } } - /// Extracts the referenced source text as an owned string. - fn source_text_to_string(self, cx: &impl HasSession) -> Option<String> { - self.with_source_text(cx, ToOwned::to_owned) + /// Gets the source text. + pub fn as_str(&self) -> &str { + self.0.as_str().unwrap() + } + + /// Converts this into an owned string. + pub fn to_owned(&self) -> String { + self.as_str().to_owned() + } +} +impl Deref for SourceText { + type Target = str; + fn deref(&self) -> &Self::Target { + self.as_str() + } +} +impl AsRef<str> for SourceText { + fn as_ref(&self) -> &str { + self.as_str() + } +} +impl<T> Index<T> for SourceText +where + str: Index<T>, +{ + type Output = <str as Index<T>>::Output; + fn index(&self, idx: T) -> &Self::Output { + &self.as_str()[idx] + } +} +impl fmt::Display for SourceText { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_str().fmt(f) } } -impl<T: SpanRange> SpanRangeExt for T {} -fn get_source_text(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> { +fn get_source_range(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> { let start = sm.lookup_byte_offset(sp.start); let end = sm.lookup_byte_offset(sp.end); if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { return None; } + sm.ensure_source_file_source_present(&start.sf); let range = start.pos.to_usize()..end.pos.to_usize(); Some(SourceFileRange { sf: start.sf, range }) } fn with_source_text<T>(sm: &SourceMap, sp: Range<BytePos>, f: impl for<'a> FnOnce(&'a str) -> T) -> Option<T> { - if let Some(src) = get_source_text(sm, sp) + if let Some(src) = get_source_range(sm, sp) && let Some(src) = src.as_str() { Some(f(src)) @@ -183,7 +227,7 @@ fn with_source_text_and_range<T>( sp: Range<BytePos>, f: impl for<'a> FnOnce(&'a str, Range<usize>) -> T, ) -> Option<T> { - if let Some(src) = get_source_text(sm, sp) + if let Some(src) = get_source_range(sm, sp) && let Some(text) = &src.sf.src { Some(f(text, src.range)) @@ -198,7 +242,7 @@ fn map_range( sp: Range<BytePos>, f: impl for<'a> FnOnce(&'a str, Range<usize>) -> Option<Range<usize>>, ) -> Option<Range<BytePos>> { - if let Some(src) = get_source_text(sm, sp.clone()) + if let Some(src) = get_source_range(sm, sp.clone()) && let Some(text) = &src.sf.src && let Some(range) = f(text, src.range.clone()) { @@ -232,13 +276,6 @@ fn trim_start(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> { .unwrap_or(sp) } -fn write_source_text_to(sm: &SourceMap, sp: Range<BytePos>, dst: &mut impl fmt::Write) -> fmt::Result { - match with_source_text(sm, sp, |src| dst.write_str(src)) { - Some(x) => x, - None => Err(fmt::Error), - } -} - pub struct SourceFileRange { pub sf: Lrc<SourceFile>, pub range: Range<usize>, @@ -247,7 +284,11 @@ impl SourceFileRange { /// Attempts to get the text from the source file. This can fail if the source text isn't /// loaded. pub fn as_str(&self) -> Option<&str> { - self.sf.src.as_ref().and_then(|x| x.get(self.range.clone())) + self.sf + .src + .as_ref() + .or_else(|| self.sf.external_src.get().and_then(|src| src.get_source())) + .and_then(|x| x.get(self.range.clone())) } } @@ -548,9 +589,10 @@ pub fn snippet_block_with_context<'a>( (reindent_multiline(snip, true, indent), from_macro) } -/// Same as `snippet_with_applicability`, but first walks the span up to the given context. This -/// will result in the macro call, rather than the expansion, if the span is from a child context. -/// If the span is not from a child context, it will be used directly instead. +/// Same as `snippet_with_applicability`, but first walks the span up to the given context. +/// +/// This will result in the macro call, rather than the expansion, if the span is from a child +/// context. If the span is not from a child context, it will be used directly instead. /// /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR node /// would result in `box []`. If given the context of the address of expression, this function will @@ -593,9 +635,10 @@ fn snippet_with_context_sess<'a>( } /// Walks the span up to the target context, thereby returning the macro call site if the span is -/// inside a macro expansion, or the original span if it is not. Note this will return `None` in the -/// case of the span being in a macro expansion, but the target context is from expanding a macro -/// argument. +/// inside a macro expansion, or the original span if it is not. +/// +/// Note this will return `None` in the case of the span being in a macro expansion, but the target +/// context is from expanding a macro argument. /// /// Given the following /// diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 2f6faba073e..f80981c11af 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -160,8 +160,10 @@ pub fn get_type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<Symb } /// Returns true if `ty` is a type on which calling `Clone` through a function instead of -/// as a method, such as `Arc::clone()` is considered idiomatic. Lints should avoid suggesting to -/// replace instances of `ty::Clone()` by `.clone()` for objects of those types. +/// as a method, such as `Arc::clone()` is considered idiomatic. +/// +/// Lints should avoid suggesting to replace instances of `ty::Clone()` by `.clone()` for objects +/// of those types. pub fn should_call_clone_as_function(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { matches!( get_type_diagnostic_name(cx, ty), @@ -398,8 +400,10 @@ fn is_normalizable_helper<'tcx>( } /// Returns `true` if the given type is a non aggregate primitive (a `bool` or `char`, any -/// integer or floating-point number type). For checking aggregation of primitive types (e.g. -/// tuples and slices of primitive type) see `is_recursively_primitive_type` +/// integer or floating-point number type). +/// +/// For checking aggregation of primitive types (e.g. tuples and slices of primitive type) see +/// `is_recursively_primitive_type` pub fn is_non_aggregate_primitive_type(ty: Ty<'_>) -> bool { matches!(ty.kind(), ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_)) } @@ -455,11 +459,6 @@ pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: LangItem) } } -/// Gets the diagnostic name of the type, if it has one -pub fn type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<Symbol> { - ty.ty_adt_def().and_then(|adt| cx.tcx.get_diagnostic_name(adt.did())) -} - /// Return `true` if the passed `typ` is `isize` or `usize`. pub fn is_isize_or_usize(typ: Ty<'_>) -> bool { matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize)) @@ -476,9 +475,10 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { } } -/// Checks if the drop order for a type matters. Some std types implement drop solely to -/// deallocate memory. For these types, and composites containing them, changing the drop order -/// won't result in any observable side effects. +/// Checks if the drop order for a type matters. +/// +/// Some std types implement drop solely to deallocate memory. For these types, and composites +/// containing them, changing the drop order won't result in any observable side effects. pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { fn needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet<Ty<'tcx>>) -> bool { if !seen.insert(ty) { @@ -1311,6 +1311,7 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl } /// Checks if a Ty<'_> has some inherent method Symbol. +/// /// This does not look for impls in the type's `Deref::Target` type. /// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`. pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> { diff --git a/src/tools/clippy/declare_clippy_lint/src/lib.rs b/src/tools/clippy/declare_clippy_lint/src/lib.rs index ca070f6c250..6aa24329b06 100644 --- a/src/tools/clippy/declare_clippy_lint/src/lib.rs +++ b/src/tools/clippy/declare_clippy_lint/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(let_chains)] +#![feature(let_chains, proc_macro_span)] // warn on lints, that are included in `rust-lang/rust`s bootstrap #![warn(rust_2018_idioms, unused_lifetimes)] @@ -23,6 +23,7 @@ fn parse_attr<const LEN: usize>(path: [&'static str; LEN], attr: &Attribute) -> struct ClippyLint { attrs: Vec<Attribute>, + version: Option<LitStr>, explanation: String, name: Ident, category: Ident, @@ -41,8 +42,14 @@ impl Parse for ClippyLint { let value = lit.value(); let line = value.strip_prefix(' ').unwrap_or(&value); - if line.starts_with("```") { - explanation += "```\n"; + if let Some(lang) = line.strip_prefix("```") { + let tag = lang.split_once(',').map_or(lang, |(left, _)| left); + if !in_code && matches!(tag, "" | "rust" | "ignore" | "should_panic" | "no_run" | "compile_fail") { + explanation += "```rust\n"; + } else { + explanation += line; + explanation.push('\n'); + } in_code = !in_code; } else if !(in_code && line.starts_with("# ")) { explanation += line; @@ -68,6 +75,7 @@ impl Parse for ClippyLint { Ok(Self { attrs, + version, explanation, name, category, @@ -123,6 +131,7 @@ impl Parse for ClippyLint { pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { let ClippyLint { attrs, + version, explanation, name, category, @@ -146,6 +155,14 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { (&mut category[0..1]).make_ascii_uppercase(); let category_variant = format_ident!("{category}"); + let name_span = name.span().unwrap(); + let location = format!("{}#L{}", name_span.source_file().path().display(), name_span.line()); + + let version = match version { + Some(version) => quote!(Some(#version)), + None => quote!(None), + }; + let output = quote! { rustc_session::declare_tool_lint! { #(#attrs)* @@ -159,6 +176,8 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream { lint: &#name, category: crate::LintCategory::#category_variant, explanation: #explanation, + location: #location, + version: #version, }; }; diff --git a/src/tools/clippy/lintcheck/src/json.rs b/src/tools/clippy/lintcheck/src/json.rs index 4211bce90b2..ee0c80aea52 100644 --- a/src/tools/clippy/lintcheck/src/json.rs +++ b/src/tools/clippy/lintcheck/src/json.rs @@ -12,21 +12,21 @@ const TRUNCATION_TOTAL_TARGET: usize = 1000; #[derive(Debug, Deserialize, Serialize)] struct LintJson { - lint: String, - krate: String, - file_name: String, - byte_pos: (u32, u32), - file_link: String, + /// The lint name e.g. `clippy::bytes_nth` + name: String, + /// The filename and line number e.g. `anyhow-1.0.86/src/error.rs:42` + file_line: String, + file_url: String, rendered: String, } impl LintJson { fn key(&self) -> impl Ord + '_ { - (self.lint.as_str(), self.file_name.as_str(), self.byte_pos) + (self.name.as_str(), self.file_line.as_str()) } fn info_text(&self, action: &str) -> String { - format!("{action} `{}` in `{}` at {}", self.lint, self.krate, self.file_link) + format!("{action} `{}` at [`{}`]({})", self.name, self.file_line, self.file_url) } } @@ -36,13 +36,16 @@ pub(crate) fn output(clippy_warnings: Vec<ClippyWarning>) -> String { .into_iter() .map(|warning| { let span = warning.span(); + let file_name = span + .file_name + .strip_prefix("target/lintcheck/sources/") + .unwrap_or(&span.file_name); + let file_line = format!("{file_name}:{}", span.line_start); LintJson { - file_name: span.file_name.clone(), - byte_pos: (span.byte_start, span.byte_end), - krate: warning.krate, - file_link: warning.url, - lint: warning.lint, - rendered: warning.diag.rendered.unwrap(), + name: warning.name, + file_line, + file_url: warning.url, + rendered: warning.diag.rendered.unwrap().trim().to_string(), } }) .collect(); @@ -63,7 +66,7 @@ pub(crate) fn diff(old_path: &Path, new_path: &Path, truncate: bool) { let mut lint_warnings = vec![]; for (name, changes) in &itertools::merge_join_by(old_warnings, new_warnings, |old, new| old.key().cmp(&new.key())) - .chunk_by(|change| change.as_ref().into_left().lint.to_string()) + .chunk_by(|change| change.as_ref().into_left().name.clone()) { let mut added = Vec::new(); let mut removed = Vec::new(); @@ -162,7 +165,7 @@ fn print_warnings(title: &str, warnings: &[LintJson], truncate_after: usize) { return; } - print_h3(&warnings[0].lint, title); + print_h3(&warnings[0].name, title); println!(); let warnings = truncate(warnings, truncate_after); @@ -171,7 +174,7 @@ fn print_warnings(title: &str, warnings: &[LintJson], truncate_after: usize) { println!("{}", warning.info_text(title)); println!(); println!("```"); - println!("{}", warning.rendered.trim_end()); + println!("{}", warning.rendered); println!("```"); println!(); } @@ -182,7 +185,7 @@ fn print_changed_diff(changed: &[(LintJson, LintJson)], truncate_after: usize) { return; } - print_h3(&changed[0].0.lint, "Changed"); + print_h3(&changed[0].0.name, "Changed"); println!(); let changed = truncate(changed, truncate_after); @@ -191,7 +194,7 @@ fn print_changed_diff(changed: &[(LintJson, LintJson)], truncate_after: usize) { println!("{}", new.info_text("Changed")); println!(); println!("```diff"); - for change in diff::lines(old.rendered.trim_end(), new.rendered.trim_end()) { + for change in diff::lines(&old.rendered, &new.rendered) { use diff::Result::{Both, Left, Right}; match change { diff --git a/src/tools/clippy/lintcheck/src/output.rs b/src/tools/clippy/lintcheck/src/output.rs index 15378630695..e38036315c2 100644 --- a/src/tools/clippy/lintcheck/src/output.rs +++ b/src/tools/clippy/lintcheck/src/output.rs @@ -51,7 +51,7 @@ impl RustcIce { /// A single warning that clippy issued while checking a `Crate` #[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct ClippyWarning { - pub lint: String, + pub name: String, pub diag: Diagnostic, pub krate: String, /// The URL that points to the file and line of the lint emission @@ -60,8 +60,8 @@ pub struct ClippyWarning { impl ClippyWarning { pub fn new(mut diag: Diagnostic, base_url: &str, krate: &str) -> Option<Self> { - let lint = diag.code.clone()?.code; - if !(lint.contains("clippy") || diag.message.contains("clippy")) + let name = diag.code.clone()?.code; + if !(name.contains("clippy") || diag.message.contains("clippy")) || diag.message.contains("could not read cargo metadata") { return None; @@ -92,7 +92,7 @@ impl ClippyWarning { }; Some(Self { - lint, + name, diag, url, krate: krate.to_string(), @@ -108,7 +108,7 @@ impl ClippyWarning { let mut file = span.file_name.clone(); let file_with_pos = format!("{file}:{}:{}", span.line_start, span.line_end); match format { - OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.lint, self.diag.message), + OutputFormat::Text => format!("{file_with_pos} {} \"{}\"\n", self.name, self.diag.message), OutputFormat::Markdown => { if file.starts_with("target") { file.insert_str(0, "../"); @@ -116,7 +116,7 @@ impl ClippyWarning { let mut output = String::from("| "); write!(output, "[`{file_with_pos}`]({file}#L{})", span.line_start).unwrap(); - write!(output, r#" | `{:<50}` | "{}" |"#, self.lint, self.diag.message).unwrap(); + write!(output, r#" | `{:<50}` | "{}" |"#, self.name, self.diag.message).unwrap(); output.push('\n'); output }, @@ -164,7 +164,7 @@ fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) let mut counter: HashMap<&String, usize> = HashMap::new(); warnings .iter() - .for_each(|wrn| *counter.entry(&wrn.lint).or_insert(0) += 1); + .for_each(|wrn| *counter.entry(&wrn.name).or_insert(0) += 1); // collect into a tupled list for sorting let mut stats: Vec<(&&String, &usize)> = counter.iter().collect(); diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 5fbe4e544a9..0be2e81810e 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-08-08" +channel = "nightly-2024-08-23" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 64253514fbe..9754254cdd0 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -1,25 +1,31 @@ -// We need this feature as it changes `dylib` linking behavior and allows us to link to -// `rustc_driver`. -#![feature(rustc_private)] +#![feature(rustc_private, let_chains)] #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unused_extern_crates)] +use cargo_metadata::diagnostic::{Applicability, Diagnostic}; +use cargo_metadata::Message; +use clippy_config::ClippyConfiguration; +use clippy_lints::declared_lints::LINTS; +use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; +use clippy_lints::LintInfo; +use serde::{Deserialize, Serialize}; +use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::custom_flags::rustfix::RustfixMode; +use ui_test::custom_flags::Flag; use ui_test::spanned::Spanned; +use ui_test::test_result::TestRun; use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, OutputConflictHandling}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use std::env::{self, set_var, var_os}; use std::ffi::{OsStr, OsString}; -use std::fs; +use std::fmt::Write; use std::path::{Path, PathBuf}; -use std::sync::LazyLock; -use test_utils::IS_RUSTC_TEST_SUITE; +use std::sync::mpsc::{channel, Sender}; +use std::{fs, iter, thread}; // Test dependencies may need an `extern crate` here to ensure that they show up // in the depinfo file (otherwise cargo thinks they are unused) -extern crate clippy_lints; -extern crate clippy_utils; extern crate futures; extern crate if_chain; extern crate itertools; @@ -55,7 +61,7 @@ static TEST_DEPENDENCIES: &[&str] = &[ /// dependencies must be added to Cargo.toml at the project root. Test /// dependencies that are not *directly* used by this test module require an /// `extern crate` declaration. -static EXTERN_FLAGS: LazyLock<Vec<String>> = LazyLock::new(|| { +fn extern_flags() -> Vec<String> { let current_exe_depinfo = { let mut path = env::current_exe().unwrap(); path.set_extension("d"); @@ -103,70 +109,93 @@ static EXTERN_FLAGS: LazyLock<Vec<String>> = LazyLock::new(|| { .into_iter() .map(|(name, path)| format!("--extern={name}={path}")) .collect() -}); +} // whether to run internal tests or not const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal"); -fn base_config(test_dir: &str) -> (Config, Args) { - let mut args = Args::test().unwrap(); - args.bless |= var_os("RUSTC_BLESS").is_some_and(|v| v != "0"); - - let target_dir = PathBuf::from(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into())); - let mut config = Config { - output_conflict_handling: OutputConflictHandling::Error, - filter_files: env::var("TESTNAME") - .map(|filters| filters.split(',').map(str::to_string).collect()) - .unwrap_or_default(), - target: None, - bless_command: Some("cargo uibless".into()), - out_dir: target_dir.join("ui_test"), - ..Config::rustc(Path::new("tests").join(test_dir)) - }; - config.comment_defaults.base().exit_status = None.into(); - config.comment_defaults.base().require_annotations = None.into(); - config - .comment_defaults - .base() - .set_custom("rustfix", RustfixMode::Everything); - config.comment_defaults.base().diagnostic_code_prefix = Some(Spanned::dummy("clippy::".into())).into(); - config.with_args(&args); - let current_exe_path = env::current_exe().unwrap(); - let deps_path = current_exe_path.parent().unwrap(); - let profile_path = deps_path.parent().unwrap(); - - config.program.args.extend( - [ - "--emit=metadata", - "-Aunused", - "-Ainternal_features", - "-Zui-testing", - "-Zdeduplicate-diagnostics=no", - "-Dwarnings", - &format!("-Ldependency={}", deps_path.display()), - ] - .map(OsString::from), - ); - - config.program.args.extend(EXTERN_FLAGS.iter().map(OsString::from)); - // Prevent rustc from creating `rustc-ice-*` files the console output is enough. - config.program.envs.push(("RUSTC_ICE".into(), Some("0".into()))); +struct TestContext { + args: Args, + extern_flags: Vec<String>, + diagnostic_collector: Option<DiagnosticCollector>, + collector_thread: Option<thread::JoinHandle<()>>, +} - if let Some(host_libs) = option_env!("HOST_LIBS") { - let dep = format!("-Ldependency={}", Path::new(host_libs).join("deps").display()); - config.program.args.push(dep.into()); +impl TestContext { + fn new() -> Self { + let mut args = Args::test().unwrap(); + args.bless |= var_os("RUSTC_BLESS").is_some_and(|v| v != "0"); + let (diagnostic_collector, collector_thread) = var_os("COLLECT_METADATA") + .is_some() + .then(DiagnosticCollector::spawn) + .unzip(); + Self { + args, + extern_flags: extern_flags(), + diagnostic_collector, + collector_thread, + } } - config.program.program = profile_path.join(if cfg!(windows) { - "clippy-driver.exe" - } else { - "clippy-driver" - }); - (config, args) + fn base_config(&self, test_dir: &str) -> Config { + let target_dir = PathBuf::from(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into())); + let mut config = Config { + output_conflict_handling: OutputConflictHandling::Error, + filter_files: env::var("TESTNAME") + .map(|filters| filters.split(',').map(str::to_string).collect()) + .unwrap_or_default(), + target: None, + bless_command: Some("cargo uibless".into()), + out_dir: target_dir.join("ui_test"), + ..Config::rustc(Path::new("tests").join(test_dir)) + }; + let defaults = config.comment_defaults.base(); + defaults.exit_status = None.into(); + defaults.require_annotations = None.into(); + defaults.diagnostic_code_prefix = Some(Spanned::dummy("clippy::".into())).into(); + defaults.set_custom("rustfix", RustfixMode::Everything); + if let Some(collector) = self.diagnostic_collector.clone() { + defaults.set_custom("diagnostic-collector", collector); + } + config.with_args(&self.args); + let current_exe_path = env::current_exe().unwrap(); + let deps_path = current_exe_path.parent().unwrap(); + let profile_path = deps_path.parent().unwrap(); + + config.program.args.extend( + [ + "--emit=metadata", + "-Aunused", + "-Ainternal_features", + "-Zui-testing", + "-Zdeduplicate-diagnostics=no", + "-Dwarnings", + &format!("-Ldependency={}", deps_path.display()), + ] + .map(OsString::from), + ); + + config.program.args.extend(self.extern_flags.iter().map(OsString::from)); + // Prevent rustc from creating `rustc-ice-*` files the console output is enough. + config.program.envs.push(("RUSTC_ICE".into(), Some("0".into()))); + + if let Some(host_libs) = option_env!("HOST_LIBS") { + let dep = format!("-Ldependency={}", Path::new(host_libs).join("deps").display()); + config.program.args.push(dep.into()); + } + + config.program.program = profile_path.join(if cfg!(windows) { + "clippy-driver.exe" + } else { + "clippy-driver" + }); + + config + } } -fn run_ui() { - let (mut config, args) = base_config("ui"); +fn run_ui(cx: &TestContext) { + let mut config = cx.base_config("ui"); config .program .envs @@ -176,30 +205,29 @@ fn run_ui() { vec![config], ui_test::default_file_filter, ui_test::default_per_file_config, - status_emitter::Text::from(args.format), + status_emitter::Text::from(cx.args.format), ) .unwrap(); } -fn run_internal_tests() { - // only run internal tests with the internal-tests feature +fn run_internal_tests(cx: &TestContext) { if !RUN_INTERNAL_TESTS { return; } - let (mut config, args) = base_config("ui-internal"); + let mut config = cx.base_config("ui-internal"); config.bless_command = Some("cargo uitest --features internal -- -- --bless".into()); ui_test::run_tests_generic( vec![config], ui_test::default_file_filter, ui_test::default_per_file_config, - status_emitter::Text::from(args.format), + status_emitter::Text::from(cx.args.format), ) .unwrap(); } -fn run_ui_toml() { - let (mut config, args) = base_config("ui-toml"); +fn run_ui_toml(cx: &TestContext) { + let mut config = cx.base_config("ui-toml"); config .comment_defaults @@ -217,19 +245,19 @@ fn run_ui_toml() { .envs .push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into()))); }, - status_emitter::Text::from(args.format), + status_emitter::Text::from(cx.args.format), ) .unwrap(); } // Allow `Default::default` as `OptWithSpan` is not nameable #[allow(clippy::default_trait_access)] -fn run_ui_cargo() { +fn run_ui_cargo(cx: &TestContext) { if IS_RUSTC_TEST_SUITE { return; } - let (mut config, args) = base_config("ui-cargo"); + let mut config = cx.base_config("ui-cargo"); config.program.input_file_flag = CommandBuilder::cargo().input_file_flag; config.program.out_dir_flag = CommandBuilder::cargo().out_dir_flag; config.program.args = vec!["clippy".into(), "--color".into(), "never".into(), "--quiet".into()]; @@ -264,23 +292,25 @@ fn run_ui_cargo() { .then(|| ui_test::default_any_file_filter(path, config) && !ignored_32bit(path)) }, |_config, _file_contents| {}, - status_emitter::Text::from(args.format), + status_emitter::Text::from(cx.args.format), ) .unwrap(); } fn main() { set_var("CLIPPY_DISABLE_DOCS_LINKS", "true"); + + let cx = TestContext::new(); + // The SPEEDTEST_* env variables can be used to check Clippy's performance on your PR. It runs the // affected test 1000 times and gets the average. if let Ok(speedtest) = std::env::var("SPEEDTEST") { println!("----------- STARTING SPEEDTEST -----------"); let f = match speedtest.as_str() { - "ui" => run_ui as fn(), - "cargo" => run_ui_cargo as fn(), - "toml" => run_ui_toml as fn(), - "internal" => run_internal_tests as fn(), - "ui-cargo-toml-metadata" => ui_cargo_toml_metadata as fn(), + "ui" => run_ui, + "cargo" => run_ui_cargo, + "toml" => run_ui_toml, + "internal" => run_internal_tests, _ => panic!("unknown speedtest: {speedtest} || accepted speedtests are: [ui, cargo, toml, internal]"), }; @@ -297,7 +327,7 @@ fn main() { let mut sum = 0; for _ in 0..iterations { let start = std::time::Instant::now(); - f(); + f(&cx); sum += start.elapsed().as_millis(); } println!( @@ -306,11 +336,17 @@ fn main() { sum / u128::from(iterations) ); } else { - run_ui(); - run_ui_toml(); - run_ui_cargo(); - run_internal_tests(); + run_ui(&cx); + run_ui_toml(&cx); + run_ui_cargo(&cx); + run_internal_tests(&cx); + drop(cx.diagnostic_collector); + ui_cargo_toml_metadata(); + + if let Some(thread) = cx.collector_thread { + thread.join().unwrap(); + } } } @@ -349,3 +385,180 @@ fn ui_cargo_toml_metadata() { ); } } + +#[derive(Deserialize)] +#[serde(untagged)] +enum DiagnosticOrMessage { + Diagnostic(Diagnostic), + Message(Message), +} + +/// Collects applicabilities from the diagnostics produced for each UI test, producing the +/// `util/gh-pages/lints.json` file used by <https://rust-lang.github.io/rust-clippy/> +#[derive(Debug, Clone)] +struct DiagnosticCollector { + sender: Sender<Vec<u8>>, +} + +impl DiagnosticCollector { + #[allow(clippy::assertions_on_constants)] + fn spawn() -> (Self, thread::JoinHandle<()>) { + assert!(!IS_RUSTC_TEST_SUITE && !RUN_INTERNAL_TESTS); + + let (sender, receiver) = channel::<Vec<u8>>(); + + let handle = thread::spawn(|| { + let mut applicabilities = HashMap::new(); + + for stderr in receiver { + for line in stderr.split(|&byte| byte == b'\n') { + let diag = match serde_json::from_slice(line) { + Ok(DiagnosticOrMessage::Diagnostic(diag)) => diag, + Ok(DiagnosticOrMessage::Message(Message::CompilerMessage(message))) => message.message, + _ => continue, + }; + + if let Some(lint) = diag.code.as_ref().and_then(|code| code.code.strip_prefix("clippy::")) { + let applicability = applicabilities + .entry(lint.to_string()) + .or_insert(Applicability::Unspecified); + let diag_applicability = diag + .children + .iter() + .flat_map(|child| &child.spans) + .filter_map(|span| span.suggestion_applicability.clone()) + .max_by_key(applicability_ord); + if let Some(diag_applicability) = diag_applicability + && applicability_ord(&diag_applicability) > applicability_ord(applicability) + { + *applicability = diag_applicability; + } + } + } + } + + let configs = clippy_config::get_configuration_metadata(); + let mut metadata: Vec<LintMetadata> = LINTS + .iter() + .map(|lint| LintMetadata::new(lint, &applicabilities, &configs)) + .chain( + iter::zip(DEPRECATED, DEPRECATED_VERSION) + .map(|((lint, reason), version)| LintMetadata::new_deprecated(lint, reason, version)), + ) + .collect(); + metadata.sort_unstable_by(|a, b| a.id.cmp(&b.id)); + + let json = serde_json::to_string_pretty(&metadata).unwrap(); + fs::write("util/gh-pages/lints.json", json).unwrap(); + }); + + (Self { sender }, handle) + } +} + +fn applicability_ord(applicability: &Applicability) -> u8 { + match applicability { + Applicability::MachineApplicable => 4, + Applicability::HasPlaceholders => 3, + Applicability::MaybeIncorrect => 2, + Applicability::Unspecified => 1, + _ => unimplemented!(), + } +} + +impl Flag for DiagnosticCollector { + fn post_test_action( + &self, + _config: &ui_test::per_test_config::TestConfig<'_>, + _cmd: &mut std::process::Command, + output: &std::process::Output, + _build_manager: &ui_test::build_manager::BuildManager<'_>, + ) -> Result<Vec<TestRun>, ui_test::Errored> { + if !output.stderr.is_empty() { + self.sender.send(output.stderr.clone()).unwrap(); + } + Ok(Vec::new()) + } + + fn clone_inner(&self) -> Box<dyn Flag> { + Box::new(self.clone()) + } + + fn must_be_unique(&self) -> bool { + true + } +} + +#[derive(Debug, Serialize)] +struct LintMetadata { + id: String, + id_location: Option<&'static str>, + group: &'static str, + level: &'static str, + docs: String, + version: &'static str, + applicability: Applicability, +} + +impl LintMetadata { + fn new(lint: &LintInfo, applicabilities: &HashMap<String, Applicability>, configs: &[ClippyConfiguration]) -> Self { + let name = lint.name_lower(); + let applicability = applicabilities + .get(&name) + .cloned() + .unwrap_or(Applicability::Unspecified); + let past_names = RENAMED + .iter() + .filter(|(_, new_name)| new_name.strip_prefix("clippy::") == Some(&name)) + .map(|(old_name, _)| old_name.strip_prefix("clippy::").unwrap()) + .collect::<Vec<_>>(); + let mut docs = lint.explanation.to_string(); + if !past_names.is_empty() { + docs.push_str("\n### Past names\n\n"); + for past_name in past_names { + writeln!(&mut docs, " * {past_name}").unwrap(); + } + } + let configs: Vec<_> = configs + .iter() + .filter(|conf| conf.lints.contains(&name.as_str())) + .collect(); + if !configs.is_empty() { + docs.push_str("\n### Configuration\n\n"); + for config in configs { + writeln!(&mut docs, "{config}").unwrap(); + } + } + Self { + id: name, + id_location: Some(lint.location), + group: lint.category_str(), + level: lint.lint.default_level.as_str(), + docs, + version: lint.version.unwrap(), + applicability, + } + } + + fn new_deprecated(name: &str, reason: &str, version: &'static str) -> Self { + // The reason starts with a lowercase letter and ends without a period. + // This needs to be fixed for the website. + let mut reason = reason.to_owned(); + if let Some(reason) = reason.get_mut(0..1) { + reason.make_ascii_uppercase(); + } + Self { + id: name.strip_prefix("clippy::").unwrap().into(), + id_location: None, + group: "deprecated", + level: "none", + version, + docs: format!( + "### What it does\n\n\ + Nothing. This lint has been deprecated\n\n\ + ### Deprecation reason\n\n{reason}.\n", + ), + applicability: Applicability::Unspecified, + } + } +} diff --git a/src/tools/clippy/tests/config-metadata.rs b/src/tools/clippy/tests/config-metadata.rs new file mode 100644 index 00000000000..3e3711873ba --- /dev/null +++ b/src/tools/clippy/tests/config-metadata.rs @@ -0,0 +1,78 @@ +#![feature(rustc_private)] + +use clippy_config::{get_configuration_metadata, ClippyConfiguration}; +use itertools::Itertools; +use regex::Regex; +use std::borrow::Cow; +use std::{env, fs}; + +fn metadata() -> impl Iterator<Item = ClippyConfiguration> { + get_configuration_metadata() + .into_iter() + .filter(|config| config.deprecation_reason.is_none()) + .filter(|config| !config.lints.is_empty()) +} + +#[test] +fn book() { + let path = "book/src/lint_configuration.md"; + let current = fs::read_to_string(path).unwrap(); + + let configs = metadata().map(|conf| conf.to_markdown_paragraph()).join("\n"); + let expected = format!( + r#"<!-- +This file is generated by `cargo bless --test config-metadata`. +Please use that command to update the file and do not edit it by hand. +--> + +# Lint Configuration Options + +The following list shows each configuration option, along with a description, its default value, an example +and lints affected. + +--- + +{} +"#, + configs.trim(), + ); + + if current != expected { + if env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0") { + fs::write(path, expected).unwrap(); + } else { + panic!("`{path}` is out of date, run `cargo bless --test config-metadata` to update it"); + } + } +} + +#[test] +fn changelog() { + let path = "CHANGELOG.md"; + let current = fs::read_to_string(path).unwrap(); + + let configs = metadata().map(|conf| conf.to_markdown_link()).join("\n"); + + let re = Regex::new( + "(?s)\ + (<!-- begin autogenerated links to configuration documentation -->)\ + .*\ + (<!-- end autogenerated links to configuration documentation -->)\ + ", + ) + .unwrap(); + let expected = re.replace(¤t, format!("$1\n{configs}\n$2")); + + assert!( + matches!(expected, Cow::Owned(_)), + "failed to find configuration section in `{path}`" + ); + + if current != expected { + if env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0") { + fs::write(path, expected.as_bytes()).unwrap(); + } else { + panic!("`{path}` is out of date, run `cargo bless --test config-metadata` to update it"); + } + } +} diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr index 1cc1034cd89..d24b0cd6162 100644 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr @@ -1,29 +1,44 @@ error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:40:5 + --> tests/ui-toml/absolute_paths/absolute_paths.rs:14:13 | -LL | std::f32::MAX; - | ^^^^^^^^^^^^^ +LL | let _ = std::path::is_separator(' '); + | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::absolute-paths` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::absolute_paths)]` +note: the lint level is defined here + --> tests/ui-toml/absolute_paths/absolute_paths.rs:7:9 + | +LL | #![deny(clippy::absolute_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:20:13 + | +LL | let _ = ::std::path::MAIN_SEPARATOR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:25:13 + | +LL | let _ = std::collections::hash_map::HashMap::<i32, i32>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:41:5 + --> tests/ui-toml/absolute_paths/absolute_paths.rs:28:31 | -LL | core::f32::MAX; - | ^^^^^^^^^^^^^^ +LL | let _: &std::path::Path = std::path::Path::new(""); + | ^^^^^^^^^^^^^^^ error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:42:5 + --> tests/ui-toml/absolute_paths/absolute_paths.rs:28:13 | -LL | ::core::f32::MAX; - | ^^^^^^^^^^^^^^^^ +LL | let _: &std::path::Path = std::path::Path::new(""); + | ^^^^^^^^^^^^^^^ error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:58:5 + --> tests/ui-toml/absolute_paths/absolute_paths.rs:43:13 | -LL | ::std::f32::MAX; - | ^^^^^^^^^^^^^^^ +LL | let _ = std::option::Option::None::<i32>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_long.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_long.stderr new file mode 100644 index 00000000000..0cc6566af3a --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_long.stderr @@ -0,0 +1,14 @@ +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:25:13 + | +LL | let _ = std::collections::hash_map::HashMap::<i32, i32>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui-toml/absolute_paths/absolute_paths.rs:7:9 + | +LL | #![deny(clippy::absolute_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.default.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.default.stderr new file mode 100644 index 00000000000..53aa9030e0d --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.default.stderr @@ -0,0 +1,80 @@ +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:14:13 + | +LL | let _ = std::path::is_separator(' '); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui-toml/absolute_paths/absolute_paths.rs:7:9 + | +LL | #![deny(clippy::absolute_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:20:13 + | +LL | let _ = ::std::path::MAIN_SEPARATOR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:25:13 + | +LL | let _ = std::collections::hash_map::HashMap::<i32, i32>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:28:31 + | +LL | let _: &std::path::Path = std::path::Path::new(""); + | ^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:28:13 + | +LL | let _: &std::path::Path = std::path::Path::new(""); + | ^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:37:13 + | +LL | let _ = ::core::clone::Clone::clone(&0i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:40:13 + | +LL | let _ = <i32 as core::clone::Clone>::clone(&0i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:43:13 + | +LL | let _ = std::option::Option::None::<i32>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:65:17 + | +LL | impl<T: core::cmp::Eq> core::fmt::Display for X<T> + | ^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:70:18 + | +LL | where T: core::clone::Clone + | ^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:65:32 + | +LL | impl<T: core::cmp::Eq> core::fmt::Display for X<T> + | ^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:116:5 + | +LL | crate::m1::S + | ^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr deleted file mode 100644 index f342ebf6632..00000000000 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr +++ /dev/null @@ -1,71 +0,0 @@ -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:40:5 - | -LL | std::f32::MAX; - | ^^^^^^^^^^^^^ - | - = note: `-D clippy::absolute-paths` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::absolute_paths)]` - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:41:5 - | -LL | core::f32::MAX; - | ^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:42:5 - | -LL | ::core::f32::MAX; - | ^^^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:43:5 - | -LL | crate::a::b::c::C; - | ^^^^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:44:5 - | -LL | crate::a::b::c::d::e::f::F; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:45:5 - | -LL | crate::a::A; - | ^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:46:5 - | -LL | crate::a::b::B; - | ^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:47:5 - | -LL | crate::a::b::c::C::ZERO; - | ^^^^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:48:5 - | -LL | helper::b::c::d::e::f(); - | ^^^^^^^^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:49:5 - | -LL | ::helper::b::c::d::e::f(); - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:58:5 - | -LL | ::std::f32::MAX; - | ^^^^^^^^^^^^^^^ - -error: aborting due to 11 previous errors - diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr new file mode 100644 index 00000000000..70d71f6c4ea --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr @@ -0,0 +1,98 @@ +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:14:13 + | +LL | let _ = std::path::is_separator(' '); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui-toml/absolute_paths/absolute_paths.rs:7:9 + | +LL | #![deny(clippy::absolute_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:20:13 + | +LL | let _ = ::std::path::MAIN_SEPARATOR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:25:13 + | +LL | let _ = std::collections::hash_map::HashMap::<i32, i32>::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:28:31 + | +LL | let _: &std::path::Path = std::path::Path::new(""); + | ^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:28:13 + | +LL | let _: &std::path::Path = std::path::Path::new(""); + | ^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:37:13 + | +LL | let _ = ::core::clone::Clone::clone(&0i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:40:13 + | +LL | let _ = <i32 as core::clone::Clone>::clone(&0i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:43:13 + | +LL | let _ = std::option::Option::None::<i32>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:65:17 + | +LL | impl<T: core::cmp::Eq> core::fmt::Display for X<T> + | ^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:70:18 + | +LL | where T: core::clone::Clone + | ^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:65:32 + | +LL | impl<T: core::cmp::Eq> core::fmt::Display for X<T> + | ^^^^^^^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:113:14 + | +LL | pub const _: crate::S = { + | ^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:114:9 + | +LL | let crate::S = m1::S; + | ^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:116:5 + | +LL | crate::m1::S + | ^^^^^^^^^^^^ + +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths.rs:122:14 + | +LL | let _ = <crate::S as Clone>::clone(&m1::S); + | ^^^^^^^^ + +error: aborting due to 15 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs index a828701bcee..c024f2f513c 100644 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs @@ -1,97 +1,123 @@ //@aux-build:../../ui/auxiliary/proc_macros.rs -//@aux-build:helper.rs -//@revisions: allow_crates disallow_crates +//@revisions: default allow_crates allow_long no_short +//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/default //@[allow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_crates -//@[disallow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/disallow_crates -#![allow(clippy::no_effect, clippy::legacy_numeric_constants, unused)] -#![warn(clippy::absolute_paths)] -#![feature(decl_macro)] +//@[allow_long] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_long +//@[no_short] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/no_short +#![deny(clippy::absolute_paths)] -extern crate helper; -#[macro_use] extern crate proc_macros; +use proc_macros::{external, inline_macros, with_span}; -pub mod a { - pub mod b { - pub mod c { - pub struct C; +#[inline_macros] +fn main() { + let _ = std::path::is_separator(' '); + //~[default]^ absolute_paths + //~[allow_crates]| absolute_paths + //~[no_short]| absolute_paths - impl C { - pub const ZERO: u32 = 0; - } + // Make sure this is treated as having three path segments, not four. + let _ = ::std::path::MAIN_SEPARATOR; + //~[default]^ absolute_paths + //~[allow_crates]| absolute_paths + //~[no_short]| absolute_paths - pub mod d { - pub mod e { - pub mod f { - pub struct F; - } - } - } - } + let _ = std::collections::hash_map::HashMap::<i32, i32>::new(); //~ absolute_paths - pub struct B; - } + // Note `std::path::Path::new` is treated as having three parts + let _: &std::path::Path = std::path::Path::new(""); + //~[default]^ absolute_paths + //~[default]| absolute_paths + //~[allow_crates]| absolute_paths + //~[allow_crates]| absolute_paths + //~[no_short]| absolute_paths + //~[no_short]| absolute_paths - pub struct A; -} + // Treated as having three parts. + let _ = ::core::clone::Clone::clone(&0i32); + //~[default]^ absolute_paths + //~[no_short]| absolute_paths + let _ = <i32 as core::clone::Clone>::clone(&0i32); + //~[default]^ absolute_paths + //~[no_short]| absolute_paths + let _ = std::option::Option::None::<i32>; + //~[default]^ absolute_paths + //~[allow_crates]| absolute_paths + //~[no_short]| absolute_paths -fn main() { - f32::max(1.0, 2.0); - std::f32::MAX; - core::f32::MAX; - ::core::f32::MAX; - crate::a::b::c::C; - crate::a::b::c::d::e::f::F; - crate::a::A; - crate::a::b::B; - crate::a::b::c::C::ZERO; - helper::b::c::d::e::f(); - ::helper::b::c::d::e::f(); - fn b() -> a::b::B { - todo!() + { + // FIXME: macro calls should be checked. + let x = 1i32; + let _ = core::ptr::addr_of!(x); } - std::println!("a"); - let x = 1; - std::ptr::addr_of!(x); - // Test we handle max segments with `PathRoot` properly; this has 4 segments but we should say it - // has 3 - ::std::f32::MAX; - // Do not lint due to the above - ::helper::a(); - // Do not lint - helper::a(); - use crate::a::b::c::C; - use a::b; - use std::f32::MAX; - a::b::c::d::e::f::F; - b::c::C; - fn a() -> a::A { - todo!() - } - use a::b::c; - fn c() -> c::C { - todo!() + { + // FIXME: derive macro paths should be checked. + #[derive(core::clone::Clone)] + struct S; } - fn d() -> Result<(), ()> { - todo!() + + { + use core::fmt; + use core::marker::PhantomData; + + struct X<T>(PhantomData<T>); + impl<T: core::cmp::Eq> core::fmt::Display for X<T> + //~[default]^ absolute_paths + //~[default]| absolute_paths + //~[no_short]| absolute_paths + //~[no_short]| absolute_paths + where T: core::clone::Clone + //~[no_short]^ absolute_paths + //~[default]| absolute_paths + { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + } } - external! { - crate::a::b::c::C::ZERO; + + { + mod m1 { + pub(crate) mod m2 { + pub(crate) const FOO: i32 = 0; + } + } + let _ = m1::m2::FOO; } - // For some reason, `path.span.from_expansion()` takes care of this for us + with_span! { span - crate::a::b::c::C::ZERO; + let _ = std::path::is_separator(' '); } - macro_rules! local_crate { - () => { - crate::a::b::c::C::ZERO; - }; + + external! { + let _ = std::path::is_separator(' '); } - macro local_crate_2_0() { - crate::a::b::c::C::ZERO; + + inline! { + let _ = std::path::is_separator(' '); } - local_crate!(); - local_crate_2_0!(); +} + +pub use core::cmp::Ordering; +pub use std::fs::File; + +#[derive(Clone)] +pub struct S; +mod m1 { + pub use crate::S; +} + +//~[no_short]v absolute_paths +pub const _: crate::S = { + let crate::S = m1::S; //~[no_short] absolute_paths + + crate::m1::S + //~[default]^ absolute_paths + //~[no_short]| absolute_paths +}; + +pub fn f() { + let _ = <crate::S as Clone>::clone(&m1::S); //~[no_short] absolute_paths } diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.default.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.default.stderr new file mode 100644 index 00000000000..6fc495f0180 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.default.stderr @@ -0,0 +1,14 @@ +error: consider bringing this path into scope with the `use` keyword + --> tests/ui-toml/absolute_paths/absolute_paths_2015.rs:15:13 + | +LL | let _ = ::m1::m2::X; + | ^^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui-toml/absolute_paths/absolute_paths_2015.rs:6:9 + | +LL | #![deny(clippy::absolute_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.rs new file mode 100644 index 00000000000..033c4780919 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.rs @@ -0,0 +1,16 @@ +//@revisions: default allow_crates +//@[default]rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/default +//@[allow_crates]rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_crates +//@edition:2015 + +#![deny(clippy::absolute_paths)] + +mod m1 { + pub mod m2 { + pub struct X; + } +} + +fn main() { + let _ = ::m1::m2::X; //~[default] absolute_paths +} diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml b/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml index 59a621e9d1d..9da49abcd31 100644 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml @@ -1,2 +1 @@ -absolute-paths-max-segments = 2 -absolute-paths-allowed-crates = ["crate", "helper"] +absolute-paths-allowed-crates = ["core", "crate"] diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/allow_long/clippy.toml b/src/tools/clippy/tests/ui-toml/absolute_paths/allow_long/clippy.toml new file mode 100644 index 00000000000..5992fd1ed82 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/allow_long/clippy.toml @@ -0,0 +1 @@ +absolute-paths-max-segments = 3 diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs deleted file mode 100644 index 8e2678f5fe6..00000000000 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub fn a() {} - -pub mod b { - pub mod c { - pub mod d { - pub mod e { - pub fn f() {} - } - } - } -} diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/default/clippy.toml b/src/tools/clippy/tests/ui-toml/absolute_paths/default/clippy.toml new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/default/clippy.toml diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml b/src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml deleted file mode 100644 index d44d648c641..00000000000 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -absolute-paths-max-segments = 2 diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/no_short/clippy.toml b/src/tools/clippy/tests/ui-toml/absolute_paths/no_short/clippy.toml new file mode 100644 index 00000000000..357524420c5 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/no_short/clippy.toml @@ -0,0 +1 @@ +absolute-paths-max-segments = 0 diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs index a312df5a43a..3dafea56514 100644 --- a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs +++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs @@ -1,7 +1,7 @@ //! Tests macro_metavars_in_unsafe with default configuration #![feature(decl_macro)] #![warn(clippy::macro_metavars_in_unsafe)] -#![allow(clippy::no_effect)] +#![allow(clippy::no_effect, clippy::not_unsafe_ptr_arg_deref)] #[macro_export] macro_rules! allow_works { @@ -237,6 +237,19 @@ macro_rules! nested_macros { }}; } +pub mod issue13219 { + #[macro_export] + macro_rules! m { + ($e:expr) => { + // Metavariable in a block tail expression + unsafe { $e } + }; + } + pub fn f(p: *const i32) -> i32 { + m!(*p) + } +} + fn main() { allow_works!(1); simple!(1); diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr index d6b97f6fde1..6f0ebcbba02 100644 --- a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr +++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr @@ -1,4 +1,16 @@ error: this macro expands metavariables in an unsafe block + --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:245:13 + | +LL | unsafe { $e } + | ^^^^^^^^^^^^^ + | + = note: this allows the user of the macro to write unsafe code outside of an unsafe block + = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable + = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite + = note: `-D clippy::macro-metavars-in-unsafe` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::macro_metavars_in_unsafe)]` + +error: this macro expands metavariables in an unsafe block --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:19:9 | LL | / unsafe { @@ -10,8 +22,6 @@ LL | | } = note: this allows the user of the macro to write unsafe code outside of an unsafe block = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite - = note: `-D clippy::macro-metavars-in-unsafe` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::macro_metavars_in_unsafe)]` error: this macro expands metavariables in an unsafe block --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:30:9 @@ -183,5 +193,5 @@ LL | | } = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/assigning_clones.fixed b/src/tools/clippy/tests/ui/assigning_clones.fixed index b376d55a402..09732d1a50c 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.fixed +++ b/src/tools/clippy/tests/ui/assigning_clones.fixed @@ -396,3 +396,23 @@ impl<T: Clone> Clone for DerefWrapperWithClone<T> { *self = Self(source.0.clone()); } } + +#[cfg(test)] +mod test { + #[derive(Default)] + struct Data { + field: String, + } + + fn test_data() -> Data { + Data { + field: "default_value".to_string(), + } + } + + #[test] + fn test() { + let mut data = test_data(); + data.field = "override_value".to_owned(); + } +} diff --git a/src/tools/clippy/tests/ui/assigning_clones.rs b/src/tools/clippy/tests/ui/assigning_clones.rs index 11a5d4459c3..6be25ae17a5 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.rs +++ b/src/tools/clippy/tests/ui/assigning_clones.rs @@ -396,3 +396,23 @@ impl<T: Clone> Clone for DerefWrapperWithClone<T> { *self = Self(source.0.clone()); } } + +#[cfg(test)] +mod test { + #[derive(Default)] + struct Data { + field: String, + } + + fn test_data() -> Data { + Data { + field: "default_value".to_string(), + } + } + + #[test] + fn test() { + let mut data = test_data(); + data.field = "override_value".to_owned(); + } +} diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr index f7e659b10de..329be4d3662 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr +++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.stderr @@ -2,7 +2,7 @@ error: called `unwrap` on `x` after checking its variant with `is_some` --> tests/ui/checked_unwrap/complex_conditionals_nested.rs:13:13 | LL | if x.is_some() { - | -------------- help: try: `if let Some(..) = x` + | -------------- help: try: `if let Some(<item>) = x` LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr index ddd600418af..f7e338935a7 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -2,7 +2,7 @@ error: called `unwrap` on `x` after checking its variant with `is_some` --> tests/ui/checked_unwrap/simple_conditionals.rs:46:9 | LL | if x.is_some() { - | -------------- help: try: `if let Some(..) = x` + | -------------- help: try: `if let Some(<item>) = x` LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ @@ -17,7 +17,7 @@ error: called `expect` on `x` after checking its variant with `is_some` --> tests/ui/checked_unwrap/simple_conditionals.rs:49:9 | LL | if x.is_some() { - | -------------- help: try: `if let Some(..) = x` + | -------------- help: try: `if let Some(<item>) = x` ... LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -59,7 +59,7 @@ error: called `unwrap` on `x` after checking its variant with `is_none` --> tests/ui/checked_unwrap/simple_conditionals.rs:65:9 | LL | if x.is_none() { - | -------------- help: try: `if let Some(..) = x` + | -------------- help: try: `if let Some(<item>) = x` ... LL | x.unwrap(); | ^^^^^^^^^^ @@ -68,7 +68,7 @@ error: called `unwrap` on `x` after checking its variant with `is_some` --> tests/ui/checked_unwrap/simple_conditionals.rs:13:13 | LL | if $a.is_some() { - | --------------- help: try: `if let Some(..) = x` + | --------------- help: try: `if let Some(<item>) = x` LL | // unnecessary LL | $a.unwrap(); | ^^^^^^^^^^^ @@ -82,7 +82,7 @@ error: called `unwrap` on `x` after checking its variant with `is_ok` --> tests/ui/checked_unwrap/simple_conditionals.rs:78:9 | LL | if x.is_ok() { - | ------------ help: try: `if let Ok(..) = x` + | ------------ help: try: `if let Ok(<item>) = x` LL | // unnecessary LL | x.unwrap(); | ^^^^^^^^^^ @@ -91,7 +91,7 @@ error: called `expect` on `x` after checking its variant with `is_ok` --> tests/ui/checked_unwrap/simple_conditionals.rs:81:9 | LL | if x.is_ok() { - | ------------ help: try: `if let Ok(..) = x` + | ------------ help: try: `if let Ok(<item>) = x` ... LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -127,7 +127,7 @@ error: called `unwrap_err` on `x` after checking its variant with `is_ok` --> tests/ui/checked_unwrap/simple_conditionals.rs:94:9 | LL | if x.is_ok() { - | ------------ help: try: `if let Err(..) = x` + | ------------ help: try: `if let Err(<item>) = x` ... LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ error: called `unwrap_err` on `x` after checking its variant with `is_err` --> tests/ui/checked_unwrap/simple_conditionals.rs:102:9 | LL | if x.is_err() { - | ------------- help: try: `if let Err(..) = x` + | ------------- help: try: `if let Err(<item>) = x` ... LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ error: called `unwrap` on `x` after checking its variant with `is_err` --> tests/ui/checked_unwrap/simple_conditionals.rs:106:9 | LL | if x.is_err() { - | ------------- help: try: `if let Ok(..) = x` + | ------------- help: try: `if let Ok(<item>) = x` ... LL | x.unwrap(); | ^^^^^^^^^^ @@ -172,7 +172,7 @@ error: called `unwrap` on `option` after checking its variant with `is_some` --> tests/ui/checked_unwrap/simple_conditionals.rs:134:9 | LL | if option.is_some() { - | ------------------- help: try: `if let Some(..) = &option` + | ------------------- help: try: `if let Some(<item>) = &option` LL | option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +189,7 @@ error: called `unwrap` on `result` after checking its variant with `is_ok` --> tests/ui/checked_unwrap/simple_conditionals.rs:144:9 | LL | if result.is_ok() { - | ----------------- help: try: `if let Ok(..) = &result` + | ----------------- help: try: `if let Ok(<item>) = &result` LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -206,7 +206,7 @@ error: called `unwrap` on `option` after checking its variant with `is_some` --> tests/ui/checked_unwrap/simple_conditionals.rs:153:9 | LL | if option.is_some() { - | ------------------- help: try: `if let Some(..) = &mut option` + | ------------------- help: try: `if let Some(<item>) = &mut option` LL | option.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -223,7 +223,7 @@ error: called `unwrap` on `result` after checking its variant with `is_ok` --> tests/ui/checked_unwrap/simple_conditionals.rs:162:9 | LL | if result.is_ok() { - | ----------------- help: try: `if let Ok(..) = &mut result` + | ----------------- help: try: `if let Ok(<item>) = &mut result` LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr index 01944baee79..1da78b56239 100644 --- a/src/tools/clippy/tests/ui/collapsible_match.stderr +++ b/src/tools/clippy/tests/ui/collapsible_match.stderr @@ -223,7 +223,7 @@ help: the outer pattern can be modified to include the inner pattern LL | if let Issue9647::A { a, .. } = x { | ^ replace this binding LL | if let Some(u) = a { - | ^^^^^^^ with this pattern, prefixed by a: + | ^^^^^^^ with this pattern, prefixed by `a`: error: this `if let` can be collapsed into the outer `if let` --> tests/ui/collapsible_match.rs:292:9 diff --git a/src/tools/clippy/tests/ui/crashes/ice-3717.fixed b/src/tools/clippy/tests/ui/crashes/ice-3717.fixed new file mode 100644 index 00000000000..3f54b326979 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-3717.fixed @@ -0,0 +1,11 @@ +#![deny(clippy::implicit_hasher)] + +use std::collections::HashSet; + +fn main() {} + +pub fn ice_3717<S: ::std::hash::BuildHasher + Default>(_: &HashSet<usize, S>) { + //~^ ERROR: parameter of type `HashSet` should be generalized over different hashers + let _ = [0u8; 0]; + let _: HashSet<usize> = HashSet::default(); +} diff --git a/src/tools/clippy/tests/ui/crashes/ice-3717.rs b/src/tools/clippy/tests/ui/crashes/ice-3717.rs index 770f6cf448a..2890a9277c7 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3717.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3717.rs @@ -1,7 +1,5 @@ #![deny(clippy::implicit_hasher)] -//@no-rustfix: need to change the suggestion to a multipart suggestion - use std::collections::HashSet; fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-3717.stderr b/src/tools/clippy/tests/ui/crashes/ice-3717.stderr index 4b4618ee1bb..aac72c66965 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3717.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-3717.stderr @@ -1,5 +1,5 @@ error: parameter of type `HashSet` should be generalized over different hashers - --> tests/ui/crashes/ice-3717.rs:9:21 + --> tests/ui/crashes/ice-3717.rs:7:21 | LL | pub fn ice_3717(_: &HashSet<usize>) { | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs index 56a8d22cb1c..9dafad8b784 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::cell::Cell; use std::fmt::Display; +use std::ptr; use std::sync::atomic::AtomicUsize; use std::sync::Once; @@ -53,4 +54,20 @@ mod issue_8493 { issue_8493!(); } +#[repr(C, align(8))] +struct NoAtomic(usize); +#[repr(C, align(8))] +struct WithAtomic(AtomicUsize); + +const fn with_non_null() -> *const WithAtomic { + const NO_ATOMIC: NoAtomic = NoAtomic(0); + (&NO_ATOMIC as *const NoAtomic).cast() +} +const WITH_ATOMIC: *const WithAtomic = with_non_null(); + +struct Generic<T>(T); +impl<T> Generic<T> { + const RAW_POINTER: *const Cell<T> = ptr::null(); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr index 1f2b9561ce5..4a725147142 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr @@ -1,5 +1,5 @@ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:9:1 + --> tests/ui/declare_interior_mutable_const/others.rs:10:1 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:10:1 + --> tests/ui/declare_interior_mutable_const/others.rs:11:1 | LL | const CELL: Cell<usize> = Cell::new(6); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | const CELL: Cell<usize> = Cell::new(6); = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:11:1 + --> tests/ui/declare_interior_mutable_const/others.rs:12:1 | LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], V = help: consider making this a static item error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:16:9 + --> tests/ui/declare_interior_mutable_const/others.rs:17:9 | LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | declare_const!(_ONCE: Once = Once::new()); = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:44:13 + --> tests/ui/declare_interior_mutable_const/others.rs:45:13 | LL | const _BAZ: Cell<usize> = Cell::new(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.fixed b/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.fixed new file mode 100644 index 00000000000..fb0f40b34a4 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.fixed @@ -0,0 +1,13 @@ +// This test checks that words starting with capital letters and ending with "ified" don't +// trigger the lint. + +#![deny(clippy::doc_markdown)] + +pub enum OutputFormat { + /// `HumaNified` + //~^ ERROR: item in documentation is missing backticks + Plain, + // Should not warn! + /// JSONified console output + Json, +} diff --git a/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.rs b/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.rs new file mode 100644 index 00000000000..8c1e1a3cd6c --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.rs @@ -0,0 +1,13 @@ +// This test checks that words starting with capital letters and ending with "ified" don't +// trigger the lint. + +#![deny(clippy::doc_markdown)] + +pub enum OutputFormat { + /// HumaNified + //~^ ERROR: item in documentation is missing backticks + Plain, + // Should not warn! + /// JSONified console output + Json, +} diff --git a/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.stderr b/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.stderr new file mode 100644 index 00000000000..ae68a767ec9 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.stderr @@ -0,0 +1,18 @@ +error: item in documentation is missing backticks + --> tests/ui/doc/doc_markdown-issue_13097.rs:7:9 + | +LL | /// HumaNified + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> tests/ui/doc/doc_markdown-issue_13097.rs:4:9 + | +LL | #![deny(clippy::doc_markdown)] + | ^^^^^^^^^^^^^^^^^^^^ +help: try + | +LL | /// `HumaNified` + | ~~~~~~~~~~~~ + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/double_must_use.rs b/src/tools/clippy/tests/ui/double_must_use.rs index 615de3e2474..4460aeb075b 100644 --- a/src/tools/clippy/tests/ui/double_must_use.rs +++ b/src/tools/clippy/tests/ui/double_must_use.rs @@ -3,19 +3,19 @@ #[must_use] pub fn must_use_result() -> Result<(), ()> { - //~^ ERROR: this function has an empty `#[must_use]` attribute, but returns a type already + //~^ ERROR: this function has a `#[must_use]` attribute with no message, but returns a type already unimplemented!(); } #[must_use] pub fn must_use_tuple() -> (Result<(), ()>, u8) { - //~^ ERROR: this function has an empty `#[must_use]` attribute, but returns a type already + //~^ ERROR: this function has a `#[must_use]` attribute with no message, but returns a type already unimplemented!(); } #[must_use] pub fn must_use_array() -> [Result<(), ()>; 1] { - //~^ ERROR: this function has an empty `#[must_use]` attribute, but returns a type already + //~^ ERROR: this function has a `#[must_use]` attribute with no message, but returns a type already unimplemented!(); } @@ -32,7 +32,7 @@ async fn async_must_use() -> usize { #[must_use] async fn async_must_use_result() -> Result<(), ()> { - //~^ ERROR: this function has an empty `#[must_use]` attribute, but returns a type already + //~^ ERROR: this function has a `#[must_use]` attribute with no message, but returns a type already Ok(()) } diff --git a/src/tools/clippy/tests/ui/double_must_use.stderr b/src/tools/clippy/tests/ui/double_must_use.stderr index 0f2154ecbcf..b26d1e48a8b 100644 --- a/src/tools/clippy/tests/ui/double_must_use.stderr +++ b/src/tools/clippy/tests/ui/double_must_use.stderr @@ -1,36 +1,36 @@ -error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` +error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` --> tests/ui/double_must_use.rs:5:1 | LL | pub fn must_use_result() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: either add some descriptive text or remove the attribute + = help: either add some descriptive message or remove the attribute = note: `-D clippy::double-must-use` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::double_must_use)]` -error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` +error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` --> tests/ui/double_must_use.rs:11:1 | LL | pub fn must_use_tuple() -> (Result<(), ()>, u8) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: either add some descriptive text or remove the attribute + = help: either add some descriptive message or remove the attribute -error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` +error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` --> tests/ui/double_must_use.rs:17:1 | LL | pub fn must_use_array() -> [Result<(), ()>; 1] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: either add some descriptive text or remove the attribute + = help: either add some descriptive message or remove the attribute -error: this function has an empty `#[must_use]` attribute, but returns a type already marked as `#[must_use]` +error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` --> tests/ui/double_must_use.rs:34:1 | LL | async fn async_must_use_result() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: either add some descriptive text or remove the attribute + = help: either add some descriptive message or remove the attribute error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed index f38b34c5a7c..1148f0f6c6a 100644 --- a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed +++ b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed @@ -153,3 +153,15 @@ fn main() { let r = &x; for _ in r {} } + +#[clippy::msrv = "1.79"] +pub fn issue_13184() { + // https://github.com/rust-lang/rust-clippy/issues/13184 + // No need to fix, as IntoIterator for Box is valid starting from 1.80 + let mut values: Box<[u32]> = Box::new([1, 2]); + for _ in values.iter() {} + for _ in values.iter_mut() {} + + let rvalues = &values; + for _ in rvalues.iter() {} +} diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.rs b/src/tools/clippy/tests/ui/explicit_iter_loop.rs index 2e701ada5ac..4dda2f13e5b 100644 --- a/src/tools/clippy/tests/ui/explicit_iter_loop.rs +++ b/src/tools/clippy/tests/ui/explicit_iter_loop.rs @@ -153,3 +153,15 @@ fn main() { let r = &x; for _ in r.iter() {} } + +#[clippy::msrv = "1.79"] +pub fn issue_13184() { + // https://github.com/rust-lang/rust-clippy/issues/13184 + // No need to fix, as IntoIterator for Box is valid starting from 1.80 + let mut values: Box<[u32]> = Box::new([1, 2]); + for _ in values.iter() {} + for _ in values.iter_mut() {} + + let rvalues = &values; + for _ in rvalues.iter() {} +} diff --git a/src/tools/clippy/tests/ui/floating_point_abs.fixed b/src/tools/clippy/tests/ui/floating_point_abs.fixed index 5312a8b29c6..33183c76972 100644 --- a/src/tools/clippy/tests/ui/floating_point_abs.fixed +++ b/src/tools/clippy/tests/ui/floating_point_abs.fixed @@ -1,4 +1,3 @@ -#![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] /// Allow suboptimal ops in constant context diff --git a/src/tools/clippy/tests/ui/floating_point_abs.rs b/src/tools/clippy/tests/ui/floating_point_abs.rs index 8619177130c..a08d5bbcef5 100644 --- a/src/tools/clippy/tests/ui/floating_point_abs.rs +++ b/src/tools/clippy/tests/ui/floating_point_abs.rs @@ -1,4 +1,3 @@ -#![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] /// Allow suboptimal ops in constant context diff --git a/src/tools/clippy/tests/ui/floating_point_abs.stderr b/src/tools/clippy/tests/ui/floating_point_abs.stderr index f5a778c5b76..0c1f68f3b7f 100644 --- a/src/tools/clippy/tests/ui/floating_point_abs.stderr +++ b/src/tools/clippy/tests/ui/floating_point_abs.stderr @@ -1,5 +1,5 @@ error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:15:5 + --> tests/ui/floating_point_abs.rs:14:5 | LL | if num >= 0.0 { num } else { -num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.abs()` @@ -8,43 +8,43 @@ LL | if num >= 0.0 { num } else { -num } = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:19:5 + --> tests/ui/floating_point_abs.rs:18:5 | LL | if 0.0 < num { num } else { -num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.abs()` error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:23:5 + --> tests/ui/floating_point_abs.rs:22:5 | LL | if a.a > 0.0 { a.a } else { -a.a } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.a.abs()` error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:27:5 + --> tests/ui/floating_point_abs.rs:26:5 | LL | if 0.0 >= num { -num } else { num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.abs()` error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:31:5 + --> tests/ui/floating_point_abs.rs:30:5 | LL | if a.a < 0.0 { -a.a } else { a.a } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.a.abs()` error: manual implementation of negation of `abs` method - --> tests/ui/floating_point_abs.rs:35:5 + --> tests/ui/floating_point_abs.rs:34:5 | LL | if num < 0.0 { num } else { -num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-num.abs()` error: manual implementation of negation of `abs` method - --> tests/ui/floating_point_abs.rs:39:5 + --> tests/ui/floating_point_abs.rs:38:5 | LL | if 0.0 >= num { num } else { -num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-num.abs()` error: manual implementation of negation of `abs` method - --> tests/ui/floating_point_abs.rs:44:12 + --> tests/ui/floating_point_abs.rs:43:12 | LL | a: if a.a >= 0.0 { -a.a } else { a.a }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-a.a.abs()` diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed index 3ce2edf2c71..164aac2601a 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed @@ -1,4 +1,3 @@ -#![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] /// Allow suboptimal_ops in constant context diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.rs b/src/tools/clippy/tests/ui/floating_point_mul_add.rs index b5e4a8db4db..ae024b7f224 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.rs +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.rs @@ -1,4 +1,3 @@ -#![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] /// Allow suboptimal_ops in constant context diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr index 3e1a071de73..9c75909f715 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr @@ -1,5 +1,5 @@ error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:20:13 + --> tests/ui/floating_point_mul_add.rs:19:13 | LL | let _ = a * b + c; | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` @@ -8,73 +8,73 @@ LL | let _ = a * b + c; = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:21:13 + --> tests/ui/floating_point_mul_add.rs:20:13 | LL | let _ = a * b - c; | ^^^^^^^^^ help: consider using: `a.mul_add(b, -c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:22:13 + --> tests/ui/floating_point_mul_add.rs:21:13 | LL | let _ = c + a * b; | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:23:13 + --> tests/ui/floating_point_mul_add.rs:22:13 | LL | let _ = c - a * b; | ^^^^^^^^^ help: consider using: `a.mul_add(-b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:24:13 + --> tests/ui/floating_point_mul_add.rs:23:13 | LL | let _ = a + 2.0 * 4.0; | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:25:13 + --> tests/ui/floating_point_mul_add.rs:24:13 | LL | let _ = a + 2. * 4.; | ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:27:13 + --> tests/ui/floating_point_mul_add.rs:26:13 | LL | let _ = (a * b) + c; | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:28:13 + --> tests/ui/floating_point_mul_add.rs:27:13 | LL | let _ = c + (a * b); | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:29:13 + --> tests/ui/floating_point_mul_add.rs:28:13 | LL | let _ = a * b * c + d; | ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:31:13 + --> tests/ui/floating_point_mul_add.rs:30:13 | LL | let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:32:13 + --> tests/ui/floating_point_mul_add.rs:31:13 | LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:34:13 + --> tests/ui/floating_point_mul_add.rs:33:13 | LL | let _ = (a * a + b).sqrt(); | ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:37:13 + --> tests/ui/floating_point_mul_add.rs:36:13 | LL | let _ = a - (b * u as f64); | ^^^^^^^^^^^^^^^^^^ help: consider using: `b.mul_add(-(u as f64), a)` diff --git a/src/tools/clippy/tests/ui/floating_point_rad.fixed b/src/tools/clippy/tests/ui/floating_point_rad.fixed index a710bd9bd60..2f93d233cb4 100644 --- a/src/tools/clippy/tests/ui/floating_point_rad.fixed +++ b/src/tools/clippy/tests/ui/floating_point_rad.fixed @@ -1,4 +1,3 @@ -#![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] /// Allow suboptimal_flops in constant context diff --git a/src/tools/clippy/tests/ui/floating_point_rad.rs b/src/tools/clippy/tests/ui/floating_point_rad.rs index 14656f021df..9690effc4e1 100644 --- a/src/tools/clippy/tests/ui/floating_point_rad.rs +++ b/src/tools/clippy/tests/ui/floating_point_rad.rs @@ -1,4 +1,3 @@ -#![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] /// Allow suboptimal_flops in constant context diff --git a/src/tools/clippy/tests/ui/floating_point_rad.stderr b/src/tools/clippy/tests/ui/floating_point_rad.stderr index 64674342c2b..b834f5374e0 100644 --- a/src/tools/clippy/tests/ui/floating_point_rad.stderr +++ b/src/tools/clippy/tests/ui/floating_point_rad.stderr @@ -1,5 +1,5 @@ error: conversion to radians can be done more accurately - --> tests/ui/floating_point_rad.rs:11:13 + --> tests/ui/floating_point_rad.rs:10:13 | LL | let _ = degrees as f64 * std::f64::consts::PI / 180.0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_radians()` @@ -8,43 +8,43 @@ LL | let _ = degrees as f64 * std::f64::consts::PI / 180.0; = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: conversion to degrees can be done more accurately - --> tests/ui/floating_point_rad.rs:12:13 + --> tests/ui/floating_point_rad.rs:11:13 | LL | let _ = degrees as f64 * 180.0 / std::f64::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_degrees()` error: conversion to degrees can be done more accurately - --> tests/ui/floating_point_rad.rs:17:13 + --> tests/ui/floating_point_rad.rs:16:13 | LL | let _ = x * 180f32 / std::f32::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()` error: conversion to degrees can be done more accurately - --> tests/ui/floating_point_rad.rs:18:13 + --> tests/ui/floating_point_rad.rs:17:13 | LL | let _ = 90. * 180f64 / std::f64::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_degrees()` error: conversion to degrees can be done more accurately - --> tests/ui/floating_point_rad.rs:19:13 + --> tests/ui/floating_point_rad.rs:18:13 | LL | let _ = 90.5 * 180f64 / std::f64::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_degrees()` error: conversion to radians can be done more accurately - --> tests/ui/floating_point_rad.rs:20:13 + --> tests/ui/floating_point_rad.rs:19:13 | LL | let _ = x * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()` error: conversion to radians can be done more accurately - --> tests/ui/floating_point_rad.rs:21:13 + --> tests/ui/floating_point_rad.rs:20:13 | LL | let _ = 90. * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_radians()` error: conversion to radians can be done more accurately - --> tests/ui/floating_point_rad.rs:22:13 + --> tests/ui/floating_point_rad.rs:21:13 | LL | let _ = 90.5 * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_radians()` diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed index 5778f8f526f..4c324587c96 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed @@ -15,6 +15,14 @@ struct Foo { z: i32, } +#[derive(Default)] +#[allow(clippy::inconsistent_struct_constructor)] +struct Bar { + x: i32, + y: i32, + z: i32, +} + mod without_base { use super::Foo; @@ -70,4 +78,17 @@ mod with_base { } } +mod with_allow_ty_def { + use super::Bar; + + fn test() { + let x = 1; + let y = 1; + let z = 1; + + // Should NOT lint because `Bar` is defined with `#[allow(clippy::inconsistent_struct_constructor)]` + Bar { y, x, z }; + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs index 9efaf068934..d49f236b9b0 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs @@ -15,6 +15,14 @@ struct Foo { z: i32, } +#[derive(Default)] +#[allow(clippy::inconsistent_struct_constructor)] +struct Bar { + x: i32, + y: i32, + z: i32, +} + mod without_base { use super::Foo; @@ -74,4 +82,17 @@ mod with_base { } } +mod with_allow_ty_def { + use super::Bar; + + fn test() { + let x = 1; + let y = 1; + let z = 1; + + // Should NOT lint because `Bar` is defined with `#[allow(clippy::inconsistent_struct_constructor)]` + Bar { y, x, z }; + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr index 1192271f911..97bb7c789a7 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr @@ -1,5 +1,5 @@ error: struct constructor field order is inconsistent with struct definition field order - --> tests/ui/inconsistent_struct_constructor.rs:28:9 + --> tests/ui/inconsistent_struct_constructor.rs:36:9 | LL | Foo { y, x, z }; | ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }` @@ -8,7 +8,7 @@ LL | Foo { y, x, z }; = help: to override `-D warnings` add `#[allow(clippy::inconsistent_struct_constructor)]` error: struct constructor field order is inconsistent with struct definition field order - --> tests/ui/inconsistent_struct_constructor.rs:55:9 + --> tests/ui/inconsistent_struct_constructor.rs:63:9 | LL | / Foo { LL | | z, diff --git a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs index 2dccadd9fce..c8409d78ed7 100644 --- a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs +++ b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs @@ -17,7 +17,7 @@ mod multiple { //~^ ERROR: `clippy::msrv` is defined multiple times mod foo { - #![clippy::msrv = "1"] + #![clippy::msrv = "1.0"] #![clippy::msrv = "1.0.0"] //~^ ERROR: `clippy::msrv` is defined multiple times } diff --git a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr index b4cb1b5713f..dbc276ed89d 100644 --- a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr +++ b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr @@ -31,8 +31,8 @@ LL | #![clippy::msrv = "1.0.0"] note: first definition found here --> tests/ui/min_rust_version_invalid_attr.rs:20:9 | -LL | #![clippy::msrv = "1"] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![clippy::msrv = "1.0"] + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/string_slice.rs b/src/tools/clippy/tests/ui/string_slice.rs index 440a86b104a..1d1911aaa1d 100644 --- a/src/tools/clippy/tests/ui/string_slice.rs +++ b/src/tools/clippy/tests/ui/string_slice.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + #[warn(clippy::string_slice)] #[allow(clippy::no_effect)] @@ -11,4 +13,7 @@ fn main() { let s = String::from(m); &s[0..2]; //~^ ERROR: indexing into a string may panic if the index is within a UTF-8 character + let a = Cow::Borrowed("foo"); + &a[0..3]; + //~^ ERROR: indexing into a string may panic if the index is within a UTF-8 character } diff --git a/src/tools/clippy/tests/ui/string_slice.stderr b/src/tools/clippy/tests/ui/string_slice.stderr index 7a4596b5f2d..bc0fcde34b8 100644 --- a/src/tools/clippy/tests/ui/string_slice.stderr +++ b/src/tools/clippy/tests/ui/string_slice.stderr @@ -1,5 +1,5 @@ error: indexing into a string may panic if the index is within a UTF-8 character - --> tests/ui/string_slice.rs:5:6 + --> tests/ui/string_slice.rs:7:6 | LL | &"Ölkanne"[1..]; | ^^^^^^^^^^^^^^ @@ -8,16 +8,22 @@ LL | &"Ölkanne"[1..]; = help: to override `-D warnings` add `#[allow(clippy::string_slice)]` error: indexing into a string may panic if the index is within a UTF-8 character - --> tests/ui/string_slice.rs:9:6 + --> tests/ui/string_slice.rs:11:6 | LL | &m[2..5]; | ^^^^^^^ error: indexing into a string may panic if the index is within a UTF-8 character - --> tests/ui/string_slice.rs:12:6 + --> tests/ui/string_slice.rs:14:6 | LL | &s[0..2]; | ^^^^^^^ -error: aborting due to 3 previous errors +error: indexing into a string may panic if the index is within a UTF-8 character + --> tests/ui/string_slice.rs:17:6 + | +LL | &a[0..3]; + | ^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.fixed b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.fixed new file mode 100644 index 00000000000..d4a0cdf3447 --- /dev/null +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.fixed @@ -0,0 +1,9 @@ +#![warn(clippy::too_long_first_doc_paragraph)] + +/// A very short summary. +/// +/// A much longer explanation that goes into a lot more detail about +/// how the thing works, possibly with doclinks and so one, +/// and probably spanning a many rows. Blablabla, it needs to be over +/// 200 characters so I needed to write something longeeeeeeer. +pub struct Foo; diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.rs b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.rs new file mode 100644 index 00000000000..5a3b6c42a32 --- /dev/null +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.rs @@ -0,0 +1,8 @@ +#![warn(clippy::too_long_first_doc_paragraph)] + +/// A very short summary. +/// A much longer explanation that goes into a lot more detail about +/// how the thing works, possibly with doclinks and so one, +/// and probably spanning a many rows. Blablabla, it needs to be over +/// 200 characters so I needed to write something longeeeeeeer. +pub struct Foo; diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr new file mode 100644 index 00000000000..6403265a39c --- /dev/null +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr @@ -0,0 +1,20 @@ +error: first doc comment paragraph is too long + --> tests/ui/too_long_first_doc_paragraph-fix.rs:3:1 + | +LL | / /// A very short summary. +LL | | /// A much longer explanation that goes into a lot more detail about +LL | | /// how the thing works, possibly with doclinks and so one, +LL | | /// and probably spanning a many rows. Blablabla, it needs to be over +LL | | /// 200 characters so I needed to write something longeeeeeeer. + | |_ + | + = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]` +help: add an empty line + | +LL ~ /// A very short summary. +LL + /// + | + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.rs b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.rs new file mode 100644 index 00000000000..1042249c5b7 --- /dev/null +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.rs @@ -0,0 +1,53 @@ +//@no-rustfix + +#![warn(clippy::too_long_first_doc_paragraph)] + +/// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +/// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +/// gravida non lacinia at, rhoncus eu lacus. +pub struct Bar; + +// Should not warn! (not an item visible on mod page) +/// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +/// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +/// gravida non lacinia at, rhoncus eu lacus. +impl Bar {} + +// Should not warn! (less than 80 characters) +/// Lorem ipsum dolor sit amet, consectetur adipiscing elit. +/// +/// Nunc turpis nunc, lacinia +/// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +/// gravida non lacinia at, rhoncus eu lacus. +pub enum Enum { + A, +} + +/// Lorem +/// ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +/// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +/// gravida non lacinia at, rhoncus eu lacus. +pub union Union { + a: u8, + b: u8, +} + +// Should not warn! (title) +/// # bla +/// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +/// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +/// gravida non lacinia at, rhoncus eu lacus. +pub union Union2 { + a: u8, + b: u8, +} + +// Should not warn! (not public) +/// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +/// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +/// gravida non lacinia at, rhoncus eu lacus. +fn f() {} + +fn main() { + // test code goes here +} diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr new file mode 100644 index 00000000000..7f48e5cf884 --- /dev/null +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr @@ -0,0 +1,22 @@ +error: first doc comment paragraph is too long + --> tests/ui/too_long_first_doc_paragraph.rs:5:1 + | +LL | / /// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +LL | | /// gravida non lacinia at, rhoncus eu lacus. + | |_ + | + = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]` + +error: first doc comment paragraph is too long + --> tests/ui/too_long_first_doc_paragraph.rs:26:1 + | +LL | / /// Lorem +LL | | /// ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, +LL | | /// gravida non lacinia at, rhoncus eu lacus. + | |_ + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr index fcd60f48bcc..bcdf65b217e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr @@ -2,316 +2,432 @@ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:83:13 | LL | let _ = opt.unwrap_or_else(|| 2); - | ^^^^-------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]` +help: use `unwrap_or` instead + | +LL | let _ = opt.unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:84:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); - | ^^^^--------------------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = opt.unwrap_or(astronomers_pi); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:85:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); - | ^^^^------------------------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = opt.unwrap_or(ext_str.some_field); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:87:13 | LL | let _ = opt.and_then(|_| ext_opt); - | ^^^^--------------------- - | | - | help: use `and(..)` instead: `and(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `and` instead + | +LL | let _ = opt.and(ext_opt); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:88:13 | LL | let _ = opt.or_else(|| ext_opt); - | ^^^^------------------- - | | - | help: use `or(..)` instead: `or(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _ = opt.or(ext_opt); + | ~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:89:13 | LL | let _ = opt.or_else(|| None); - | ^^^^---------------- - | | - | help: use `or(..)` instead: `or(None)` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _ = opt.or(None); + | ~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:90:13 | LL | let _ = opt.get_or_insert_with(|| 2); - | ^^^^------------------------ - | | - | help: use `get_or_insert(..)` instead: `get_or_insert(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `get_or_insert` instead + | +LL | let _ = opt.get_or_insert(2); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:91:13 | LL | let _ = opt.ok_or_else(|| 2); - | ^^^^---------------- - | | - | help: use `ok_or(..)` instead: `ok_or(2)` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `ok_or` instead + | +LL | let _ = opt.ok_or(2); + | ~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:92:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); - | ^^^^^^^^^^^^^^^^^------------------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = nested_tuple_opt.unwrap_or(Some((1, 2))); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:93:13 | LL | let _ = cond.then(|| astronomers_pi); - | ^^^^^----------------------- - | | - | help: use `then_some(..)` instead: `then_some(astronomers_pi)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _ = cond.then_some(astronomers_pi); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:94:13 | LL | let _ = true.then(|| -> _ {}); - | ^^^^^---------------- - | | - | help: use `then_some(..)` instead: `then_some({})` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _ = true.then_some({}); + | ~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:95:13 | LL | let _ = true.then(|| {}); - | ^^^^^----------- - | | - | help: use `then_some(..)` instead: `then_some({})` + | ^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _ = true.then_some({}); + | ~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:99:13 | LL | let _ = Some(1).unwrap_or_else(|| *r); - | ^^^^^^^^--------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(*r)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Some(1).unwrap_or(*r); + | ~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:101:13 | LL | let _ = Some(1).unwrap_or_else(|| *b); - | ^^^^^^^^--------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(*b)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Some(1).unwrap_or(*b); + | ~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:103:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r); - | ^^^^^^^^^^^^^^^^^--------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(&r)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Some(1).as_ref().unwrap_or(&r); + | ~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:104:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b); - | ^^^^^^^^^^^^^^^^^--------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(&b)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Some(1).as_ref().unwrap_or(&b); + | ~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:107:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); - | ^^^^^^^^^-------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Some(10).unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:108:13 | LL | let _ = Some(10).and_then(|_| ext_opt); - | ^^^^^^^^^--------------------- - | | - | help: use `and(..)` instead: `and(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `and` instead + | +LL | let _ = Some(10).and(ext_opt); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:109:28 | LL | let _: Option<usize> = None.or_else(|| ext_opt); - | ^^^^^------------------- - | | - | help: use `or(..)` instead: `or(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _: Option<usize> = None.or(ext_opt); + | ~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:110:13 | LL | let _ = None.get_or_insert_with(|| 2); - | ^^^^^------------------------ - | | - | help: use `get_or_insert(..)` instead: `get_or_insert(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `get_or_insert` instead + | +LL | let _ = None.get_or_insert(2); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:111:35 | LL | let _: Result<usize, usize> = None.ok_or_else(|| 2); - | ^^^^^---------------- - | | - | help: use `ok_or(..)` instead: `ok_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `ok_or` instead + | +LL | let _: Result<usize, usize> = None.ok_or(2); + | ~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:112:28 | LL | let _: Option<usize> = None.or_else(|| None); - | ^^^^^---------------- - | | - | help: use `or(..)` instead: `or(None)` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _: Option<usize> = None.or(None); + | ~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:115:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); - | ^^^^^^^-------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = deep.0.unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:116:13 | LL | let _ = deep.0.and_then(|_| ext_opt); - | ^^^^^^^--------------------- - | | - | help: use `and(..)` instead: `and(ext_opt)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `and` instead + | +LL | let _ = deep.0.and(ext_opt); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:117:13 | LL | let _ = deep.0.or_else(|| None); - | ^^^^^^^---------------- - | | - | help: use `or(..)` instead: `or(None)` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _ = deep.0.or(None); + | ~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:118:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); - | ^^^^^^^------------------------ - | | - | help: use `get_or_insert(..)` instead: `get_or_insert(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `get_or_insert` instead + | +LL | let _ = deep.0.get_or_insert(2); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:119:13 | LL | let _ = deep.0.ok_or_else(|| 2); - | ^^^^^^^---------------- - | | - | help: use `ok_or(..)` instead: `ok_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `ok_or` instead + | +LL | let _ = deep.0.ok_or(2); + | ~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:150:28 | LL | let _: Option<usize> = None.or_else(|| Some(3)); - | ^^^^^------------------- - | | - | help: use `or(..)` instead: `or(Some(3))` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _: Option<usize> = None.or(Some(3)); + | ~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:151:13 | LL | let _ = deep.0.or_else(|| Some(3)); - | ^^^^^^^------------------- - | | - | help: use `or(..)` instead: `or(Some(3))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _ = deep.0.or(Some(3)); + | ~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Option::None` --> tests/ui/unnecessary_lazy_eval.rs:152:13 | LL | let _ = opt.or_else(|| Some(3)); - | ^^^^------------------- - | | - | help: use `or(..)` instead: `or(Some(3))` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _ = opt.or(Some(3)); + | ~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:158:13 | LL | let _ = res2.unwrap_or_else(|_| 2); - | ^^^^^--------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = res2.unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:159:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); - | ^^^^^---------------------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = res2.unwrap_or(astronomers_pi); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:160:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); - | ^^^^^-------------------------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = res2.unwrap_or(ext_str.some_field); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:182:35 | LL | let _: Result<usize, usize> = res.and_then(|_| Err(2)); - | ^^^^-------------------- - | | - | help: use `and(..)` instead: `and(Err(2))` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `and` instead + | +LL | let _: Result<usize, usize> = res.and(Err(2)); + | ~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:183:35 | LL | let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi)); - | ^^^^--------------------------------- - | | - | help: use `and(..)` instead: `and(Err(astronomers_pi))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `and` instead + | +LL | let _: Result<usize, usize> = res.and(Err(astronomers_pi)); + | ~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:184:35 | LL | let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field)); - | ^^^^------------------------------------- - | | - | help: use `and(..)` instead: `and(Err(ext_str.some_field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `and` instead + | +LL | let _: Result<usize, usize> = res.and(Err(ext_str.some_field)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:186:35 | LL | let _: Result<usize, usize> = res.or_else(|_| Ok(2)); - | ^^^^------------------ - | | - | help: use `or(..)` instead: `or(Ok(2))` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _: Result<usize, usize> = res.or(Ok(2)); + | ~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:187:35 | LL | let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi)); - | ^^^^------------------------------- - | | - | help: use `or(..)` instead: `or(Ok(astronomers_pi))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _: Result<usize, usize> = res.or(Ok(astronomers_pi)); + | ~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:188:35 | LL | let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field)); - | ^^^^----------------------------------- - | | - | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `or` instead + | +LL | let _: Result<usize, usize> = res.or(Ok(ext_str.some_field)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval.rs:189:35 @@ -324,193 +440,265 @@ LL | | // some lines ... | LL | | // some lines LL | | or_else(|_| Ok(ext_str.some_field)); - | |_____----------------------------------^ - | | - | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` + | |_______________________________________^ + | +help: use `or` instead + | +LL | or(Ok(ext_str.some_field)); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:219:14 | LL | let _x = false.then(|| i32::MAX + 1); - | ^^^^^^--------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MAX + 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MAX + 1); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:221:14 | LL | let _x = false.then(|| i32::MAX * 2); - | ^^^^^^--------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MAX * 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MAX * 2); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:223:14 | LL | let _x = false.then(|| i32::MAX - 1); - | ^^^^^^--------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MAX - 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MAX - 1); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:225:14 | LL | let _x = false.then(|| i32::MIN - 1); - | ^^^^^^--------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MIN - 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MIN - 1); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:227:14 | LL | let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2); - | ^^^^^^------------------------------------- - | | - | help: use `then_some(..)` instead: `then_some((1 + 2 * 3 - 2 / 3 + 9) << 2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some((1 + 2 * 3 - 2 / 3 + 9) << 2); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:229:14 | LL | let _x = false.then(|| 255u8 << 7); - | ^^^^^^------------------- - | | - | help: use `then_some(..)` instead: `then_some(255u8 << 7)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(255u8 << 7); + | ~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:231:14 | LL | let _x = false.then(|| 255u8 << 8); - | ^^^^^^------------------- - | | - | help: use `then_some(..)` instead: `then_some(255u8 << 8)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(255u8 << 8); + | ~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:233:14 | LL | let _x = false.then(|| 255u8 >> 8); - | ^^^^^^------------------- - | | - | help: use `then_some(..)` instead: `then_some(255u8 >> 8)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(255u8 >> 8); + | ~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:236:14 | LL | let _x = false.then(|| i32::MAX + -1); - | ^^^^^^---------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MAX + -1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MAX + -1); + | ~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:238:14 | LL | let _x = false.then(|| -i32::MAX); - | ^^^^^^------------------ - | | - | help: use `then_some(..)` instead: `then_some(-i32::MAX)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(-i32::MAX); + | ~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:240:14 | LL | let _x = false.then(|| -i32::MIN); - | ^^^^^^------------------ - | | - | help: use `then_some(..)` instead: `then_some(-i32::MIN)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(-i32::MIN); + | ~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:243:14 | LL | let _x = false.then(|| 255 >> -7); - | ^^^^^^------------------ - | | - | help: use `then_some(..)` instead: `then_some(255 >> -7)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(255 >> -7); + | ~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:245:14 | LL | let _x = false.then(|| 255 << -1); - | ^^^^^^------------------ - | | - | help: use `then_some(..)` instead: `then_some(255 << -1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(255 << -1); + | ~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:247:14 | LL | let _x = false.then(|| 1 / 0); - | ^^^^^^-------------- - | | - | help: use `then_some(..)` instead: `then_some(1 / 0)` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(1 / 0); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:249:14 | LL | let _x = false.then(|| x << -1); - | ^^^^^^---------------- - | | - | help: use `then_some(..)` instead: `then_some(x << -1)` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(x << -1); + | ~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:251:14 | LL | let _x = false.then(|| x << 2); - | ^^^^^^--------------- - | | - | help: use `then_some(..)` instead: `then_some(x << 2)` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(x << 2); + | ~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:261:14 | LL | let _x = false.then(|| x / 0); - | ^^^^^^-------------- - | | - | help: use `then_some(..)` instead: `then_some(x / 0)` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(x / 0); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:263:14 | LL | let _x = false.then(|| x % 0); - | ^^^^^^-------------- - | | - | help: use `then_some(..)` instead: `then_some(x % 0)` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(x % 0); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:266:14 | LL | let _x = false.then(|| 1 / -1); - | ^^^^^^--------------- - | | - | help: use `then_some(..)` instead: `then_some(1 / -1)` + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(1 / -1); + | ~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:268:14 | LL | let _x = false.then(|| i32::MIN / -1); - | ^^^^^^---------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MIN / -1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MIN / -1); + | ~~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:271:14 | LL | let _x = false.then(|| i32::MIN / 0); - | ^^^^^^--------------------- - | | - | help: use `then_some(..)` instead: `then_some(i32::MIN / 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(i32::MIN / 0); + | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:273:14 | LL | let _x = false.then(|| 4 / 2); - | ^^^^^^-------------- - | | - | help: use `then_some(..)` instead: `then_some(4 / 2)` + | ^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(4 / 2); + | ~~~~~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval.rs:281:14 | LL | let _x = false.then(|| f1 + f2); - | ^^^^^^---------------- - | | - | help: use `then_some(..)` instead: `then_some(f1 + f2)` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _x = false.then_some(f1 + f2); + | ~~~~~~~~~~~~~~~~~~ error: aborting due to 63 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr index b566b119571..390235b2124 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -2,36 +2,47 @@ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval_unfixable.rs:13:13 | LL | let _ = Ok(1).unwrap_or_else(|()| 2); - | ^^^^^^---------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]` +help: use `unwrap_or` instead + | +LL | let _ = Ok(1).unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval_unfixable.rs:19:13 | LL | let _ = Ok(1).unwrap_or_else(|e::E| 2); - | ^^^^^^------------------------ - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Ok(1).unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used to substitute value for `Result::Err` --> tests/ui/unnecessary_lazy_eval_unfixable.rs:21:13 | LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); - | ^^^^^^------------------------------------- - | | - | help: use `unwrap_or(..)` instead: `unwrap_or(2)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `unwrap_or` instead + | +LL | let _ = Ok(1).unwrap_or(2); + | ~~~~~~~~~~~~ error: unnecessary closure used with `bool::then` --> tests/ui/unnecessary_lazy_eval_unfixable.rs:31:13 | LL | let _ = true.then(|| -> &[u8] { &[] }); - | ^^^^^------------------------- - | | - | help: use `then_some(..)` instead: `then_some({ &[] })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `then_some` instead + | +LL | let _ = true.then_some({ &[] }); + | ~~~~~~~~~~~~~~~~~~ error: aborting due to 4 previous errors diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index dcf00e4e384..99b3560a064 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -20,6 +20,7 @@ new_pr = true [assign] contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md" users_on_vacation = [ + "flip1995", "matthiaskrgr", "giraffate", ] diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html index 300c9de178f..f3d7e504fdf 100644 --- a/src/tools/clippy/util/gh-pages/index.html +++ b/src/tools/clippy/util/gh-pages/index.html @@ -23,378 +23,25 @@ Otherwise, have a great day =^.^= <link id="styleHighlight" rel="stylesheet" href="https://rust-lang.github.io/mdBook/highlight.css"> <link id="styleNight" rel="stylesheet" href="https://rust-lang.github.io/mdBook/tomorrow-night.css" disabled="true"> <link id="styleAyu" rel="stylesheet" href="https://rust-lang.github.io/mdBook/ayu-highlight.css" disabled="true"> - <style> - blockquote { font-size: 1em; } - [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } - - .dropdown-menu { - color: var(--fg); - background: var(--theme-popup-bg); - border: 1px solid var(--theme-popup-border); - } - - .dropdown-menu .divider { - background-color: var(--theme-popup-border); - } - - .dropdown-menu .checkbox { - display: block; - white-space: nowrap; - margin: 0; - } - .dropdown-menu .checkbox label { - padding: 3px 20px; - width: 100%; - } - - .dropdown-menu .checkbox input { - position: relative; - margin: 0 0.5rem 0; - padding: 0; - } - - .dropdown-menu .checkbox:hover { - background-color: var(--theme-hover); - } - - div.panel div.panel-body button { - background: var(--searchbar-bg); - color: var(--searchbar-fg); - border-color: var(--theme-popup-border); - } - - div.panel div.panel-body button:hover { - box-shadow: 0 0 3px var(--searchbar-shadow-color); - } - - div.panel div.panel-body button.open { - filter: brightness(90%); - } - - .dropdown-toggle .badge { - background-color: #777; - } - - .panel-heading { cursor: pointer; } - - .panel-title { display: flex; flex-wrap: wrap;} - .panel-title .label { display: inline-block; } - - .panel-title-name { flex: 1; min-width: 400px;} - .panel-title-name span { vertical-align: bottom; } - - .panel .panel-title-name .anchor { display: none; } - .panel:hover .panel-title-name .anchor { display: inline;} - - .search-control { - margin-top: 15px; - } - - @media (min-width: 992px) { - .search-control { - margin-top: 0; - } - } - - @media (min-width: 405px) { - #upper-filters { - display: flex; - flex-wrap: wrap; - } - } - - @media (max-width: 430px) { - /* Turn the version filter list to the left */ - #version-filter-selector { - right: 0; - left: auto; - } - } - - @media (max-width: 412px) { - #upper-filters, - .panel-body .search-control { - padding-right: 8px; - padding-left: 8px; - } - } - - .label { - padding-top: 0.3em; - padding-bottom: 0.3em; - } - - .label-lint-group { - min-width: 8em; - } - .label-lint-level { - min-width: 4em; - } - - .label-lint-level-allow { - background-color: #5cb85c; - } - .label-lint-level-warn { - background-color: #f0ad4e; - } - .label-lint-level-deny { - background-color: #d9534f; - } - .label-lint-level-none { - background-color: #777777; - opacity: 0.5; - } - - .label-group-deprecated { - opacity: 0.5; - } - - .label-doc-folding { - color: #000; - background-color: #fff; - border: 1px solid var(--theme-popup-border); - } - .label-doc-folding:hover { - background-color: #e6e6e6; - } - - .lint-doc-md > h3 { - border-top: 1px solid var(--theme-popup-border); - padding: 10px 15px; - margin: 0 -15px; - font-size: 18px; - } - .lint-doc-md > h3:first-child { - border-top: none; - padding-top: 0px; - } - - @media (max-width:749px) { - .lint-additional-info-container { - display: flex; - flex-flow: column; - } - .lint-additional-info-item + .lint-additional-info-item { - border-top: 1px solid var(--theme-popup-border); - } - } - @media (min-width:750px) { - .lint-additional-info-container { - display: flex; - flex-flow: row; - } - .lint-additional-info-item + .lint-additional-info-item { - border-left: 1px solid var(--theme-popup-border); - } - } - - .lint-additional-info-item { - display: inline-flex; - min-width: 200px; - flex-grow: 1; - padding: 9px 5px 5px 15px; - } - - .label-applicability { - background-color: #777777; - margin: auto 5px; - } - - .label-version { - background-color: #777777; - margin: auto 5px; - font-family: monospace; - } - - details { - border-radius: 4px; - padding: .5em .5em 0; - } - - code { - white-space: pre !important; - } - - summary { - font-weight: bold; - margin: -.5em -.5em 0; - padding: .5em; - display: revert; - } - - details[open] { - padding: .5em; - } - </style> - <style> - /* Expanding the mdBoom theme*/ - .light { - --inline-code-bg: #f6f7f6; - } - .rust { - --inline-code-bg: #f6f7f6; - } - .coal { - --inline-code-bg: #1d1f21; - } - .navy { - --inline-code-bg: #1d1f21; - } - .ayu { - --inline-code-bg: #191f26; - } - - .theme-dropdown { - position: absolute; - margin: 0.7em; - z-index: 10; - } - - /* Applying the mdBook theme */ - .theme-icon { - text-align: center; - width: 2em; - height: 2em; - line-height: 2em; - border: solid 1px var(--icons); - border-radius: 5px; - user-select: none; - cursor: pointer; - } - .theme-icon:hover { - background: var(--theme-hover); - } - .theme-choice { - display: none; - list-style: none; - border: 1px solid var(--theme-popup-border); - border-radius: 5px; - color: var(--fg); - background: var(--theme-popup-bg); - padding: 0 0; - overflow: hidden; - } - - .theme-dropdown.open .theme-choice { - display: block; - } - - .theme-choice > li { - padding: 5px 10px; - font-size: 0.8em; - user-select: none; - cursor: pointer; - } - - .theme-choice > li:hover { - background: var(--theme-hover); - } - - .alert { - color: var(--fg); - background: var(--theme-hover); - border: 1px solid var(--theme-popup-border); - } - .page-header { - border-color: var(--theme-popup-border); - } - .panel-default > .panel-heading { - background: var(--theme-hover); - color: var(--fg); - border: 1px solid var(--theme-popup-border); - } - .panel-default > .panel-heading:hover { - filter: brightness(90%); - } - .list-group-item { - background: 0%; - border: 1px solid var(--theme-popup-border); - } - .panel, pre, hr { - background: var(--bg); - border: 1px solid var(--theme-popup-border); - } - - #version-filter-selector .checkbox { - display: flex; - } - - #version-filter { - min-width: available; - } - - #version-filter li label { - padding-right: 0; - width: 35%; - } - - .version-filter-input { - height: 60%; - width: 30%; - text-align: center; - border: none; - border-bottom: 1px solid #000000; - } - - #filter-label, .filter-clear { - background: var(--searchbar-bg); - color: var(--searchbar-fg); - border-color: var(--theme-popup-border); - filter: brightness(95%); - } - #filter-label:hover, .filter-clear:hover { - filter: brightness(90%); - } - .filter-input { - background: var(--searchbar-bg); - color: var(--searchbar-fg); - border-color: var(--theme-popup-border); - } - - .filter-input::-webkit-input-placeholder, - .filter-input::-moz-placeholder { - color: var(--searchbar-fg); - opacity: 30%; - } - - .expansion-group { - margin-top: 15px; - padding: 0px 8px; - display: flex; - flex-wrap: nowrap; - } - - @media (min-width: 992px) { - .expansion-group { - margin-top: 0; - padding: 0px 15px; - } - } - - .expansion-control { - width: 50%; - } - - :not(pre) > code { - color: var(--inline-code-color); - background-color: var(--inline-code-bg); - } - html { - scrollbar-color: var(--scrollbar) var(--bg); - } - body { - background: var(--bg); - color: var(--fg); - } - - </style> + <link rel="stylesheet" href="style.css"> </head> <body ng-app="clippy" ng-controller="lintList"> - <div theme-dropdown class="theme-dropdown"> - <div id="theme-icon" class="theme-icon">🖌</div> - <ul id="theme-menu" class="theme-choice"> - <li id="{{id}}" ng-repeat="(id, name) in themes" ng-click="selectTheme(id)">{{name}}</li> - </ul> + <div id="settings-dropdown"> + <div class="settings-icon" tabindex="-1"></div> + <div class="settings-menu" tabindex="-1"> + <div class="setting-radio-name">Theme</div> + <select id="theme-choice" onchange="setTheme(this.value, true)"> + <option value="ayu">Ayu</option> + <option value="coal">Coal</option> + <option value="light">Light</option> + <option value="navy">Navy</option> + <option value="rust">Rust</option> + </select> + <label> + <input type="checkbox" id="disable-shortcuts" onchange="changeSetting(this)"> + <span>Disable keyboard shortcuts</span> + </label> + </div> </div> <div class="container"> @@ -592,7 +239,7 @@ Otherwise, have a great day =^.^= <!-- Applicability --> <div class="lint-additional-info-item"> <span> Applicability: </span> - <span class="label label-default label-applicability">{{lint.applicability.applicability}}</span> + <span class="label label-default label-applicability">{{lint.applicability}}</span> <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html#variants">(?)</a> </div> <!-- Clippy version --> @@ -605,8 +252,8 @@ Otherwise, have a great day =^.^= <a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a> </div> <!-- Jump to source --> - <div class="lint-additional-info-item" ng-if="lint.id_span"> - <a href="https://github.com/rust-lang/rust-clippy/blob/{{docVersion}}/clippy_lints/{{lint.id_span.path}}#L{{lint.id_span.line}}">View Source</a> + <div class="lint-additional-info-item" ng-if="lint.id_location"> + <a href="https://github.com/rust-lang/rust-clippy/blob/{{docVersion}}/{{lint.id_location}}">View Source</a> </div> </div> </div> diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js index ed1e090e1b5..1a5330bc0e5 100644 --- a/src/tools/clippy/util/gh-pages/script.js +++ b/src/tools/clippy/util/gh-pages/script.js @@ -50,24 +50,6 @@ ); }; }) - .directive('themeDropdown', function ($document) { - return { - restrict: 'A', - link: function ($scope, $element, $attr) { - $element.bind('click', function () { - $element.toggleClass('open'); - $element.addClass('open-recent'); - }); - - $document.bind('click', function () { - if (!$element.hasClass('open-recent')) { - $element.removeClass('open'); - } - $element.removeClass('open-recent'); - }) - } - } - }) .directive('filterDropdown', function ($document) { return { restrict: 'A', @@ -114,28 +96,19 @@ cargo: true, complexity: true, correctness: true, - deprecated: false, nursery: true, pedantic: true, perf: true, restriction: true, style: true, suspicious: true, + deprecated: false, } $scope.groups = { ...GROUPS_FILTER_DEFAULT }; - const THEMES_DEFAULT = { - light: "Light", - rust: "Rust", - coal: "Coal", - navy: "Navy", - ayu: "Ayu" - }; - $scope.themes = THEMES_DEFAULT; - $scope.versionFilters = { "≥": {enabled: false, minorVersion: null }, "≤": {enabled: false, minorVersion: null }, @@ -153,11 +126,10 @@ ); const APPLICABILITIES_FILTER_DEFAULT = { - Unspecified: true, - Unresolved: true, MachineApplicable: true, MaybeIncorrect: true, - HasPlaceholders: true + HasPlaceholders: true, + Unspecified: true, }; $scope.applicabilities = { @@ -321,10 +293,6 @@ $location.path($scope.search); } - $scope.selectTheme = function (theme) { - setTheme(theme, true); - } - $scope.toggleLevels = function (value) { const levels = $scope.levels; for (const key in levels) { @@ -456,7 +424,7 @@ } $scope.byApplicabilities = function (lint) { - return $scope.applicabilities[lint.applicability.applicability]; + return $scope.applicabilities[lint.applicability]; }; // Show details for one lint @@ -537,6 +505,16 @@ function getQueryVariable(variable) { } } +function storeValue(settingName, value) { + try { + localStorage.setItem(`clippy-lint-list-${settingName}`, value); + } catch (e) { } +} + +function loadValue(settingName) { + return localStorage.getItem(`clippy-lint-list-${settingName}`); +} + function setTheme(theme, store) { let enableHighlight = false; let enableNight = false; @@ -569,14 +547,14 @@ function setTheme(theme, store) { document.getElementById("styleAyu").disabled = !enableAyu; if (store) { - try { - localStorage.setItem('clippy-lint-list-theme', theme); - } catch (e) { } + storeValue("theme", theme); + } else { + document.getElementById(`theme-choice`).value = theme; } } function handleShortcut(ev) { - if (ev.ctrlKey || ev.altKey || ev.metaKey) { + if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) { return; } @@ -601,11 +579,51 @@ function handleShortcut(ev) { document.addEventListener("keypress", handleShortcut); document.addEventListener("keydown", handleShortcut); +function changeSetting(elem) { + if (elem.id === "disable-shortcuts") { + disableShortcuts = elem.checked; + storeValue(elem.id, elem.checked); + } +} + +function onEachLazy(lazyArray, func) { + const arr = Array.prototype.slice.call(lazyArray); + for (const el of arr) { + func(el); + } +} + +function handleBlur(event) { + const parent = document.getElementById("settings-dropdown"); + if (!parent.contains(document.activeElement) && + !parent.contains(event.relatedTarget) + ) { + parent.classList.remove("open"); + } +} + +function generateSettings() { + const settings = document.getElementById("settings-dropdown"); + const settingsButton = settings.querySelector(".settings-icon") + settingsButton.onclick = () => settings.classList.toggle("open"); + settingsButton.onblur = handleBlur; + const settingsMenu = settings.querySelector(".settings-menu"); + settingsMenu.onblur = handleBlur; + onEachLazy( + settingsMenu.querySelectorAll("input"), + el => el.onblur = handleBlur, + ); +} + +generateSettings(); + // loading the theme after the initial load const prefersDark = window.matchMedia("(prefers-color-scheme: dark)"); -const theme = localStorage.getItem('clippy-lint-list-theme'); +const theme = loadValue('theme'); if (prefersDark.matches && !theme) { setTheme("coal", false); } else { setTheme(theme, false); } +let disableShortcuts = loadValue('disable-shortcuts') === "true"; +document.getElementById("disable-shortcuts").checked = disableShortcuts; diff --git a/src/tools/clippy/util/gh-pages/style.css b/src/tools/clippy/util/gh-pages/style.css new file mode 100644 index 00000000000..a9485d51104 --- /dev/null +++ b/src/tools/clippy/util/gh-pages/style.css @@ -0,0 +1,398 @@ +blockquote { font-size: 1em; } + +[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { + display: none !important; +} + +.dropdown-menu { + color: var(--fg); + background: var(--theme-popup-bg); + border: 1px solid var(--theme-popup-border); +} + +.dropdown-menu .divider { + background-color: var(--theme-popup-border); +} + +.dropdown-menu .checkbox { + display: block; + white-space: nowrap; + margin: 0; +} +.dropdown-menu .checkbox label { + padding: 3px 20px; + width: 100%; +} + +.dropdown-menu .checkbox input { + position: relative; + margin: 0 0.5rem 0; + padding: 0; +} + +.dropdown-menu .checkbox:hover { + background-color: var(--theme-hover); +} + +div.panel div.panel-body button { + background: var(--searchbar-bg); + color: var(--searchbar-fg); + border-color: var(--theme-popup-border); +} + +div.panel div.panel-body button:hover { + box-shadow: 0 0 3px var(--searchbar-shadow-color); +} + +div.panel div.panel-body button.open { + filter: brightness(90%); +} + +.dropdown-toggle .badge { + background-color: #777; +} + +.panel-heading { cursor: pointer; } + +.panel-title { display: flex; flex-wrap: wrap;} +.panel-title .label { display: inline-block; } + +.panel-title-name { flex: 1; min-width: 400px;} +.panel-title-name span { vertical-align: bottom; } + +.panel .panel-title-name .anchor { display: none; } +.panel:hover .panel-title-name .anchor { display: inline;} + +.search-control { + margin-top: 15px; +} + +@media (min-width: 992px) { + .search-control { + margin-top: 0; + } +} + +@media (min-width: 405px) { + #upper-filters { + display: flex; + flex-wrap: wrap; + } +} + +@media (max-width: 430px) { + /* Turn the version filter list to the left */ + #version-filter-selector { + right: 0; + left: auto; + } +} + +@media (max-width: 412px) { + #upper-filters, + .panel-body .search-control { + padding-right: 8px; + padding-left: 8px; + } +} + +.label { + padding-top: 0.3em; + padding-bottom: 0.3em; +} + +.label-lint-group { + min-width: 8em; +} +.label-lint-level { + min-width: 4em; +} + +.label-lint-level-allow { + background-color: #5cb85c; +} +.label-lint-level-warn { + background-color: #f0ad4e; +} +.label-lint-level-deny { + background-color: #d9534f; +} +.label-lint-level-none { + background-color: #777777; + opacity: 0.5; +} + +.label-group-deprecated { + opacity: 0.5; +} + +.label-doc-folding { + color: #000; + background-color: #fff; + border: 1px solid var(--theme-popup-border); +} +.label-doc-folding:hover { + background-color: #e6e6e6; +} + +.lint-doc-md > h3 { + border-top: 1px solid var(--theme-popup-border); + padding: 10px 15px; + margin: 0 -15px; + font-size: 18px; +} +.lint-doc-md > h3:first-child { + border-top: none; + padding-top: 0px; +} + +@media (max-width:749px) { + .lint-additional-info-container { + display: flex; + flex-flow: column; + } + .lint-additional-info-item + .lint-additional-info-item { + border-top: 1px solid var(--theme-popup-border); + } +} +@media (min-width:750px) { + .lint-additional-info-container { + display: flex; + flex-flow: row; + } + .lint-additional-info-item + .lint-additional-info-item { + border-left: 1px solid var(--theme-popup-border); + } +} + +.lint-additional-info-item { + display: inline-flex; + min-width: 200px; + flex-grow: 1; + padding: 9px 5px 5px 15px; +} + +.label-applicability { + background-color: #777777; + margin: auto 5px; +} + +.label-version { + background-color: #777777; + margin: auto 5px; + font-family: monospace; +} + +details { + border-radius: 4px; + padding: .5em .5em 0; +} + +code { + white-space: pre !important; +} + +summary { + font-weight: bold; + margin: -.5em -.5em 0; + padding: .5em; + display: revert; +} + +details[open] { + padding: .5em; +} + +/* Expanding the mdBook theme*/ +.light { + --inline-code-bg: #f6f7f6; +} +.rust { + --inline-code-bg: #f6f7f6; +} +.coal { + --inline-code-bg: #1d1f21; +} +.navy { + --inline-code-bg: #1d1f21; +} +.ayu { + --inline-code-bg: #191f26; +} + +#settings-dropdown { + position: absolute; + margin: 0.7em; + z-index: 10; + display: flex; +} + +/* Applying the mdBook theme */ +.settings-icon { + text-align: center; + width: 2em; + height: 2em; + line-height: 2em; + border: solid 1px var(--icons); + border-radius: 5px; + user-select: none; + cursor: pointer; + background: var(--theme-hover); +} +.settings-menu { + display: none; + list-style: none; + border: 1px solid var(--theme-popup-border); + border-radius: 5px; + color: var(--fg); + background: var(--theme-popup-bg); + overflow: hidden; + padding: 9px; + width: 207px; + position: absolute; + top: 28px; +} + +.settings-icon::before { + /* Wheel <https://www.svgrepo.com/svg/384069/settings-cog-gear> */ + content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \ +enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\ +<path d="M10.25,6c0-0.1243286-0.0261841-0.241333-0.0366211-0.362915l1.6077881-1.5545654l\ +-1.25-2.1650391 c0,0-1.2674561,0.3625488-2.1323853,0.6099854c-0.2034912-0.1431885-0.421875\ +-0.2639771-0.6494751-0.3701782L7.25,0h-2.5 c0,0-0.3214111,1.2857666-0.5393066,2.1572876\ +C3.9830933,2.2634888,3.7647095,2.3842773,3.5612183,2.5274658L1.428833,1.9174805 \ +l-1.25,2.1650391c0,0,0.9641113,0.9321899,1.6077881,1.5545654C1.7761841,5.758667,\ +1.75,5.8756714,1.75,6 s0.0261841,0.241333,0.0366211,0.362915L0.178833,7.9174805l1.25,\ +2.1650391l2.1323853-0.6099854 c0.2034912,0.1432495,0.421875,0.2639771,0.6494751,0.3701782\ +L4.75,12h2.5l0.5393066-2.1572876 c0.2276001-0.1062012,0.4459839-0.2269287,0.6494751\ +-0.3701782l2.1323853,0.6099854l1.25-2.1650391L10.2133789,6.362915 C10.2238159,6.241333,\ +10.25,6.1243286,10.25,6z M6,7.5C5.1715698,7.5,4.5,6.8284302,4.5,6S5.1715698,4.5,6,4.5S7.5\ +,5.1715698,7.5,6 S6.8284302,7.5,6,7.5z" fill="black"/></svg>'); + width: 18px; + height: 18px; + display: block; + filter: invert(0.7); + padding-left: 4px; + padding-top: 3px; +} + +.settings-menu * { + font-weight: normal; +} + +.settings-menu label { + cursor: pointer; +} + +#settings-dropdown.open .settings-menu { + display: block; +} + +#theme-choice { + margin-bottom: 10px; + background: var(--searchbar-bg); + color: var(--searchbar-fg); + border-color: var(--theme-popup-border); + border-radius: 5px; + cursor: pointer; + width: 100%; + border-width: 1px; + padding: 5px; +} + +.alert { + color: var(--fg); + background: var(--theme-hover); + border: 1px solid var(--theme-popup-border); +} +.page-header { + border-color: var(--theme-popup-border); +} +.panel-default > .panel-heading { + background: var(--theme-hover); + color: var(--fg); + border: 1px solid var(--theme-popup-border); +} +.panel-default > .panel-heading:hover { + filter: brightness(90%); +} +.list-group-item { + background: 0%; + border: 1px solid var(--theme-popup-border); +} +.panel, pre, hr { + background: var(--bg); + border: 1px solid var(--theme-popup-border); +} + +#version-filter-selector .checkbox { + display: flex; +} + +#version-filter { + min-width: available; +} + +#version-filter li label { + padding-right: 0; + width: 35%; +} + +.version-filter-input { + height: 60%; + width: 30%; + text-align: center; + border: none; + border-bottom: 1px solid #000000; +} + +#filter-label, .filter-clear { + background: var(--searchbar-bg); + color: var(--searchbar-fg); + border-color: var(--theme-popup-border); + filter: brightness(95%); +} +#filter-label:hover, .filter-clear:hover { + filter: brightness(90%); +} +.filter-input { + background: var(--searchbar-bg); + color: var(--searchbar-fg); + border-color: var(--theme-popup-border); +} + +.filter-input::-webkit-input-placeholder, +.filter-input::-moz-placeholder { + color: var(--searchbar-fg); + opacity: 30%; +} + +.expansion-group { + margin-top: 15px; + padding: 0px 8px; + display: flex; + flex-wrap: nowrap; +} + +@media (min-width: 992px) { + .expansion-group { + margin-top: 0; + padding: 0px 15px; + } +} + +.expansion-control { + width: 50%; +} + +:not(pre) > code { + color: var(--inline-code-color); + background-color: var(--inline-code-bg); +} +html { + scrollbar-color: var(--scrollbar) var(--bg); +} +body { + background: var(--bg); + color: var(--fg); +} diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 72448c1180a..fa77ab1e011 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -6,8 +6,10 @@ //! script is to check all relative links in our documentation to make sure they //! actually point to a valid place. //! -//! Currently this doesn't actually do any HTML parsing or anything fancy like -//! that, it just has a simple "regex" to search for `href` and `id` tags. +//! Currently uses a combination of HTML parsing to +//! extract the `href` and `id` attributes, +//! and regex search on the orignal markdown to handle intra-doc links. +//! //! These values are then translated to file URLs if possible and then the //! destination is asserted to exist. //! diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index e0aef13ca79..72bb9db7e74 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -444,6 +444,7 @@ impl<'a> LintExtractor<'a> { let mut cmd = Command::new(self.rustc_path); if options.contains(&"edition2024") { cmd.arg("--edition=2024"); + cmd.arg("-Zunstable-options"); } else if options.contains(&"edition2021") { cmd.arg("--edition=2021"); } else if options.contains(&"edition2018") { diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index f72591f0c4b..a4d3e3f7af3 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -1157,7 +1157,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } #[inline] - fn get_thread_name<'c>(&'c self, thread: ThreadId) -> Option<&[u8]> + fn get_thread_name<'c>(&'c self, thread: ThreadId) -> Option<&'c [u8]> where 'tcx: 'c, { diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr index 42beed4ecde..a11a2b95689 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/exported_symbol_bad_unwind1.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding --> $DIR/exported_symbol_bad_unwind1.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index 112a9687837..12425cc4892 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: panic in a function that cannot unwind stack backtrace: diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index 112a9687837..12425cc4892 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: panic in a function that cannot unwind stack backtrace: diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr index bc3e4858716..f9e299bf5d2 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/exported_symbol_bad_unwind2.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr index a2fa4c1d590..83efc9974e8 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/return_pointer_on_unwind.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/return_pointer_on_unwind.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr index 8dd76edafea..67fd60e572e 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: aborted execution: attempted to instantiate uninhabited type `!` note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr index 55f66a275b6..f89a1fc4bbb 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: aborted execution: attempted to zero-initialize type `fn()`, which is invalid note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/bad_unwind.stderr b/src/tools/miri/tests/fail/panic/bad_unwind.stderr index 230e8337c7c..c08fe5153b1 100644 --- a/src/tools/miri/tests/fail/panic/bad_unwind.stderr +++ b/src/tools/miri/tests/fail/panic/bad_unwind.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/bad_unwind.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding --> $DIR/bad_unwind.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index 5829c1897bb..0395fe418d9 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/double_panic.rs:LL:CC: first note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect thread 'main' panicked at $DIR/double_panic.rs:LL:CC: second stack backtrace: diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.stderr b/src/tools/miri/tests/fail/panic/panic_abort1.stderr index d4abf19cd1e..6c7cac23bec 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort1.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/panic_abort1.rs:LL:CC: panicking from libstd note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.stderr b/src/tools/miri/tests/fail/panic/panic_abort2.stderr index 507f17abf4e..1eda5449d1b 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort2.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/panic_abort2.rs:LL:CC: 42-panicking from libstd note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.stderr b/src/tools/miri/tests/fail/panic/panic_abort3.stderr index a5d8b4d2eeb..5c7c5e17bee 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort3.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/panic_abort3.rs:LL:CC: panicking from libcore note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.stderr b/src/tools/miri/tests/fail/panic/panic_abort4.stderr index 62fbbf942cb..c8104f570f6 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort4.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/panic_abort4.rs:LL:CC: 42-panicking from libcore note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr index a5fa0b3e07a..6384689c563 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.stderr +++ b/src/tools/miri/tests/fail/terminate-terminator.stderr @@ -3,7 +3,7 @@ warning: You have explicitly enabled MIR optimizations, overriding Miri's defaul thread 'main' panicked at $DIR/terminate-terminator.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: panic in a function that cannot unwind stack backtrace: diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr index 547d550d3d0..fd67bdf4a90 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr +++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/unwind-action-terminate.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC: panic in a function that cannot unwind stack backtrace: diff --git a/src/tools/miri/tests/panic/alloc_error_handler_hook.stderr b/src/tools/miri/tests/panic/alloc_error_handler_hook.stderr index 5b309ed09bb..319a10febb3 100644 --- a/src/tools/miri/tests/panic/alloc_error_handler_hook.stderr +++ b/src/tools/miri/tests/panic/alloc_error_handler_hook.stderr @@ -1,5 +1,5 @@ thread 'main' panicked at $DIR/alloc_error_handler_hook.rs:LL:CC: alloc error hook called note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect yes we are unwinding! diff --git a/src/tools/miri/tests/panic/alloc_error_handler_panic.stderr b/src/tools/miri/tests/panic/alloc_error_handler_panic.stderr index 3d5457799f6..2cdff03f10f 100644 --- a/src/tools/miri/tests/panic/alloc_error_handler_panic.stderr +++ b/src/tools/miri/tests/panic/alloc_error_handler_panic.stderr @@ -1,5 +1,5 @@ thread 'main' panicked at RUSTLIB/std/src/alloc.rs:LL:CC: memory allocation of 4 bytes failed note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect yes we are unwinding! diff --git a/src/tools/miri/tests/panic/div-by-zero-2.stderr b/src/tools/miri/tests/panic/div-by-zero-2.stderr index f0b84ea6fd6..ed394f76b0e 100644 --- a/src/tools/miri/tests/panic/div-by-zero-2.stderr +++ b/src/tools/miri/tests/panic/div-by-zero-2.stderr @@ -1,4 +1,4 @@ thread 'main' panicked at $DIR/div-by-zero-2.rs:LL:CC: attempt to divide by zero note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr b/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr index f77f6f01119..6733f2e42c1 100644 --- a/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr +++ b/src/tools/miri/tests/panic/function_calls/exported_symbol_good_unwind.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/exported_symbol_good_unwind.rs:LL:CC: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect thread 'main' panicked at $DIR/exported_symbol_good_unwind.rs:LL:CC: explicit panic thread 'main' panicked at $DIR/exported_symbol_good_unwind.rs:LL:CC: diff --git a/src/tools/miri/tests/panic/oob_subslice.stderr b/src/tools/miri/tests/panic/oob_subslice.stderr index c116f8eb525..46f0f643a47 100644 --- a/src/tools/miri/tests/panic/oob_subslice.stderr +++ b/src/tools/miri/tests/panic/oob_subslice.stderr @@ -1,4 +1,4 @@ thread 'main' panicked at $DIR/oob_subslice.rs:LL:CC: range end index 5 out of range for slice of length 4 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/overflowing-lsh-neg.stderr b/src/tools/miri/tests/panic/overflowing-lsh-neg.stderr index 1d057ea5eb4..be822bd0285 100644 --- a/src/tools/miri/tests/panic/overflowing-lsh-neg.stderr +++ b/src/tools/miri/tests/panic/overflowing-lsh-neg.stderr @@ -1,4 +1,4 @@ thread 'main' panicked at $DIR/overflowing-lsh-neg.rs:LL:CC: attempt to shift left with overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/overflowing-rsh-1.stderr b/src/tools/miri/tests/panic/overflowing-rsh-1.stderr index d1a79400bfa..fc090aba5fd 100644 --- a/src/tools/miri/tests/panic/overflowing-rsh-1.stderr +++ b/src/tools/miri/tests/panic/overflowing-rsh-1.stderr @@ -1,4 +1,4 @@ thread 'main' panicked at $DIR/overflowing-rsh-1.rs:LL:CC: attempt to shift right with overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/overflowing-rsh-2.stderr b/src/tools/miri/tests/panic/overflowing-rsh-2.stderr index 612b0c0c4c2..77160e1870f 100644 --- a/src/tools/miri/tests/panic/overflowing-rsh-2.stderr +++ b/src/tools/miri/tests/panic/overflowing-rsh-2.stderr @@ -1,4 +1,4 @@ thread 'main' panicked at $DIR/overflowing-rsh-2.rs:LL:CC: attempt to shift right with overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/panic2.stderr b/src/tools/miri/tests/panic/panic2.stderr index 792c71346fd..f7408310093 100644 --- a/src/tools/miri/tests/panic/panic2.stderr +++ b/src/tools/miri/tests/panic/panic2.stderr @@ -1,4 +1,4 @@ thread 'main' panicked at $DIR/panic2.rs:LL:CC: 42-panicking from libstd note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/panic3.stderr b/src/tools/miri/tests/panic/panic3.stderr index f8016bc3912..32ba400e025 100644 --- a/src/tools/miri/tests/panic/panic3.stderr +++ b/src/tools/miri/tests/panic/panic3.stderr @@ -1,4 +1,4 @@ thread 'main' panicked at $DIR/panic3.rs:LL:CC: panicking from libcore note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/panic4.stderr b/src/tools/miri/tests/panic/panic4.stderr index 67410bf3b1a..a8a23ee3ce1 100644 --- a/src/tools/miri/tests/panic/panic4.stderr +++ b/src/tools/miri/tests/panic/panic4.stderr @@ -1,4 +1,4 @@ thread 'main' panicked at $DIR/panic4.rs:LL:CC: 42-panicking from libcore note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/transmute_fat2.stderr b/src/tools/miri/tests/panic/transmute_fat2.stderr index 2ee01d46931..021ca1c4b32 100644 --- a/src/tools/miri/tests/panic/transmute_fat2.stderr +++ b/src/tools/miri/tests/panic/transmute_fat2.stderr @@ -1,4 +1,4 @@ thread 'main' panicked at $DIR/transmute_fat2.rs:LL:CC: index out of bounds: the len is 0 but the index is 0 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/unsupported_foreign_function.stderr b/src/tools/miri/tests/panic/unsupported_foreign_function.stderr index d0a7d8dafc5..fcc4220bfce 100644 --- a/src/tools/miri/tests/panic/unsupported_foreign_function.stderr +++ b/src/tools/miri/tests/panic/unsupported_foreign_function.stderr @@ -1,4 +1,4 @@ thread 'main' panicked at $DIR/unsupported_foreign_function.rs:LL:CC: unsupported Miri functionality: can't call foreign function `foo` on $OS note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/panic/unsupported_syscall.stderr b/src/tools/miri/tests/panic/unsupported_syscall.stderr index f802159cb1c..660cfba8900 100644 --- a/src/tools/miri/tests/panic/unsupported_syscall.stderr +++ b/src/tools/miri/tests/panic/unsupported_syscall.stderr @@ -1,4 +1,4 @@ thread 'main' panicked at $DIR/unsupported_syscall.rs:LL:CC: unsupported Miri functionality: can't execute syscall with ID 0 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/miri/tests/pass/panic/catch_panic.stderr b/src/tools/miri/tests/pass/panic/catch_panic.stderr index a472a5d80cb..f61b39493ed 100644 --- a/src/tools/miri/tests/pass/panic/catch_panic.stderr +++ b/src/tools/miri/tests/pass/panic/catch_panic.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/catch_panic.rs:LL:CC: Hello from std::panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect Caught panic message (&str): Hello from std::panic thread 'main' panicked at $DIR/catch_panic.rs:LL:CC: Hello from std::panic: 1 diff --git a/src/tools/miri/tests/pass/panic/concurrent-panic.stderr b/src/tools/miri/tests/pass/panic/concurrent-panic.stderr index b2a5cf4922c..fe0d16ca78a 100644 --- a/src/tools/miri/tests/pass/panic/concurrent-panic.stderr +++ b/src/tools/miri/tests/pass/panic/concurrent-panic.stderr @@ -3,7 +3,7 @@ Thread 1 reported it has started thread '<unnamed>' panicked at $DIR/concurrent-panic.rs:LL:CC: panic in thread 2 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect Thread 2 blocking on thread 1 Thread 2 reported it has started Unlocking mutex diff --git a/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr index 3efb4be40f9..a346d31f645 100644 --- a/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr +++ b/src/tools/miri/tests/pass/panic/nested_panic_caught.stderr @@ -1,7 +1,7 @@ thread 'main' panicked at $DIR/nested_panic_caught.rs:LL:CC: once note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect thread 'main' panicked at $DIR/nested_panic_caught.rs:LL:CC: twice stack backtrace: diff --git a/src/tools/miri/tests/pass/panic/thread_panic.stderr b/src/tools/miri/tests/pass/panic/thread_panic.stderr index bdfe4f98ba3..0fde5922c19 100644 --- a/src/tools/miri/tests/pass/panic/thread_panic.stderr +++ b/src/tools/miri/tests/pass/panic/thread_panic.stderr @@ -1,6 +1,6 @@ thread '<unnamed>' panicked at $DIR/thread_panic.rs:LL:CC: Hello! note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -note: in Miri, you may have to set `-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect +note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect thread 'childthread' panicked at $DIR/thread_panic.rs:LL:CC: Hello, world! diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 1a13d56b0e4..77df6e7beb5 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -12,3 +12,4 @@ regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace gimli = "0.31.0" build_helper = { path = "../build_helper" } serde_json = "1.0" +libc = "0.2" diff --git a/src/tools/run-make-support/src/env.rs b/src/tools/run-make-support/src/env.rs index e6460fb93d3..9acbb16d73e 100644 --- a/src/tools/run-make-support/src/env.rs +++ b/src/tools/run-make-support/src/env.rs @@ -24,3 +24,11 @@ pub fn env_var_os(name: &str) -> OsString { pub fn no_debug_assertions() -> bool { std::env::var_os("NO_DEBUG_ASSERTIONS").is_some() } + +/// A wrapper around [`std::env::set_current_dir`] which includes the directory +/// path in the panic message. +#[track_caller] +pub fn set_current_dir<P: AsRef<std::path::Path>>(dir: P) { + std::env::set_current_dir(dir.as_ref()) + .expect(&format!("could not set current directory to \"{}\"", dir.as_ref().display())); +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index fc20fd3b2e8..989d00d4c2f 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -36,6 +36,7 @@ pub mod rfs { // Re-exports of third-party library crates. pub use bstr; pub use gimli; +pub use libc; pub use object; pub use regex; pub use serde_json; @@ -64,7 +65,7 @@ pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; pub use diff::{diff, Diff}; /// Panic-on-fail [`std::env::var`] and [`std::env::var_os`] wrappers. -pub use env::{env_var, env_var_os}; +pub use env::{env_var, env_var_os, set_current_dir}; /// Convenience helpers for running binaries and other commands. pub use run::{cmd, run, run_fail, run_with_args}; diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs index 1e6e44c4584..87901793a92 100644 --- a/src/tools/run-make-support/src/path_helpers.rs +++ b/src/tools/run-make-support/src/path_helpers.rs @@ -21,6 +21,7 @@ pub fn cwd() -> PathBuf { /// # Example /// /// ```rust +/// # use run_make_support::path; /// let p = path("support_file.txt"); /// ``` pub fn path<P: AsRef<Path>>(p: P) -> PathBuf { diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index 12088e5d3b5..3eeba6fd526 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -29,6 +29,7 @@ fn run_common(name: &str, args: Option<&[&str]>) -> Command { } env::join_paths(paths.iter()).unwrap() }); + cmd.env("LC_ALL", "C"); // force english locale if is_windows() { let mut paths = vec![]; @@ -84,5 +85,6 @@ pub fn run_fail(name: &str) -> CompletedProcess { pub fn cmd<S: AsRef<OsStr>>(program: S) -> Command { let mut command = Command::new(program); set_host_rpath(&mut command); + command.env("LC_ALL", "C"); // force english locale command } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index f55abb513b8..22d1e93bf39 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -6,9 +6,7 @@ run-make/incr-add-rust-src-component/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile run-make/jobserver-error/Makefile run-make/libs-through-symlinks/Makefile -run-make/libtest-thread-limit/Makefile run-make/macos-deployment-target/Makefile run-make/split-debuginfo/Makefile run-make/symbol-mangling-hashed/Makefile run-make/translation/Makefile -run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 57310977704..5205fa14294 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1289,8 +1289,7 @@ ui/imports/auxiliary/issue-52891.rs ui/imports/auxiliary/issue-55811.rs ui/imports/auxiliary/issue-56125.rs ui/imports/auxiliary/issue-59764.rs -ui/imports/auxiliary/issue-85992-extern-1.rs -ui/imports/auxiliary/issue-85992-extern-2.rs +ui/imports/auxiliary/issue-85992-extern.rs ui/imports/issue-109148.rs ui/imports/issue-109343.rs ui/imports/issue-113953.rs diff --git a/tests/assembly/x86_64-cmp.rs b/tests/assembly/x86_64-cmp.rs index 31efdda1bfa..67b7ff99ae2 100644 --- a/tests/assembly/x86_64-cmp.rs +++ b/tests/assembly/x86_64-cmp.rs @@ -1,6 +1,9 @@ -//@ revisions: DEBUG OPTIM +//@ revisions: DEBUG LLVM-PRE-20-OPTIM LLVM-20-OPTIM //@ [DEBUG] compile-flags: -C opt-level=0 -//@ [OPTIM] compile-flags: -C opt-level=3 +//@ [LLVM-PRE-20-OPTIM] compile-flags: -C opt-level=3 +//@ [LLVM-PRE-20-OPTIM] ignore-llvm-version: 20 - 99 +//@ [LLVM-20-OPTIM] compile-flags: -C opt-level=3 +//@ [LLVM-20-OPTIM] min-llvm-version: 20 //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -C llvm-args=-x86-asm-syntax=intel //@ only-x86_64 @@ -21,12 +24,18 @@ pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { // DEBUG: and // DEBUG: sub - // OPTIM: xor - // OPTIM: cmp - // OPTIM: setne - // OPTIM: mov - // OPTIM: cmovge - // OPTIM: ret + // LLVM-PRE-20-OPTIM: xor + // LLVM-PRE-20-OPTIM: cmp + // LLVM-PRE-20-OPTIM: setne + // LLVM-PRE-20-OPTIM: mov + // LLVM-PRE-20-OPTIM: cmovge + // LLVM-PRE-20-OPTIM: ret + // + // LLVM-20-OPTIM: cmp + // LLVM-20-OPTIM: setl + // LLVM-20-OPTIM: setg + // LLVM-20-OPTIM: sub + // LLVM-20-OPTIM: ret three_way_compare(a, b) } @@ -41,11 +50,16 @@ pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering { // DEBUG: and // DEBUG: sub - // OPTIM: xor - // OPTIM: cmp - // OPTIM: setne - // OPTIM: mov - // OPTIM: cmovae - // OPTIM: ret + // LLVM-PRE-20-OPTIM: xor + // LLVM-PRE-20-OPTIM: cmp + // LLVM-PRE-20-OPTIM: setne + // LLVM-PRE-20-OPTIM: mov + // LLVM-PRE-20-OPTIM: cmovae + // LLVM-PRE-20-OPTIM: ret + // + // LLVM-20-OPTIM: cmp + // LLVM-20-OPTIM: seta + // LLVM-20-OPTIM: sbb + // LLVM-20-OPTIM: ret three_way_compare(a, b) } diff --git a/tests/codegen/integer-cmp.rs b/tests/codegen/integer-cmp.rs index bba112b246f..8df68d8d490 100644 --- a/tests/codegen/integer-cmp.rs +++ b/tests/codegen/integer-cmp.rs @@ -1,6 +1,9 @@ // This is test for more optimal Ord implementation for integers. // See <https://github.com/rust-lang/rust/issues/63758> for more info. +//@ revisions: llvm-pre-20 llvm-20 +//@ [llvm-20] min-llvm-version: 20 +//@ [llvm-pre-20] ignore-llvm-version: 20 - 99 //@ compile-flags: -C opt-level=3 #![crate_type = "lib"] @@ -10,19 +13,21 @@ use std::cmp::Ordering; // CHECK-LABEL: @cmp_signed #[no_mangle] pub fn cmp_signed(a: i64, b: i64) -> Ordering { - // CHECK: icmp slt - // CHECK: icmp ne - // CHECK: zext i1 - // CHECK: select i1 + // llvm-20: @llvm.scmp.i8.i64 + // llvm-pre-20: icmp slt + // llvm-pre-20: icmp ne + // llvm-pre-20: zext i1 + // llvm-pre-20: select i1 a.cmp(&b) } // CHECK-LABEL: @cmp_unsigned #[no_mangle] pub fn cmp_unsigned(a: u32, b: u32) -> Ordering { - // CHECK: icmp ult - // CHECK: icmp ne - // CHECK: zext i1 - // CHECK: select i1 + // llvm-20: @llvm.ucmp.i8.i32 + // llvm-pre-20: icmp ult + // llvm-pre-20: icmp ne + // llvm-pre-20: zext i1 + // llvm-pre-20: select i1 a.cmp(&b) } diff --git a/tests/codegen/intrinsics/rustc_intrinsic_must_be_overridden.rs b/tests/codegen/intrinsics/rustc_intrinsic_must_be_overridden.rs new file mode 100644 index 00000000000..b41e441d309 --- /dev/null +++ b/tests/codegen/intrinsics/rustc_intrinsic_must_be_overridden.rs @@ -0,0 +1,14 @@ +//@ revisions: OPT0 OPT1 +//@ [OPT0] compile-flags: -Copt-level=0 +//@ [OPT1] compile-flags: -Copt-level=1 +//@ compile-flags: -Cno-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +// CHECK-NOT: core::intrinsics::size_of_val + +#[no_mangle] +pub unsafe fn size_of_val(ptr: *const i32) -> usize { + core::intrinsics::size_of_val(ptr) +} diff --git a/tests/codegen/sanitizer/cfi/add-cfi-normalize-integers-flag.rs b/tests/codegen/sanitizer/cfi/add-cfi-normalize-integers-flag.rs new file mode 100644 index 00000000000..a54a6d84a80 --- /dev/null +++ b/tests/codegen/sanitizer/cfi/add-cfi-normalize-integers-flag.rs @@ -0,0 +1,10 @@ +// Verifies that "cfi-normalize-integers" module flag is added. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers + +#![crate_type = "lib"] + +pub fn foo() {} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"cfi-normalize-integers", i32 1} diff --git a/tests/codegen/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs b/tests/codegen/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs new file mode 100644 index 00000000000..d48e4016a16 --- /dev/null +++ b/tests/codegen/sanitizer/kcfi/add-cfi-normalize-integers-flag.rs @@ -0,0 +1,21 @@ +// Verifies that "cfi-normalize-integers" module flag is added. +// +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: x86 +//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Zsanitizer-cfi-normalize-integers + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +pub fn foo() {} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"cfi-normalize-integers", i32 1} diff --git a/tests/codegen/sanitizer/kcfi/add-kcfi-offset-flag.rs b/tests/codegen/sanitizer/kcfi/add-kcfi-offset-flag.rs new file mode 100644 index 00000000000..b4924719f4c --- /dev/null +++ b/tests/codegen/sanitizer/kcfi/add-kcfi-offset-flag.rs @@ -0,0 +1,21 @@ +// Verifies that "kcfi-offset" module flag is added. +// +//@ revisions: aarch64 x86_64 +//@ [aarch64] compile-flags: --target aarch64-unknown-none +//@ [aarch64] needs-llvm-components: aarch64 +//@ [x86_64] compile-flags: --target x86_64-unknown-none +//@ [x86_64] needs-llvm-components: x86 +//@ compile-flags: -Ctarget-feature=-crt-static -Zsanitizer=kcfi -Z patchable-function-entry=4,3 + +#![feature(no_core, lang_items, patchable_function_entry)] +#![crate_type = "lib"] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +pub fn foo() {} + +// CHECK: !{{[0-9]+}} = !{i32 4, !"kcfi-offset", i32 3} diff --git a/tests/crashes/127972.rs b/tests/crashes/127972.rs index d0764f875db..797dd7e6020 100644 --- a/tests/crashes/127972.rs +++ b/tests/crashes/127972.rs @@ -1,5 +1,5 @@ //@ known-bug: #127962 -#![feature(generic_const_exprs)] +#![feature(generic_const_exprs, const_arg_path)] fn zero_init<const usize: usize>() -> Substs1<{ (N) }> { Substs1([0; { (usize) }]) diff --git a/tests/crashes/128016.rs b/tests/crashes/128016.rs deleted file mode 100644 index d23721ae14e..00000000000 --- a/tests/crashes/128016.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #128016 -macro_rules! len { - () => { - target - }; -} - -fn main() { - let val: [str; len!()] = []; -} diff --git a/tests/debuginfo/dummy_span.rs b/tests/debuginfo/dummy_span.rs new file mode 100644 index 00000000000..d02eead470f --- /dev/null +++ b/tests/debuginfo/dummy_span.rs @@ -0,0 +1,45 @@ +//@ min-lldb-version: 310 + +//@ compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:run 7 + +// gdb-command:next +// gdb-command:next +// gdb-check:[...]#loc1[...] +// gdb-command:next +// gdb-check:[...]#loc2[...] + +// === LLDB TESTS ================================================================================== + +// lldb-command:run 7 + +// lldb-command:next +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc1[...] +// lldb-command:next +// lldb-command:frame select +// lldb-check:[...]#loc2[...] + +use std::env; +use std::num::ParseIntError; + +fn main() -> Result<(), ParseIntError> { + let args = env::args(); + let number_str = args.skip(1).next().unwrap(); + let number = number_str.parse::<i32>()?; + zzz(); // #break + if number % 7 == 0 { + // This generates code with a dummy span for + // some reason. If that ever changes this + // test will not test what it wants to test. + return Ok(()); // #loc1 + } + println!("{}", number); + Ok(()) +} // #loc2 + +fn zzz() { () } diff --git a/tests/incremental/decl_macro.rs b/tests/incremental/decl_macro.rs new file mode 100644 index 00000000000..74810ae4227 --- /dev/null +++ b/tests/incremental/decl_macro.rs @@ -0,0 +1,34 @@ +//@ revisions: rpass1 rpass2 + +// issue#112680 + +#![feature(decl_macro)] + +pub trait T { + type Key; + fn index_from_key(key: Self::Key) -> usize; +} + +pub macro m($key_ty:ident, $val_ty:ident) { + struct $key_ty { + inner: usize, + } + + impl T for $val_ty { + type Key = $key_ty; + + fn index_from_key(key: Self::Key) -> usize { + key.inner + } + } +} + +m!(TestId, Test); + +#[cfg(rpass1)] +struct Test(u32); + +#[cfg(rpass2)] +struct Test; + +fn main() {} diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs index 13585edf6cc..95a9011669e 100644 --- a/tests/run-make/crate-loading/rmake.rs +++ b/tests/run-make/crate-loading/rmake.rs @@ -27,7 +27,7 @@ fn main() { | | | required by a bound introduced by this call | -help: there are multiple different versions of crate `dependency` the your dependency graph +help: there are multiple different versions of crate `dependency` in the dependency graph --> multiple-dep-versions.rs:1:1 | 1 | extern crate dep_2_reexport; diff --git a/tests/run-make/debugger-visualizer-dep-info/foo.py b/tests/run-make/debugger-visualizer-dep-info/foo.py deleted file mode 100644 index 1bb8bf6d7fd..00000000000 --- a/tests/run-make/debugger-visualizer-dep-info/foo.py +++ /dev/null @@ -1 +0,0 @@ -# empty diff --git a/tests/run-make/debugger-visualizer-dep-info/main.rs b/tests/run-make/debugger-visualizer-dep-info/main.rs index 3aede2215ea..3539b305be3 100644 --- a/tests/run-make/debugger-visualizer-dep-info/main.rs +++ b/tests/run-make/debugger-visualizer-dep-info/main.rs @@ -1,4 +1,4 @@ -#![debugger_visualizer(gdb_script_file = "foo.py")] +#![debugger_visualizer(gdb_script_file = "my_gdb_script.py")] fn main() { const _UNUSED: u32 = { diff --git a/tests/run-make/debugger-visualizer-dep-info/my_gdb_script.py b/tests/run-make/debugger-visualizer-dep-info/my_gdb_script.py new file mode 100644 index 00000000000..d319792657e --- /dev/null +++ b/tests/run-make/debugger-visualizer-dep-info/my_gdb_script.py @@ -0,0 +1,6 @@ +# This is a Python script, but we don't actually run it. +# So if you're trying to remove Python scripts from the test suite, +# be aware that there's no value in trying to get rid of this one. +# +# It just needs to exist so that the compiler can embed it via +# `#![debugger_visualizer(gdb_script_file = "...")]`. diff --git a/tests/run-make/debugger-visualizer-dep-info/rmake.rs b/tests/run-make/debugger-visualizer-dep-info/rmake.rs index 65ffb2373e7..f5cf39157ac 100644 --- a/tests/run-make/debugger-visualizer-dep-info/rmake.rs +++ b/tests/run-make/debugger-visualizer-dep-info/rmake.rs @@ -6,6 +6,6 @@ use run_make_support::{invalid_utf8_contains, rustc}; fn main() { rustc().emit("dep-info").input("main.rs").run(); - invalid_utf8_contains("main.d", "foo.py"); + invalid_utf8_contains("main.d", "my_gdb_script.py"); invalid_utf8_contains("main.d", "my_visualizers/bar.natvis"); } diff --git a/tests/run-make/libtest-junit/validate_junit.py b/tests/run-make/libtest-junit/validate_junit.py index 0d9b34a3cf7..f92473751b0 100755 --- a/tests/run-make/libtest-junit/validate_junit.py +++ b/tests/run-make/libtest-junit/validate_junit.py @@ -1,5 +1,15 @@ #!/usr/bin/env python +# Trivial Python script that reads lines from stdin, and checks that each line +# is a well-formed XML document. +# +# This takes advantage of the fact that Python has a built-in XML parser, +# whereas doing the same check in Rust would require us to pull in an XML +# crate just for this relatively-minor test. +# +# If you're trying to remove Python scripts from the test suite, think twice +# before removing this one. You could do so, but it's probably not worth it. + import sys import xml.etree.ElementTree as ET diff --git a/tests/run-make/libtest-thread-limit/Makefile b/tests/run-make/libtest-thread-limit/Makefile deleted file mode 100644 index 9496fa30159..00000000000 --- a/tests/run-make/libtest-thread-limit/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -# only-linux - -all: - $(RUSTC) test.rs --test --target $(TARGET) - $(shell ulimit -p 0 && $(call RUN,test)) diff --git a/tests/run-make/libtest-thread-limit/rmake.rs b/tests/run-make/libtest-thread-limit/rmake.rs new file mode 100644 index 00000000000..be0eeaf1717 --- /dev/null +++ b/tests/run-make/libtest-thread-limit/rmake.rs @@ -0,0 +1,64 @@ +// libtest used to panic if it hit the thread limit. This often resulted in spurious test failures +// (thread 'main' panicked at 'called Result::unwrap() on an Err value: Os +// { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }' ... +// error: test failed, to rerun pass '--lib'). +// Since the fix in #81546, the test should continue to run synchronously +// if it runs out of threads. Therefore, this test's final execution step +// should succeed without an error. +// See https://github.com/rust-lang/rust/pull/81546 + +//@ only-linux +// Reason: thread limit modification +//@ ignore-cross-compile +// Reason: this test fails armhf-gnu, reasons unknown + +use std::ffi::{self, CStr, CString}; +use std::path::PathBuf; + +use run_make_support::{libc, run, rustc}; + +fn main() { + rustc().input("test.rs").arg("--test").run(); + + // We need to emulate an environment for libtest where threads are exhausted and spawning + // new threads are guaranteed to fail. This was previously achieved by ulimit shell builtin + // that called out to prlimit64 underneath to set resource limits (specifically thread + // number limits). Now that we don't have a shell, we need to implement that ourselves. + // See https://linux.die.net/man/2/setrlimit + + // The fork + exec is required because we cannot first try to limit the number of + // processes/threads to 1 and then try to spawn a new process to run the test. We need to + // setrlimit and run the libtest test program in the same process. + let pid = unsafe { libc::fork() }; + assert!(pid >= 0); + + // If the process ID is 0, this is the child process responsible for running the test + // program. + if pid == 0 { + let test = CString::new("test").unwrap(); + // The argv array should be terminated with a NULL pointer. + let argv = [test.as_ptr(), std::ptr::null()]; + // rlim_cur is soft limit, rlim_max is hard limit. + // By setting the limit very low (max 1), we ensure that libtest is unable to create new + // threads. + let rlimit = libc::rlimit { rlim_cur: 1, rlim_max: 1 }; + // RLIMIT_NPROC: The maximum number of processes (or, more precisely on Linux, + // threads) that can be created for the real user ID of the calling process. Upon + // encountering this limit, fork(2) fails with the error EAGAIN. + // Therefore, set the resource limit to RLIMIT_NPROC. + let ret = unsafe { libc::setrlimit(libc::RLIMIT_NPROC, &rlimit as *const libc::rlimit) }; + assert_eq!(ret, 0); + + // Finally, execute the 2 tests in test.rs. + let ret = unsafe { libc::execv(test.as_ptr(), argv.as_ptr()) }; + assert_eq!(ret, 0); + } else { + // Otherwise, other process IDs indicate that this is the parent process. + + let mut status: libc::c_int = 0; + let ret = unsafe { libc::waitpid(pid, &mut status as *mut libc::c_int, 0) }; + assert_eq!(ret, pid); + assert!(libc::WIFEXITED(status)); + assert_eq!(libc::WEXITSTATUS(status), 0); + } +} diff --git a/tests/run-make/libtest-thread-limit/test.rs b/tests/run-make/libtest-thread-limit/test.rs index 87e1d519171..d4eb1242615 100644 --- a/tests/run-make/libtest-thread-limit/test.rs +++ b/tests/run-make/libtest-thread-limit/test.rs @@ -10,7 +10,12 @@ fn spawn_thread_would_block() { THREAD_ID.set(thread::current().id()).unwrap(); } +// Tests are run in alphabetical order, and the second test is dependent on the +// first to set THREAD_ID. Do not rename the tests in such a way that `test_run_in_same_thread` +// would run before `spawn_thread_would_block`. +// See https://doc.rust-lang.org/rustc/tests/index.html#--shuffle + #[test] -fn run_in_same_thread() { +fn test_run_in_same_thread() { assert_eq!(*THREAD_ID.get().unwrap(), thread::current().id()); } diff --git a/tests/run-make/msvc-wholearchive/c.c b/tests/run-make/msvc-wholearchive/c.c new file mode 100644 index 00000000000..d6847845c68 --- /dev/null +++ b/tests/run-make/msvc-wholearchive/c.c @@ -0,0 +1 @@ +// This page is intentionally left blank diff --git a/tests/run-make/msvc-wholearchive/dll.def b/tests/run-make/msvc-wholearchive/dll.def new file mode 100644 index 00000000000..d55819e0d5e --- /dev/null +++ b/tests/run-make/msvc-wholearchive/dll.def @@ -0,0 +1,4 @@ +LIBRARY dll +EXPORTS + hello + number diff --git a/tests/run-make/msvc-wholearchive/rmake.rs b/tests/run-make/msvc-wholearchive/rmake.rs new file mode 100644 index 00000000000..98586fd8cc8 --- /dev/null +++ b/tests/run-make/msvc-wholearchive/rmake.rs @@ -0,0 +1,52 @@ +//! This is a regression test for #129020 +//! It ensures we can use `/WHOLEARCHIVE` to link a rust staticlib into DLL +//! using the MSVC linker + +//@ only-msvc +// Reason: this is testing the MSVC linker + +use std::path::PathBuf; + +use run_make_support::{cc, cmd, env_var, extra_c_flags, rustc}; + +fn main() { + // Build the staticlib + rustc().crate_type("staticlib").input("static.rs").output("static.lib").run(); + // Build an empty object to pass to the linker. + cc().input("c.c").output("c.obj").args(["-c"]).run(); + + // Find the C toolchain's linker. + let mut linker = PathBuf::from(env_var("CC")); + let linker_flavour = if linker.file_stem().is_some_and(|s| s == "cl") { + linker.set_file_name("link.exe"); + "msvc" + } else if linker.file_stem().is_some_and(|s| s == "clang-cl") { + linker.set_file_name("lld-link.exe"); + "llvm" + } else { + panic!("unknown C toolchain"); + }; + + // As a sanity check, make sure this works without /WHOLEARCHIVE. + // Otherwise the actual test failure may be caused by something else. + cmd(&linker) + .args(["c.obj", "./static.lib", "-dll", "-def:dll.def", "-out:dll.dll"]) + .args(extra_c_flags()) + .run(); + + // FIXME(@ChrisDenton): this doesn't currently work with llvm's lld-link for other reasons. + // May need LLVM patches. + if linker_flavour == "msvc" { + // Link in the staticlib using `/WHOLEARCHIVE` and produce a DLL. + cmd(&linker) + .args([ + "c.obj", + "-WHOLEARCHIVE:./static.lib", + "-dll", + "-def:dll.def", + "-out:dll_whole_archive.dll", + ]) + .args(extra_c_flags()) + .run(); + } +} diff --git a/tests/run-make/msvc-wholearchive/static.rs b/tests/run-make/msvc-wholearchive/static.rs new file mode 100644 index 00000000000..881c8856573 --- /dev/null +++ b/tests/run-make/msvc-wholearchive/static.rs @@ -0,0 +1,9 @@ +#[no_mangle] +pub extern "C" fn hello() { + println!("Hello world!"); +} + +#[no_mangle] +pub extern "C" fn number() -> u32 { + 42 +} diff --git a/tests/run-make/remove-dir-all-race/rmake.rs b/tests/run-make/remove-dir-all-race/rmake.rs new file mode 100644 index 00000000000..03c94b76127 --- /dev/null +++ b/tests/run-make/remove-dir-all-race/rmake.rs @@ -0,0 +1,62 @@ +//@ ignore-windows + +// This test attempts to make sure that running `remove_dir_all` +// doesn't result in a NotFound error one of the files it +// is deleting is deleted concurrently. +// +// The windows implementation for `remove_dir_all` is significantly +// more complicated, and has not yet been brought up to par with +// the implementation on other platforms, so this test is marked as +// `ignore-windows` until someone more expirenced with windows can +// sort that out. + +use std::fs::remove_dir_all; +use std::path::Path; +use std::thread; +use std::time::Duration; + +use run_make_support::rfs::{create_dir, write}; +use run_make_support::run_in_tmpdir; + +fn main() { + let mut race_happened = false; + run_in_tmpdir(|| { + for i in 0..150 { + create_dir("outer"); + create_dir("outer/inner"); + write("outer/inner.txt", b"sometext"); + + thread::scope(|scope| { + let t1 = scope.spawn(|| { + thread::sleep(Duration::from_nanos(i)); + remove_dir_all("outer").unwrap(); + }); + + let race_happened_ref = &race_happened; + let t2 = scope.spawn(|| { + let r1 = remove_dir_all("outer/inner"); + let r2 = remove_dir_all("outer/inner.txt"); + if r1.is_ok() && r2.is_err() { + race_happened = true; + } + }); + }); + + assert!(!Path::new("outer").exists()); + + // trying to remove a nonexistant top-level directory should + // still result in an error. + let Err(err) = remove_dir_all("outer") else { + panic!("removing nonexistant dir did not result in an error"); + }; + assert_eq!(err.kind(), std::io::ErrorKind::NotFound); + } + }); + if !race_happened { + eprintln!( + "WARNING: multithreaded deletion never raced, \ + try increasing the number of attempts or \ + adjusting the sleep timing" + ); + } +} diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile deleted file mode 100644 index 3c88ec34f43..00000000000 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -include ../tools.mk - -#only-x86_64-fortanix-unknown-sgx - -# For cargo setting -export RUSTC := $(RUSTC_ORIGINAL) -export LD_LIBRARY_PATH := $(HOST_RPATH_DIR) -# We need to be outside of 'src' dir in order to run cargo -export WORK_DIR := $(TMPDIR) -export TEST_DIR := $(shell pwd) - -## clean up unused env variables which might cause harm. -unexport RUSTC_LINKER -unexport RUSTC_BOOTSTRAP -unexport RUST_BUILD_STAGE -unexport RUST_TEST_THREADS -unexport RUST_TEST_TMPDIR -unexport AR -unexport CC -unexport CXX - -all: - bash script.sh diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs new file mode 100644 index 00000000000..130781a4293 --- /dev/null +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs @@ -0,0 +1,96 @@ +// ignore-tidy-linelength +// Reason: intel.com link + +// This security test checks that the disassembled form of certain symbols +// is "hardened" - that means, the assembly instructions match a pattern that +// mitigate potential Load Value Injection vulnerabilities. +// To do so, a test crate is compiled, and certain symbols are found, disassembled +// and checked one by one. +// See https://github.com/rust-lang/rust/pull/77008 + +// On load value injection: +// https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/load-value-injection.html + +//@ only-x86_64-fortanix-unknown-sgx + +use run_make_support::{cmd, cwd, llvm_filecheck, llvm_objdump, regex, set_current_dir, target}; + +fn main() { + let main_dir = cwd(); + set_current_dir("enclave"); + // HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. + // These come from the top-level Rust workspace, that this crate is not a + // member of, but Cargo tries to load the workspace `Cargo.toml` anyway. + cmd("cargo") + .env("RUSTC_BOOTSTRAP", "1") + .arg("-v") + .arg("run") + .arg("--target") + .arg(target()) + .run(); + set_current_dir(&main_dir); + // Rust has various ways of adding code to a binary: + // - Rust code + // - Inline assembly + // - Global assembly + // - C/C++ code compiled as part of Rust crates + // For those different kinds, we do have very small code examples that should be + // mitigated in some way. Mostly we check that ret instructions should no longer be present. + check("unw_getcontext", "unw_getcontext.checks"); + check("__libunwind_Registers_x86_64_jumpto", "jumpto.checks"); + + check("std::io::stdio::_print::[[:alnum:]]+", "print.with_frame_pointers.checks"); + + check("rust_plus_one_global_asm", "rust_plus_one_global_asm.checks"); + + check("cc_plus_one_c", "cc_plus_one_c.checks"); + check("cc_plus_one_c_asm", "cc_plus_one_c_asm.checks"); + check("cc_plus_one_cxx", "cc_plus_one_cxx.checks"); + check("cc_plus_one_cxx_asm", "cc_plus_one_cxx_asm.checks"); + check("cc_plus_one_asm", "cc_plus_one_asm.checks"); + + check("cmake_plus_one_c", "cmake_plus_one_c.checks"); + check("cmake_plus_one_c_asm", "cmake_plus_one_c_asm.checks"); + check("cmake_plus_one_c_global_asm", "cmake_plus_one_c_global_asm.checks"); + check("cmake_plus_one_cxx", "cmake_plus_one_cxx.checks"); + check("cmake_plus_one_cxx_asm", "cmake_plus_one_cxx_asm.checks"); + check("cmake_plus_one_cxx_global_asm", "cmake_plus_one_cxx_global_asm.checks"); + check("cmake_plus_one_asm", "cmake_plus_one_asm.checks"); +} + +fn check(func_re: &str, mut checks: &str) { + let dump = llvm_objdump() + .input("enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave") + .args(&["--syms", "--demangle"]) + .run() + .stdout_utf8(); + let re = regex::Regex::new(&format!("[[:blank:]]+{func_re}")).unwrap(); + let func = re.find_iter(&dump).map(|m| m.as_str().trim()).collect::<Vec<&str>>().join(","); + assert!(!func.is_empty()); + let dump = llvm_objdump() + .input("enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave") + .args(&["--demangle", &format!("--disassemble-symbols={func}")]) + .run() + .stdout_utf8(); + let dump = dump.as_bytes(); + + // Unique case, must succeed at one of two possible tests. + // This is because frame pointers are optional, and them being enabled requires + // an additional `popq` in the pattern checking file. + if func_re == "std::io::stdio::_print::[[:alnum:]]+" { + let output = llvm_filecheck().stdin(&dump).patterns(checks).run_unchecked(); + if !output.status().success() { + checks = "print.without_frame_pointers.checks"; + llvm_filecheck().stdin(&dump).patterns(checks).run(); + } + } else { + llvm_filecheck().stdin(&dump).patterns(checks).run(); + } + if !["rust_plus_one_global_asm", "cmake_plus_one_c_global_asm", "cmake_plus_one_cxx_global_asm"] + .contains(&func_re) + { + // The assembler cannot avoid explicit `ret` instructions. Sequences + // of `shlq $0x0, (%rsp); lfence; retq` are used instead. + llvm_filecheck().args(&["--implicit-check-not", "ret"]).stdin(dump).patterns(checks).run(); + } +} diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh deleted file mode 100644 index a7c4ae13ecb..00000000000 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash -set -exuo pipefail - -function build { - CRATE=enclave - - mkdir -p "${WORK_DIR}" - pushd "${WORK_DIR}" - rm -rf "${CRATE}" - cp -a "${TEST_DIR}"/enclave . - pushd $CRATE - echo "${WORK_DIR}" - # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. - # These come from the top-level Rust workspace, that this crate is not a - # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. - env RUSTC_BOOTSTRAP=1 - cargo -v run --target "${TARGET}" - popd - popd -} - -function check { - local func_re="$1" - local checks="${TEST_DIR}/$2" - local asm="" - local objdump="${LLVM_BIN_DIR}/llvm-objdump" - local filecheck="${LLVM_BIN_DIR}/FileCheck" - local enclave=${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave - - asm=$(mktemp) - func="$(${objdump} --syms --demangle "${enclave}" | \ - grep --only-matching -E "[[:blank:]]+${func_re}\$" | \ - sed -e 's/^[[:space:]]*//' )" - ${objdump} --disassemble-symbols="${func}" --demangle \ - "${enclave}" > "${asm}" - ${filecheck} --input-file "${asm}" "${checks}" - - if [ "${func_re}" != "rust_plus_one_global_asm" ] && - [ "${func_re}" != "cmake_plus_one_c_global_asm" ] && - [ "${func_re}" != "cmake_plus_one_cxx_global_asm" ]; then - # The assembler cannot avoid explicit `ret` instructions. Sequences - # of `shlq $0x0, (%rsp); lfence; retq` are used instead. - # https://www.intel.com/content/www/us/en/developer/articles/technical/ - # software-security-guidance/technical-documentation/load-value-injection.html - ${filecheck} --implicit-check-not ret --input-file "${asm}" "${checks}" - fi -} - -build - -check "unw_getcontext" unw_getcontext.checks -check "__libunwind_Registers_x86_64_jumpto" jumpto.checks -check 'std::io::stdio::_print::[[:alnum:]]+' print.with_frame_pointers.checks || - check 'std::io::stdio::_print::[[:alnum:]]+' print.without_frame_pointers.checks -check rust_plus_one_global_asm rust_plus_one_global_asm.checks - -check cc_plus_one_c cc_plus_one_c.checks -check cc_plus_one_c_asm cc_plus_one_c_asm.checks -check cc_plus_one_cxx cc_plus_one_cxx.checks -check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks -check cc_plus_one_asm cc_plus_one_asm.checks - -check cmake_plus_one_c cmake_plus_one_c.checks -check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks -check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks -check cmake_plus_one_cxx cmake_plus_one_cxx.checks -check cmake_plus_one_cxx_asm cmake_plus_one_cxx_asm.checks -check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks -check cmake_plus_one_asm cmake_plus_one_asm.checks diff --git a/tests/rustdoc-gui/target.goml b/tests/rustdoc-gui/target.goml index 82bd34ed274..92846f8e01d 100644 --- a/tests/rustdoc-gui/target.goml +++ b/tests/rustdoc-gui/target.goml @@ -11,7 +11,7 @@ define-function: ( [theme, background, border], block { call-function: ("switch-theme", {"theme": |theme|}) - assert-css: ("#method\.a_method:target", { + wait-for-css: ("#method\.a_method:target", { "background-color": |background|, "border-right": "3px solid " + |border|, }) diff --git a/tests/rustdoc-js-std/exact-case.js b/tests/rustdoc-js-std/exact-case.js new file mode 100644 index 00000000000..d9faff22fff --- /dev/null +++ b/tests/rustdoc-js-std/exact-case.js @@ -0,0 +1,7 @@ +const EXPECTED = { + 'query': 'Copy', + 'others': [ + { 'path': 'std::marker', 'name': 'Copy' }, + { 'path': 'std::fs', 'name': 'copy' }, + ], +} diff --git a/tests/rustdoc-json/impl-trait-precise-capturing.rs b/tests/rustdoc-json/impl-trait-precise-capturing.rs index f9fee788ffe..0c116a10290 100644 --- a/tests/rustdoc-json/impl-trait-precise-capturing.rs +++ b/tests/rustdoc-json/impl-trait-precise-capturing.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing)] - //@ is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[0]" \"\'a\" //@ is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[1]" \"T\" //@ is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[2]" \"N\" diff --git a/tests/rustdoc/doc-hidden-crate.rs b/tests/rustdoc/doc-hidden-crate.rs new file mode 100644 index 00000000000..dac557107a9 --- /dev/null +++ b/tests/rustdoc/doc-hidden-crate.rs @@ -0,0 +1,27 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/126796>. +// `doc(hidden)` should still be able to hide extern crates, only the local crates +// cannot be hidden because we still need to generate its `index.html` file. + +#![crate_name = "foo"] +#![doc(hidden)] + +//@ has 'foo/index.html' +// First we check that the page contains the crate name (`foo`). +//@ has - '//*' 'foo' +// But doesn't contain any of the other items. +//@ !has - '//*' 'other' +//@ !has - '//*' 'marker' +//@ !has - '//*' 'PhantomData' + +#[doc(inline)] +pub use std as other; + +#[doc(inline)] +pub use std::marker; + +#[doc(inline)] +pub use std::marker::PhantomData; + +//@ !has - '//*' 'myself' +#[doc(inline)] +pub use crate as myself; diff --git a/tests/rustdoc/impl-trait-precise-capturing.rs b/tests/rustdoc/impl-trait-precise-capturing.rs index a964a1f8518..3ec8c578013 100644 --- a/tests/rustdoc/impl-trait-precise-capturing.rs +++ b/tests/rustdoc/impl-trait-precise-capturing.rs @@ -1,7 +1,6 @@ //@ aux-build:precise-capturing.rs #![crate_name = "foo"] -#![feature(precise_capturing)] extern crate precise_capturing; diff --git a/tests/rustdoc/primitive-tuple-variadic.rs b/tests/rustdoc/primitive-tuple-variadic.rs index 4b2fb786a89..b15e996f929 100644 --- a/tests/rustdoc/primitive-tuple-variadic.rs +++ b/tests/rustdoc/primitive-tuple-variadic.rs @@ -16,3 +16,20 @@ pub trait Bar {} //@ has - '//section[@id="impl-Bar-for-(U,)"]/h3' 'impl<U: Foo> Bar for (U₁, U₂, …, Uₙ)' #[doc(fake_variadic)] impl<U: Foo> Bar for (U,) {} + +pub trait Baz<T> { fn baz(&self) -> T { todo!() } } + +//@ has foo/trait.Baz.html +//@ has - '//section[@id="impl-Baz%3C(T,)%3E-for-%5BT;+1%5D"]/h3' 'impl<T> Baz<(T₁, T₂, …, Tₙ)> for [T; N]' +#[doc(fake_variadic)] +impl<T> Baz<(T,)> for [T; 1] {} + +//@ has foo/trait.Baz.html +//@ has - '//section[@id="impl-Baz%3C%5BT;+1%5D%3E-for-(T,)"]/h3' 'impl<T> Baz<[T; N]> for (T₁, T₂, …, Tₙ)' +#[doc(fake_variadic)] +impl<T> Baz<[T; 1]> for (T,) {} + +//@ has foo/trait.Baz.html +//@ has - '//section[@id="impl-Baz%3CT%3E-for-(T,)"]/h3' 'impl<T> Baz<T> for (T₁, T₂, …, Tₙ)' +#[doc(fake_variadic)] +impl<T> Baz<T> for (T,) {} diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs index 5fcff74064a..442f9d72c3f 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.rs +++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs @@ -117,4 +117,11 @@ pub fn skipped_because_of_annotation<'a>(dcx: DiagCtxtHandle<'a>) { fn f(_x: impl Into<DiagMessage>, _y: impl Into<SubdiagMessage>) {} fn g() { f(crate::fluent_generated::no_crate_example, crate::fluent_generated::no_crate_example); + f("untranslatable diagnostic", crate::fluent_generated::no_crate_example); + //~^ ERROR diagnostics should be created using translatable messages + f(crate::fluent_generated::no_crate_example, "untranslatable diagnostic"); + //~^ ERROR diagnostics should be created using translatable messages + f("untranslatable diagnostic", "untranslatable diagnostic"); + //~^ ERROR diagnostics should be created using translatable messages + //~^^ ERROR diagnostics should be created using translatable messages } diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.stderr b/tests/ui-fulldeps/internal-lints/diagnostics.stderr index 669324ce5d4..36dd3cf4be7 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.stderr +++ b/tests/ui-fulldeps/internal-lints/diagnostics.stderr @@ -1,8 +1,8 @@ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:43:9 + --> $DIR/diagnostics.rs:43:31 | LL | Diag::new(dcx, level, "untranslatable diagnostic") - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/diagnostics.rs:7:9 @@ -11,16 +11,16 @@ LL | #![deny(rustc::untranslatable_diagnostic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:64:14 + --> $DIR/diagnostics.rs:64:19 | LL | diag.note("untranslatable diagnostic"); - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:85:14 + --> $DIR/diagnostics.rs:85:19 | LL | diag.note("untranslatable diagnostic"); - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls --> $DIR/diagnostics.rs:99:21 @@ -41,10 +41,34 @@ LL | let _diag = dcx.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:102:21 + --> $DIR/diagnostics.rs:102:32 | LL | let _diag = dcx.struct_err("untranslatable diagnostic"); - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: diagnostics should be created using translatable messages + --> $DIR/diagnostics.rs:120:7 + | +LL | f("untranslatable diagnostic", crate::fluent_generated::no_crate_example); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: diagnostics should be created using translatable messages + --> $DIR/diagnostics.rs:122:50 + | +LL | f(crate::fluent_generated::no_crate_example, "untranslatable diagnostic"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: diagnostics should be created using translatable messages + --> $DIR/diagnostics.rs:124:7 + | +LL | f("untranslatable diagnostic", "untranslatable diagnostic"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: diagnostics should be created using translatable messages + --> $DIR/diagnostics.rs:124:36 + | +LL | f("untranslatable diagnostic", "untranslatable diagnostic"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 5e3f2557566..5449c09d35a 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -17,12 +17,14 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use mir::{mono::Instance, TerminatorKind::*}; +use std::io::Write; +use std::ops::ControlFlow; + +use mir::mono::Instance; +use mir::TerminatorKind::*; use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind}; use stable_mir::*; -use std::io::Write; -use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; @@ -33,7 +35,7 @@ fn test_stable_mir() -> ControlFlow<()> { // Get all items and split generic vs monomorphic items. let (generic, mono): (Vec<_>, Vec<_>) = items.into_iter().partition(|item| item.requires_monomorphization()); - assert_eq!(mono.len(), 3, "Expected 3 mono functions"); + assert_eq!(mono.len(), 4, "Expected 3 mono functions"); assert_eq!(generic.len(), 2, "Expected 2 generic functions"); // For all monomorphic items, get the correspondent instances. diff --git a/tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr index 5ae1d78a92b..167b5ee4425 100644 --- a/tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr +++ b/tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr @@ -26,10 +26,10 @@ LL | | (a, b) LL | | } | |_^ | -help: to declare that `impl Trait<'a>` captures `'b`, you can add an explicit `'b` lifetime bound +help: add a `use<...>` bound to explicitly capture `'b` | -LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b { - | ++++ +LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + use<'a, 'b> { + | +++++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/attributes/rustc_pub_transparent.rs b/tests/ui/attributes/rustc_pub_transparent.rs new file mode 100644 index 00000000000..4508fa39baf --- /dev/null +++ b/tests/ui/attributes/rustc_pub_transparent.rs @@ -0,0 +1,25 @@ +#![feature(rustc_attrs, transparent_unions)] + +#[rustc_pub_transparent] +#[repr(transparent)] +union E<T: Copy> { + value: T, + uninit: (), +} + +#[repr(transparent)] +#[rustc_pub_transparent] +struct S<T>(T); + +#[rustc_pub_transparent] //~ ERROR attribute should be applied to `#[repr(transparent)]` types +#[repr(C)] +struct S1 { + A: u8, +} + +#[rustc_pub_transparent] //~ ERROR attribute should be applied to `#[repr(transparent)]` types +struct S2<T> { + value: T, +} + +fn main() {} diff --git a/tests/ui/attributes/rustc_pub_transparent.stderr b/tests/ui/attributes/rustc_pub_transparent.stderr new file mode 100644 index 00000000000..1d1f9437cb2 --- /dev/null +++ b/tests/ui/attributes/rustc_pub_transparent.stderr @@ -0,0 +1,23 @@ +error: attribute should be applied to `#[repr(transparent)]` types + --> $DIR/rustc_pub_transparent.rs:14:1 + | +LL | #[rustc_pub_transparent] + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[repr(C)] +LL | / struct S1 { +LL | | A: u8, +LL | | } + | |_- not a `#[repr(transparent)]` type + +error: attribute should be applied to `#[repr(transparent)]` types + --> $DIR/rustc_pub_transparent.rs:20:1 + | +LL | #[rustc_pub_transparent] + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / struct S2<T> { +LL | | value: T, +LL | | } + | |_- not a `#[repr(transparent)]` type + +error: aborting due to 2 previous errors + diff --git a/tests/ui/borrowck/alias-liveness/opaque-type-param.stderr b/tests/ui/borrowck/alias-liveness/opaque-type-param.stderr index 73de5864953..1a32d120057 100644 --- a/tests/ui/borrowck/alias-liveness/opaque-type-param.stderr +++ b/tests/ui/borrowck/alias-liveness/opaque-type-param.stderr @@ -7,6 +7,11 @@ LL | fn foo<'a>(s: &'a str) -> impl Trait + 'static { | hidden type `impl Trait + 'static` captures the lifetime `'a` as defined here LL | bar(s) | ^^^^^^ + | +help: add a `use<...>` bound to explicitly capture `'a` + | +LL | fn foo<'a>(s: &'a str) -> impl Trait + 'static + use<'a> { + | +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr index 54d8f26f4ea..5f0347bdb4d 100644 --- a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr +++ b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr @@ -30,9 +30,9 @@ note: the lifetime `'c` as defined here... LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { | ^^ note: ...does not necessarily outlive the lifetime `'c` as defined here - --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24 + --> $DIR/regions-bound-missing-bound-in-impl.rs:12:24 | -LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { +LL | fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>); | ^^ error[E0308]: method not compatible with trait @@ -44,16 +44,15 @@ LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d = note: expected signature `fn(&'a _, Inv<'c>, Inv<'c>, Inv<'_>)` found signature `fn(&'a _, Inv<'_>, Inv<'c>, Inv<'_>)` note: the lifetime `'c` as defined here... - --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24 + --> $DIR/regions-bound-missing-bound-in-impl.rs:12:24 | -LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { +LL | fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>); | ^^ note: ...does not necessarily outlive the lifetime `'c` as defined here --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24 | LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { | ^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0195]: lifetime parameters or bounds on method `wrong_bound2` do not match the trait declaration --> $DIR/regions-bound-missing-bound-in-impl.rs:42:20 diff --git a/tests/ui/coercion/cast-higher-ranked-unsafe-fn-ptr.rs b/tests/ui/coercion/cast-higher-ranked-unsafe-fn-ptr.rs new file mode 100644 index 00000000000..19723bee4d4 --- /dev/null +++ b/tests/ui/coercion/cast-higher-ranked-unsafe-fn-ptr.rs @@ -0,0 +1,14 @@ +//@ check-pass + +fn higher_ranked_fndef(ctx: &mut ()) {} + +fn test(higher_ranked_fnptr: fn(&mut ())) { + fn as_unsafe<T>(_: unsafe fn(T)) {} + + // Make sure that we can cast higher-ranked fn items and pointers to + // a non-higher-ranked target. + as_unsafe(higher_ranked_fndef); + as_unsafe(higher_ranked_fnptr); +} + +fn main() {} diff --git a/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs b/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs index e07fa78463c..cdfeb9c434e 100644 --- a/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs +++ b/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs @@ -5,7 +5,9 @@ #![feature(with_negative_coherence)] trait Trait {} impl<const N: u8> Trait for [(); N] {} +//~^ ERROR: mismatched types impl<const N: i8> Trait for [(); N] {} //~^ ERROR: conflicting implementations of trait `Trait` +//~| ERROR: mismatched types fn main() {} diff --git a/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr b/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr index 2087be8e711..d65450845bc 100644 --- a/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr +++ b/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr @@ -1,11 +1,25 @@ error[E0119]: conflicting implementations of trait `Trait` for type `[(); _]` - --> $DIR/generic_const_type_mismatch.rs:8:1 + --> $DIR/generic_const_type_mismatch.rs:9:1 | LL | impl<const N: u8> Trait for [(); N] {} | ----------------------------------- first implementation here +LL | LL | impl<const N: i8> Trait for [(); N] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); _]` -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/generic_const_type_mismatch.rs:7:34 + | +LL | impl<const N: u8> Trait for [(); N] {} + | ^ expected `usize`, found `u8` + +error[E0308]: mismatched types + --> $DIR/generic_const_type_mismatch.rs:9:34 + | +LL | impl<const N: i8> Trait for [(); N] {} + | ^ expected `usize`, found `i8` + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0119`. +Some errors have detailed explanations: E0119, E0308. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/const-generics/bad-subst-const-kind.rs b/tests/ui/const-generics/bad-subst-const-kind.rs index cc2ff9b8dea..c4e74596e9f 100644 --- a/tests/ui/const-generics/bad-subst-const-kind.rs +++ b/tests/ui/const-generics/bad-subst-const-kind.rs @@ -7,6 +7,7 @@ trait Q { impl<const N: u64> Q for [u8; N] { //~^ ERROR: the constant `N` is not of type `usize` + //~| ERROR: mismatched types const ASSOC: usize = 1; } diff --git a/tests/ui/const-generics/bad-subst-const-kind.stderr b/tests/ui/const-generics/bad-subst-const-kind.stderr index 5c8d9c90363..21ec8f0768c 100644 --- a/tests/ui/const-generics/bad-subst-const-kind.stderr +++ b/tests/ui/const-generics/bad-subst-const-kind.stderr @@ -5,7 +5,7 @@ LL | impl<const N: u64> Q for [u8; N] { | ^^^^^^^ expected `usize`, found `u64` error: the constant `13` is not of type `u64` - --> $DIR/bad-subst-const-kind.rs:13:24 + --> $DIR/bad-subst-const-kind.rs:14:24 | LL | pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { | ^^^^^^^^ expected `u64`, found `usize` @@ -18,5 +18,12 @@ LL | impl<const N: u64> Q for [u8; N] { | | | unsatisfied trait bound introduced here -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/bad-subst-const-kind.rs:8:31 + | +LL | impl<const N: u64> Q for [u8; N] { + | ^ expected `usize`, found `u64` + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-nested.rs b/tests/ui/const-generics/early/trivial-const-arg-macro-nested.rs new file mode 100644 index 00000000000..f9730cf8566 --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-nested.rs @@ -0,0 +1,21 @@ +//@ check-pass + +// This is a regression test for #128016. + +macro_rules! len_inner { + () => { + BAR + }; +} + +macro_rules! len { + () => { + len_inner!() + }; +} + +const BAR: usize = 0; + +fn main() { + let val: [bool; len!()] = []; +} diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-param.rs b/tests/ui/const-generics/early/trivial-const-arg-macro-param.rs new file mode 100644 index 00000000000..f123e55c028 --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-param.rs @@ -0,0 +1,13 @@ +//@ check-pass + +macro_rules! len { + ($x:ident) => { + $x + }; +} + +fn bar<const N: usize>() { + let val: [bool; len!(N)] = [true; N]; +} + +fn main() {} diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-res-error.rs b/tests/ui/const-generics/early/trivial-const-arg-macro-res-error.rs new file mode 100644 index 00000000000..f218caac0cf --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-res-error.rs @@ -0,0 +1,13 @@ +// This is a regression test for #128016. + +macro_rules! len { + () => { + target + //~^ ERROR cannot find value `target` + }; +} + +fn main() { + let val: [str; len!()] = []; + //~^ ERROR the size for values +} diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-res-error.stderr b/tests/ui/const-generics/early/trivial-const-arg-macro-res-error.stderr new file mode 100644 index 00000000000..ab289e5a6b7 --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-res-error.stderr @@ -0,0 +1,24 @@ +error[E0425]: cannot find value `target` in this scope + --> $DIR/trivial-const-arg-macro-res-error.rs:5:9 + | +LL | target + | ^^^^^^ not found in this scope +... +LL | let val: [str; len!()] = []; + | ------ in this macro invocation + | + = note: this error originates in the macro `len` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/trivial-const-arg-macro-res-error.rs:11:14 + | +LL | let val: [str; len!()] = []; + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: slice and array elements must have `Sized` type + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0425. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro.rs b/tests/ui/const-generics/early/trivial-const-arg-macro.rs new file mode 100644 index 00000000000..a19d9abfdcb --- /dev/null +++ b/tests/ui/const-generics/early/trivial-const-arg-macro.rs @@ -0,0 +1,15 @@ +//@ check-pass + +// This is a regression test for #128016. + +macro_rules! len { + () => { + BAR + }; +} + +const BAR: usize = 0; + +fn main() { + let val: [bool; len!()] = []; +} diff --git a/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr b/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr index 7a9572d000d..24f3ed7cdf1 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr @@ -30,10 +30,10 @@ LL | fn a(&self) -> impl Iterator { LL | self.0.iter_mut() | ^^^^^^^^^^^^^^^^^ | -help: to declare that `impl Iterator` captures `'_`, you can add an explicit `'_` lifetime bound +help: add a `use<...>` bound to explicitly capture `'_` | -LL | fn a(&self) -> impl Iterator + '_ { - | ++++ +LL | fn a(&self) -> impl Iterator + use<'_> { + | +++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs index 8e5e23b2337..a45deabbb0f 100644 --- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs +++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs @@ -8,6 +8,7 @@ trait Q { impl<const N: u64> Q for [u8; N] {} //~^ ERROR not all trait items implemented //~| ERROR the constant `N` is not of type `usize` +//~| ERROR mismatched types pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {} //~^ ERROR the constant `13` is not of type `u64` diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr index e03580ec007..68870a8d38d 100644 --- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr +++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr @@ -14,7 +14,7 @@ LL | impl<const N: u64> Q for [u8; N] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `ASSOC` in implementation error: the constant `13` is not of type `u64` - --> $DIR/type_mismatch.rs:12:26 + --> $DIR/type_mismatch.rs:13:26 | LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {} | ^^^^^^^^ expected `u64`, found `usize` @@ -28,14 +28,20 @@ LL | impl<const N: u64> Q for [u8; N] {} | unsatisfied trait bound introduced here error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:12:20 + --> $DIR/type_mismatch.rs:13:20 | LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {} | ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `[u8; <[u8; 13] as Q>::ASSOC]`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression -error: aborting due to 4 previous errors +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:8:31 + | +LL | impl<const N: u64> Q for [u8; N] {} + | ^ expected `usize`, found `u64` + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0046, E0308. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs index 8b7ee577569..05a3487ffca 100644 --- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs +++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs @@ -14,8 +14,8 @@ mod v20 { //~^ ERROR cannot find value `v8` in this scope //~| ERROR cannot find function `v6` in this scope pub struct v17<const v10: usize, const v7: v11> { - //~^ WARN type `v17` should have an upper camel case name - //~| ERROR `[[usize; v4]; v4]` is forbidden as the type of a const generic parameter + //~^ WARN type `v17` should have an upper camel case name + //~| ERROR `[[usize; v4]; v4]` is forbidden as the type of a const generic parameter _p: (), } @@ -25,10 +25,10 @@ mod v20 { } impl<const v10: usize> v17<v10, v2> { - //~^ ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0} - //~| ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0} + //~^ ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1} + //~| ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1} pub const fn v21() -> v18 { - //~^ ERROR cannot find type `v18` in this scope + //~^ ERROR cannot find type `v18` in this scope v18 { _p: () } //~^ ERROR cannot find struct, variant or union type `v18` in this scope } diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr index 15d3c472585..39f022fbee9 100644 --- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr @@ -72,13 +72,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more LL + #![feature(adt_const_params)] | -error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0} +error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1} --> $DIR/unevaluated-const-ice-119731.rs:27:37 | LL | impl<const v10: usize> v17<v10, v2> { | ^^ -error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0} +error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1} --> $DIR/unevaluated-const-ice-119731.rs:27:37 | LL | impl<const v10: usize> v17<v10, v2> { diff --git a/tests/ui/const-generics/transmute-fail.rs b/tests/ui/const-generics/transmute-fail.rs index 59b77c678e8..a9b297ffb62 100644 --- a/tests/ui/const-generics/transmute-fail.rs +++ b/tests/ui/const-generics/transmute-fail.rs @@ -2,108 +2,108 @@ #![feature(generic_const_exprs)] #![allow(incomplete_features)] -fn foo<const W: usize, const H: usize>(v: [[u32;H+1]; W]) -> [[u32; W+1]; H] { - unsafe { - std::mem::transmute(v) - //~^ ERROR cannot transmute - } +fn foo<const W: usize, const H: usize>(v: [[u32; H + 1]; W]) -> [[u32; W + 1]; H] { + unsafe { + std::mem::transmute(v) + //~^ ERROR cannot transmute + } } fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { - //~^ ERROR the constant `W` is not of type `usize` - unsafe { - std::mem::transmute(v) - //~^ ERROR the constant `W` is not of type `usize` - } + //~^ ERROR: the constant `W` is not of type `usize` + //~| ERROR: mismatched types + //~| ERROR: mismatched types + unsafe { + std::mem::transmute(v) + //~^ ERROR: the constant `W` is not of type `usize` + } } fn baz<const W: usize, const H: usize>(v: [[u32; H]; W]) -> [u32; W * H * H] { - unsafe { - std::mem::transmute(v) - //~^ ERROR cannot transmute - } + unsafe { + std::mem::transmute(v) + //~^ ERROR cannot transmute + } } fn overflow(v: [[[u32; 8888888]; 9999999]; 777777777]) -> [[[u32; 9999999]; 777777777]; 8888888] { - unsafe { - std::mem::transmute(v) - //~^ ERROR cannot transmute - } + unsafe { + std::mem::transmute(v) + //~^ ERROR cannot transmute + } } -fn transpose<const W: usize, const H: usize>(v: [[u32;H]; W]) -> [[u32; W]; H] { - unsafe { - std::mem::transmute(v) - //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types - } +fn transpose<const W: usize, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { + unsafe { + std::mem::transmute(v) + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types + } } fn ident<const W: usize, const H: usize>(v: [[u32; H]; W]) -> [[u32; H]; W] { - unsafe { - std::mem::transmute(v) - } + unsafe { std::mem::transmute(v) } } fn flatten<const W: usize, const H: usize>(v: [[u32; H]; W]) -> [u32; W * H] { - unsafe { - std::mem::transmute(v) - //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types - } + unsafe { + std::mem::transmute(v) + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types + } } -fn coagulate<const W: usize, const H: usize>(v: [u32; H*W]) -> [[u32; W];H] { - unsafe { - std::mem::transmute(v) - //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types - } +fn coagulate<const W: usize, const H: usize>(v: [u32; H * W]) -> [[u32; W]; H] { + unsafe { + std::mem::transmute(v) + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types + } } fn flatten_3d<const W: usize, const H: usize, const D: usize>( - v: [[[u32; D]; H]; W] + v: [[[u32; D]; H]; W], ) -> [u32; D * W * H] { - unsafe { - std::mem::transmute(v) - //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types - } + unsafe { + std::mem::transmute(v) + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types + } } fn flatten_somewhat<const W: usize, const H: usize, const D: usize>( - v: [[[u32; D]; H]; W] + v: [[[u32; D]; H]; W], ) -> [[u32; D * W]; H] { - unsafe { - std::mem::transmute(v) - //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types - } + unsafe { + std::mem::transmute(v) + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types + } } fn known_size<const L: usize>(v: [u16; L]) -> [u8; L * 2] { - unsafe { - std::mem::transmute(v) - //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types - } + unsafe { + std::mem::transmute(v) + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types + } } fn condense_bytes<const L: usize>(v: [u8; L * 2]) -> [u16; L] { - unsafe { - std::mem::transmute(v) - //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types - } + unsafe { + std::mem::transmute(v) + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types + } } -fn singleton_each<const L: usize>(v: [u8; L]) -> [[u8;1]; L] { - unsafe { - std::mem::transmute(v) - //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types - } +fn singleton_each<const L: usize>(v: [u8; L]) -> [[u8; 1]; L] { + unsafe { + std::mem::transmute(v) + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types + } } fn transpose_with_const<const W: usize, const H: usize>( - v: [[u32; 2 * H]; W + W] + v: [[u32; 2 * H]; W + W], ) -> [[u32; W + W]; 2 * H] { - unsafe { - std::mem::transmute(v) - //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types - } + unsafe { + std::mem::transmute(v) + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types + } } fn main() {} diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr index b40fb23c331..124fbee8850 100644 --- a/tests/ui/const-generics/transmute-fail.stderr +++ b/tests/ui/const-generics/transmute-fail.stderr @@ -5,119 +5,132 @@ LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { | ^^^^^^^^^^^^^ expected `usize`, found `bool` error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:7:5 + --> $DIR/transmute-fail.rs:7:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[[u32; H+1]; W]` (size can vary because of [u32; H+1]) - = note: target type: `[[u32; W+1]; H]` (size can vary because of [u32; W+1]) + = note: source type: `[[u32; H + 1]; W]` (size can vary because of [u32; H + 1]) + = note: target type: `[[u32; W + 1]; H]` (size can vary because of [u32; W + 1]) error: the constant `W` is not of type `usize` - --> $DIR/transmute-fail.rs:15:5 + --> $DIR/transmute-fail.rs:17:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:22:5 + --> $DIR/transmute-fail.rs:24:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `[[u32; H]; W]` (size can vary because of [u32; H]) = note: target type: `[u32; W * H * H]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:29:5 + --> $DIR/transmute-fail.rs:31:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[u32; 8888888]; 9999999]` are too big for the current architecture) = note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[u32; 9999999]; 777777777]` are too big for the current architecture) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:36:5 + --> $DIR/transmute-fail.rs:38:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `[[u32; H]; W]` (size can vary because of [u32; H]) = note: target type: `[[u32; W]; H]` (size can vary because of [u32; W]) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:49:5 + --> $DIR/transmute-fail.rs:49:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `[[u32; H]; W]` (size can vary because of [u32; H]) = note: target type: `[u32; W * H]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:56:5 + --> $DIR/transmute-fail.rs:56:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[u32; H*W]` (this type does not have a fixed size) + = note: source type: `[u32; H * W]` (this type does not have a fixed size) = note: target type: `[[u32; W]; H]` (size can vary because of [u32; W]) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:65:5 + --> $DIR/transmute-fail.rs:65:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `[[[u32; D]; H]; W]` (size can vary because of [u32; D]) = note: target type: `[u32; D * W * H]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:74:5 + --> $DIR/transmute-fail.rs:74:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `[[[u32; D]; H]; W]` (size can vary because of [u32; D]) = note: target type: `[[u32; D * W]; H]` (size can vary because of [u32; D * W]) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:81:5 + --> $DIR/transmute-fail.rs:81:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `[u16; L]` (this type does not have a fixed size) = note: target type: `[u8; L * 2]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:88:5 + --> $DIR/transmute-fail.rs:88:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `[u8; L * 2]` (this type does not have a fixed size) = note: target type: `[u16; L]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:95:5 + --> $DIR/transmute-fail.rs:95:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `[u8; L]` (this type does not have a fixed size) = note: target type: `[[u8; 1]; L]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:104:5 + --> $DIR/transmute-fail.rs:104:9 | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `[[u32; 2 * H]; W + W]` (size can vary because of [u32; 2 * H]) = note: target type: `[[u32; W + W]; 2 * H]` (size can vary because of [u32; W + W]) -error: aborting due to 14 previous errors +error[E0308]: mismatched types + --> $DIR/transmute-fail.rs:12:53 + | +LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { + | ^ expected `usize`, found `bool` + +error[E0308]: mismatched types + --> $DIR/transmute-fail.rs:12:67 + | +LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { + | ^ expected `usize`, found `bool` + +error: aborting due to 16 previous errors -For more information about this error, try `rustc --explain E0512`. +Some errors have detailed explanations: E0308, E0512. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/type_mismatch.rs b/tests/ui/const-generics/type_mismatch.rs index 8187c785cd1..9c7217cd83e 100644 --- a/tests/ui/const-generics/type_mismatch.rs +++ b/tests/ui/const-generics/type_mismatch.rs @@ -1,10 +1,12 @@ fn foo<const N: usize>() -> [u8; N] { bar::<N>() //~^ ERROR the constant `N` is not of type `u8` + //~| ERROR: mismatched types } fn bar<const N: u8>() -> [u8; N] {} //~^ ERROR the constant `N` is not of type `usize` +//~| ERROR: mismatched types //~| ERROR mismatched types fn main() {} diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr index d1bb5c1242f..77e9f5e2b44 100644 --- a/tests/ui/const-generics/type_mismatch.stderr +++ b/tests/ui/const-generics/type_mismatch.stderr @@ -1,5 +1,5 @@ error: the constant `N` is not of type `usize` - --> $DIR/type_mismatch.rs:6:26 + --> $DIR/type_mismatch.rs:7:26 | LL | fn bar<const N: u8>() -> [u8; N] {} | ^^^^^^^ expected `usize`, found `u8` @@ -11,19 +11,31 @@ LL | bar::<N>() | ^ expected `u8`, found `usize` | note: required by a const generic parameter in `bar` - --> $DIR/type_mismatch.rs:6:8 + --> $DIR/type_mismatch.rs:7:8 | LL | fn bar<const N: u8>() -> [u8; N] {} | ^^^^^^^^^^^ required by this const generic parameter in `bar` error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:6:26 + --> $DIR/type_mismatch.rs:7:26 | LL | fn bar<const N: u8>() -> [u8; N] {} | --- ^^^^^^^ expected `[u8; N]`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:2:11 + | +LL | bar::<N>() + | ^ expected `u8`, found `usize` + +error[E0308]: mismatched types + --> $DIR/type_mismatch.rs:7:31 + | +LL | fn bar<const N: u8>() -> [u8; N] {} + | ^ expected `usize`, found `u8` + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.rs b/tests/ui/consts/const-eval/ub-write-through-immutable.rs index 945367f1823..9860b8fde4a 100644 --- a/tests/ui/consts/const-eval/ub-write-through-immutable.rs +++ b/tests/ui/consts/const-eval/ub-write-through-immutable.rs @@ -1,6 +1,5 @@ //! Ensure we catch UB due to writing through a shared reference. #![feature(const_mut_refs, const_refs_to_cell)] -#![deny(writes_through_immutable_pointer)] #![allow(invalid_reference_casting)] use std::mem; @@ -9,15 +8,15 @@ use std::cell::UnsafeCell; const WRITE_AFTER_CAST: () = unsafe { let mut x = 0; let ptr = &x as *const i32 as *mut i32; - *ptr = 0; //~ERROR: writes_through_immutable_pointer - //~^ previously accepted + *ptr = 0; //~ERROR: evaluation of constant value failed + //~| immutable }; const WRITE_AFTER_TRANSMUTE: () = unsafe { let mut x = 0; let ptr: *mut i32 = mem::transmute(&x); - *ptr = 0; //~ERROR: writes_through_immutable_pointer - //~^ previously accepted + *ptr = 0; //~ERROR: evaluation of constant value failed + //~| immutable }; // it's okay when there is interior mutability; diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.stderr b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr index 27eb2d2c0d1..dbcd35e0b88 100644 --- a/tests/ui/consts/const-eval/ub-write-through-immutable.stderr +++ b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr @@ -1,55 +1,15 @@ -error: writing through a pointer that was derived from a shared (immutable) reference - --> $DIR/ub-write-through-immutable.rs:12:5 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-write-through-immutable.rs:11:5 | LL | *ptr = 0; - | ^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X> -note: the lint level is defined here - --> $DIR/ub-write-through-immutable.rs:3:9 - | -LL | #![deny(writes_through_immutable_pointer)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ writing through a pointer that was derived from a shared (immutable) reference -error: writing through a pointer that was derived from a shared (immutable) reference - --> $DIR/ub-write-through-immutable.rs:19:5 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-write-through-immutable.rs:18:5 | LL | *ptr = 0; - | ^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X> + | ^^^^^^^^ writing through a pointer that was derived from a shared (immutable) reference error: aborting due to 2 previous errors -Future incompatibility report: Future breakage diagnostic: -error: writing through a pointer that was derived from a shared (immutable) reference - --> $DIR/ub-write-through-immutable.rs:12:5 - | -LL | *ptr = 0; - | ^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X> -note: the lint level is defined here - --> $DIR/ub-write-through-immutable.rs:3:9 - | -LL | #![deny(writes_through_immutable_pointer)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -error: writing through a pointer that was derived from a shared (immutable) reference - --> $DIR/ub-write-through-immutable.rs:19:5 - | -LL | *ptr = 0; - | ^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X> -note: the lint level is defined here - --> $DIR/ub-write-through-immutable.rs:3:9 - | -LL | #![deny(writes_through_immutable_pointer)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs index c7078e46fa6..efc0a1c2fba 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs @@ -1,9 +1,5 @@ #![feature(const_extern_fn)] -const extern "C" fn unsize(x: &[u8; 3]) -> &[u8] { x } -const unsafe extern "C" fn closure() -> fn() { || {} } -const unsafe extern "C" fn use_float() { 1.0 + 1.0; } -//~^ ERROR floating point arithmetic const extern "C" fn ptr_cast(val: *const u8) { val as usize; } //~^ ERROR pointers cannot be cast to integers diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr index 29fa90d611c..9cdeec159be 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr @@ -1,15 +1,5 @@ -error[E0658]: floating point arithmetic is not allowed in constant functions - --> $DIR/const-extern-fn-min-const-fn.rs:5:42 - | -LL | const unsafe extern "C" fn use_float() { 1.0 + 1.0; } - | ^^^^^^^^^ - | - = note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information - = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error: pointers cannot be cast to integers during const eval - --> $DIR/const-extern-fn-min-const-fn.rs:7:48 + --> $DIR/const-extern-fn-min-const-fn.rs:3:48 | LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; } | ^^^^^^^^^^^^ @@ -17,6 +7,5 @@ LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; } = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn.rs b/tests/ui/consts/const-extern-fn/const-extern-fn.rs index 57f5da8d0af..4b164767064 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn.rs +++ b/tests/ui/consts/const-extern-fn/const-extern-fn.rs @@ -17,6 +17,19 @@ const unsafe extern "C" fn bar2(val: bool) -> bool { !val } +#[allow(improper_ctypes_definitions)] +const extern "C" fn unsize(x: &[u8; 3]) -> &[u8] { + x +} + +#[allow(improper_ctypes_definitions)] +const unsafe extern "C" fn closure() -> fn() { + || {} +} + +const unsafe extern "C" fn use_float() -> f32 { + 1.0 + 1.0 +} fn main() { let a: [u8; foo1(25) as usize] = [0; 26]; @@ -32,4 +45,8 @@ fn main() { let _foo2_cast: extern "C" fn(u8) -> u8 = foo2; let _bar1_cast: unsafe extern "C" fn(bool) -> bool = bar1; let _bar2_cast: unsafe extern "C" fn(bool) -> bool = bar2; + + unsize(&[0, 1, 2]); + unsafe { closure(); } + unsafe { use_float(); } } diff --git a/tests/ui/consts/const_fn_floating_point_arithmetic.gated.stderr b/tests/ui/consts/const_fn_floating_point_arithmetic.gated.stderr deleted file mode 100644 index e1b8154a287..00000000000 --- a/tests/ui/consts/const_fn_floating_point_arithmetic.gated.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/const_fn_floating_point_arithmetic.rs:20:1 - | -LL | fn main() {} - | ^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/consts/const_fn_floating_point_arithmetic.rs b/tests/ui/consts/const_fn_floating_point_arithmetic.rs deleted file mode 100644 index b0d0bc6b9f4..00000000000 --- a/tests/ui/consts/const_fn_floating_point_arithmetic.rs +++ /dev/null @@ -1,20 +0,0 @@ -// gate-test-const_fn_floating_point_arithmetic - -//@ revisions: stock gated - -#![feature(rustc_attrs)] -#![cfg_attr(gated, feature(const_fn_floating_point_arithmetic))] - -const fn add(f: f32) -> f32 { f + 2.0 } -//[stock]~^ floating point arithmetic -const fn sub(f: f32) -> f32 { 2.0 - f } -//[stock]~^ floating point arithmetic -const fn mul(f: f32, g: f32) -> f32 { f * g } -//[stock]~^ floating point arithmetic -const fn div(f: f32, g: f32) -> f32 { f / g } -//[stock]~^ floating point arithmetic -const fn neg(f: f32) -> f32 { -f } -//[stock]~^ floating point arithmetic - -#[rustc_error] -fn main() {} //[gated]~ fatal error triggered by #[rustc_error] diff --git a/tests/ui/consts/const_fn_floating_point_arithmetic.stock.stderr b/tests/ui/consts/const_fn_floating_point_arithmetic.stock.stderr deleted file mode 100644 index b5b94786ebb..00000000000 --- a/tests/ui/consts/const_fn_floating_point_arithmetic.stock.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error[E0658]: floating point arithmetic is not allowed in constant functions - --> $DIR/const_fn_floating_point_arithmetic.rs:8:31 - | -LL | const fn add(f: f32) -> f32 { f + 2.0 } - | ^^^^^^^ - | - = note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information - = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: floating point arithmetic is not allowed in constant functions - --> $DIR/const_fn_floating_point_arithmetic.rs:10:31 - | -LL | const fn sub(f: f32) -> f32 { 2.0 - f } - | ^^^^^^^ - | - = note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information - = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: floating point arithmetic is not allowed in constant functions - --> $DIR/const_fn_floating_point_arithmetic.rs:12:39 - | -LL | const fn mul(f: f32, g: f32) -> f32 { f * g } - | ^^^^^ - | - = note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information - = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: floating point arithmetic is not allowed in constant functions - --> $DIR/const_fn_floating_point_arithmetic.rs:14:39 - | -LL | const fn div(f: f32, g: f32) -> f32 { f / g } - | ^^^^^ - | - = note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information - = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: floating point arithmetic is not allowed in constant functions - --> $DIR/const_fn_floating_point_arithmetic.rs:16:31 - | -LL | const fn neg(f: f32) -> f32 { -f } - | ^^ - | - = note: see issue #57241 <https://github.com/rust-lang/rust/issues/57241> for more information - = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const_let_eq_float.rs b/tests/ui/consts/const_let_eq_float.rs index 30d839cdc2a..c9ca6b8b7ea 100644 --- a/tests/ui/consts/const_let_eq_float.rs +++ b/tests/ui/consts/const_let_eq_float.rs @@ -1,7 +1,5 @@ //@ run-pass -#![feature(const_fn_floating_point_arithmetic)] - struct Foo<T>(T); struct Bar<T> { x: T } struct W(f32); diff --git a/tests/ui/consts/issue-36163.stderr b/tests/ui/consts/issue-36163.stderr index 52d3e003f0a..8a7a0981f41 100644 --- a/tests/ui/consts/issue-36163.stderr +++ b/tests/ui/consts/issue-36163.stderr @@ -1,10 +1,10 @@ -error[E0391]: cycle detected when simplifying constant for the type system `Foo::{constant#0}` +error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{constant#0}` --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ | -note: ...which requires const-evaluating + checking `Foo::{constant#0}`... +note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`... --> $DIR/issue-36163.rs:4:9 | LL | B = A, @@ -19,7 +19,7 @@ note: ...which requires const-evaluating + checking `A`... | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^ - = note: ...which again requires simplifying constant for the type system `Foo::{constant#0}`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle note: cycle used when checking that `Foo` is well-formed --> $DIR/issue-36163.rs:3:1 | diff --git a/tests/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/tests/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs index a97eeadd92f..fe92787aec1 100644 --- a/tests/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs +++ b/tests/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs @@ -1,6 +1,4 @@ //@ run-pass -#![feature(rustc_allow_const_fn_unstable)] - #![feature(rustc_attrs, staged_api)] #![stable(feature = "rust1", since = "1.0.0")] diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index bb240fb4ad6..480b16b28a5 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn_floating_point_arithmetic, foo, foo2)] +#![feature(const_refs_to_cell, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] @@ -25,9 +25,15 @@ const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] -// Const-stable functions cannot rely on unstable const-eval features. -const fn bar3() -> u32 { (5f32 + 6f32) as u32 } -//~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` +// conformity is required +const fn bar3() -> u32 { + let x = std::cell::Cell::new(0u32); + x.get(); + //~^ ERROR const-stable function cannot use `#[feature(const_refs_to_cell)]` + //~| ERROR cannot call non-const fn + foo() + //~^ ERROR is not yet stable as a const fn +} // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] diff --git a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index 7ec2508ca93..019deda063c 100644 --- a/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -14,30 +14,47 @@ LL | const fn bar2() -> u32 { foo2() } | = help: const-stable functions can only call other const-stable functions -error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` - --> $DIR/min_const_fn_libstd_stability.rs:29:26 +error: const-stable function cannot use `#[feature(const_refs_to_cell)]` + --> $DIR/min_const_fn_libstd_stability.rs:31:5 | -LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } - | ^^^^^^^^^^^^^ +LL | x.get(); + | ^ | help: if it is not part of the public API, make this function unstably const | LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } +LL | const fn bar3() -> u32 { | -help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks +help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval) | -LL + #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] -LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } +LL + #[rustc_allow_const_fn_unstable(const_refs_to_cell)] +LL | const fn bar3() -> u32 { | +error[E0015]: cannot call non-const fn `Cell::<u32>::get` in constant functions + --> $DIR/min_const_fn_libstd_stability.rs:31:7 + | +LL | x.get(); + | ^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: `foo` is not yet stable as a const fn + --> $DIR/min_const_fn_libstd_stability.rs:34:5 + | +LL | foo() + | ^^^^^ + | + = help: const-stable functions can only call other const-stable functions + error: `foo2_gated` is not yet stable as a const fn - --> $DIR/min_const_fn_libstd_stability.rs:39:32 + --> $DIR/min_const_fn_libstd_stability.rs:45:32 | LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | = help: const-stable functions can only call other const-stable functions -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index 03084c8674d..f2a54b8a13d 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn_floating_point_arithmetic, foo, foo2)] +#![feature(const_refs_to_cell, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] @@ -23,12 +23,6 @@ const unsafe fn foo2() -> u32 { 42 } // can't call non-min_const_fn const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "rust1", since = "1.0.0")] -// conformity is required -const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } -//~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` - // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] const unsafe fn foo2_gated() -> u32 { 42 } diff --git a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index 72c1f175d1d..353b117efbc 100644 --- a/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/tests/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -14,30 +14,13 @@ LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | = help: const-stable functions can only call other const-stable functions -error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33 - | -LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } - | ^^^^^^^^^^^^^ - | -help: if it is not part of the public API, make this function unstably const - | -LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } - | -help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks - | -LL + #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] -LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } - | - error: `foo2_gated` is not yet stable as a const fn - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:39:48 + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:33:48 | LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | ^^^^^^^^^^^^ | = help: const-stable functions can only call other const-stable functions -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/consts/packed_pattern.stderr b/tests/ui/consts/packed_pattern.stderr index a0b434b2d78..dc26078fb63 100644 --- a/tests/ui/consts/packed_pattern.stderr +++ b/tests/ui/consts/packed_pattern.stderr @@ -2,9 +2,9 @@ warning: unreachable pattern --> $DIR/packed_pattern.rs:16:9 | LL | Foo { field: (5, 6, 7, 8) } => {}, - | --------------------------- matches all the values already + | --------------------------- matches all the relevant values LL | FOO => unreachable!(), - | ^^^ unreachable pattern + | ^^^ no value can reach this | = note: `#[warn(unreachable_patterns)]` on by default diff --git a/tests/ui/consts/packed_pattern2.stderr b/tests/ui/consts/packed_pattern2.stderr index 4785f4d0297..013f61f733c 100644 --- a/tests/ui/consts/packed_pattern2.stderr +++ b/tests/ui/consts/packed_pattern2.stderr @@ -2,9 +2,9 @@ warning: unreachable pattern --> $DIR/packed_pattern2.rs:24:9 | LL | Bar { a: Foo { field: (5, 6) } } => {}, - | -------------------------------- matches all the values already + | -------------------------------- matches all the relevant values LL | FOO => unreachable!(), - | ^^^ unreachable pattern + | ^^^ no value can reach this | = note: `#[warn(unreachable_patterns)]` on by default diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr index d4fc1717538..ec01225c6bf 100644 --- a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr +++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr @@ -48,10 +48,10 @@ LL | const STATIC: &str = ""; = note: expected reference `&'static _` found reference `&_` note: the anonymous lifetime as defined here... - --> $DIR/elided-lifetime.rs:15:18 + --> $DIR/elided-lifetime.rs:16:19 | -LL | impl Bar for Foo<'_> { - | ^^ +LL | const STATIC: &str = ""; + | ^ = note: ...does not necessarily outlive the static lifetime error: aborting due to 3 previous errors diff --git a/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr index 8e4c27875ab..b8e2f412b49 100644 --- a/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr +++ b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr @@ -30,10 +30,10 @@ LL | const STATIC: &str = ""; = note: expected reference `&_` found reference `&_` note: the anonymous lifetime as defined here... - --> $DIR/static-trait-impl.rs:8:10 + --> $DIR/static-trait-impl.rs:9:19 | -LL | impl Bar<'_> for A { - | ^^ +LL | const STATIC: &str = ""; + | ^ note: ...does not necessarily outlive the anonymous lifetime as defined here --> $DIR/static-trait-impl.rs:8:10 | diff --git a/tests/ui/delegation/inner-attr.stderr b/tests/ui/delegation/inner-attr.stderr index f3b53e331ad..257ab760ffc 100644 --- a/tests/ui/delegation/inner-attr.stderr +++ b/tests/ui/delegation/inner-attr.stderr @@ -8,11 +8,6 @@ LL | fn main() {} | ------------ the inner attribute doesn't annotate this function | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files -help: to annotate the function, change the attribute from inner to outer style - | -LL - reuse a as b { #![rustc_dummy] self } -LL + reuse a as b { #[rustc_dummy] self } - | error: aborting due to 1 previous error diff --git a/tests/ui/drop/lint-tail-expr-drop-order-gated.rs b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs new file mode 100644 index 00000000000..b22e72bcfad --- /dev/null +++ b/tests/ui/drop/lint-tail-expr-drop-order-gated.rs @@ -0,0 +1,35 @@ +// This test ensures that `tail_expr_drop_order` does not activate in case Edition 2024 is not used +// or the feature gate `shorter_tail_lifetimes` is disabled. + +//@ revisions: neither no_feature_gate edition_less_than_2024 +//@ check-pass +//@ [neither] edition: 2021 +//@ [no_feature_gate] compile-flags: -Z unstable-options +//@ [no_feature_gate] edition: 2024 +//@ [edition_less_than_2024] edition: 2021 + +#![deny(tail_expr_drop_order)] +#![cfg_attr(edition_less_than_2024, feature(shorter_tail_lifetimes))] + +struct LoudDropper; +impl Drop for LoudDropper { + fn drop(&mut self) { + // This destructor should be considered significant because it is a custom destructor + // and we will assume that the destructor can generate side effects arbitrarily so that + // a change in drop order is visible. + println!("loud drop"); + } +} +impl LoudDropper { + fn get(&self) -> i32 { + 0 + } +} + +fn should_not_lint() -> i32 { + let x = LoudDropper; + x.get() + LoudDropper.get() + // Lint should not action +} + +fn main() {} diff --git a/tests/ui/drop/lint-tail-expr-drop-order.rs b/tests/ui/drop/lint-tail-expr-drop-order.rs new file mode 100644 index 00000000000..0aa0ef02610 --- /dev/null +++ b/tests/ui/drop/lint-tail-expr-drop-order.rs @@ -0,0 +1,71 @@ +//@ compile-flags: -Z unstable-options +//@ edition: 2024 + +// Edition 2024 lint for change in drop order at tail expression +// This lint is to capture potential change in program semantics +// due to implementation of RFC 3606 <https://github.com/rust-lang/rfcs/pull/3606> + +#![deny(tail_expr_drop_order)] +#![feature(shorter_tail_lifetimes)] + +struct LoudDropper; +impl Drop for LoudDropper { + fn drop(&mut self) { + // This destructor should be considered significant because it is a custom destructor + // and we will assume that the destructor can generate side effects arbitrarily so that + // a change in drop order is visible. + println!("loud drop"); + } +} +impl LoudDropper { + fn get(&self) -> i32 { + 0 + } +} + +fn should_lint() -> i32 { + let x = LoudDropper; + // Should lint + x.get() + LoudDropper.get() + //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 + //~| WARN: this changes meaning in Rust 2024 +} + +fn should_lint_closure() -> impl FnOnce() -> i32 { + let x = LoudDropper; + move || x.get() + LoudDropper.get() + //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 + //~| WARN: this changes meaning in Rust 2024 +} + +fn should_not_lint() -> i32 { + let x = LoudDropper; + // Should not lint + x.get() +} + +fn should_not_lint_in_nested_block() -> i32 { + let x = LoudDropper; + // Should not lint because Edition 2021 drops temporaries in blocks earlier already + { LoudDropper.get() } +} + +fn should_not_lint_in_match_arm() -> i32 { + let x = LoudDropper; + // Should not lint because Edition 2021 drops temporaries in blocks earlier already + match &x { + _ => LoudDropper.get(), + } +} + +fn should_lint_in_nested_items() { + fn should_lint_me() -> i32 { + let x = LoudDropper; + // Should lint + x.get() + LoudDropper.get() + //~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 + //~| WARN: this changes meaning in Rust 2024 + } +} + +fn main() {} diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr new file mode 100644 index 00000000000..630f0a80f09 --- /dev/null +++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr @@ -0,0 +1,42 @@ +error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 + --> $DIR/lint-tail-expr-drop-order.rs:29:15 + | +LL | let x = LoudDropper; + | - these values have significant drop implementation and will observe changes in drop order under Edition 2024 +LL | // Should lint +LL | x.get() + LoudDropper.get() + | ^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739> +note: the lint level is defined here + --> $DIR/lint-tail-expr-drop-order.rs:8:9 + | +LL | #![deny(tail_expr_drop_order)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 + --> $DIR/lint-tail-expr-drop-order.rs:36:23 + | +LL | let x = LoudDropper; + | - these values have significant drop implementation and will observe changes in drop order under Edition 2024 +LL | move || x.get() + LoudDropper.get() + | ^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739> + +error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 + --> $DIR/lint-tail-expr-drop-order.rs:65:19 + | +LL | let x = LoudDropper; + | - these values have significant drop implementation and will observe changes in drop order under Edition 2024 +LL | // Should lint +LL | x.get() + LoudDropper.get() + | ^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739> + +error: aborting due to 3 previous errors + diff --git a/tests/ui/dst/dst-rvalue.stderr b/tests/ui/dst/dst-rvalue.stderr index 8d0a82b707d..d8c529617f7 100644 --- a/tests/ui/dst/dst-rvalue.stderr +++ b/tests/ui/dst/dst-rvalue.stderr @@ -9,6 +9,11 @@ LL | let _x: Box<str> = Box::new(*"hello world"); = help: the trait `Sized` is not implemented for `str` note: required by a bound in `Box::<T>::new` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let _x: Box<str> = Box::new(*"hello world"); +LL + let _x: Box<str> = Box::new("hello world"); + | error[E0277]: the size for values of type `[isize]` cannot be known at compilation time --> $DIR/dst-rvalue.rs:8:37 @@ -21,6 +26,11 @@ LL | let _x: Box<[isize]> = Box::new(*array); = help: the trait `Sized` is not implemented for `[isize]` note: required by a bound in `Box::<T>::new` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let _x: Box<[isize]> = Box::new(*array); +LL + let _x: Box<[isize]> = Box::new(array); + | error: aborting due to 2 previous errors diff --git a/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs b/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs new file mode 100644 index 00000000000..19b5edb620f --- /dev/null +++ b/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.rs @@ -0,0 +1,14 @@ +//@ edition: 2021 + +trait Trait {} + +impl dyn Trait { + const CONST: () = (); +} + +fn main() { + match () { + Trait::CONST => {} + //~^ ERROR trait objects must include the `dyn` keyword + } +} diff --git a/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr b/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr new file mode 100644 index 00000000000..4446a89b63b --- /dev/null +++ b/tests/ui/dyn-keyword/suggest-dyn-on-bare-trait-in-pat.stderr @@ -0,0 +1,14 @@ +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-dyn-on-bare-trait-in-pat.rs:11:9 + | +LL | Trait::CONST => {} + | ^^^^^ + | +help: add `dyn` keyword before this trait + | +LL | <dyn Trait>::CONST => {} + | ++++ + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0782`. diff --git a/tests/ui/error-codes/E0001.stderr b/tests/ui/error-codes/E0001.stderr index 40008230ec8..30d0df960f3 100644 --- a/tests/ui/error-codes/E0001.stderr +++ b/tests/ui/error-codes/E0001.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/E0001.rs:8:9 | LL | _ => {/* ... */} - | ^ unreachable pattern + | ^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/E0001.rs:8:9 | LL | Some(_) => {/* ... */} diff --git a/tests/ui/error-codes/E0208.rs b/tests/ui/error-codes/E0208.rs index 74c138af483..2713ba6ed6c 100644 --- a/tests/ui/error-codes/E0208.rs +++ b/tests/ui/error-codes/E0208.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] #[rustc_variance] -struct Foo<'a, T> { //~ ERROR [+, o] +struct Foo<'a, T> { //~ ERROR ['a: +, T: o] t: &'a mut T, } diff --git a/tests/ui/error-codes/E0208.stderr b/tests/ui/error-codes/E0208.stderr index 77b6ceae4dc..a39e93afab3 100644 --- a/tests/ui/error-codes/E0208.stderr +++ b/tests/ui/error-codes/E0208.stderr @@ -1,4 +1,4 @@ -error: [+, o] +error: ['a: +, T: o] --> $DIR/E0208.rs:4:1 | LL | struct Foo<'a, T> { diff --git a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr index 83492988479..044c1ae2dd4 100644 --- a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr +++ b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr @@ -1,21 +1,21 @@ -warning: `extern` fn uses type `[i8 or u8 (arch dependant)]`, which is not FFI-safe +warning: `extern` fn uses type `CStr`, which is not FFI-safe --> $DIR/extern-C-non-FFI-safe-arg-ice-52334.rs:7:12 | LL | type Foo = extern "C" fn(::std::ffi::CStr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider using a raw pointer instead - = note: slices have no C equivalent + = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` + = note: `CStr`/`CString` do not have a guaranteed layout = note: `#[warn(improper_ctypes_definitions)]` on by default -warning: `extern` block uses type `[i8 or u8 (arch dependant)]`, which is not FFI-safe +warning: `extern` block uses type `CStr`, which is not FFI-safe --> $DIR/extern-C-non-FFI-safe-arg-ice-52334.rs:10:18 | LL | fn meh(blah: Foo); | ^^^ not FFI-safe | - = help: consider using a raw pointer instead - = note: slices have no C equivalent + = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` + = note: `CStr`/`CString` do not have a guaranteed layout = note: `#[warn(improper_ctypes)]` on by default warning: 2 warnings emitted diff --git a/tests/ui/feature-gates/feature-gate-const-arg-path.rs b/tests/ui/feature-gates/feature-gate-const-arg-path.rs new file mode 100644 index 00000000000..0938c5733a2 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-const-arg-path.rs @@ -0,0 +1,5 @@ +//@ check-pass + +// this doesn't really have any user facing impact.... + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-lifetime-capture-rules-2024.stderr b/tests/ui/feature-gates/feature-gate-lifetime-capture-rules-2024.stderr index 173e3dc02cc..d0b18df6a5e 100644 --- a/tests/ui/feature-gates/feature-gate-lifetime-capture-rules-2024.stderr +++ b/tests/ui/feature-gates/feature-gate-lifetime-capture-rules-2024.stderr @@ -8,10 +8,10 @@ LL | fn foo(x: &Vec<i32>) -> impl Sized { LL | x | ^ | -help: to declare that `impl Sized` captures `'_`, you can add an explicit `'_` lifetime bound +help: add a `use<...>` bound to explicitly capture `'_` | -LL | fn foo(x: &Vec<i32>) -> impl Sized + '_ { - | ++++ +LL | fn foo(x: &Vec<i32>) -> impl Sized + use<'_> { + | +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-precise-capturing.rs b/tests/ui/feature-gates/feature-gate-precise-capturing.rs deleted file mode 100644 index 47a21539d37..00000000000 --- a/tests/ui/feature-gates/feature-gate-precise-capturing.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn hello() -> impl Sized + use<> {} -//~^ ERROR precise captures on `impl Trait` are experimental - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-precise-capturing.stderr b/tests/ui/feature-gates/feature-gate-precise-capturing.stderr deleted file mode 100644 index 04365408880..00000000000 --- a/tests/ui/feature-gates/feature-gate-precise-capturing.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: precise captures on `impl Trait` are experimental - --> $DIR/feature-gate-precise-capturing.rs:1:28 - | -LL | fn hello() -> impl Sized + use<> {} - | ^^^ - | - = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information - = help: add `#![feature(precise_capturing)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-repr-simd.stderr b/tests/ui/feature-gates/feature-gate-repr-simd.stderr index 5b490c0c0c3..5a0ceb2dd74 100644 --- a/tests/ui/feature-gates/feature-gate-repr-simd.stderr +++ b/tests/ui/feature-gates/feature-gate-repr-simd.stderr @@ -35,3 +35,17 @@ error: aborting due to 3 previous errors Some errors have detailed explanations: E0566, E0658. For more information about an error, try `rustc --explain E0566`. +Future incompatibility report: Future breakage diagnostic: +error[E0566]: conflicting representation hints + --> $DIR/feature-gate-repr-simd.rs:4:8 + | +LL | #[repr(C)] + | ^ +LL | +LL | #[repr(simd)] + | ^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585> + = note: `#[deny(conflicting_repr_hints)]` on by default + diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr b/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr index d1decc0c3f1..37491ca12b0 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr +++ b/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr @@ -51,7 +51,7 @@ LL | type A<'a> where Self: 'a; = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead: Fooy Fooer<T> - = note: required for the cast from `Box<Fooer<{integer}>>` to `Box<(dyn Foo<A = &'a ()> + 'static)>` + = note: required for the cast from `Box<Fooer<{integer}>>` to `Box<(dyn Foo<A<'a> = &'a ()> + 'static)>` error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/issue-76535.base.stderr b/tests/ui/generic-associated-types/issue-76535.base.stderr index bb14e297174..88c08051da7 100644 --- a/tests/ui/generic-associated-types/issue-76535.base.stderr +++ b/tests/ui/generic-associated-types/issue-76535.base.stderr @@ -47,7 +47,7 @@ LL | type SubType<'a>: SubTrait where Self: 'a; = help: consider moving `SubType` to another trait = help: only type `SuperStruct` is seen to implement the trait in this crate, consider using it directly instead = note: `SuperTrait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type - = note: required for the cast from `Box<SuperStruct>` to `Box<dyn SuperTrait<SubType = SubStruct<'_>>>` + = note: required for the cast from `Box<SuperStruct>` to `Box<dyn SuperTrait<SubType<'_> = SubStruct<'_>>>` error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/issue-79422.base.stderr b/tests/ui/generic-associated-types/issue-79422.base.stderr index bcc6382cf7c..551ad2a8fdf 100644 --- a/tests/ui/generic-associated-types/issue-79422.base.stderr +++ b/tests/ui/generic-associated-types/issue-79422.base.stderr @@ -49,7 +49,7 @@ LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `MapLike` for this new enum and using it instead: std::collections::BTreeMap<K, V> Source - = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>` + = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont<'_> = (dyn RefCont<'_, u8> + 'static)>>` error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/issue-79422.extended.stderr b/tests/ui/generic-associated-types/issue-79422.extended.stderr index ae1526296a7..031f8d8d851 100644 --- a/tests/ui/generic-associated-types/issue-79422.extended.stderr +++ b/tests/ui/generic-associated-types/issue-79422.extended.stderr @@ -28,7 +28,7 @@ LL | type VRefCont<'a> = &'a V where Self: 'a; = note: expected trait object `(dyn RefCont<'_, u8> + 'static)` found reference `&u8` = help: `&u8` implements `RefCont` so you could box the found value and coerce it to the trait object `Box<dyn RefCont>`, you will have to change the expected type as well - = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>` + = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont<'_> = (dyn RefCont<'_, u8> + 'static)>>` error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr index 825682c52f9..a2d00edbb6d 100644 --- a/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr +++ b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr @@ -8,10 +8,10 @@ LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a { LL | step1::<'a, 'b>() | ^^^^^^^^^^^^^^^^^ | -help: to declare that `impl Sized + 'a` captures `'b`, you can add an explicit `'b` lifetime bound +help: add a `use<...>` bound to explicitly capture `'b` | -LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a + 'b { - | ++++ +LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a + use<'a, 'b> { + | +++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr index b87e31acc12..a1e92e53384 100644 --- a/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr +++ b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr @@ -8,10 +8,10 @@ LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a { LL | x | ^ | -help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound +help: add a `use<...>` bound to explicitly capture `'b` | -LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + 'b { - | ++++ +LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + use<'a, 'b, T> { + | ++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/call_method_ambiguous.next.stderr b/tests/ui/impl-trait/call_method_ambiguous.next.stderr index a1f9a8b40a8..5251555f574 100644 --- a/tests/ui/impl-trait/call_method_ambiguous.next.stderr +++ b/tests/ui/impl-trait/call_method_ambiguous.next.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/call_method_ambiguous.rs:28:13 + --> $DIR/call_method_ambiguous.rs:26:13 | LL | let mut iter = foo(n - 1, m); | ^^^^^^^^ diff --git a/tests/ui/impl-trait/call_method_ambiguous.rs b/tests/ui/impl-trait/call_method_ambiguous.rs index 4dac605d6b8..8fd6f727b73 100644 --- a/tests/ui/impl-trait/call_method_ambiguous.rs +++ b/tests/ui/impl-trait/call_method_ambiguous.rs @@ -2,8 +2,6 @@ //@[next] compile-flags: -Znext-solver //@[current] run-pass -#![feature(precise_capturing)] - trait Get { fn get(&mut self) -> u32; } diff --git a/tests/ui/impl-trait/capture-lifetime-not-in-hir.rs b/tests/ui/impl-trait/capture-lifetime-not-in-hir.rs index 9c067cb6934..2fde0f200c0 100644 --- a/tests/ui/impl-trait/capture-lifetime-not-in-hir.rs +++ b/tests/ui/impl-trait/capture-lifetime-not-in-hir.rs @@ -6,13 +6,13 @@ trait Bar<'a> { } fn foo<'a, T: Bar<'a>>() -> impl Into<T::Assoc> { - //~^ ERROR [o, o] + //~^ ERROR ['a: o, T: o] // captures both T and 'a invariantly () } fn foo2<'a, T: Bar<'a>>() -> impl Into<T::Assoc> + 'a { - //~^ ERROR [o, o, o] + //~^ ERROR ['a: o, T: o, 'a: o] // captures both T and 'a invariantly, and also duplicates `'a` // i.e. the opaque looks like `impl Into<<T as Bar<'a>>::Assoc> + 'a_duplicated` () diff --git a/tests/ui/impl-trait/capture-lifetime-not-in-hir.stderr b/tests/ui/impl-trait/capture-lifetime-not-in-hir.stderr index 9d52001b024..fe8a2772a00 100644 --- a/tests/ui/impl-trait/capture-lifetime-not-in-hir.stderr +++ b/tests/ui/impl-trait/capture-lifetime-not-in-hir.stderr @@ -1,10 +1,10 @@ -error: [o, o] +error: ['a: o, T: o] --> $DIR/capture-lifetime-not-in-hir.rs:8:29 | LL | fn foo<'a, T: Bar<'a>>() -> impl Into<T::Assoc> { | ^^^^^^^^^^^^^^^^^^^ -error: [o, o, o] +error: ['a: o, T: o, 'a: o] --> $DIR/capture-lifetime-not-in-hir.rs:14:30 | LL | fn foo2<'a, T: Bar<'a>>() -> impl Into<T::Assoc> + 'a { diff --git a/tests/ui/impl-trait/hidden-lifetimes.stderr b/tests/ui/impl-trait/hidden-lifetimes.stderr index bc8f559fdee..70d8c816ecb 100644 --- a/tests/ui/impl-trait/hidden-lifetimes.stderr +++ b/tests/ui/impl-trait/hidden-lifetimes.stderr @@ -8,10 +8,10 @@ LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a { LL | x | ^ | -help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound +help: add a `use<...>` bound to explicitly capture `'b` | -LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b { - | ++++ +LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + use<'a, 'b, T> { + | ++++++++++++++++ error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds --> $DIR/hidden-lifetimes.rs:46:5 @@ -23,10 +23,10 @@ LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl S LL | x | ^ | -help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound +help: add a `use<...>` bound to explicitly capture `'b` | -LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + 'b { - | ++++ +LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + use<'a, 'b, T> { + | ++++++++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/implicit-capture-late.stderr b/tests/ui/impl-trait/implicit-capture-late.stderr index 080750f8497..3adf78322d2 100644 --- a/tests/ui/impl-trait/implicit-capture-late.stderr +++ b/tests/ui/impl-trait/implicit-capture-late.stderr @@ -10,7 +10,7 @@ note: lifetime declared here LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> { | ^^ -error: [o] +error: ['a: o] --> $DIR/implicit-capture-late.rs:10:55 | LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> { diff --git a/tests/ui/impl-trait/in-trait/cannot-capture-intersection.rs b/tests/ui/impl-trait/in-trait/cannot-capture-intersection.rs index d7b62436d2d..e00214fe8e0 100644 --- a/tests/ui/impl-trait/in-trait/cannot-capture-intersection.rs +++ b/tests/ui/impl-trait/in-trait/cannot-capture-intersection.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing)] - use std::future::Future; use std::pin::Pin; diff --git a/tests/ui/impl-trait/in-trait/cannot-capture-intersection.stderr b/tests/ui/impl-trait/in-trait/cannot-capture-intersection.stderr index 92ef66c5504..a8f5bfc94c1 100644 --- a/tests/ui/impl-trait/in-trait/cannot-capture-intersection.stderr +++ b/tests/ui/impl-trait/in-trait/cannot-capture-intersection.stderr @@ -1,5 +1,5 @@ error[E0700]: hidden type for `impl Future<Output = i32>` captures lifetime that does not appear in bounds - --> $DIR/cannot-capture-intersection.rs:24:9 + --> $DIR/cannot-capture-intersection.rs:22:9 | LL | fn foo<'a, 'b>(&'a self, x: &'b i32) -> impl Future<Output = i32> { | ------------------------- opaque type defined here diff --git a/tests/ui/impl-trait/in-trait/refine-err.rs b/tests/ui/impl-trait/in-trait/refine-err.rs new file mode 100644 index 00000000000..7518cee97c4 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/refine-err.rs @@ -0,0 +1,14 @@ +#![deny(refining_impl_trait)] + +trait FromRow { + fn prepare(self) -> impl Fn() -> T; + //~^ ERROR cannot find type `T` in this scope +} + +impl<T> FromRow for T { + fn prepare(self) -> impl Fn() -> T { + || todo!() + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/refine-err.stderr b/tests/ui/impl-trait/in-trait/refine-err.stderr new file mode 100644 index 00000000000..6b4ef74d50a --- /dev/null +++ b/tests/ui/impl-trait/in-trait/refine-err.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `T` in this scope + --> $DIR/refine-err.rs:4:38 + | +LL | fn prepare(self) -> impl Fn() -> T; + | ^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs index 7a51037324f..ab21dae7dc5 100644 --- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs +++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs @@ -14,7 +14,6 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I { //~^ ERROR binding for associated type `Item` references lifetime `'missing` //~| ERROR binding for associated type `Item` references lifetime `'missing` //~| ERROR `()` is not an iterator - //~| WARNING impl trait in impl method signature does not match trait method signature } fn main() {} diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr index 67c4df0f3a9..d8a2eef94a1 100644 --- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr +++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr @@ -32,24 +32,7 @@ LL | fn iter(&self) -> impl for<'missing> Iterator<Item = Self::Item<'missin | = help: the trait `Iterator` is not implemented for `()` -warning: impl trait in impl method signature does not match trait method signature - --> $DIR/span-bug-issue-121457.rs:13:51 - | -LL | fn iter(&self) -> impl Iterator; - | ------------- return type from trait method defined here -... -LL | fn iter(&self) -> impl for<'missing> Iterator<Item = Self::Item<'missing>> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this bound is stronger than that defined on the trait - | - = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate - = note: we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information - = note: `#[warn(refining_impl_trait_reachable)]` on by default -help: replace the return type so that it matches the trait - | -LL | fn iter(&self) -> impl Iterator {} - | ~~~~~~~~~~~~~ - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0195, E0277, E0582. For more information about an error, try `rustc --explain E0195`. diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs index 65565dcc2a6..0ac44bf7546 100644 --- a/tests/ui/impl-trait/in-trait/variance.rs +++ b/tests/ui/impl-trait/in-trait/variance.rs @@ -7,14 +7,16 @@ impl<T> Captures<'_> for T {} trait Foo<'i> { fn implicit_capture_early<'a: 'a>() -> impl Sized {} - //~^ [o, *, *, o, o] - // Self, 'i, 'a, 'i_duplicated, 'a_duplicated + //~^ [Self: o, 'i: *, 'a: *, 'a: o, 'i: o] - fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ [o, *, *, o, o] + fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} + //~^ [Self: o, 'i: *, 'a: *, 'a: o, 'i: o] - fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} //~ [o, *, o, o] + fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} + //~^ [Self: o, 'i: *, 'a: o, 'i: o] - fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ [o, *, o, o] + fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} + //~^ [Self: o, 'i: *, 'a: o, 'i: o] } fn main() {} diff --git a/tests/ui/impl-trait/in-trait/variance.stderr b/tests/ui/impl-trait/in-trait/variance.stderr index 8cae5a92f0d..54e0afbaa95 100644 --- a/tests/ui/impl-trait/in-trait/variance.stderr +++ b/tests/ui/impl-trait/in-trait/variance.stderr @@ -1,23 +1,23 @@ -error: [o, *, *, o, o] +error: [Self: o, 'i: *, 'a: *, 'a: o, 'i: o] --> $DIR/variance.rs:9:44 | LL | fn implicit_capture_early<'a: 'a>() -> impl Sized {} | ^^^^^^^^^^ -error: [o, *, *, o, o] - --> $DIR/variance.rs:13:44 +error: [Self: o, 'i: *, 'a: *, 'a: o, 'i: o] + --> $DIR/variance.rs:12:44 | LL | fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o, *, o, o] +error: [Self: o, 'i: *, 'a: o, 'i: o] --> $DIR/variance.rs:15:48 | LL | fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} | ^^^^^^^^^^ -error: [o, *, o, o] - --> $DIR/variance.rs:17:48 +error: [Self: o, 'i: *, 'a: o, 'i: o] + --> $DIR/variance.rs:18:48 | LL | fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 273f51ddbe3..f620bf6dc38 100644 --- a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -7,10 +7,10 @@ LL | fn elided(x: &i32) -> impl Copy { x } | | opaque type defined here | hidden type `&i32` captures the anonymous lifetime defined here | -help: to declare that `impl Copy` captures `'_`, you can add an explicit `'_` lifetime bound +help: add a `use<...>` bound to explicitly capture `'_` | -LL | fn elided(x: &i32) -> impl Copy + '_ { x } - | ++++ +LL | fn elided(x: &i32) -> impl Copy + use<'_> { x } + | +++++++++ error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear in bounds --> $DIR/must_outlive_least_region_or_bound.rs:6:44 @@ -21,10 +21,10 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | | opaque type defined here | hidden type `&'a i32` captures the lifetime `'a` as defined here | -help: to declare that `impl Copy` captures `'a`, you can add an explicit `'a` lifetime bound +help: add a `use<...>` bound to explicitly capture `'a` | -LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } - | ++++ +LL | fn explicit<'a>(x: &'a i32) -> impl Copy + use<'a> { x } + | +++++++++ error: lifetime may not live long enough --> $DIR/must_outlive_least_region_or_bound.rs:9:46 @@ -108,10 +108,10 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 LL | move |_| println!("{}", y) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that `impl Fn(&'a u32)` captures `'b`, you can add an explicit `'b` lifetime bound +help: add a `use<...>` bound to explicitly capture `'b` | -LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + 'b { - | ++++ +LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + use<'a, 'b> { + | +++++++++++++ error[E0310]: the parameter type `T` may not live long enough --> $DIR/must_outlive_least_region_or_bound.rs:47:5 diff --git a/tests/ui/impl-trait/nested-return-type4.stderr b/tests/ui/impl-trait/nested-return-type4.stderr index f1e3b97be02..407800eff18 100644 --- a/tests/ui/impl-trait/nested-return-type4.stderr +++ b/tests/ui/impl-trait/nested-return-type4.stderr @@ -8,14 +8,10 @@ LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized LL | async move { let _s = s; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that `impl Future<Output = impl Sized>` captures `'s`, you can add an explicit `'s` lifetime bound +help: add a `use<...>` bound to explicitly capture `'s` | -LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> + 's { - | ++++ -help: to declare that `impl Sized` captures `'s`, you can add an explicit `'s` lifetime bound - | -LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized + 's> { - | ++++ +LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> + use<'s> { + | +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/precise-capturing/apit.rs b/tests/ui/impl-trait/precise-capturing/apit.rs index 64c15d6df96..447d8fdf2cd 100644 --- a/tests/ui/impl-trait/precise-capturing/apit.rs +++ b/tests/ui/impl-trait/precise-capturing/apit.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing)] - fn hello(_: impl Sized + use<>) {} //~^ ERROR `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` diff --git a/tests/ui/impl-trait/precise-capturing/apit.stderr b/tests/ui/impl-trait/precise-capturing/apit.stderr index 1d6225a1ff8..7573e0838ab 100644 --- a/tests/ui/impl-trait/precise-capturing/apit.stderr +++ b/tests/ui/impl-trait/precise-capturing/apit.stderr @@ -1,5 +1,5 @@ error: `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` - --> $DIR/apit.rs:3:26 + --> $DIR/apit.rs:1:26 | LL | fn hello(_: impl Sized + use<>) {} | ^^^^^ diff --git a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs index d2d4570c570..161fe23c899 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs +++ b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing)] - fn no_elided_lt() -> impl Sized + use<'_> {} //~^ ERROR missing lifetime specifier //~| ERROR expected lifetime parameter in `use<...>` precise captures list, found `'_` diff --git a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr index 550996ab5e5..a8acecf10c7 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr +++ b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifier - --> $DIR/bad-lifetimes.rs:3:39 + --> $DIR/bad-lifetimes.rs:1:39 | LL | fn no_elided_lt() -> impl Sized + use<'_> {} | ^^ expected named lifetime parameter @@ -11,7 +11,7 @@ LL | fn no_elided_lt() -> impl Sized + use<'static> {} | ~~~~~~~ error[E0261]: use of undeclared lifetime name `'missing` - --> $DIR/bad-lifetimes.rs:10:37 + --> $DIR/bad-lifetimes.rs:8:37 | LL | fn missing_lt() -> impl Sized + use<'missing> {} | - ^^^^^^^^ undeclared lifetime @@ -19,13 +19,13 @@ LL | fn missing_lt() -> impl Sized + use<'missing> {} | help: consider introducing lifetime `'missing` here: `<'missing>` error: expected lifetime parameter in `use<...>` precise captures list, found `'_` - --> $DIR/bad-lifetimes.rs:3:39 + --> $DIR/bad-lifetimes.rs:1:39 | LL | fn no_elided_lt() -> impl Sized + use<'_> {} | ^^ error: expected lifetime parameter in `use<...>` precise captures list, found `'static` - --> $DIR/bad-lifetimes.rs:7:36 + --> $DIR/bad-lifetimes.rs:5:36 | LL | fn static_lt() -> impl Sized + use<'static> {} | ^^^^^^^ diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.rs b/tests/ui/impl-trait/precise-capturing/bad-params.rs index 08eee67c0e5..17b517abd74 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.rs +++ b/tests/ui/impl-trait/precise-capturing/bad-params.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing)] - fn missing() -> impl Sized + use<T> {} //~^ ERROR cannot find type `T` in this scope diff --git a/tests/ui/impl-trait/precise-capturing/bad-params.stderr b/tests/ui/impl-trait/precise-capturing/bad-params.stderr index e104f115aa3..06ccf356948 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-params.stderr +++ b/tests/ui/impl-trait/precise-capturing/bad-params.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `T` in this scope - --> $DIR/bad-params.rs:3:34 + --> $DIR/bad-params.rs:1:34 | LL | fn missing() -> impl Sized + use<T> {} | ^ not found in this scope @@ -10,7 +10,7 @@ LL | fn missing<T>() -> impl Sized + use<T> {} | +++ error[E0411]: cannot find type `Self` in this scope - --> $DIR/bad-params.rs:6:39 + --> $DIR/bad-params.rs:4:39 | LL | fn missing_self() -> impl Sized + use<Self> {} | ------------ ^^^^ `Self` is only available in impls, traits, and type definitions @@ -18,7 +18,7 @@ LL | fn missing_self() -> impl Sized + use<Self> {} | `Self` not allowed in a function error: `Self` can't be captured in `use<...>` precise captures list, since it is an alias - --> $DIR/bad-params.rs:11:48 + --> $DIR/bad-params.rs:9:48 | LL | impl MyType { | ----------- `Self` is not a generic argument, but an alias to the type of the implementation @@ -26,7 +26,7 @@ LL | fn self_is_not_param() -> impl Sized + use<Self> {} | ^^^^ error: expected type or const parameter in `use<...>` precise captures list, found function - --> $DIR/bad-params.rs:15:32 + --> $DIR/bad-params.rs:13:32 | LL | fn hello() -> impl Sized + use<hello> {} | ^^^^^ diff --git a/tests/ui/impl-trait/precise-capturing/bound-modifiers.rs b/tests/ui/impl-trait/precise-capturing/bound-modifiers.rs index 15f21882628..47695814668 100644 --- a/tests/ui/impl-trait/precise-capturing/bound-modifiers.rs +++ b/tests/ui/impl-trait/precise-capturing/bound-modifiers.rs @@ -1,7 +1,5 @@ //@ edition: 2021 -#![feature(precise_capturing)] - fn polarity() -> impl Sized + ?use<> {} //~^ ERROR expected identifier, found keyword `use` //~| ERROR cannot find trait `r#use` in this scope diff --git a/tests/ui/impl-trait/precise-capturing/bound-modifiers.stderr b/tests/ui/impl-trait/precise-capturing/bound-modifiers.stderr index 4602225e7b9..aaebfe2a86e 100644 --- a/tests/ui/impl-trait/precise-capturing/bound-modifiers.stderr +++ b/tests/ui/impl-trait/precise-capturing/bound-modifiers.stderr @@ -1,53 +1,53 @@ error: expected identifier, found keyword `use` - --> $DIR/bound-modifiers.rs:5:32 + --> $DIR/bound-modifiers.rs:3:32 | LL | fn polarity() -> impl Sized + ?use<> {} | ^^^ expected identifier, found keyword error: expected identifier, found keyword `use` - --> $DIR/bound-modifiers.rs:11:38 + --> $DIR/bound-modifiers.rs:9:38 | LL | fn asyncness() -> impl Sized + async use<> {} | ^^^ expected identifier, found keyword error: expected identifier, found keyword `use` - --> $DIR/bound-modifiers.rs:16:38 + --> $DIR/bound-modifiers.rs:14:38 | LL | fn constness() -> impl Sized + const use<> {} | ^^^ expected identifier, found keyword error: expected identifier, found keyword `use` - --> $DIR/bound-modifiers.rs:21:37 + --> $DIR/bound-modifiers.rs:19:37 | LL | fn binder() -> impl Sized + for<'a> use<> {} | ^^^ expected identifier, found keyword error[E0405]: cannot find trait `r#use` in this scope - --> $DIR/bound-modifiers.rs:5:32 + --> $DIR/bound-modifiers.rs:3:32 | LL | fn polarity() -> impl Sized + ?use<> {} | ^^^ not found in this scope error[E0405]: cannot find trait `r#use` in this scope - --> $DIR/bound-modifiers.rs:11:38 + --> $DIR/bound-modifiers.rs:9:38 | LL | fn asyncness() -> impl Sized + async use<> {} | ^^^ not found in this scope error[E0405]: cannot find trait `r#use` in this scope - --> $DIR/bound-modifiers.rs:16:38 + --> $DIR/bound-modifiers.rs:14:38 | LL | fn constness() -> impl Sized + const use<> {} | ^^^ not found in this scope error[E0405]: cannot find trait `r#use` in this scope - --> $DIR/bound-modifiers.rs:21:37 + --> $DIR/bound-modifiers.rs:19:37 | LL | fn binder() -> impl Sized + for<'a> use<> {} | ^^^ not found in this scope error[E0658]: async closures are unstable - --> $DIR/bound-modifiers.rs:11:32 + --> $DIR/bound-modifiers.rs:9:32 | LL | fn asyncness() -> impl Sized + async use<> {} | ^^^^^ @@ -58,7 +58,7 @@ LL | fn asyncness() -> impl Sized + async use<> {} = help: to use an async block, remove the `||`: `async {` error[E0658]: const trait impls are experimental - --> $DIR/bound-modifiers.rs:16:32 + --> $DIR/bound-modifiers.rs:14:32 | LL | fn constness() -> impl Sized + const use<> {} | ^^^^^ @@ -68,13 +68,13 @@ LL | fn constness() -> impl Sized + const use<> {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/bound-modifiers.rs:5:31 + --> $DIR/bound-modifiers.rs:3:31 | LL | fn polarity() -> impl Sized + ?use<> {} | ^^^^^^ warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default - --> $DIR/bound-modifiers.rs:5:31 + --> $DIR/bound-modifiers.rs:3:31 | LL | fn polarity() -> impl Sized + ?use<> {} | ^^^^^^ diff --git a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs index 82b953bfed4..c41f136b96f 100644 --- a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs +++ b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing)] - trait Tr { type Assoc; } diff --git a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr index b521ee0a902..f02b8d7c850 100644 --- a/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr +++ b/tests/ui/impl-trait/precise-capturing/capture-parent-arg.stderr @@ -1,5 +1,5 @@ error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/capture-parent-arg.rs:27:31 + --> $DIR/capture-parent-arg.rs:25:31 | LL | impl<'a> W<'a> { | -- this lifetime parameter is captured @@ -7,7 +7,7 @@ LL | fn bad1() -> impl Into<<W<'a> as Tr>::Assoc> + use<> {} | -------------^^------------------------ lifetime captured due to being mentioned in the bounds of the `impl Trait` error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/capture-parent-arg.rs:33:18 + --> $DIR/capture-parent-arg.rs:31:18 | LL | impl<'a> W<'a> { | -- this lifetime parameter is captured diff --git a/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr b/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr index d8edd672b48..95132c611e5 100644 --- a/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr +++ b/tests/ui/impl-trait/precise-capturing/duplicated-use.real.stderr @@ -1,5 +1,5 @@ error: duplicate `use<...>` precise capturing syntax - --> $DIR/duplicated-use.rs:7:32 + --> $DIR/duplicated-use.rs:5:32 | LL | fn hello<'a>() -> impl Sized + use<'a> + use<'a> {} | ^^^^^^^ ------- second `use<...>` here diff --git a/tests/ui/impl-trait/precise-capturing/duplicated-use.rs b/tests/ui/impl-trait/precise-capturing/duplicated-use.rs index bfbdcdbf311..b5632dc1577 100644 --- a/tests/ui/impl-trait/precise-capturing/duplicated-use.rs +++ b/tests/ui/impl-trait/precise-capturing/duplicated-use.rs @@ -1,8 +1,6 @@ //@ revisions: real pre_expansion //@[pre_expansion] check-pass -#![feature(precise_capturing)] - #[cfg(real)] fn hello<'a>() -> impl Sized + use<'a> + use<'a> {} //[real]~^ ERROR duplicate `use<...>` precise capturing syntax diff --git a/tests/ui/impl-trait/precise-capturing/dyn-use.rs b/tests/ui/impl-trait/precise-capturing/dyn-use.rs index ce7a0f3c7b2..fb2f83e2d21 100644 --- a/tests/ui/impl-trait/precise-capturing/dyn-use.rs +++ b/tests/ui/impl-trait/precise-capturing/dyn-use.rs @@ -1,4 +1,2 @@ -#![feature(precise_capturing)] - fn dyn() -> &'static dyn use<> { &() } //~^ ERROR expected one of `!`, `(`, `::`, `<`, `where`, or `{`, found keyword `use` diff --git a/tests/ui/impl-trait/precise-capturing/dyn-use.stderr b/tests/ui/impl-trait/precise-capturing/dyn-use.stderr index 5519633de1f..d8903fc4129 100644 --- a/tests/ui/impl-trait/precise-capturing/dyn-use.stderr +++ b/tests/ui/impl-trait/precise-capturing/dyn-use.stderr @@ -1,5 +1,5 @@ error: expected one of `!`, `(`, `::`, `<`, `where`, or `{`, found keyword `use` - --> $DIR/dyn-use.rs:3:26 + --> $DIR/dyn-use.rs:1:26 | LL | fn dyn() -> &'static dyn use<> { &() } | ^^^ expected one of `!`, `(`, `::`, `<`, `where`, or `{` diff --git a/tests/ui/impl-trait/precise-capturing/elided.rs b/tests/ui/impl-trait/precise-capturing/elided.rs index 34d1ba620dc..472bac9d722 100644 --- a/tests/ui/impl-trait/precise-capturing/elided.rs +++ b/tests/ui/impl-trait/precise-capturing/elided.rs @@ -1,7 +1,5 @@ //@ check-pass -#![feature(precise_capturing)] - fn elided(x: &()) -> impl Sized + use<'_> { x } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs index 26d29e456ea..2bf2e5fef18 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing)] - fn constant<const C: usize>() -> impl Sized + use<> {} //~^ ERROR `impl Trait` must mention all const parameters in scope diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr index 989ed136d4c..e8fab0a8ad6 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-const.stderr @@ -1,5 +1,5 @@ error: `impl Trait` must mention all const parameters in scope in `use<...>` - --> $DIR/forgot-to-capture-const.rs:3:34 + --> $DIR/forgot-to-capture-const.rs:1:34 | LL | fn constant<const C: usize>() -> impl Sized + use<> {} | -------------- ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs index f18dbca6c5e..64bac0c8aca 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing)] - fn lifetime_in_bounds<'a>(x: &'a ()) -> impl Into<&'a ()> + use<> { x } //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr index 979c0ca6d7b..907ed00f8c0 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-lifetime.stderr @@ -1,5 +1,5 @@ error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/forgot-to-capture-lifetime.rs:3:52 + --> $DIR/forgot-to-capture-lifetime.rs:1:52 | LL | fn lifetime_in_bounds<'a>(x: &'a ()) -> impl Into<&'a ()> + use<> { x } | -- -----------^^------------ @@ -8,7 +8,7 @@ LL | fn lifetime_in_bounds<'a>(x: &'a ()) -> impl Into<&'a ()> + use<> { x } | this lifetime parameter is captured error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds - --> $DIR/forgot-to-capture-lifetime.rs:6:62 + --> $DIR/forgot-to-capture-lifetime.rs:4:62 | LL | fn lifetime_in_hidden<'a>(x: &'a ()) -> impl Sized + use<> { x } | -- ------------------ ^ diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs index 0028a45cbf3..9d68819f657 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing)] - fn type_param<T>() -> impl Sized + use<> {} //~^ ERROR `impl Trait` must mention all type parameters in scope diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr index 89bd4df4431..d9be9d543e4 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr @@ -1,5 +1,5 @@ error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/forgot-to-capture-type.rs:7:30 + --> $DIR/forgot-to-capture-type.rs:5:30 | LL | fn bar() -> impl Sized + use<>; | ^^^^^ @@ -7,7 +7,7 @@ LL | fn bar() -> impl Sized + use<>; = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope error: `impl Trait` must mention all type parameters in scope in `use<...>` - --> $DIR/forgot-to-capture-type.rs:3:23 + --> $DIR/forgot-to-capture-type.rs:1:23 | LL | fn type_param<T>() -> impl Sized + use<> {} | - ^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | fn type_param<T>() -> impl Sized + use<> {} = note: currently, all type parameters are required to be mentioned in the precise captures list error: `impl Trait` must mention the `Self` type of the trait in `use<...>` - --> $DIR/forgot-to-capture-type.rs:7:17 + --> $DIR/forgot-to-capture-type.rs:5:17 | LL | trait Foo { | --------- `Self` type parameter is implicitly captured by this `impl Trait` diff --git a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs index b50780643f1..d34c6135596 100644 --- a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs +++ b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing)] - fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b> { //~^ HELP add `'a` to the `use<...>` bound x diff --git a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr index 1007a835894..b0c4cc2fea0 100644 --- a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr +++ b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr @@ -1,5 +1,5 @@ error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds - --> $DIR/hidden-type-suggestion.rs:5:5 + --> $DIR/hidden-type-suggestion.rs:3:5 | LL | fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b> { | -- -------------------- opaque type defined here @@ -15,7 +15,7 @@ LL | fn lifetime<'a, 'b>(x: &'a ()) -> impl Sized + use<'b, 'a> { | ++++ error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds - --> $DIR/hidden-type-suggestion.rs:11:5 + --> $DIR/hidden-type-suggestion.rs:9:5 | LL | fn param<'a, T>(x: &'a ()) -> impl Sized + use<T> { | -- ------------------- opaque type defined here @@ -31,7 +31,7 @@ LL | fn param<'a, T>(x: &'a ()) -> impl Sized + use<'a, T> { | +++ error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds - --> $DIR/hidden-type-suggestion.rs:17:5 + --> $DIR/hidden-type-suggestion.rs:15:5 | LL | fn empty<'a>(x: &'a ()) -> impl Sized + use<> { | -- ------------------ opaque type defined here @@ -47,7 +47,7 @@ LL | fn empty<'a>(x: &'a ()) -> impl Sized + use<'a> { | ++ error[E0700]: hidden type for `impl Captures<'captured>` captures lifetime that does not appear in bounds - --> $DIR/hidden-type-suggestion.rs:26:5 + --> $DIR/hidden-type-suggestion.rs:24:5 | LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> { | -- ------------------------ opaque type defined here @@ -63,7 +63,7 @@ LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captu | ++++++++++++++++++++++++++++++ error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds - --> $DIR/hidden-type-suggestion.rs:32:5 + --> $DIR/hidden-type-suggestion.rs:30:5 | LL | fn no_params_yet(_: impl Sized, y: &()) -> impl Sized { | --- ---------- opaque type defined here @@ -74,7 +74,7 @@ LL | y | ^ | note: you could use a `use<...>` bound to explicitly capture `'_`, but argument-position `impl Trait`s are not nameable - --> $DIR/hidden-type-suggestion.rs:30:21 + --> $DIR/hidden-type-suggestion.rs:28:21 | LL | fn no_params_yet(_: impl Sized, y: &()) -> impl Sized { | ^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | fn no_params_yet<T: Sized>(_: T, y: &()) -> impl Sized + use<'_, T> { | ++++++++++ ~ ++++++++++++ error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds - --> $DIR/hidden-type-suggestion.rs:38:5 + --> $DIR/hidden-type-suggestion.rs:36:5 | LL | fn yes_params_yet<'a, T>(_: impl Sized, y: &'a ()) -> impl Sized { | -- ---------- opaque type defined here @@ -95,7 +95,7 @@ LL | y | ^ | note: you could use a `use<...>` bound to explicitly capture `'a`, but argument-position `impl Trait`s are not nameable - --> $DIR/hidden-type-suggestion.rs:36:29 + --> $DIR/hidden-type-suggestion.rs:34:29 | LL | fn yes_params_yet<'a, T>(_: impl Sized, y: &'a ()) -> impl Sized { | ^^^^^^^^^^ diff --git a/tests/ui/impl-trait/precise-capturing/higher-ranked.rs b/tests/ui/impl-trait/precise-capturing/higher-ranked.rs index 21ac19640bc..3dc8523e963 100644 --- a/tests/ui/impl-trait/precise-capturing/higher-ranked.rs +++ b/tests/ui/impl-trait/precise-capturing/higher-ranked.rs @@ -2,7 +2,7 @@ // Show how precise captures allow us to skip capturing a higher-ranked lifetime -#![feature(lifetime_capture_rules_2024, precise_capturing)] +#![feature(lifetime_capture_rules_2024)] trait Trait<'a> { type Item; diff --git a/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr b/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr index 2b234bcb6a5..95eb49daf28 100644 --- a/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr +++ b/tests/ui/impl-trait/precise-capturing/illegal-positions.real.stderr @@ -1,53 +1,53 @@ error: `use<...>` precise capturing syntax not allowed in supertrait bounds - --> $DIR/illegal-positions.rs:8:12 + --> $DIR/illegal-positions.rs:6:12 | LL | trait Foo: use<> { | ^^^^^ error: `use<...>` precise capturing syntax not allowed in bounds - --> $DIR/illegal-positions.rs:10:33 + --> $DIR/illegal-positions.rs:8:33 | LL | type Assoc: use<> where (): use<>; | ^^^^^ error: `use<...>` precise capturing syntax not allowed in bounds - --> $DIR/illegal-positions.rs:10:17 + --> $DIR/illegal-positions.rs:8:17 | LL | type Assoc: use<> where (): use<>; | ^^^^^ error: `use<...>` precise capturing syntax not allowed in bounds - --> $DIR/illegal-positions.rs:16:11 + --> $DIR/illegal-positions.rs:14:11 | LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {} | ^^^^^ error: `use<...>` precise capturing syntax not allowed in bounds - --> $DIR/illegal-positions.rs:16:43 + --> $DIR/illegal-positions.rs:14:43 | LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {} | ^^^^^ error: at least one trait must be specified - --> $DIR/illegal-positions.rs:16:21 + --> $DIR/illegal-positions.rs:14:21 | LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {} | ^^^^^^^^^^ error: `use<...>` precise capturing syntax not allowed in `dyn` trait object bounds - --> $DIR/illegal-positions.rs:23:25 + --> $DIR/illegal-positions.rs:21:25 | LL | fn dynamic() -> Box<dyn use<>> {} | ^^^^^ error: `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` - --> $DIR/illegal-positions.rs:16:26 + --> $DIR/illegal-positions.rs:14:26 | LL | fn fun<T: use<>>(_: impl use<>) where (): use<> {} | ^^^^^ error[E0224]: at least one trait is required for an object type - --> $DIR/illegal-positions.rs:23:21 + --> $DIR/illegal-positions.rs:21:21 | LL | fn dynamic() -> Box<dyn use<>> {} | ^^^^^^^^^ diff --git a/tests/ui/impl-trait/precise-capturing/illegal-positions.rs b/tests/ui/impl-trait/precise-capturing/illegal-positions.rs index 681458e25f8..d446a50d92d 100644 --- a/tests/ui/impl-trait/precise-capturing/illegal-positions.rs +++ b/tests/ui/impl-trait/precise-capturing/illegal-positions.rs @@ -2,8 +2,6 @@ //@[pre_expansion] check-pass //@ edition: 2021 -#![feature(precise_capturing)] - #[cfg(real)] trait Foo: use<> { //[real]~^ ERROR `use<...>` precise capturing syntax not allowed diff --git a/tests/ui/impl-trait/precise-capturing/ordering.rs b/tests/ui/impl-trait/precise-capturing/ordering.rs index eb570a120cc..20638e0a623 100644 --- a/tests/ui/impl-trait/precise-capturing/ordering.rs +++ b/tests/ui/impl-trait/precise-capturing/ordering.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing)] - fn lt<'a>() -> impl Sized + use<'a, 'a> {} //~^ ERROR cannot capture parameter `'a` twice diff --git a/tests/ui/impl-trait/precise-capturing/ordering.stderr b/tests/ui/impl-trait/precise-capturing/ordering.stderr index ecd47159059..05dec2d5c5a 100644 --- a/tests/ui/impl-trait/precise-capturing/ordering.stderr +++ b/tests/ui/impl-trait/precise-capturing/ordering.stderr @@ -1,23 +1,23 @@ error: cannot capture parameter `'a` twice - --> $DIR/ordering.rs:3:33 + --> $DIR/ordering.rs:1:33 | LL | fn lt<'a>() -> impl Sized + use<'a, 'a> {} | ^^ -- parameter captured again here error: cannot capture parameter `T` twice - --> $DIR/ordering.rs:6:32 + --> $DIR/ordering.rs:4:32 | LL | fn ty<T>() -> impl Sized + use<T, T> {} | ^ - parameter captured again here error: cannot capture parameter `N` twice - --> $DIR/ordering.rs:9:45 + --> $DIR/ordering.rs:7:45 | LL | fn ct<const N: usize>() -> impl Sized + use<N, N> {} | ^ - parameter captured again here error: lifetime parameter `'a` must be listed before non-lifetime parameters - --> $DIR/ordering.rs:12:45 + --> $DIR/ordering.rs:10:45 | LL | fn ordering<'a, T>() -> impl Sized + use<T, 'a> {} | - ^^ diff --git a/tests/ui/impl-trait/precise-capturing/outlives.rs b/tests/ui/impl-trait/precise-capturing/outlives.rs index 26ac922b5b9..f86a61be1e0 100644 --- a/tests/ui/impl-trait/precise-capturing/outlives.rs +++ b/tests/ui/impl-trait/precise-capturing/outlives.rs @@ -2,7 +2,7 @@ // Show that precise captures allow us to skip a lifetime param for outlives -#![feature(lifetime_capture_rules_2024, precise_capturing)] +#![feature(lifetime_capture_rules_2024)] fn hello<'a: 'a, 'b: 'b>() -> impl Sized + use<'a> { } diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed index 5ac296a9cbd..6bca8ef12ec 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed @@ -1,7 +1,6 @@ //@ run-rustfix -#![feature(precise_capturing)] -#![allow(unused, incomplete_features)] +#![allow(unused)] #![deny(impl_trait_overcaptures)] fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x } diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs index e4b7828d60f..5b6726b49e0 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs @@ -1,7 +1,6 @@ //@ run-rustfix -#![feature(precise_capturing)] -#![allow(unused, incomplete_features)] +#![allow(unused)] #![deny(impl_trait_overcaptures)] fn named<'a>(x: &'a i32) -> impl Sized { *x } diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr index f8bb7f099af..fec640aa83a 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr @@ -1,17 +1,17 @@ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:7:29 + --> $DIR/overcaptures-2024.rs:6:29 | LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } | ^^^^^^^^^^ | note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:7:10 + --> $DIR/overcaptures-2024.rs:6:10 | LL | fn named<'a>(x: &'a i32) -> impl Sized { *x } | ^^ = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 note: the lint level is defined here - --> $DIR/overcaptures-2024.rs:5:9 + --> $DIR/overcaptures-2024.rs:4:9 | LL | #![deny(impl_trait_overcaptures)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -21,13 +21,13 @@ LL | fn named<'a>(x: &'a i32) -> impl Sized + use<> { *x } | +++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:10:25 + --> $DIR/overcaptures-2024.rs:9:25 | LL | fn implicit(x: &i32) -> impl Sized { *x } | ^^^^^^^^^^ | note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:10:16 + --> $DIR/overcaptures-2024.rs:9:16 | LL | fn implicit(x: &i32) -> impl Sized { *x } | ^ @@ -38,13 +38,13 @@ LL | fn implicit(x: &i32) -> impl Sized + use<> { *x } | +++++++ error: `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:15:33 + --> $DIR/overcaptures-2024.rs:14:33 | LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self } | ^^^^^^^^^^^^^^^ | note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:15:24 + --> $DIR/overcaptures-2024.rs:14:24 | LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self } | ^ @@ -55,13 +55,13 @@ LL | fn hello(&self, x: &i32) -> impl Sized + '_ + use<'_> { self } | +++++++++ error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024 - --> $DIR/overcaptures-2024.rs:26:47 + --> $DIR/overcaptures-2024.rs:25:47 | LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} | ^^^^^^^^^^ | note: specifically, this lifetime is in scope but not mentioned in the type's bounds - --> $DIR/overcaptures-2024.rs:26:23 + --> $DIR/overcaptures-2024.rs:25:23 | LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {} | ^^ diff --git a/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr b/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr index 44bc9f7daad..d1bcbaa33ae 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr +++ b/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr @@ -1,5 +1,5 @@ warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:7:19 + --> $DIR/redundant.rs:5:19 | LL | fn hello<'a>() -> impl Sized + use<'a> {} | ^^^^^^^^^^^^^------- @@ -9,7 +9,7 @@ LL | fn hello<'a>() -> impl Sized + use<'a> {} = note: `#[warn(impl_trait_redundant_captures)]` on by default warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:12:27 + --> $DIR/redundant.rs:10:27 | LL | fn inherent(&self) -> impl Sized + use<'_> {} | ^^^^^^^^^^^^^------- diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr b/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr index 9aa73353126..213888356e5 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr +++ b/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr @@ -1,5 +1,5 @@ error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/redundant.rs:18:35 + --> $DIR/redundant.rs:16:35 | LL | fn in_trait() -> impl Sized + use<'a, Self>; | ^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | fn in_trait() -> impl Sized + use<'a, Self>; = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/redundant.rs:23:35 + --> $DIR/redundant.rs:21:35 | LL | fn in_trait() -> impl Sized + use<'a> {} | ^^^^^^^ diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs index ef4f05bd7e4..4a08ffb61be 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.rs +++ b/tests/ui/impl-trait/precise-capturing/redundant.rs @@ -2,8 +2,6 @@ //@ revisions: normal rpitit //@[normal] check-pass -#![feature(precise_capturing)] - fn hello<'a>() -> impl Sized + use<'a> {} //[normal]~^ WARN all possible in-scope parameters are already captured diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.rs b/tests/ui/impl-trait/precise-capturing/rpitit.rs index 4eb053573e1..feeeb1461e8 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit.rs @@ -5,8 +5,6 @@ // To fix this soundly, we need to make sure that all the trait header args // remain captured, since they affect trait selection. -#![feature(precise_capturing)] - trait Foo<'a> { fn hello() -> impl PartialEq + use<Self>; } diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.stderr b/tests/ui/impl-trait/precise-capturing/rpitit.stderr index 45eceef2f49..5a120df9f04 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit.stderr +++ b/tests/ui/impl-trait/precise-capturing/rpitit.stderr @@ -1,5 +1,5 @@ error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/rpitit.rs:11:36 + --> $DIR/rpitit.rs:9:36 | LL | fn hello() -> impl PartialEq + use<Self>; | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | fn hello() -> impl PartialEq + use<Self>; = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/rpitit.rs:11:19 + --> $DIR/rpitit.rs:9:19 | LL | trait Foo<'a> { | -- this lifetime parameter is captured @@ -15,7 +15,7 @@ LL | fn hello() -> impl PartialEq + use<Self>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait` error: lifetime may not live long enough - --> $DIR/rpitit.rs:15:5 + --> $DIR/rpitit.rs:13:5 | LL | fn test<'a, 'b, T: for<'r> Foo<'r>>() { | -- -- lifetime `'b` defined here @@ -30,7 +30,7 @@ LL | | ); = help: consider adding the following bound: `'a: 'b` error: lifetime may not live long enough - --> $DIR/rpitit.rs:15:5 + --> $DIR/rpitit.rs:13:5 | LL | fn test<'a, 'b, T: for<'r> Foo<'r>>() { | -- -- lifetime `'b` defined here diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.rs b/tests/ui/impl-trait/precise-capturing/self-capture.rs index 07bb417f9f7..a61a7f06edc 100644 --- a/tests/ui/impl-trait/precise-capturing/self-capture.rs +++ b/tests/ui/impl-trait/precise-capturing/self-capture.rs @@ -1,5 +1,3 @@ -#![feature(precise_capturing)] - trait Foo { fn bar<'a>() -> impl Sized + use<Self>; //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.stderr b/tests/ui/impl-trait/precise-capturing/self-capture.stderr index 351de86dd5f..c1974600f30 100644 --- a/tests/ui/impl-trait/precise-capturing/self-capture.stderr +++ b/tests/ui/impl-trait/precise-capturing/self-capture.stderr @@ -1,5 +1,5 @@ error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/self-capture.rs:4:34 + --> $DIR/self-capture.rs:2:34 | LL | fn bar<'a>() -> impl Sized + use<Self>; | ^^^^^^^^^ diff --git a/tests/ui/impl-trait/region-escape-via-bound.stderr b/tests/ui/impl-trait/region-escape-via-bound.stderr index 43f0eeeb558..0518231cfe9 100644 --- a/tests/ui/impl-trait/region-escape-via-bound.stderr +++ b/tests/ui/impl-trait/region-escape-via-bound.stderr @@ -9,10 +9,10 @@ LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> LL | x | ^ | -help: to declare that `impl Trait<'y>` captures `'x`, you can add an explicit `'x` lifetime bound +help: add a `use<...>` bound to explicitly capture `'x` | -LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> + 'x - | ++++ +LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> + use<'y, 'x> + | +++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/static-return-lifetime-infered.stderr b/tests/ui/impl-trait/static-return-lifetime-infered.stderr index 4be244068d2..21e3187d019 100644 --- a/tests/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/tests/ui/impl-trait/static-return-lifetime-infered.stderr @@ -8,10 +8,10 @@ LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> { LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that `impl Iterator<Item = u32>` captures `'_`, you can add an explicit `'_` lifetime bound +help: add a `use<...>` bound to explicitly capture `'_` | -LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ { - | ++++ +LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + use<'_> { + | +++++++++ error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds --> $DIR/static-return-lifetime-infered.rs:11:9 @@ -23,10 +23,10 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> { LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that `impl Iterator<Item = u32>` captures `'a`, you can add an explicit `'a` lifetime bound +help: add a `use<...>` bound to explicitly capture `'a` | -LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a { - | ++++ +LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + use<'a> { + | +++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/variance.e2024.stderr b/tests/ui/impl-trait/variance.e2024.stderr index 17245055744..011ab3259c4 100644 --- a/tests/ui/impl-trait/variance.e2024.stderr +++ b/tests/ui/impl-trait/variance.e2024.stderr @@ -1,22 +1,22 @@ -error: [*, o] +error: ['a: *, 'a: o] --> $DIR/variance.rs:14:36 | LL | fn not_captured_early<'a: 'a>() -> impl Sized {} | ^^^^^^^^^^ -error: [*, o] +error: ['a: *, 'a: o] --> $DIR/variance.rs:19:32 | LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o] +error: ['a: o] --> $DIR/variance.rs:21:40 | LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {} | ^^^^^^^^^^ -error: [o] +error: ['a: o] --> $DIR/variance.rs:26:36 | LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} diff --git a/tests/ui/impl-trait/variance.new.stderr b/tests/ui/impl-trait/variance.new.stderr index 17245055744..011ab3259c4 100644 --- a/tests/ui/impl-trait/variance.new.stderr +++ b/tests/ui/impl-trait/variance.new.stderr @@ -1,22 +1,22 @@ -error: [*, o] +error: ['a: *, 'a: o] --> $DIR/variance.rs:14:36 | LL | fn not_captured_early<'a: 'a>() -> impl Sized {} | ^^^^^^^^^^ -error: [*, o] +error: ['a: *, 'a: o] --> $DIR/variance.rs:19:32 | LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o] +error: ['a: o] --> $DIR/variance.rs:21:40 | LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {} | ^^^^^^^^^^ -error: [o] +error: ['a: o] --> $DIR/variance.rs:26:36 | LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} diff --git a/tests/ui/impl-trait/variance.old.stderr b/tests/ui/impl-trait/variance.old.stderr index 9410b54b491..ac3bcd2723f 100644 --- a/tests/ui/impl-trait/variance.old.stderr +++ b/tests/ui/impl-trait/variance.old.stderr @@ -1,10 +1,10 @@ -error: [*] +error: ['a: *] --> $DIR/variance.rs:14:36 | LL | fn not_captured_early<'a: 'a>() -> impl Sized {} | ^^^^^^^^^^ -error: [*, o] +error: ['a: *, 'a: o] --> $DIR/variance.rs:19:32 | LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} @@ -16,7 +16,7 @@ error: [] LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {} | ^^^^^^^^^^ -error: [o] +error: ['a: o] --> $DIR/variance.rs:26:36 | LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} diff --git a/tests/ui/impl-trait/variance.rs b/tests/ui/impl-trait/variance.rs index 72b4a831bad..43f7207a904 100644 --- a/tests/ui/impl-trait/variance.rs +++ b/tests/ui/impl-trait/variance.rs @@ -12,17 +12,17 @@ trait Captures<'a> {} impl<T> Captures<'_> for T {} fn not_captured_early<'a: 'a>() -> impl Sized {} -//[old]~^ [*] -//[new]~^^ [*, o] -//[e2024]~^^^ [*, o] +//[old]~^ ['a: *] +//[new]~^^ ['a: *, 'a: o] +//[e2024]~^^^ ['a: *, 'a: o] -fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ [*, o] +fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ ['a: *, 'a: o] fn not_captured_late<'a>(_: &'a ()) -> impl Sized {} //[old]~^ [] -//[new]~^^ [o] -//[e2024]~^^^ [o] +//[new]~^^ ['a: o] +//[e2024]~^^^ ['a: o] -fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ [o] +fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ ['a: o] fn main() {} diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr index c8d1614a7f3..f498257e12f 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility-unnormalized.stderr @@ -5,9 +5,9 @@ LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime `'s` as defined here... - --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:12 + --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:8:12 | -LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str { +LL | fn get<'s>(s: &'s str, _: ()) -> &'static str; | ^^ note: ...so that the method type is compatible with trait --> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:11:5 diff --git a/tests/ui/imports/auxiliary/issue-85992-extern-2.rs b/tests/ui/imports/auxiliary/empty.rs index e9b6a44cfe2..e9b6a44cfe2 100644 --- a/tests/ui/imports/auxiliary/issue-85992-extern-2.rs +++ b/tests/ui/imports/auxiliary/empty.rs diff --git a/tests/ui/imports/auxiliary/issue-85992-extern-1.rs b/tests/ui/imports/auxiliary/issue-85992-extern.rs index a2d0e206065..076d6045190 100644 --- a/tests/ui/imports/auxiliary/issue-85992-extern-1.rs +++ b/tests/ui/imports/auxiliary/issue-85992-extern.rs @@ -1,6 +1,6 @@ #[macro_export] macro_rules! m { () => { - use issue_85992_extern_2::Outcome; + use empty::Outcome; } } diff --git a/tests/ui/imports/issue-85992.rs b/tests/ui/imports/issue-85992.rs index 321c3a9218d..38cf0384501 100644 --- a/tests/ui/imports/issue-85992.rs +++ b/tests/ui/imports/issue-85992.rs @@ -1,11 +1,11 @@ //@ edition: 2021 -//@ compile-flags: --extern issue_85992_extern_1 --extern issue_85992_extern_2 -//@ aux-build: issue-85992-extern-1.rs -//@ aux-build: issue-85992-extern-2.rs +//@ compile-flags: --extern issue_85992_extern --extern empty +//@ aux-build: issue-85992-extern.rs +//@ aux-build: empty.rs -issue_85992_extern_1::m!(); +issue_85992_extern::m!(); -use crate::issue_85992_extern_2; -//~^ ERROR unresolved import `crate::issue_85992_extern_2` +use crate::empty; +//~^ ERROR unresolved import `crate::empty` fn main() {} diff --git a/tests/ui/imports/issue-85992.stderr b/tests/ui/imports/issue-85992.stderr index 6c75b45d926..490b2d4d88b 100644 --- a/tests/ui/imports/issue-85992.stderr +++ b/tests/ui/imports/issue-85992.stderr @@ -1,8 +1,8 @@ -error[E0432]: unresolved import `crate::issue_85992_extern_2` +error[E0432]: unresolved import `crate::empty` --> $DIR/issue-85992.rs:8:5 | -LL | use crate::issue_85992_extern_2; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `issue_85992_extern_2` in the root +LL | use crate::empty; + | ^^^^^^^^^^^^ no `empty` in the root error: aborting due to 1 previous error diff --git a/tests/ui/imports/multiple-extern-by-macro-for-buitlin.rs b/tests/ui/imports/multiple-extern-by-macro-for-buitlin.rs new file mode 100644 index 00000000000..f0e5e4b4325 --- /dev/null +++ b/tests/ui/imports/multiple-extern-by-macro-for-buitlin.rs @@ -0,0 +1,18 @@ +//@ edition: 2021 + +// issue#128813 + +extern crate core; + +macro_rules! m { + () => { + extern crate std as core; + //~^ ERROR: the name `core` is defined multiple times + }; +} + +m!(); + +fn main() { + use ::core; +} diff --git a/tests/ui/imports/multiple-extern-by-macro-for-buitlin.stderr b/tests/ui/imports/multiple-extern-by-macro-for-buitlin.stderr new file mode 100644 index 00000000000..a84a6c42aa8 --- /dev/null +++ b/tests/ui/imports/multiple-extern-by-macro-for-buitlin.stderr @@ -0,0 +1,22 @@ +error[E0259]: the name `core` is defined multiple times + --> $DIR/multiple-extern-by-macro-for-buitlin.rs:9:9 + | +LL | extern crate core; + | ------------------ previous import of the extern crate `core` here +... +LL | extern crate std as core; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `core` reimported here +... +LL | m!(); + | ---- in this macro invocation + | + = note: `core` must be defined only once in the type namespace of this module + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you can use `as` to change the binding name of the import + | +LL | extern crate std as other_core; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0259`. diff --git a/tests/ui/imports/multiple-extern-by-macro-for-custom.rs b/tests/ui/imports/multiple-extern-by-macro-for-custom.rs new file mode 100644 index 00000000000..6bf544566e3 --- /dev/null +++ b/tests/ui/imports/multiple-extern-by-macro-for-custom.rs @@ -0,0 +1,19 @@ +//@ edition: 2021 +//@ aux-build: empty.rs + +// issue#128813 + +extern crate empty; + +macro_rules! m { + () => { + extern crate std as empty; + //~^ ERROR: the name `empty` is defined multiple times + }; +} + +m!(); + +fn main() { + use ::empty; +} diff --git a/tests/ui/imports/multiple-extern-by-macro-for-custom.stderr b/tests/ui/imports/multiple-extern-by-macro-for-custom.stderr new file mode 100644 index 00000000000..556d75a4dbb --- /dev/null +++ b/tests/ui/imports/multiple-extern-by-macro-for-custom.stderr @@ -0,0 +1,22 @@ +error[E0259]: the name `empty` is defined multiple times + --> $DIR/multiple-extern-by-macro-for-custom.rs:10:9 + | +LL | extern crate empty; + | ------------------- previous import of the extern crate `empty` here +... +LL | extern crate std as empty; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `empty` reimported here +... +LL | m!(); + | ---- in this macro invocation + | + = note: `empty` must be defined only once in the type namespace of this module + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you can use `as` to change the binding name of the import + | +LL | extern crate std as other_empty; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0259`. diff --git a/tests/ui/imports/multiple-extern-by-macro-for-inexist.rs b/tests/ui/imports/multiple-extern-by-macro-for-inexist.rs new file mode 100644 index 00000000000..c23f275b9ff --- /dev/null +++ b/tests/ui/imports/multiple-extern-by-macro-for-inexist.rs @@ -0,0 +1,19 @@ +//@ edition: 2021 + +// issue#128813 + +extern crate non_existent; +//~^ ERROR: can't find crate for `non_existent` + +macro_rules! m { + () => { + extern crate std as non_existent; + //~^ ERROR: the name `non_existent` is defined multiple times + }; +} + +m!(); + +fn main() { + use ::non_existent; +} diff --git a/tests/ui/imports/multiple-extern-by-macro-for-inexist.stderr b/tests/ui/imports/multiple-extern-by-macro-for-inexist.stderr new file mode 100644 index 00000000000..ec34489f232 --- /dev/null +++ b/tests/ui/imports/multiple-extern-by-macro-for-inexist.stderr @@ -0,0 +1,29 @@ +error[E0463]: can't find crate for `non_existent` + --> $DIR/multiple-extern-by-macro-for-inexist.rs:5:1 + | +LL | extern crate non_existent; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate + +error[E0259]: the name `non_existent` is defined multiple times + --> $DIR/multiple-extern-by-macro-for-inexist.rs:10:9 + | +LL | extern crate non_existent; + | -------------------------- previous import of the extern crate `non_existent` here +... +LL | extern crate std as non_existent; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `non_existent` reimported here +... +LL | m!(); + | ---- in this macro invocation + | + = note: `non_existent` must be defined only once in the type namespace of this module + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you can use `as` to change the binding name of the import + | +LL | extern crate std as other_non_existent; + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0259, E0463. +For more information about an error, try `rustc --explain E0259`. diff --git a/tests/ui/imports/multiple-extern-by-macro-for-underscore.rs b/tests/ui/imports/multiple-extern-by-macro-for-underscore.rs new file mode 100644 index 00000000000..ddf735d8947 --- /dev/null +++ b/tests/ui/imports/multiple-extern-by-macro-for-underscore.rs @@ -0,0 +1,18 @@ +//@ edition: 2021 + +// issue#128813 + +extern crate core as _; + +macro_rules! m { + () => { + extern crate std as _; + }; +} + +m!(); + +fn main() { + use ::_; + //~^ ERROR: expected identifier, found reserved identifier `_` +} diff --git a/tests/ui/imports/multiple-extern-by-macro-for-underscore.stderr b/tests/ui/imports/multiple-extern-by-macro-for-underscore.stderr new file mode 100644 index 00000000000..1da5aa87070 --- /dev/null +++ b/tests/ui/imports/multiple-extern-by-macro-for-underscore.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/multiple-extern-by-macro-for-underscore.rs:16:11 + | +LL | use ::_; + | ^ expected identifier, found reserved identifier + +error: aborting due to 1 previous error + diff --git a/tests/ui/internal/internal-unstable-const.rs b/tests/ui/internal/internal-unstable-const.rs deleted file mode 100644 index 4ec2426dfee..00000000000 --- a/tests/ui/internal/internal-unstable-const.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Don't allow unstable features in stable functions without `allow_internal_unstable`. - -#![stable(feature = "rust1", since = "1.0.0")] -#![feature(staged_api)] -#![feature(const_fn_floating_point_arithmetic)] - -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "rust1", since = "1.0.0")] -pub const fn foo() -> f32 { - 1.0 + 1.0 //~ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` -} - -fn main() {} diff --git a/tests/ui/internal/internal-unstable-const.stderr b/tests/ui/internal/internal-unstable-const.stderr deleted file mode 100644 index ed9196d2b63..00000000000 --- a/tests/ui/internal/internal-unstable-const.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` - --> $DIR/internal-unstable-const.rs:10:5 - | -LL | 1.0 + 1.0 - | ^^^^^^^^^ - | -help: if it is not part of the public API, make this function unstably const - | -LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | pub const fn foo() -> f32 { - | -help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks - | -LL + #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] -LL | pub const fn foo() -> f32 { - | - -error: aborting due to 1 previous error - diff --git a/tests/ui/issues/issue-17651.stderr b/tests/ui/issues/issue-17651.stderr index 0c95a3c0c40..9519507320d 100644 --- a/tests/ui/issues/issue-17651.stderr +++ b/tests/ui/issues/issue-17651.stderr @@ -9,6 +9,11 @@ LL | (|| Box::new(*(&[0][..])))(); = help: the trait `Sized` is not implemented for `[{integer}]` note: required by a bound in `Box::<T>::new` --> $SRC_DIR/alloc/src/boxed.rs:LL:COL +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - (|| Box::new(*(&[0][..])))(); +LL + (|| Box::new((&[0][..])))(); + | error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-20831-debruijn.stderr b/tests/ui/issues/issue-20831-debruijn.stderr index 60721f001b7..fe310998f09 100644 --- a/tests/ui/issues/issue-20831-debruijn.stderr +++ b/tests/ui/issues/issue-20831-debruijn.stderr @@ -5,10 +5,10 @@ LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first, the lifetime cannot outlive the anonymous lifetime as defined here... - --> $DIR/issue-20831-debruijn.rs:28:18 + --> $DIR/issue-20831-debruijn.rs:28:67 | LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) { - | ^ + | ^^^^^^^^^ note: ...but the lifetime must also be valid for the lifetime `'a` as defined here... --> $DIR/issue-20831-debruijn.rs:26:6 | diff --git a/tests/ui/issues/issue-37884.stderr b/tests/ui/issues/issue-37884.stderr index b7c0095d682..17037d2180d 100644 --- a/tests/ui/issues/issue-37884.stderr +++ b/tests/ui/issues/issue-37884.stderr @@ -7,10 +7,7 @@ LL | fn next(&'a mut self) -> Option<Self::Item> = note: expected signature `fn(&mut RepeatMut<'_, _>) -> Option<_>` found signature `fn(&'a mut RepeatMut<'_, _>) -> Option<_>` note: the anonymous lifetime as defined here... - --> $DIR/issue-37884.rs:6:5 - | -LL | fn next(&'a mut self) -> Option<Self::Item> - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL note: ...does not necessarily outlive the lifetime `'a` as defined here --> $DIR/issue-37884.rs:3:6 | diff --git a/tests/ui/issues/issue-47094.stderr b/tests/ui/issues/issue-47094.stderr index 970e3184710..1c6693403b8 100644 --- a/tests/ui/issues/issue-47094.stderr +++ b/tests/ui/issues/issue-47094.stderr @@ -23,3 +23,28 @@ LL | #[repr(u8)] error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0566`. +Future incompatibility report: Future breakage diagnostic: +error[E0566]: conflicting representation hints + --> $DIR/issue-47094.rs:1:8 + | +LL | #[repr(C, u8)] + | ^ ^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585> + = note: `#[deny(conflicting_repr_hints)]` on by default + +Future breakage diagnostic: +error[E0566]: conflicting representation hints + --> $DIR/issue-47094.rs:8:8 + | +LL | #[repr(C)] + | ^ +LL | +LL | #[repr(u8)] + | ^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585> + = note: `#[deny(conflicting_repr_hints)]` on by default + diff --git a/tests/ui/lifetimes/issue-105227.fixed b/tests/ui/lifetimes/issue-105227.fixed deleted file mode 100644 index ef64e1e6541..00000000000 --- a/tests/ui/lifetimes/issue-105227.fixed +++ /dev/null @@ -1,26 +0,0 @@ -// Regression test for issue #105227. - -//@ run-rustfix -#![allow(warnings)] -fn chars0<'a>(v :(&'a str, &'a str)) -> impl Iterator<Item = char> + 'a { -//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a` - v.0.chars().chain(v.1.chars()) - //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds -} - -fn chars1<'a>(v0 : &'a str, v1 : &'a str) -> impl Iterator<Item = char> + 'a { -//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a` - v0.chars().chain(v1.chars()) - //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bound -} - -fn chars2<'b>(v0 : &'b str, v1 : &'b str, v2 : &'b str) -> -//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can use the named lifetime parameter `'b` - (impl Iterator<Item = char> + 'b , &'b str) -{ - (v0.chars().chain(v1.chars()), v2) - //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bound -} - -fn main() { -} diff --git a/tests/ui/lifetimes/issue-105227.rs b/tests/ui/lifetimes/issue-105227.rs index f37765ffafa..8a0a49e8f0c 100644 --- a/tests/ui/lifetimes/issue-105227.rs +++ b/tests/ui/lifetimes/issue-105227.rs @@ -1,23 +1,23 @@ // Regression test for issue #105227. -//@ run-rustfix -#![allow(warnings)] +// FIXME(precise_capturing): Add rustfix here after dealing w/ elided lifetimes + +#![allow(unused)] + fn chars0(v :(& str, &str)) -> impl Iterator<Item = char> { -//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a` + //~^ HELP add a `use<...>` bound v.0.chars().chain(v.1.chars()) //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds } fn chars1(v0 : & str, v1 : &str) -> impl Iterator<Item = char> { -//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a` + //~^ HELP add a `use<...>` bound v0.chars().chain(v1.chars()) //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bound } -fn chars2<'b>(v0 : &str, v1 : &'_ str, v2 : &'b str) -> -//~^ HELP to declare that `impl Iterator<Item = char>` captures `'_`, you can use the named lifetime parameter `'b` - (impl Iterator<Item = char>, &'b str) -{ +fn chars2<'b>(v0 : &str, v1 : &'_ str, v2 : &'b str) -> (impl Iterator<Item = char>, &'b str) { + //~^ HELP add a `use<...>` bound (v0.chars().chain(v1.chars()), v2) //~^ ERROR hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bound } diff --git a/tests/ui/lifetimes/issue-105227.stderr b/tests/ui/lifetimes/issue-105227.stderr index b514db461b4..35c05f28854 100644 --- a/tests/ui/lifetimes/issue-105227.stderr +++ b/tests/ui/lifetimes/issue-105227.stderr @@ -1,5 +1,5 @@ error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds - --> $DIR/issue-105227.rs:7:5 + --> $DIR/issue-105227.rs:9:5 | LL | fn chars0(v :(& str, &str)) -> impl Iterator<Item = char> { | ----- -------------------------- opaque type defined here @@ -9,13 +9,13 @@ LL | LL | v.0.chars().chain(v.1.chars()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a` +help: add a `use<...>` bound to explicitly capture `'_` | -LL | fn chars0<'a>(v :(&'a str, &'a str)) -> impl Iterator<Item = char> + 'a { - | ++++ ++ ++ ++++ +LL | fn chars0(v :(& str, &str)) -> impl Iterator<Item = char> + use<'_> { + | +++++++++ error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds - --> $DIR/issue-105227.rs:13:5 + --> $DIR/issue-105227.rs:15:5 | LL | fn chars1(v0 : & str, v1 : &str) -> impl Iterator<Item = char> { | ----- -------------------------- opaque type defined here @@ -25,29 +25,26 @@ LL | LL | v0.chars().chain(v1.chars()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that `impl Iterator<Item = char>` captures `'_`, you can introduce a named lifetime parameter `'a` +help: add a `use<...>` bound to explicitly capture `'_` | -LL | fn chars1<'a>(v0 : &'a str, v1 : &'a str) -> impl Iterator<Item = char> + 'a { - | ++++ ++ ++ ++++ +LL | fn chars1(v0 : & str, v1 : &str) -> impl Iterator<Item = char> + use<'_> { + | +++++++++ error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime that does not appear in bounds --> $DIR/issue-105227.rs:21:5 | -LL | fn chars2<'b>(v0 : &str, v1 : &'_ str, v2 : &'b str) -> - | ---- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here +LL | fn chars2<'b>(v0 : &str, v1 : &'_ str, v2 : &'b str) -> (impl Iterator<Item = char>, &'b str) { + | ---- -------------------------- opaque type defined here + | | + | hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here LL | -LL | (impl Iterator<Item = char>, &'b str) - | -------------------------- opaque type defined here -LL | { LL | (v0.chars().chain(v1.chars()), v2) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that `impl Iterator<Item = char>` captures `'_`, you can use the named lifetime parameter `'b` - | -LL ~ fn chars2<'b>(v0 : &'b str, v1 : &'b str, v2 : &'b str) -> -LL | -LL ~ (impl Iterator<Item = char> + 'b , &'b str) +help: add a `use<...>` bound to explicitly capture `'_` | +LL | fn chars2<'b>(v0 : &str, v1 : &'_ str, v2 : &'b str) -> (impl Iterator<Item = char> + use<'_>, &'b str) { + | +++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/lifetimes/issue-95023.rs b/tests/ui/lifetimes/issue-95023.rs index bcacd01474f..8461d92fc33 100644 --- a/tests/ui/lifetimes/issue-95023.rs +++ b/tests/ui/lifetimes/issue-95023.rs @@ -2,12 +2,13 @@ struct ErrorKind; struct Error(ErrorKind); impl Fn(&isize) for Error { //~^ ERROR manual implementations of `Fn` are experimental [E0183] - //~^^ ERROR associated item constraints are not allowed here [E0229] + //~| ERROR associated item constraints are not allowed here [E0229] //~| ERROR not all trait items implemented //~| ERROR expected a `FnMut(&isize)` closure, found `Error` fn foo<const N: usize>(&self) -> Self::B<{ N }>; //~^ ERROR associated function in `impl` without body - //~^^ ERROR method `foo` is not a member of trait `Fn` [E0407] - //~^^^ ERROR associated type `B` not found for `Self` [E0220] + //~| ERROR method `foo` is not a member of trait `Fn` [E0407] + //~| ERROR associated type `B` not found for `Self` [E0220] + //~| ERROR: associated type `B` not found for `Self` } fn main() {} diff --git a/tests/ui/lifetimes/issue-95023.stderr b/tests/ui/lifetimes/issue-95023.stderr index cbc0eeebee1..310dee51406 100644 --- a/tests/ui/lifetimes/issue-95023.stderr +++ b/tests/ui/lifetimes/issue-95023.stderr @@ -56,7 +56,15 @@ error[E0220]: associated type `B` not found for `Self` LL | fn foo<const N: usize>(&self) -> Self::B<{ N }>; | ^ help: `Self` has the following associated type: `Output` -error: aborting due to 7 previous errors +error[E0220]: associated type `B` not found for `Self` + --> $DIR/issue-95023.rs:8:44 + | +LL | fn foo<const N: usize>(&self) -> Self::B<{ N }>; + | ^ help: `Self` has the following associated type: `Output` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 8 previous errors Some errors have detailed explanations: E0046, E0183, E0220, E0229, E0277, E0407. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/lint/dropping_copy_types-macros.fixed b/tests/ui/lint/dropping_copy_types-macros.fixed new file mode 100644 index 00000000000..a8ceedadc80 --- /dev/null +++ b/tests/ui/lint/dropping_copy_types-macros.fixed @@ -0,0 +1,12 @@ +//@ check-fail +//@ run-rustfix + +#![deny(dropping_copy_types)] + +use std::fmt::Write; + +fn main() { + let mut msg = String::new(); + let _ = writeln!(&mut msg, "test"); + //~^ ERROR calls to `std::mem::drop` +} diff --git a/tests/ui/lint/dropping_copy_types-macros.rs b/tests/ui/lint/dropping_copy_types-macros.rs new file mode 100644 index 00000000000..b249b0c868f --- /dev/null +++ b/tests/ui/lint/dropping_copy_types-macros.rs @@ -0,0 +1,12 @@ +//@ check-fail +//@ run-rustfix + +#![deny(dropping_copy_types)] + +use std::fmt::Write; + +fn main() { + let mut msg = String::new(); + drop(writeln!(&mut msg, "test")); + //~^ ERROR calls to `std::mem::drop` +} diff --git a/tests/ui/lint/dropping_copy_types-macros.stderr b/tests/ui/lint/dropping_copy_types-macros.stderr new file mode 100644 index 00000000000..117e9f4fe09 --- /dev/null +++ b/tests/ui/lint/dropping_copy_types-macros.stderr @@ -0,0 +1,21 @@ +error: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types-macros.rs:10:5 + | +LL | drop(writeln!(&mut msg, "test")); + | ^^^^^--------------------------^ + | | + | argument has type `Result<(), std::fmt::Error>` + | +note: the lint level is defined here + --> $DIR/dropping_copy_types-macros.rs:4:9 + | +LL | #![deny(dropping_copy_types)] + | ^^^^^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(writeln!(&mut msg, "test")); +LL + let _ = writeln!(&mut msg, "test"); + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/issue-30302.stderr b/tests/ui/lint/issue-30302.stderr index baf6c0d7a59..317fefee466 100644 --- a/tests/ui/lint/issue-30302.stderr +++ b/tests/ui/lint/issue-30302.stderr @@ -13,7 +13,7 @@ LL | Nil => true, | --- matches any value LL | LL | _ => false - | ^ unreachable pattern + | ^ no value can reach this | note: the lint level is defined here --> $DIR/issue-30302.rs:4:9 diff --git a/tests/ui/lint/lint-ctypes-cstr.rs b/tests/ui/lint/lint-ctypes-cstr.rs new file mode 100644 index 00000000000..b04decd0bca --- /dev/null +++ b/tests/ui/lint/lint-ctypes-cstr.rs @@ -0,0 +1,36 @@ +#![crate_type = "lib"] +#![deny(improper_ctypes, improper_ctypes_definitions)] + +use std::ffi::{CStr, CString}; + +extern "C" { + fn take_cstr(s: CStr); + //~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe + //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` + fn take_cstr_ref(s: &CStr); + //~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe + //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` + fn take_cstring(s: CString); + //~^ ERROR `extern` block uses type `CString`, which is not FFI-safe + //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` + fn take_cstring_ref(s: &CString); + //~^ ERROR `extern` block uses type `CString`, which is not FFI-safe + //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` + + fn no_special_help_for_mut_cstring(s: *mut CString); + //~^ ERROR `extern` block uses type `CString`, which is not FFI-safe + //~| HELP consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + + fn no_special_help_for_mut_cstring_ref(s: &mut CString); + //~^ ERROR `extern` block uses type `CString`, which is not FFI-safe + //~| HELP consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct +} + +extern "C" fn rust_take_cstr_ref(s: &CStr) {} +//~^ ERROR `extern` fn uses type `CStr`, which is not FFI-safe +//~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` +extern "C" fn rust_take_cstring(s: CString) {} +//~^ ERROR `extern` fn uses type `CString`, which is not FFI-safe +//~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` +extern "C" fn rust_no_special_help_for_mut_cstring(s: *mut CString) {} +extern "C" fn rust_no_special_help_for_mut_cstring_ref(s: &mut CString) {} diff --git a/tests/ui/lint/lint-ctypes-cstr.stderr b/tests/ui/lint/lint-ctypes-cstr.stderr new file mode 100644 index 00000000000..8957758d577 --- /dev/null +++ b/tests/ui/lint/lint-ctypes-cstr.stderr @@ -0,0 +1,84 @@ +error: `extern` block uses type `CStr`, which is not FFI-safe + --> $DIR/lint-ctypes-cstr.rs:7:21 + | +LL | fn take_cstr(s: CStr); + | ^^^^ not FFI-safe + | + = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` + = note: `CStr`/`CString` do not have a guaranteed layout +note: the lint level is defined here + --> $DIR/lint-ctypes-cstr.rs:2:9 + | +LL | #![deny(improper_ctypes, improper_ctypes_definitions)] + | ^^^^^^^^^^^^^^^ + +error: `extern` block uses type `CStr`, which is not FFI-safe + --> $DIR/lint-ctypes-cstr.rs:10:25 + | +LL | fn take_cstr_ref(s: &CStr); + | ^^^^^ not FFI-safe + | + = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` + = note: `CStr`/`CString` do not have a guaranteed layout + +error: `extern` block uses type `CString`, which is not FFI-safe + --> $DIR/lint-ctypes-cstr.rs:13:24 + | +LL | fn take_cstring(s: CString); + | ^^^^^^^ not FFI-safe + | + = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` + = note: `CStr`/`CString` do not have a guaranteed layout + +error: `extern` block uses type `CString`, which is not FFI-safe + --> $DIR/lint-ctypes-cstr.rs:16:28 + | +LL | fn take_cstring_ref(s: &CString); + | ^^^^^^^^ not FFI-safe + | + = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` + = note: `CStr`/`CString` do not have a guaranteed layout + +error: `extern` block uses type `CString`, which is not FFI-safe + --> $DIR/lint-ctypes-cstr.rs:20:43 + | +LL | fn no_special_help_for_mut_cstring(s: *mut CString); + | ^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout + +error: `extern` block uses type `CString`, which is not FFI-safe + --> $DIR/lint-ctypes-cstr.rs:24:47 + | +LL | fn no_special_help_for_mut_cstring_ref(s: &mut CString); + | ^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout + +error: `extern` fn uses type `CStr`, which is not FFI-safe + --> $DIR/lint-ctypes-cstr.rs:29:37 + | +LL | extern "C" fn rust_take_cstr_ref(s: &CStr) {} + | ^^^^^ not FFI-safe + | + = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` + = note: `CStr`/`CString` do not have a guaranteed layout +note: the lint level is defined here + --> $DIR/lint-ctypes-cstr.rs:2:26 + | +LL | #![deny(improper_ctypes, improper_ctypes_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `extern` fn uses type `CString`, which is not FFI-safe + --> $DIR/lint-ctypes-cstr.rs:32:36 + | +LL | extern "C" fn rust_take_cstring(s: CString) {} + | ^^^^^^^ not FFI-safe + | + = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` + = note: `CStr`/`CString` do not have a guaranteed layout + +error: aborting due to 8 previous errors + diff --git a/tests/ui/nll/issue-73159-rpit-static.stderr b/tests/ui/nll/issue-73159-rpit-static.stderr index 472db30fbeb..7c564b84a56 100644 --- a/tests/ui/nll/issue-73159-rpit-static.stderr +++ b/tests/ui/nll/issue-73159-rpit-static.stderr @@ -7,6 +7,11 @@ LL | fn make_it(&self) -> impl Iterator<Item = u8> { | ------------------------ opaque type defined here LL | self.0.iter().copied() | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: add a `use<...>` bound to explicitly capture `'a` + | +LL | fn make_it(&self) -> impl Iterator<Item = u8> + use<'a> { + | +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr b/tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr index cab75e630a7..911ddd3dc80 100644 --- a/tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr +++ b/tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr @@ -37,10 +37,10 @@ LL | fn test_ambiguous<'a, 'b, 'c>(s: &'a u8) -> impl Cap<'b> + Cap<'c> LL | s | ^ | -help: to declare that `impl Cap<'b> + Cap<'c>` captures `'a`, you can add an explicit `'a` lifetime bound +help: add a `use<...>` bound to explicitly capture `'a` | -LL | fn test_ambiguous<'a, 'b, 'c>(s: &'a u8) -> impl Cap<'b> + Cap<'c> + 'a - | ++++ +LL | fn test_ambiguous<'a, 'b, 'c>(s: &'a u8) -> impl Cap<'b> + Cap<'c> + use<'b, 'c, 'a> + | +++++++++++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/nll/member-constraints/nested-impl-trait-fail.stderr b/tests/ui/nll/member-constraints/nested-impl-trait-fail.stderr index 483b5822b9d..1a0611e715e 100644 --- a/tests/ui/nll/member-constraints/nested-impl-trait-fail.stderr +++ b/tests/ui/nll/member-constraints/nested-impl-trait-fail.stderr @@ -9,14 +9,10 @@ LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl LL | [a] | ^^^ | -help: to declare that `impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>` captures `'s`, you can add an explicit `'s` lifetime bound +help: add a `use<...>` bound to explicitly capture `'s` | -LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> + 's - | ++++ -help: to declare that `impl Cap<'a> + Cap<'b>` captures `'s`, you can add an explicit `'s` lifetime bound - | -LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b> + 's> - | ++++ +LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> + use<'a, 'b, 's> + | +++++++++++++++++ error[E0700]: hidden type for `impl Cap<'a> + Cap<'b>` captures lifetime that does not appear in bounds --> $DIR/nested-impl-trait-fail.rs:17:5 @@ -29,14 +25,10 @@ LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl LL | [a] | ^^^ | -help: to declare that `impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>` captures `'s`, you can add an explicit `'s` lifetime bound - | -LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> + 's - | ++++ -help: to declare that `impl Cap<'a> + Cap<'b>` captures `'s`, you can add an explicit `'s` lifetime bound +help: add a `use<...>` bound to explicitly capture `'s` | -LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b> + 's> - | ++++ +LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b> + use<'a, 'b, 's>> + | +++++++++++++++++ error[E0700]: hidden type for `impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>` captures lifetime that does not appear in bounds --> $DIR/nested-impl-trait-fail.rs:28:5 @@ -49,14 +41,10 @@ LL | ) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> { LL | [a] | ^^^ | -help: to declare that `impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>` captures `'s`, you can add an explicit `'s` lifetime bound +help: add a `use<...>` bound to explicitly capture `'s` | -LL | ) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> + 's { - | ++++ -help: to declare that `impl Cap<'a> + Cap<'b>` captures `'s`, you can add an explicit `'s` lifetime bound - | -LL | ) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b> + 's> { - | ++++ +LL | ) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> + use<'a, 'b, 's> { + | +++++++++++++++++ error[E0700]: hidden type for `impl Cap<'a> + Cap<'b>` captures lifetime that does not appear in bounds --> $DIR/nested-impl-trait-fail.rs:28:5 @@ -69,14 +57,10 @@ LL | ) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> { LL | [a] | ^^^ | -help: to declare that `impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>` captures `'s`, you can add an explicit `'s` lifetime bound - | -LL | ) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> + 's { - | ++++ -help: to declare that `impl Cap<'a> + Cap<'b>` captures `'s`, you can add an explicit `'s` lifetime bound +help: add a `use<...>` bound to explicitly capture `'s` | -LL | ) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b> + 's> { - | ++++ +LL | ) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b> + use<'a, 'b, 's>> { + | +++++++++++++++++ error: aborting due to 4 previous errors diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-116657.nll.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-116657.nll.stderr index 6f9b3303163..cdf394505a2 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-116657.nll.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-116657.nll.stderr @@ -25,10 +25,10 @@ LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne { LL | <&mut i32 as Callable>::call(y) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that `impl PlusOne` captures `'a`, you can add an explicit `'a` lifetime bound +help: add a `use<...>` bound to explicitly capture `'a` | -LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne + 'a { - | ++++ +LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne + use<'a> { + | +++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-issue-116657.polonius.stderr b/tests/ui/nll/polonius/location-insensitive-scopes-issue-116657.polonius.stderr index 6f9b3303163..cdf394505a2 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-issue-116657.polonius.stderr +++ b/tests/ui/nll/polonius/location-insensitive-scopes-issue-116657.polonius.stderr @@ -25,10 +25,10 @@ LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne { LL | <&mut i32 as Callable>::call(y) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that `impl PlusOne` captures `'a`, you can add an explicit `'a` lifetime bound +help: add a `use<...>` bound to explicitly capture `'a` | -LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne + 'a { - | ++++ +LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne + use<'a> { + | +++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr index 48569d1446d..3ceefbc4066 100644 --- a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -8,10 +8,10 @@ LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { LL | x | ^ | -help: to declare that `Opaque(DefId(0:13 ~ impl_trait_captures[aeb9]::foo::{opaque#0}), ['a/#0, T, 'a/#2])` captures `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))`, you can add an explicit `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` lifetime bound +help: add a `use<...>` bound to explicitly capture `ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_))` | -LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)) { - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + use<'a, ReLateParam(DefId(0:8 ~ impl_trait_captures[aeb9]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[aeb9]::foo::'_), '_)), T> { + | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr index 5570390b21c..6ddc0595665 100644 --- a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr +++ b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:8:9 | LL | (1 | 2,) => {} - | -------- matches all the values already + | -------- matches all the relevant values LL | (1,) => {} - | ^^^^ unreachable pattern + | ^^^^ no value can reach this | note: the lint level is defined here --> $DIR/exhaustiveness-unreachable-pattern.rs:1:9 @@ -16,17 +16,17 @@ error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:13:9 | LL | (1 | 2,) => {} - | -------- matches all the values already + | -------- matches all the relevant values LL | (2,) => {} - | ^^^^ unreachable pattern + | ^^^^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:19:9 | LL | (1 | 2,) => {} - | ^^^^^^^^ unreachable pattern + | ^^^^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/exhaustiveness-unreachable-pattern.rs:19:9 | LL | (1,) => {} @@ -40,44 +40,44 @@ error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:24:9 | LL | (1 | 2, 3 | 4) => {} - | -------------- matches all the values already + | -------------- matches all the relevant values LL | (1, 3) => {} - | ^^^^^^ unreachable pattern + | ^^^^^^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:25:9 | LL | (1 | 2, 3 | 4) => {} - | -------------- matches all the values already + | -------------- matches all the relevant values LL | (1, 3) => {} LL | (1, 4) => {} - | ^^^^^^ unreachable pattern + | ^^^^^^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:26:9 | LL | (1 | 2, 3 | 4) => {} - | -------------- matches all the values already + | -------------- matches all the relevant values ... LL | (2, 4) => {} - | ^^^^^^ unreachable pattern + | ^^^^^^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:27:9 | LL | (1 | 2, 3 | 4) => {} - | -------------- matches all the values already + | -------------- matches all the relevant values ... LL | (2 | 1, 4) => {} - | ^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:29:9 | LL | (1, 4 | 5) => {} - | ^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/exhaustiveness-unreachable-pattern.rs:29:9 | LL | (1 | 2, 3 | 4) => {} @@ -92,107 +92,107 @@ error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:34:13 | LL | (0, 0, 0) => {} - | - matches all the values already + | - matches all the relevant values LL | (0, 0 | 1, 0) => {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:42:9 | LL | (None | Some(1 | 2),) => {} - | --------------------- matches all the values already + | --------------------- matches all the relevant values LL | (Some(1),) => {} - | ^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:43:9 | LL | (None | Some(1 | 2),) => {} - | --------------------- matches all the values already + | --------------------- matches all the relevant values LL | (Some(1),) => {} LL | (None,) => {} - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:48:9 | LL | ((1 | 2,) | (3 | 4,),) => {} - | ---------------------- matches all the values already + | ---------------------- matches all the relevant values LL | ((1..=4,),) => {} - | ^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:53:14 | LL | (1 | 1,) => {} - | - ^ unreachable pattern + | - ^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:57:19 | LL | (0 | 1) | 1 => {} - | - ^ unreachable pattern + | - ^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:63:14 | LL | 0 | (0 | 0) => {} - | - ^ unreachable pattern + | - ^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:63:18 | LL | 0 | (0 | 0) => {} - | - ^ unreachable pattern + | - ^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:71:13 | LL | Some(0) | - | ------- matches all the values already + | ------- matches all the relevant values LL | / Some( LL | | 0 | 0) => {} - | |______________________^ unreachable pattern + | |______________________^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:77:15 | LL | [0 - | - matches all the values already + | - matches all the relevant values LL | | 0 - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:79:15 | LL | , 0 - | - matches all the values already + | - matches all the relevant values LL | | 0] => {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:83:20 | LL | (true, 0 | 0) => {} - | - ^ unreachable pattern + | - ^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:84:17 | LL | (_, 0 | 0) => {} - | ^ unreachable pattern + | ^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/exhaustiveness-unreachable-pattern.rs:84:17 | LL | (true, 0 | 0) => {} @@ -206,25 +206,25 @@ error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:92:10 | LL | [1, ..] => {} - | - matches all the values already + | - matches all the relevant values LL | [1 - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:104:10 | LL | [true, ..] => {} - | ---- matches all the values already + | ---- matches all the relevant values LL | [true - | ^^^^ unreachable pattern + | ^^^^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:111:36 | LL | (true | false, None | Some(true - | ^^^^ unreachable pattern + | ^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/exhaustiveness-unreachable-pattern.rs:111:36 | LL | (true, Some(_)) => {} @@ -238,12 +238,12 @@ error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:116:14 | LL | (true - | ^^^^ unreachable pattern + | ^^^^ no value can reach this ... LL | (true | false, None | Some(t_or_f!())) => {} | --------- in this macro invocation | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/exhaustiveness-unreachable-pattern.rs:116:14 | LL | (true @@ -261,26 +261,26 @@ error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:127:14 | LL | Some(0) => {} - | - matches all the values already + | - matches all the relevant values LL | Some(0 - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:146:19 | LL | Some(false) => {} - | ----- matches all the values already + | ----- matches all the relevant values LL | None | Some(true LL | | false) => {} - | ^^^^^ unreachable pattern + | ^^^^^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:154:15 | LL | | true) => {} - | ^^^^ unreachable pattern + | ^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/exhaustiveness-unreachable-pattern.rs:154:15 | LL | (false, true) => {} @@ -295,9 +295,9 @@ error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:160:15 | LL | | true, - | ^^^^ unreachable pattern + | ^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/exhaustiveness-unreachable-pattern.rs:160:15 | LL | (true, false) => {} @@ -314,13 +314,13 @@ error: unreachable pattern LL | (x, y) | ------ matches any value LL | | (y, x) => {} - | ^^^^^^ unreachable pattern + | ^^^^^^ no value can reach this error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:169:30 | LL | fn unreachable_in_param((_ | (_, _)): (bool, bool)) {} - | - ^^^^^^ unreachable pattern + | - ^^^^^^ no value can reach this | | | matches any value @@ -328,7 +328,7 @@ error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:176:14 | LL | let (_ | (_, _)) = bool_pair; - | - ^^^^^^ unreachable pattern + | - ^^^^^^ no value can reach this | | | matches any value @@ -336,7 +336,7 @@ error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:178:14 | LL | for (_ | (_, _)) in [bool_pair] {} - | - ^^^^^^ unreachable pattern + | - ^^^^^^ no value can reach this | | | matches any value @@ -344,25 +344,25 @@ error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:181:20 | LL | let (Some(_) | Some(true)) = bool_option else { return }; - | ------- ^^^^^^^^^^ unreachable pattern + | ------- ^^^^^^^^^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:183:22 | LL | if let Some(_) | Some(true) = bool_option {} - | ------- ^^^^^^^^^^ unreachable pattern + | ------- ^^^^^^^^^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/exhaustiveness-unreachable-pattern.rs:185:25 | LL | while let Some(_) | Some(true) = bool_option {} - | ------- ^^^^^^^^^^ unreachable pattern + | ------- ^^^^^^^^^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: aborting due to 36 previous errors diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr index 1ba130e20b5..bd860841b80 100644 --- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr @@ -359,11 +359,6 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } | previous outer attribute | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files -help: to annotate the item macro invocation, change the attribute from inner to outer style - | -LL - #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } -LL + #[cfg(FALSE)] fn s() { #[attr] #[attr] foo!(); } - | error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:77:32 @@ -375,11 +370,6 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } | previous outer attribute | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files -help: to annotate the item macro invocation, change the attribute from inner to outer style - | -LL - #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } -LL + #[cfg(FALSE)] fn s() { #[attr] #[attr] foo![]; } - | error: an inner attribute is not permitted following an outer attribute --> $DIR/attr-stmt-expr-attr-bad.rs:79:32 @@ -391,11 +381,6 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } | previous outer attribute | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files -help: to annotate the item macro invocation, change the attribute from inner to outer style - | -LL - #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } -LL + #[cfg(FALSE)] fn s() { #[attr] #[attr] foo!{}; } - | error[E0586]: inclusive range with no end --> $DIR/attr-stmt-expr-attr-bad.rs:85:35 diff --git a/tests/ui/parser/attribute/attr.stderr b/tests/ui/parser/attribute/attr.stderr index 2e0b16efb6c..a79a5246c2a 100644 --- a/tests/ui/parser/attribute/attr.stderr +++ b/tests/ui/parser/attribute/attr.stderr @@ -7,11 +7,6 @@ LL | fn foo() {} | ----------- the inner attribute doesn't annotate this function | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files -help: to annotate the function, change the attribute from inner to outer style - | -LL - #![lang = "foo"] -LL + #[lang = "foo"] - | error: aborting due to 1 previous error diff --git a/tests/ui/parser/inner-attr-after-doc-comment.stderr b/tests/ui/parser/inner-attr-after-doc-comment.stderr index 6dbc0fd93fd..f087c2e4d65 100644 --- a/tests/ui/parser/inner-attr-after-doc-comment.stderr +++ b/tests/ui/parser/inner-attr-after-doc-comment.stderr @@ -13,11 +13,6 @@ LL | fn main() {} | ------------ the inner attribute doesn't annotate this function | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files -help: to annotate the function, change the attribute from inner to outer style - | -LL - #![recursion_limit="100"] -LL + #[recursion_limit="100"] - | error: aborting due to 1 previous error diff --git a/tests/ui/parser/inner-attr.stderr b/tests/ui/parser/inner-attr.stderr index 57ca164fc15..18a82ea4c38 100644 --- a/tests/ui/parser/inner-attr.stderr +++ b/tests/ui/parser/inner-attr.stderr @@ -10,11 +10,6 @@ LL | fn main() {} | ------------ the inner attribute doesn't annotate this function | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files -help: to annotate the function, change the attribute from inner to outer style - | -LL - #![recursion_limit="100"] -LL + #[recursion_limit="100"] - | error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.rs b/tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.rs new file mode 100644 index 00000000000..26541a89a56 --- /dev/null +++ b/tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.rs @@ -0,0 +1,10 @@ +#![allow(dead_code)] +fn foo() {} + +#![feature(iter_array_chunks)] //~ ERROR an inner attribute is not permitted in this context +fn bar() {} + +fn main() { + foo(); + bar(); +} diff --git a/tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.stderr b/tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.stderr new file mode 100644 index 00000000000..d6daa21e741 --- /dev/null +++ b/tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.stderr @@ -0,0 +1,12 @@ +error: an inner attribute is not permitted in this context + --> $DIR/isgg-invalid-outer-attttr-issue-127930.rs:4:1 + | +LL | #![feature(iter_array_chunks)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar() {} + | ----------- the inner attribute doesn't annotate this function + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/issue-30318.fixed b/tests/ui/parser/issues/issue-30318.fixed index d1661be5193..d4720834746 100644 --- a/tests/ui/parser/issues/issue-30318.fixed +++ b/tests/ui/parser/issues/issue-30318.fixed @@ -6,7 +6,7 @@ fn foo() { } //~^ ERROR expected outer doc comment fn bar() { } //~ NOTE the inner doc comment doesn't annotate this function -#[test] //~ ERROR an inner attribute is not permitted in this context +#[cfg(test)] //~ ERROR an inner attribute is not permitted in this context fn baz() { } //~ NOTE the inner attribute doesn't annotate this function //~^^ NOTE inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually diff --git a/tests/ui/parser/issues/issue-30318.rs b/tests/ui/parser/issues/issue-30318.rs index 6f055cd4f7e..0555379836a 100644 --- a/tests/ui/parser/issues/issue-30318.rs +++ b/tests/ui/parser/issues/issue-30318.rs @@ -6,7 +6,7 @@ fn foo() { } //~^ ERROR expected outer doc comment fn bar() { } //~ NOTE the inner doc comment doesn't annotate this function -#![test] //~ ERROR an inner attribute is not permitted in this context +#![cfg(test)] //~ ERROR an inner attribute is not permitted in this context fn baz() { } //~ NOTE the inner attribute doesn't annotate this function //~^^ NOTE inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually diff --git a/tests/ui/parser/issues/issue-30318.stderr b/tests/ui/parser/issues/issue-30318.stderr index c441a92abad..56bc200db1d 100644 --- a/tests/ui/parser/issues/issue-30318.stderr +++ b/tests/ui/parser/issues/issue-30318.stderr @@ -15,16 +15,16 @@ LL | /// Misplaced comment... error: an inner attribute is not permitted in this context --> $DIR/issue-30318.rs:9:1 | -LL | #![test] - | ^^^^^^^^ +LL | #![cfg(test)] + | ^^^^^^^^^^^^^ LL | fn baz() { } | ------------ the inner attribute doesn't annotate this function | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files help: to annotate the function, change the attribute from inner to outer style | -LL - #![test] -LL + #[test] +LL - #![cfg(test)] +LL + #[cfg(test)] | error[E0753]: expected outer doc comment diff --git a/tests/ui/pattern/issue-14221.stderr b/tests/ui/pattern/issue-14221.stderr index 7ea51b5f804..44b2923d606 100644 --- a/tests/ui/pattern/issue-14221.stderr +++ b/tests/ui/pattern/issue-14221.stderr @@ -19,7 +19,7 @@ LL | A => "A", | - matches any value LL | LL | B => "B", - | ^ unreachable pattern + | ^ no value can reach this | note: the lint level is defined here --> $DIR/issue-14221.rs:1:9 diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr index 9d3a35321ca..32d385eecb4 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.stderr +++ b/tests/ui/pattern/usefulness/consts-opaque.stderr @@ -52,7 +52,7 @@ error: unreachable pattern LL | Bar => {} | --- matches any value LL | BAR => {} - | ^^^ unreachable pattern + | ^^^ no value can reach this | note: the lint level is defined here --> $DIR/consts-opaque.rs:6:9 @@ -67,7 +67,7 @@ LL | Bar => {} | --- matches any value ... LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/consts-opaque.rs:56:9 @@ -75,7 +75,7 @@ error: unreachable pattern LL | BAR => {} | --- matches any value LL | Bar => {} - | ^^^ unreachable pattern + | ^^^ no value can reach this error: unreachable pattern --> $DIR/consts-opaque.rs:58:9 @@ -84,7 +84,7 @@ LL | BAR => {} | --- matches any value ... LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/consts-opaque.rs:64:9 @@ -92,7 +92,7 @@ error: unreachable pattern LL | BAR => {} | --- matches any value LL | BAR => {} // should not be emitting unreachable warning - | ^^^ unreachable pattern + | ^^^ no value can reach this error: unreachable pattern --> $DIR/consts-opaque.rs:66:9 @@ -101,31 +101,31 @@ LL | BAR => {} | --- matches any value ... LL | _ => {} // should not be emitting unreachable warning - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/consts-opaque.rs:72:9 | LL | BAZ => {} - | --- matches all the values already + | --- matches all the relevant values LL | Baz::Baz1 => {} // should not be emitting unreachable warning - | ^^^^^^^^^ unreachable pattern + | ^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/consts-opaque.rs:79:9 | LL | Baz::Baz1 => {} - | --------- matches all the values already + | --------- matches all the relevant values LL | BAZ => {} - | ^^^ unreachable pattern + | ^^^ no value can reach this error: unreachable pattern --> $DIR/consts-opaque.rs:87:9 | LL | _ => {} // should not be emitting unreachable warning - | ^ unreachable pattern + | ^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/consts-opaque.rs:87:9 | LL | BAZ => {} diff --git a/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr index 1b65ff7aa57..60ab4d52c30 100644 --- a/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/empty-match-check-notes.rs:17:9 | LL | _ => {} - | ^ + | ^ matches no values because `EmptyEnum` is uninhabited | - = note: this pattern matches no values because `EmptyEnum` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here --> $DIR/empty-match-check-notes.rs:7:9 | @@ -12,31 +12,31 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-match-check-notes.rs:21:9 + --> $DIR/empty-match-check-notes.rs:22:9 | LL | _ if false => {} - | ^ + | ^ matches no values because `EmptyEnum` is uninhabited | - = note: this pattern matches no values because `EmptyEnum` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-match-check-notes.rs:29:9 + --> $DIR/empty-match-check-notes.rs:31:9 | LL | _ => {} - | ^ + | ^ matches no values because `EmptyForeignEnum` is uninhabited | - = note: this pattern matches no values because `EmptyForeignEnum` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-match-check-notes.rs:33:9 + --> $DIR/empty-match-check-notes.rs:36:9 | LL | _ if false => {} - | ^ + | ^ matches no values because `EmptyForeignEnum` is uninhabited | - = note: this pattern matches no values because `EmptyForeignEnum` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0005]: refutable pattern in local binding - --> $DIR/empty-match-check-notes.rs:39:9 + --> $DIR/empty-match-check-notes.rs:43:9 | LL | let None = *x; | ^^^^ pattern `Some(_)` not covered @@ -51,7 +51,7 @@ LL | if let None = *x { todo!() }; | ++ +++++++++++ error[E0004]: non-exhaustive patterns: `0_u8..=u8::MAX` not covered - --> $DIR/empty-match-check-notes.rs:49:11 + --> $DIR/empty-match-check-notes.rs:53:11 | LL | match 0u8 { | ^^^ pattern `0_u8..=u8::MAX` not covered diff --git a/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr b/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr index 1b65ff7aa57..60ab4d52c30 100644 --- a/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/empty-match-check-notes.rs:17:9 | LL | _ => {} - | ^ + | ^ matches no values because `EmptyEnum` is uninhabited | - = note: this pattern matches no values because `EmptyEnum` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here --> $DIR/empty-match-check-notes.rs:7:9 | @@ -12,31 +12,31 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-match-check-notes.rs:21:9 + --> $DIR/empty-match-check-notes.rs:22:9 | LL | _ if false => {} - | ^ + | ^ matches no values because `EmptyEnum` is uninhabited | - = note: this pattern matches no values because `EmptyEnum` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-match-check-notes.rs:29:9 + --> $DIR/empty-match-check-notes.rs:31:9 | LL | _ => {} - | ^ + | ^ matches no values because `EmptyForeignEnum` is uninhabited | - = note: this pattern matches no values because `EmptyForeignEnum` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/empty-match-check-notes.rs:33:9 + --> $DIR/empty-match-check-notes.rs:36:9 | LL | _ if false => {} - | ^ + | ^ matches no values because `EmptyForeignEnum` is uninhabited | - = note: this pattern matches no values because `EmptyForeignEnum` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0005]: refutable pattern in local binding - --> $DIR/empty-match-check-notes.rs:39:9 + --> $DIR/empty-match-check-notes.rs:43:9 | LL | let None = *x; | ^^^^ pattern `Some(_)` not covered @@ -51,7 +51,7 @@ LL | if let None = *x { todo!() }; | ++ +++++++++++ error[E0004]: non-exhaustive patterns: `0_u8..=u8::MAX` not covered - --> $DIR/empty-match-check-notes.rs:49:11 + --> $DIR/empty-match-check-notes.rs:53:11 | LL | match 0u8 { | ^^^ pattern `0_u8..=u8::MAX` not covered diff --git a/tests/ui/pattern/usefulness/empty-match-check-notes.rs b/tests/ui/pattern/usefulness/empty-match-check-notes.rs index 61a75e6c801..48d20fd2d5c 100644 --- a/tests/ui/pattern/usefulness/empty-match-check-notes.rs +++ b/tests/ui/pattern/usefulness/empty-match-check-notes.rs @@ -16,10 +16,12 @@ fn empty_enum(x: EmptyEnum) { match x { _ => {} //~ ERROR unreachable pattern //~^ NOTE matches no values + //~| NOTE to learn more about uninhabited types, see } match x { _ if false => {} //~ ERROR unreachable pattern //~^ NOTE matches no values + //~| NOTE to learn more about uninhabited types, see } } @@ -28,10 +30,12 @@ fn empty_foreign_enum(x: empty::EmptyForeignEnum) { match x { _ => {} //~ ERROR unreachable pattern //~^ NOTE matches no values + //~| NOTE to learn more about uninhabited types, see } match x { _ if false => {} //~ ERROR unreachable pattern //~^ NOTE matches no values + //~| NOTE to learn more about uninhabited types, see } } diff --git a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr index f6f341d6f2f..9decddfe5de 100644 --- a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/empty-types.rs:49:9 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here --> $DIR/empty-types.rs:15:9 | @@ -15,9 +15,9 @@ error: unreachable pattern --> $DIR/empty-types.rs:52:9 | LL | _x => {} - | ^^ + | ^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `&!` is non-empty --> $DIR/empty-types.rs:56:11 @@ -38,33 +38,33 @@ error: unreachable pattern --> $DIR/empty-types.rs:70:9 | LL | (_, _) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `(u32, !)` is uninhabited | - = note: this pattern matches no values because `(u32, !)` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:76:9 | LL | _ => {} - | ^ + | ^ matches no values because `(!, !)` is uninhabited | - = note: this pattern matches no values because `(!, !)` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:79:9 | LL | (_, _) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `(!, !)` is uninhabited | - = note: this pattern matches no values because `(!, !)` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:83:9 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `Ok(_)` not covered --> $DIR/empty-types.rs:87:11 @@ -89,17 +89,17 @@ error: unreachable pattern --> $DIR/empty-types.rs:94:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:99:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered --> $DIR/empty-types.rs:96:11 @@ -137,153 +137,153 @@ error: unreachable pattern --> $DIR/empty-types.rs:112:9 | LL | _ => {} - | ^ + | ^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:115:9 | LL | Ok(_) => {} - | ^^^^^ + | ^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:118:9 | LL | Ok(_) => {} - | ^^^^^ + | ^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:119:9 | LL | _ => {} - | ^ + | ^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:122:9 | LL | Ok(_) => {} - | ^^^^^ + | ^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:123:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:132:13 | LL | _ => {} - | ^ + | ^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:135:13 | LL | _ if false => {} - | ^ + | ^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:143:13 | LL | Some(_) => {} - | ^^^^^^^ + | ^^^^^^^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:147:13 | LL | None => {} - | ---- matches all the values already + | ---- matches all the relevant values LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/empty-types.rs:199:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:204:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:209:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:214:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:220:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:281:9 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:284:9 | LL | (_, _) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `(!, !)` is uninhabited | - = note: this pattern matches no values because `(!, !)` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:287:9 | LL | Ok(_) => {} - | ^^^^^ + | ^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:288:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty --> $DIR/empty-types.rs:327:11 @@ -344,25 +344,25 @@ error: unreachable pattern --> $DIR/empty-types.rs:368:9 | LL | _ => {} - | ^ + | ^ matches no values because `[!; 3]` is uninhabited | - = note: this pattern matches no values because `[!; 3]` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:371:9 | LL | [_, _, _] => {} - | ^^^^^^^^^ + | ^^^^^^^^^ matches no values because `[!; 3]` is uninhabited | - = note: this pattern matches no values because `[!; 3]` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:374:9 | LL | [_, ..] => {} - | ^^^^^^^ + | ^^^^^^^ matches no values because `[!; 3]` is uninhabited | - = note: this pattern matches no values because `[!; 3]` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty --> $DIR/empty-types.rs:388:11 @@ -382,9 +382,9 @@ error: unreachable pattern --> $DIR/empty-types.rs:395:9 | LL | [] => {} - | -- matches all the values already + | -- matches all the relevant values LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error[E0004]: non-exhaustive patterns: `[]` not covered --> $DIR/empty-types.rs:397:11 @@ -404,67 +404,67 @@ error: unreachable pattern --> $DIR/empty-types.rs:416:9 | LL | Some(_) => {} - | ^^^^^^^ + | ^^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:421:9 | LL | Some(_a) => {} - | ^^^^^^^^ + | ^^^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:426:9 | LL | None => {} - | ---- matches all the values already + | ---- matches all the relevant values LL | // !useful, !reachable LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/empty-types.rs:431:9 | LL | None => {} - | ---- matches all the values already + | ---- matches all the relevant values LL | // !useful, !reachable LL | _a => {} - | ^^ unreachable pattern + | ^^ no value can reach this error: unreachable pattern --> $DIR/empty-types.rs:603:9 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:606:9 | LL | _x => {} - | ^^ + | ^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:609:9 | LL | _ if false => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:612:9 | LL | _x if false => {} - | ^^ + | ^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: aborting due to 49 previous errors diff --git a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr index 55a138c2d1c..68213a2d661 100644 --- a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr +++ b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr @@ -11,9 +11,9 @@ error: unreachable pattern --> $DIR/empty-types.rs:49:9 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here --> $DIR/empty-types.rs:15:9 | @@ -24,9 +24,9 @@ error: unreachable pattern --> $DIR/empty-types.rs:52:9 | LL | _x => {} - | ^^ + | ^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `&!` is non-empty --> $DIR/empty-types.rs:56:11 @@ -47,33 +47,33 @@ error: unreachable pattern --> $DIR/empty-types.rs:70:9 | LL | (_, _) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `(u32, !)` is uninhabited | - = note: this pattern matches no values because `(u32, !)` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:76:9 | LL | _ => {} - | ^ + | ^ matches no values because `(!, !)` is uninhabited | - = note: this pattern matches no values because `(!, !)` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:79:9 | LL | (_, _) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `(!, !)` is uninhabited | - = note: this pattern matches no values because `(!, !)` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:83:9 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `Ok(_)` not covered --> $DIR/empty-types.rs:87:11 @@ -98,17 +98,17 @@ error: unreachable pattern --> $DIR/empty-types.rs:94:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:99:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered --> $DIR/empty-types.rs:96:11 @@ -160,81 +160,81 @@ error: unreachable pattern --> $DIR/empty-types.rs:112:9 | LL | _ => {} - | ^ + | ^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:115:9 | LL | Ok(_) => {} - | ^^^^^ + | ^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:118:9 | LL | Ok(_) => {} - | ^^^^^ + | ^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:119:9 | LL | _ => {} - | ^ + | ^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:122:9 | LL | Ok(_) => {} - | ^^^^^ + | ^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:123:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:132:13 | LL | _ => {} - | ^ + | ^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:135:13 | LL | _ if false => {} - | ^ + | ^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:143:13 | LL | Some(_) => {} - | ^^^^^^^ + | ^^^^^^^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:147:13 | LL | None => {} - | ---- matches all the values already + | ---- matches all the relevant values LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error[E0004]: non-exhaustive patterns: `Some(!)` not covered --> $DIR/empty-types.rs:156:15 @@ -259,73 +259,73 @@ error: unreachable pattern --> $DIR/empty-types.rs:199:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:204:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:209:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:214:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:220:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:281:9 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:284:9 | LL | (_, _) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `(!, !)` is uninhabited | - = note: this pattern matches no values because `(!, !)` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:287:9 | LL | Ok(_) => {} - | ^^^^^ + | ^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:288:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0005]: refutable pattern in local binding --> $DIR/empty-types.rs:297:13 @@ -478,25 +478,25 @@ error: unreachable pattern --> $DIR/empty-types.rs:368:9 | LL | _ => {} - | ^ + | ^ matches no values because `[!; 3]` is uninhabited | - = note: this pattern matches no values because `[!; 3]` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:371:9 | LL | [_, _, _] => {} - | ^^^^^^^^^ + | ^^^^^^^^^ matches no values because `[!; 3]` is uninhabited | - = note: this pattern matches no values because `[!; 3]` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:374:9 | LL | [_, ..] => {} - | ^^^^^^^ + | ^^^^^^^ matches no values because `[!; 3]` is uninhabited | - = note: this pattern matches no values because `[!; 3]` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty --> $DIR/empty-types.rs:388:11 @@ -516,9 +516,9 @@ error: unreachable pattern --> $DIR/empty-types.rs:395:9 | LL | [] => {} - | -- matches all the values already + | -- matches all the relevant values LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error[E0004]: non-exhaustive patterns: `[]` not covered --> $DIR/empty-types.rs:397:11 @@ -538,35 +538,35 @@ error: unreachable pattern --> $DIR/empty-types.rs:416:9 | LL | Some(_) => {} - | ^^^^^^^ + | ^^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:421:9 | LL | Some(_a) => {} - | ^^^^^^^^ + | ^^^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:426:9 | LL | None => {} - | ---- matches all the values already + | ---- matches all the relevant values LL | // !useful, !reachable LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/empty-types.rs:431:9 | LL | None => {} - | ---- matches all the values already + | ---- matches all the relevant values LL | // !useful, !reachable LL | _a => {} - | ^^ unreachable pattern + | ^^ no value can reach this error[E0004]: non-exhaustive patterns: `&Some(!)` not covered --> $DIR/empty-types.rs:451:11 @@ -662,33 +662,33 @@ error: unreachable pattern --> $DIR/empty-types.rs:603:9 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:606:9 | LL | _x => {} - | ^^ + | ^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:609:9 | LL | _ if false => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:612:9 | LL | _x if false => {} - | ^^ + | ^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `&!` not covered --> $DIR/empty-types.rs:637:11 diff --git a/tests/ui/pattern/usefulness/empty-types.normal.stderr b/tests/ui/pattern/usefulness/empty-types.normal.stderr index 83b3989ffde..8f60dad4467 100644 --- a/tests/ui/pattern/usefulness/empty-types.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-types.normal.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/empty-types.rs:49:9 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here --> $DIR/empty-types.rs:15:9 | @@ -15,9 +15,9 @@ error: unreachable pattern --> $DIR/empty-types.rs:52:9 | LL | _x => {} - | ^^ + | ^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `&!` is non-empty --> $DIR/empty-types.rs:56:11 @@ -38,33 +38,33 @@ error: unreachable pattern --> $DIR/empty-types.rs:70:9 | LL | (_, _) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `(u32, !)` is uninhabited | - = note: this pattern matches no values because `(u32, !)` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:76:9 | LL | _ => {} - | ^ + | ^ matches no values because `(!, !)` is uninhabited | - = note: this pattern matches no values because `(!, !)` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:79:9 | LL | (_, _) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `(!, !)` is uninhabited | - = note: this pattern matches no values because `(!, !)` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:83:9 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `Ok(_)` not covered --> $DIR/empty-types.rs:87:11 @@ -89,17 +89,17 @@ error: unreachable pattern --> $DIR/empty-types.rs:94:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:99:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `Ok(1_u32..=u32::MAX)` not covered --> $DIR/empty-types.rs:96:11 @@ -151,81 +151,81 @@ error: unreachable pattern --> $DIR/empty-types.rs:112:9 | LL | _ => {} - | ^ + | ^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:115:9 | LL | Ok(_) => {} - | ^^^^^ + | ^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:118:9 | LL | Ok(_) => {} - | ^^^^^ + | ^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:119:9 | LL | _ => {} - | ^ + | ^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:122:9 | LL | Ok(_) => {} - | ^^^^^ + | ^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:123:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:132:13 | LL | _ => {} - | ^ + | ^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:135:13 | LL | _ if false => {} - | ^ + | ^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:143:13 | LL | Some(_) => {} - | ^^^^^^^ + | ^^^^^^^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:147:13 | LL | None => {} - | ---- matches all the values already + | ---- matches all the relevant values LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error[E0004]: non-exhaustive patterns: `Some(_)` not covered --> $DIR/empty-types.rs:156:15 @@ -250,73 +250,73 @@ error: unreachable pattern --> $DIR/empty-types.rs:199:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:204:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:209:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:214:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:220:13 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:281:9 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:284:9 | LL | (_, _) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `(!, !)` is uninhabited | - = note: this pattern matches no values because `(!, !)` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:287:9 | LL | Ok(_) => {} - | ^^^^^ + | ^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:288:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `Result<!, !>` is uninhabited | - = note: this pattern matches no values because `Result<!, !>` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0005]: refutable pattern in local binding --> $DIR/empty-types.rs:297:13 @@ -469,25 +469,25 @@ error: unreachable pattern --> $DIR/empty-types.rs:368:9 | LL | _ => {} - | ^ + | ^ matches no values because `[!; 3]` is uninhabited | - = note: this pattern matches no values because `[!; 3]` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:371:9 | LL | [_, _, _] => {} - | ^^^^^^^^^ + | ^^^^^^^^^ matches no values because `[!; 3]` is uninhabited | - = note: this pattern matches no values because `[!; 3]` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:374:9 | LL | [_, ..] => {} - | ^^^^^^^ + | ^^^^^^^ matches no values because `[!; 3]` is uninhabited | - = note: this pattern matches no values because `[!; 3]` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty --> $DIR/empty-types.rs:388:11 @@ -507,9 +507,9 @@ error: unreachable pattern --> $DIR/empty-types.rs:395:9 | LL | [] => {} - | -- matches all the values already + | -- matches all the relevant values LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error[E0004]: non-exhaustive patterns: `[]` not covered --> $DIR/empty-types.rs:397:11 @@ -529,35 +529,35 @@ error: unreachable pattern --> $DIR/empty-types.rs:416:9 | LL | Some(_) => {} - | ^^^^^^^ + | ^^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:421:9 | LL | Some(_a) => {} - | ^^^^^^^^ + | ^^^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:426:9 | LL | None => {} - | ---- matches all the values already + | ---- matches all the relevant values LL | // !useful, !reachable LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/empty-types.rs:431:9 | LL | None => {} - | ---- matches all the values already + | ---- matches all the relevant values LL | // !useful, !reachable LL | _a => {} - | ^^ unreachable pattern + | ^^ no value can reach this error[E0004]: non-exhaustive patterns: `&Some(_)` not covered --> $DIR/empty-types.rs:451:11 @@ -653,33 +653,33 @@ error: unreachable pattern --> $DIR/empty-types.rs:603:9 | LL | _ => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:606:9 | LL | _x => {} - | ^^ + | ^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:609:9 | LL | _ if false => {} - | ^ + | ^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/empty-types.rs:612:9 | LL | _x if false => {} - | ^^ + | ^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: `&_` not covered --> $DIR/empty-types.rs:637:11 diff --git a/tests/ui/pattern/usefulness/explain-unreachable-pats.rs b/tests/ui/pattern/usefulness/explain-unreachable-pats.rs index 44d194055d9..1cfa5212414 100644 --- a/tests/ui/pattern/usefulness/explain-unreachable-pats.rs +++ b/tests/ui/pattern/usefulness/explain-unreachable-pats.rs @@ -6,10 +6,10 @@ fn main() { match (0u8,) { (1 | 2,) => {} - //~^ NOTE matches all the values already + //~^ NOTE matches all the relevant values (2,) => {} //~^ ERROR unreachable pattern - //~| NOTE unreachable pattern + //~| NOTE no value can reach this _ => {} } @@ -20,18 +20,38 @@ fn main() { //~^ NOTE matches some of the same values (1 | 2,) => {} //~^ ERROR unreachable pattern - //~| NOTE unreachable pattern - //~| NOTE these patterns collectively make the last one unreachable + //~| NOTE no value can reach this + //~| NOTE multiple earlier patterns match some of the same values //~| NOTE collectively making this unreachable _ => {} } + match 0u8 { + 1 => {} + //~^ NOTE matches some of the same values + 2 => {} + //~^ NOTE matches some of the same values + 3 => {} + //~^ NOTE matches some of the same values + 4 => {} + //~^ NOTE matches some of the same values + 5 => {} + 6 => {} + 1 ..= 6 => {} + //~^ ERROR unreachable pattern + //~| NOTE no value can reach this + //~| NOTE multiple earlier patterns match some of the same values + //~| NOTE ...and 2 other patterns + _ => {} + } + let res: Result<(),!> = Ok(()); match res { Ok(_) => {} Err(_) => {} //~^ ERROR unreachable pattern - //~| NOTE this pattern matches no values because `!` is uninhabited + //~| NOTE matches no values because `!` is uninhabited + //~| NOTE to learn more about uninhabited types, see } #[derive(Copy, Clone)] @@ -44,22 +64,24 @@ fn main() { match (&res1, res2) { (Err(_), Err(_)) => {} //~^ ERROR unreachable pattern - //~| NOTE this pattern matches no values because `Void2` is uninhabited + //~| NOTE matches no values because `Void2` is uninhabited + //~| NOTE to learn more about uninhabited types, see _ => {} } match (res1, &res2) { (Err(_), Err(_)) => {} //~^ ERROR unreachable pattern - //~| NOTE this pattern matches no values because `Void1` is uninhabited + //~| NOTE matches no values because `Void1` is uninhabited + //~| NOTE to learn more about uninhabited types, see _ => {} } if let (0 - //~^ NOTE matches all the values already + //~^ NOTE matches all the relevant values | 0, _) = (0, 0) {} //~^ ERROR unreachable pattern - //~| NOTE unreachable pattern + //~| NOTE no value can reach this match (true, true) { (_, true) if false => {} // Guarded patterns don't cover others @@ -69,20 +91,20 @@ fn main() { //~^ NOTE matches some of the same values (_, true) => {} //~^ ERROR unreachable pattern - //~| NOTE unreachable pattern - //~| NOTE these patterns collectively make the last one unreachable + //~| NOTE no value can reach this + //~| NOTE multiple earlier patterns match some of the same values //~| NOTE collectively making this unreachable } match (true, true) { (true, _) => {} - //~^ NOTE matches all the values already + //~^ NOTE matches all the relevant values (false, _) => {} #[allow(unreachable_patterns)] (_, true) => {} // Doesn't cover below because it's already unreachable. (true, true) => {} //~^ ERROR unreachable pattern - //~| NOTE unreachable pattern + //~| NOTE no value can reach this } // Despite skipping some irrelevant cases, we still report a set of rows that covers the @@ -90,11 +112,11 @@ fn main() { match (true, true, 0) { (true, _, _) => {} (_, true, 0..10) => {} - //~^ NOTE matches all the values already + //~^ NOTE matches all the relevant values (_, true, 10..) => {} (_, true, 3) => {} //~^ ERROR unreachable pattern - //~| NOTE unreachable pattern + //~| NOTE no value can reach this _ => {} } } diff --git a/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr b/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr index 105d4f73f66..7023c2775e9 100644 --- a/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr +++ b/tests/ui/pattern/usefulness/explain-unreachable-pats.stderr @@ -2,10 +2,10 @@ error: unreachable pattern --> $DIR/explain-unreachable-pats.rs:10:9 | LL | (1 | 2,) => {} - | -------- matches all the values already + | -------- matches all the relevant values LL | LL | (2,) => {} - | ^^^^ unreachable pattern + | ^^^^ no value can reach this | note: the lint level is defined here --> $DIR/explain-unreachable-pats.rs:2:9 @@ -17,9 +17,9 @@ error: unreachable pattern --> $DIR/explain-unreachable-pats.rs:21:9 | LL | (1 | 2,) => {} - | ^^^^^^^^ unreachable pattern + | ^^^^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/explain-unreachable-pats.rs:21:9 | LL | (1,) => {} @@ -32,46 +32,70 @@ LL | (1 | 2,) => {} | ^^^^^^^^ collectively making this unreachable error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:32:9 + --> $DIR/explain-unreachable-pats.rs:40:9 + | +LL | 1 ..= 6 => {} + | ^^^^^^^ no value can reach this + | +note: multiple earlier patterns match some of the same values + --> $DIR/explain-unreachable-pats.rs:40:9 + | +LL | 1 => {} + | - matches some of the same values +LL | +LL | 2 => {} + | - matches some of the same values +LL | +LL | 3 => {} + | - matches some of the same values +LL | +LL | 4 => {} + | - matches some of the same values +... +LL | 1 ..= 6 => {} + | ^^^^^^^ ...and 2 other patterns collectively make this unreachable + +error: unreachable pattern + --> $DIR/explain-unreachable-pats.rs:51:9 | LL | Err(_) => {} - | ^^^^^^ + | ^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:45:9 + --> $DIR/explain-unreachable-pats.rs:65:9 | LL | (Err(_), Err(_)) => {} - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ matches no values because `Void2` is uninhabited | - = note: this pattern matches no values because `Void2` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:51:9 + --> $DIR/explain-unreachable-pats.rs:72:9 | LL | (Err(_), Err(_)) => {} - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ matches no values because `Void1` is uninhabited | - = note: this pattern matches no values because `Void1` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:60:11 + --> $DIR/explain-unreachable-pats.rs:82:11 | LL | if let (0 - | - matches all the values already + | - matches all the relevant values LL | LL | | 0, _) = (0, 0) {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:70:9 + --> $DIR/explain-unreachable-pats.rs:92:9 | LL | (_, true) => {} - | ^^^^^^^^^ unreachable pattern + | ^^^^^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable - --> $DIR/explain-unreachable-pats.rs:70:9 +note: multiple earlier patterns match some of the same values + --> $DIR/explain-unreachable-pats.rs:92:9 | LL | (true, _) => {} | --------- matches some of the same values @@ -83,22 +107,22 @@ LL | (_, true) => {} | ^^^^^^^^^ collectively making this unreachable error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:83:9 + --> $DIR/explain-unreachable-pats.rs:105:9 | LL | (true, _) => {} - | --------- matches all the values already + | --------- matches all the relevant values ... LL | (true, true) => {} - | ^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^ no value can reach this error: unreachable pattern - --> $DIR/explain-unreachable-pats.rs:95:9 + --> $DIR/explain-unreachable-pats.rs:117:9 | LL | (_, true, 0..10) => {} - | ---------------- matches all the values already + | ---------------- matches all the relevant values ... LL | (_, true, 3) => {} - | ^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^ no value can reach this -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/pattern/usefulness/floats.stderr b/tests/ui/pattern/usefulness/floats.stderr index d0a8841d6a8..61aaa2c7626 100644 --- a/tests/ui/pattern/usefulness/floats.stderr +++ b/tests/ui/pattern/usefulness/floats.stderr @@ -15,9 +15,9 @@ error: unreachable pattern --> $DIR/floats.rs:18:9 | LL | 0.01f16..=6.5f16 => {} - | ---------------- matches all the values already + | ---------------- matches all the relevant values LL | 0.01f16 => {} - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/floats.rs:1:9 @@ -29,117 +29,117 @@ error: unreachable pattern --> $DIR/floats.rs:19:9 | LL | 0.01f16..=6.5f16 => {} - | ---------------- matches all the values already + | ---------------- matches all the relevant values LL | 0.01f16 => {} LL | 0.02f16 => {} - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/floats.rs:20:9 | LL | 0.01f16..=6.5f16 => {} - | ---------------- matches all the values already + | ---------------- matches all the relevant values ... LL | 6.5f16 => {} - | ^^^^^^ unreachable pattern + | ^^^^^^ no value can reach this error: unreachable pattern --> $DIR/floats.rs:31:9 | LL | 0.01f32..=6.5f32 => {} - | ---------------- matches all the values already + | ---------------- matches all the relevant values LL | 0.01f32 => {} - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/floats.rs:32:9 | LL | 0.01f32..=6.5f32 => {} - | ---------------- matches all the values already + | ---------------- matches all the relevant values LL | 0.01f32 => {} LL | 0.02f32 => {} - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/floats.rs:33:9 | LL | 0.01f32..=6.5f32 => {} - | ---------------- matches all the values already + | ---------------- matches all the relevant values ... LL | 6.5f32 => {} - | ^^^^^^ unreachable pattern + | ^^^^^^ no value can reach this error: unreachable pattern --> $DIR/floats.rs:45:9 | LL | 0.01f64..=6.5f64 => {} - | ---------------- matches all the values already + | ---------------- matches all the relevant values LL | 0.005f64 => {} LL | 0.01f64 => {} - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/floats.rs:46:9 | LL | 0.01f64..=6.5f64 => {} - | ---------------- matches all the values already + | ---------------- matches all the relevant values ... LL | 0.02f64 => {} - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/floats.rs:47:9 | LL | 0.01f64..=6.5f64 => {} - | ---------------- matches all the values already + | ---------------- matches all the relevant values ... LL | 6.5f64 => {} - | ^^^^^^ unreachable pattern + | ^^^^^^ no value can reach this error: unreachable pattern --> $DIR/floats.rs:49:9 | LL | 0.01f64..=6.5f64 => {} - | ---------------- matches all the values already + | ---------------- matches all the relevant values ... LL | 1.0f64..=4.0f64 => {} - | ^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/floats.rs:62:9 | LL | 0.01f128..=6.5f128 => {} - | ------------------ matches all the values already + | ------------------ matches all the relevant values LL | 0.005f128 => {} LL | 0.01f128 => {} - | ^^^^^^^^ unreachable pattern + | ^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/floats.rs:63:9 | LL | 0.01f128..=6.5f128 => {} - | ------------------ matches all the values already + | ------------------ matches all the relevant values ... LL | 0.02f128 => {} - | ^^^^^^^^ unreachable pattern + | ^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/floats.rs:64:9 | LL | 0.01f128..=6.5f128 => {} - | ------------------ matches all the values already + | ------------------ matches all the relevant values ... LL | 6.5f128 => {} - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/floats.rs:66:9 | LL | 0.01f128..=6.5f128 => {} - | ------------------ matches all the values already + | ------------------ matches all the relevant values ... LL | 1.0f128..=4.0f128 => {} - | ^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^ no value can reach this error: aborting due to 15 previous errors diff --git a/tests/ui/pattern/usefulness/impl-trait.stderr b/tests/ui/pattern/usefulness/impl-trait.stderr index 92932e48538..34b157f0fc4 100644 --- a/tests/ui/pattern/usefulness/impl-trait.stderr +++ b/tests/ui/pattern/usefulness/impl-trait.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/impl-trait.rs:16:13 | LL | _ => {} - | ^ + | ^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here --> $DIR/impl-trait.rs:4:9 | @@ -15,49 +15,49 @@ error: unreachable pattern --> $DIR/impl-trait.rs:30:13 | LL | _ => {} - | ^ + | ^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/impl-trait.rs:44:13 | LL | Some(_) => {} - | ^^^^^^^ + | ^^^^^^^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/impl-trait.rs:48:13 | LL | None => {} - | ---- matches all the values already + | ---- matches all the relevant values LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/impl-trait.rs:58:13 | LL | Some(_) => {} - | ^^^^^^^ + | ^^^^^^^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/impl-trait.rs:62:13 | LL | None => {} - | ---- matches all the values already + | ---- matches all the relevant values LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/impl-trait.rs:75:9 | LL | _ => {} - | ^ + | ^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/impl-trait.rs:85:9 @@ -65,23 +65,23 @@ error: unreachable pattern LL | _ => {} | - matches any value LL | Some((a, b)) => {} - | ^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/impl-trait.rs:93:13 | LL | _ => {} - | ^ + | ^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/impl-trait.rs:104:9 | LL | Some((a, b)) => {} - | ------------ matches all the values already + | ------------ matches all the relevant values LL | Some((mut x, mut y)) => { - | ^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/impl-trait.rs:123:13 @@ -89,23 +89,23 @@ error: unreachable pattern LL | _ => {} | - matches any value LL | Rec { n: 0, w: Some(Rec { n: 0, w: _ }) } => {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/impl-trait.rs:137:13 | LL | _ => {} - | ^ + | ^ matches no values because `SecretelyVoid` is uninhabited | - = note: this pattern matches no values because `SecretelyVoid` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/impl-trait.rs:150:13 | LL | _ => {} - | ^ + | ^ matches no values because `SecretelyDoubleVoid` is uninhabited | - = note: this pattern matches no values because `SecretelyDoubleVoid` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error[E0004]: non-exhaustive patterns: type `impl Copy` is non-empty --> $DIR/impl-trait.rs:22:11 diff --git a/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr b/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr index 5d86007a853..0d495bcbec1 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/reachability.rs:18:17 | LL | m!(0u8, 42, 42); - | -- ^^ unreachable pattern + | -- ^^ no value can reach this | | - | matches all the values already + | matches all the relevant values | note: the lint level is defined here --> $DIR/reachability.rs:3:9 @@ -16,129 +16,129 @@ error: unreachable pattern --> $DIR/reachability.rs:22:22 | LL | m!(0u8, 20..=30, 20); - | ------- ^^ unreachable pattern + | ------- ^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:23:22 | LL | m!(0u8, 20..=30, 21); - | ------- ^^ unreachable pattern + | ------- ^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:24:22 | LL | m!(0u8, 20..=30, 25); - | ------- ^^ unreachable pattern + | ------- ^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:25:22 | LL | m!(0u8, 20..=30, 29); - | ------- ^^ unreachable pattern + | ------- ^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:26:22 | LL | m!(0u8, 20..=30, 30); - | ------- ^^ unreachable pattern + | ------- ^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:29:21 | LL | m!(0u8, 20..30, 20); - | ------ ^^ unreachable pattern + | ------ ^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:30:21 | LL | m!(0u8, 20..30, 21); - | ------ ^^ unreachable pattern + | ------ ^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:31:21 | LL | m!(0u8, 20..30, 25); - | ------ ^^ unreachable pattern + | ------ ^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:32:21 | LL | m!(0u8, 20..30, 29); - | ------ ^^ unreachable pattern + | ------ ^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:36:22 | LL | m!(0u8, 20..=30, 20..=30); - | ------- ^^^^^^^ unreachable pattern + | ------- ^^^^^^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:37:22 | LL | m!(0u8, 20.. 30, 20.. 30); - | ------- ^^^^^^^ unreachable pattern + | ------- ^^^^^^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:38:22 | LL | m!(0u8, 20..=30, 20.. 30); - | ------- ^^^^^^^ unreachable pattern + | ------- ^^^^^^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:40:22 | LL | m!(0u8, 20..=30, 21..=30); - | ------- ^^^^^^^ unreachable pattern + | ------- ^^^^^^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:41:22 | LL | m!(0u8, 20..=30, 20..=29); - | ------- ^^^^^^^ unreachable pattern + | ------- ^^^^^^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:43:24 | LL | m!('a', 'A'..='z', 'a'..='z'); - | --------- ^^^^^^^^^ unreachable pattern + | --------- ^^^^^^^^^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/reachability.rs:50:9 | LL | 5..=8 => {}, - | ^^^^^ unreachable pattern + | ^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/reachability.rs:50:9 | LL | 5 => {}, @@ -156,9 +156,9 @@ error: unreachable pattern --> $DIR/reachability.rs:56:9 | LL | 5..15 => {}, - | ^^^^^ unreachable pattern + | ^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/reachability.rs:56:9 | LL | 0..10 => {}, @@ -172,9 +172,9 @@ error: unreachable pattern --> $DIR/reachability.rs:63:9 | LL | 5..25 => {}, - | ^^^^^ unreachable pattern + | ^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/reachability.rs:63:9 | LL | 0..10 => {}, @@ -190,9 +190,9 @@ error: unreachable pattern --> $DIR/reachability.rs:71:9 | LL | 5..25 => {}, - | ^^^^^ unreachable pattern + | ^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/reachability.rs:71:9 | LL | 0..10 => {}, @@ -210,9 +210,9 @@ error: unreachable pattern --> $DIR/reachability.rs:77:9 | LL | 5..15 => {}, - | ^^^^^ unreachable pattern + | ^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/reachability.rs:77:9 | LL | 0..10 => {}, @@ -228,15 +228,15 @@ error: unreachable pattern LL | _ => {}, | - matches any value LL | '\u{D7FF}'..='\u{E000}' => {}, - | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/reachability.rs:89:9 | LL | '\u{D7FF}'..='\u{E000}' => {}, - | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/reachability.rs:89:9 | LL | '\u{0}'..='\u{D7FF}' => {}, @@ -250,18 +250,18 @@ error: unreachable pattern --> $DIR/reachability.rs:105:9 | LL | &42 => {} - | --- matches all the values already + | --- matches all the relevant values LL | &FOO => {} - | ^^^^ unreachable pattern + | ^^^^ no value can reach this error: unreachable pattern --> $DIR/reachability.rs:106:9 | LL | &42 => {} - | --- matches all the values already + | --- matches all the relevant values LL | &FOO => {} LL | BAR => {} - | ^^^ unreachable pattern + | ^^^ no value can reach this error: aborting due to 25 previous errors diff --git a/tests/ui/pattern/usefulness/issue-12116.stderr b/tests/ui/pattern/usefulness/issue-12116.stderr index b2c2be97563..5929b81f6c2 100644 --- a/tests/ui/pattern/usefulness/issue-12116.stderr +++ b/tests/ui/pattern/usefulness/issue-12116.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/issue-12116.rs:15:9 | LL | &IntList::Cons(val, box ref next_list) => tail(next_list), - | -------------------------------------- matches all the values already + | -------------------------------------- matches all the relevant values LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, Box::new(IntList::Nil)), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/issue-12116.rs:4:9 diff --git a/tests/ui/pattern/usefulness/issue-12369.stderr b/tests/ui/pattern/usefulness/issue-12369.stderr index 7754cbc2484..fb6f89379f8 100644 --- a/tests/ui/pattern/usefulness/issue-12369.stderr +++ b/tests/ui/pattern/usefulness/issue-12369.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/issue-12369.rs:9:9 | LL | &[10,a, ref rest @ ..] => 10 - | ^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/issue-12369.rs:9:9 | LL | &[a,b,c] => 3, diff --git a/tests/ui/pattern/usefulness/issue-13727.stderr b/tests/ui/pattern/usefulness/issue-13727.stderr index ca8533b33a4..fdba8c87015 100644 --- a/tests/ui/pattern/usefulness/issue-13727.stderr +++ b/tests/ui/pattern/usefulness/issue-13727.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/issue-13727.rs:7:5 | LL | 256 => print!("0b1110\n"), - | --- matches all the values already + | --- matches all the relevant values LL | 512 => print!("0b1111\n"), - | ^^^ unreachable pattern + | ^^^ no value can reach this | note: the lint level is defined here --> $DIR/issue-13727.rs:2:9 diff --git a/tests/ui/pattern/usefulness/issue-30240-b.stderr b/tests/ui/pattern/usefulness/issue-30240-b.stderr index 749515fc94b..4805083c129 100644 --- a/tests/ui/pattern/usefulness/issue-30240-b.stderr +++ b/tests/ui/pattern/usefulness/issue-30240-b.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/issue-30240-b.rs:12:9 | LL | "hello" => {} - | ------- matches all the values already + | ------- matches all the relevant values LL | "hello" => {} - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/issue-30240-b.rs:1:9 diff --git a/tests/ui/pattern/usefulness/issue-31221.stderr b/tests/ui/pattern/usefulness/issue-31221.stderr index 596f4d8096d..e198a9397ee 100644 --- a/tests/ui/pattern/usefulness/issue-31221.stderr +++ b/tests/ui/pattern/usefulness/issue-31221.stderr @@ -4,7 +4,7 @@ error: unreachable pattern LL | Var3 => (), | ---- matches any value LL | Var2 => (), - | ^^^^ unreachable pattern + | ^^^^ no value can reach this | note: the lint level is defined here --> $DIR/issue-31221.rs:4:9 @@ -18,15 +18,15 @@ error: unreachable pattern LL | &Var3 => (), | ----- matches any value LL | &Var2 => (), - | ^^^^^ unreachable pattern + | ^^^^^ no value can reach this error: unreachable pattern --> $DIR/issue-31221.rs:31:9 | LL | anything => () - | ^^^^^^^^ unreachable pattern + | ^^^^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/issue-31221.rs:31:9 | LL | (Var1, b) => (), diff --git a/tests/ui/pattern/usefulness/issue-57472.stderr b/tests/ui/pattern/usefulness/issue-57472.stderr index 68b5b7cb791..5a35dbd7f93 100644 --- a/tests/ui/pattern/usefulness/issue-57472.stderr +++ b/tests/ui/pattern/usefulness/issue-57472.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/issue-57472.rs:15:13 | LL | Punned { foo: [_], .. } => println!("foo"), - | ----------------------- matches all the values already + | ----------------------- matches all the relevant values LL | Punned { bar: [_], .. } => println!("bar"), - | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/issue-57472.rs:2:9 @@ -16,9 +16,9 @@ error: unreachable pattern --> $DIR/issue-57472.rs:32:17 | LL | Punned { foo: [_] } => println!("foo"), - | ------------------- matches all the values already + | ------------------- matches all the relevant values LL | Punned { bar: [_] } => println!("bar"), - | ^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^ no value can reach this error: aborting due to 2 previous errors diff --git a/tests/ui/pattern/usefulness/match-arm-statics.stderr b/tests/ui/pattern/usefulness/match-arm-statics.stderr index b6f2b47047d..d5b8a4e6d79 100644 --- a/tests/ui/pattern/usefulness/match-arm-statics.stderr +++ b/tests/ui/pattern/usefulness/match-arm-statics.stderr @@ -2,10 +2,10 @@ error: unreachable pattern --> $DIR/match-arm-statics.rs:25:9 | LL | TRUE_TRUE => (), - | --------- matches all the values already + | --------- matches all the relevant values ... LL | (true, true) => () - | ^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/match-arm-statics.rs:2:9 @@ -17,18 +17,18 @@ error: unreachable pattern --> $DIR/match-arm-statics.rs:40:9 | LL | Some(Some(EAST)) => (), - | ---------------- matches all the values already + | ---------------- matches all the relevant values ... LL | Some(Some(East)) => (), - | ^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/match-arm-statics.rs:60:9 | LL | Foo { bar: Some(EAST), baz: NewBool(false) } => () - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/match-arm-statics.rs:60:9 | LL | Foo { bar: _, baz: NEW_FALSE } => (), diff --git a/tests/ui/pattern/usefulness/match-byte-array-patterns.stderr b/tests/ui/pattern/usefulness/match-byte-array-patterns.stderr index 39675e2bdd4..79a0fb9a8dd 100644 --- a/tests/ui/pattern/usefulness/match-byte-array-patterns.stderr +++ b/tests/ui/pattern/usefulness/match-byte-array-patterns.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:8:9 | LL | b"AAAA" => {}, - | ------- matches all the values already + | ------- matches all the relevant values LL | &[0x41, 0x41, 0x41, 0x41] => {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/match-byte-array-patterns.rs:1:9 @@ -16,57 +16,57 @@ error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:14:9 | LL | &[0x41, 0x41, 0x41, 0x41] => {} - | ------------------------- matches all the values already + | ------------------------- matches all the relevant values LL | b"AAAA" => {}, - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:20:9 | LL | &[_, 0x41, 0x41, 0x41] => {}, - | ---------------------- matches all the values already + | ---------------------- matches all the relevant values LL | b"AAAA" => {}, - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:26:9 | LL | &[0x41, .., 0x41] => {} - | ----------------- matches all the values already + | ----------------- matches all the relevant values LL | b"AAAA" => {}, - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:34:9 | LL | b"AAAA" => {}, - | ------- matches all the values already + | ------- matches all the relevant values LL | &[0x41, 0x41, 0x41, 0x41] => {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:40:9 | LL | &[0x41, 0x41, 0x41, 0x41] => {} - | ------------------------- matches all the values already + | ------------------------- matches all the relevant values LL | b"AAAA" => {}, - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:46:9 | LL | &[_, 0x41, 0x41, 0x41] => {}, - | ---------------------- matches all the values already + | ---------------------- matches all the relevant values LL | b"AAAA" => {}, - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/match-byte-array-patterns.rs:52:9 | LL | &[0x41, .., 0x41] => {} - | ----------------- matches all the values already + | ----------------- matches all the relevant values LL | b"AAAA" => {}, - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: aborting due to 8 previous errors diff --git a/tests/ui/pattern/usefulness/match-ref-ice.stderr b/tests/ui/pattern/usefulness/match-ref-ice.stderr index 9c5af47cc1e..c5f8a95b16b 100644 --- a/tests/ui/pattern/usefulness/match-ref-ice.stderr +++ b/tests/ui/pattern/usefulness/match-ref-ice.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/match-ref-ice.rs:13:9 | LL | [1, ref _madoka, 3] => (), - | ------------------- matches all the values already + | ------------------- matches all the relevant values LL | [1, 2, 3] => (), - | ^^^^^^^^^ unreachable pattern + | ^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/match-ref-ice.rs:1:9 diff --git a/tests/ui/pattern/usefulness/match-vec-fixed.stderr b/tests/ui/pattern/usefulness/match-vec-fixed.stderr index 04507a22856..b0b8cdf887a 100644 --- a/tests/ui/pattern/usefulness/match-vec-fixed.stderr +++ b/tests/ui/pattern/usefulness/match-vec-fixed.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/match-vec-fixed.rs:7:9 | LL | [_, _, _] => {} - | --------- matches all the values already + | --------- matches all the relevant values LL | [_, _, _] => {} - | ^^^^^^^^^ unreachable pattern + | ^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/match-vec-fixed.rs:1:9 @@ -16,9 +16,9 @@ error: unreachable pattern --> $DIR/match-vec-fixed.rs:11:9 | LL | [_, 1, _] => {} - | --------- matches all the values already + | --------- matches all the relevant values LL | [_, 1, _] => {} - | ^^^^^^^^^ unreachable pattern + | ^^^^^^^^^ no value can reach this error: aborting due to 2 previous errors diff --git a/tests/ui/pattern/usefulness/match-vec-unreachable.stderr b/tests/ui/pattern/usefulness/match-vec-unreachable.stderr index 865f5b319a7..6ed8f0019fe 100644 --- a/tests/ui/pattern/usefulness/match-vec-unreachable.stderr +++ b/tests/ui/pattern/usefulness/match-vec-unreachable.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/match-vec-unreachable.rs:8:9 | LL | [a, (2, 3), _] => (), - | -------------- matches all the values already + | -------------- matches all the relevant values LL | [(1, 2), (2, 3), b] => (), - | ^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/match-vec-unreachable.rs:1:9 @@ -16,17 +16,17 @@ error: unreachable pattern --> $DIR/match-vec-unreachable.rs:18:9 | LL | [ref a, _, _, ..] => { println!("{}", a); } - | ----------------- matches all the values already + | ----------------- matches all the relevant values LL | [_, _, _, _, _] => { } - | ^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/match-vec-unreachable.rs:26:9 | LL | ['a', 'b', 'c', ref _tail @ ..] => {} - | ------------------------------- matches all the values already + | ------------------------------- matches all the relevant values LL | ['a', 'b', 'c'] => {} - | ^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^ no value can reach this error: aborting due to 3 previous errors diff --git a/tests/ui/pattern/usefulness/slice-pattern-const-2.stderr b/tests/ui/pattern/usefulness/slice-pattern-const-2.stderr index 12db48590a4..a6031eaa730 100644 --- a/tests/ui/pattern/usefulness/slice-pattern-const-2.stderr +++ b/tests/ui/pattern/usefulness/slice-pattern-const-2.stderr @@ -2,10 +2,10 @@ error: unreachable pattern --> $DIR/slice-pattern-const-2.rs:9:9 | LL | MAGIC_TEST => (), - | ---------- matches all the values already + | ---------- matches all the relevant values LL | [0x00, 0x00, 0x00, 0x00] => (), LL | [4, 5, 6, 7] => (), - | ^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/slice-pattern-const-2.rs:1:9 @@ -17,25 +17,25 @@ error: unreachable pattern --> $DIR/slice-pattern-const-2.rs:15:9 | LL | MAGIC_TEST => (), - | ---------- matches all the values already + | ---------- matches all the relevant values LL | [4, 5, 6, 7] => (), - | ^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/slice-pattern-const-2.rs:21:9 | LL | [4, 5, 6, 7] => (), - | ------------ matches all the values already + | ------------ matches all the relevant values LL | MAGIC_TEST => (), - | ^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/slice-pattern-const-2.rs:28:9 | LL | [4] => (), - | --- matches all the values already + | --- matches all the relevant values LL | FOO => (), - | ^^^ unreachable pattern + | ^^^ no value can reach this error: aborting due to 4 previous errors diff --git a/tests/ui/pattern/usefulness/slice-pattern-const-3.stderr b/tests/ui/pattern/usefulness/slice-pattern-const-3.stderr index 5a66799d9c9..bbec9f23602 100644 --- a/tests/ui/pattern/usefulness/slice-pattern-const-3.stderr +++ b/tests/ui/pattern/usefulness/slice-pattern-const-3.stderr @@ -2,10 +2,10 @@ error: unreachable pattern --> $DIR/slice-pattern-const-3.rs:9:9 | LL | MAGIC_TEST => (), - | ---------- matches all the values already + | ---------- matches all the relevant values LL | ["0x00", "0x00", "0x00", "0x00"] => (), LL | ["4", "5", "6", "7"] => (), - | ^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/slice-pattern-const-3.rs:1:9 @@ -17,25 +17,25 @@ error: unreachable pattern --> $DIR/slice-pattern-const-3.rs:15:9 | LL | MAGIC_TEST => (), - | ---------- matches all the values already + | ---------- matches all the relevant values LL | ["4", "5", "6", "7"] => (), - | ^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/slice-pattern-const-3.rs:21:9 | LL | ["4", "5", "6", "7"] => (), - | -------------------- matches all the values already + | -------------------- matches all the relevant values LL | MAGIC_TEST => (), - | ^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/slice-pattern-const-3.rs:28:9 | LL | ["boo"] => (), - | ------- matches all the values already + | ------- matches all the relevant values LL | FOO => (), - | ^^^ unreachable pattern + | ^^^ no value can reach this error: aborting due to 4 previous errors diff --git a/tests/ui/pattern/usefulness/slice-pattern-const.stderr b/tests/ui/pattern/usefulness/slice-pattern-const.stderr index 87a85acc4c5..09bbee73577 100644 --- a/tests/ui/pattern/usefulness/slice-pattern-const.stderr +++ b/tests/ui/pattern/usefulness/slice-pattern-const.stderr @@ -2,10 +2,10 @@ error: unreachable pattern --> $DIR/slice-pattern-const.rs:9:9 | LL | MAGIC_TEST => (), - | ---------- matches all the values already + | ---------- matches all the relevant values LL | [0x00, 0x00, 0x00, 0x00] => (), LL | [84, 69, 83, 84] => (), - | ^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/slice-pattern-const.rs:1:9 @@ -17,67 +17,67 @@ error: unreachable pattern --> $DIR/slice-pattern-const.rs:15:9 | LL | MAGIC_TEST => (), - | ---------- matches all the values already + | ---------- matches all the relevant values LL | [84, 69, 83, 84] => (), - | ^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/slice-pattern-const.rs:21:9 | LL | [84, 69, 83, 84] => (), - | ---------------- matches all the values already + | ---------------- matches all the relevant values LL | MAGIC_TEST => (), - | ^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/slice-pattern-const.rs:28:9 | LL | [4] => (), - | --- matches all the values already + | --- matches all the relevant values LL | FOO => (), - | ^^^ unreachable pattern + | ^^^ no value can reach this error: unreachable pattern --> $DIR/slice-pattern-const.rs:35:9 | LL | [4] => (), - | --- matches all the values already + | --- matches all the relevant values LL | BAR => (), - | ^^^ unreachable pattern + | ^^^ no value can reach this error: unreachable pattern --> $DIR/slice-pattern-const.rs:43:9 | LL | [] => (), - | -- matches all the values already + | -- matches all the relevant values LL | BOO => (), - | ^^^ unreachable pattern + | ^^^ no value can reach this error: unreachable pattern --> $DIR/slice-pattern-const.rs:44:9 | LL | [] => (), - | -- matches all the values already + | -- matches all the relevant values LL | BOO => (), LL | b"" => (), - | ^^^ unreachable pattern + | ^^^ no value can reach this error: unreachable pattern --> $DIR/slice-pattern-const.rs:45:9 | LL | [] => (), - | -- matches all the values already + | -- matches all the relevant values ... LL | _ => (), - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/slice-pattern-const.rs:51:9 | LL | CONST1 => {} - | ------ matches all the values already + | ------ matches all the relevant values LL | [true] => {} - | ^^^^^^ unreachable pattern + | ^^^^^^ no value can reach this error: aborting due to 9 previous errors diff --git a/tests/ui/pattern/usefulness/slice-patterns-reachability.stderr b/tests/ui/pattern/usefulness/slice-patterns-reachability.stderr index 40fbb00de1f..d45779f09a5 100644 --- a/tests/ui/pattern/usefulness/slice-patterns-reachability.stderr +++ b/tests/ui/pattern/usefulness/slice-patterns-reachability.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/slice-patterns-reachability.rs:8:9 | LL | [true, ..] => {} - | ---------- matches all the values already + | ---------- matches all the relevant values LL | [true, ..] => {} - | ^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/slice-patterns-reachability.rs:1:9 @@ -16,44 +16,44 @@ error: unreachable pattern --> $DIR/slice-patterns-reachability.rs:9:9 | LL | [true, ..] => {} - | ---------- matches all the values already + | ---------- matches all the relevant values LL | [true, ..] => {} LL | [true] => {} - | ^^^^^^ unreachable pattern + | ^^^^^^ no value can reach this error: unreachable pattern --> $DIR/slice-patterns-reachability.rs:14:9 | LL | [.., true] => {} - | ---------- matches all the values already + | ---------- matches all the relevant values LL | [.., true] => {} - | ^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/slice-patterns-reachability.rs:15:9 | LL | [.., true] => {} - | ---------- matches all the values already + | ---------- matches all the relevant values LL | [.., true] => {} LL | [true] => {} - | ^^^^^^ unreachable pattern + | ^^^^^^ no value can reach this error: unreachable pattern --> $DIR/slice-patterns-reachability.rs:20:9 | LL | [false, .., true] => {} - | ----------------- matches all the values already + | ----------------- matches all the relevant values LL | [false, .., true] => {} - | ^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/slice-patterns-reachability.rs:21:9 | LL | [false, .., true] => {} - | ----------------- matches all the values already + | ----------------- matches all the relevant values LL | [false, .., true] => {} LL | [false, true] => {} - | ^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^ no value can reach this error: aborting due to 6 previous errors diff --git a/tests/ui/pattern/usefulness/struct-pattern-match-useless.stderr b/tests/ui/pattern/usefulness/struct-pattern-match-useless.stderr index cc29c42e4d6..502fa2deda9 100644 --- a/tests/ui/pattern/usefulness/struct-pattern-match-useless.stderr +++ b/tests/ui/pattern/usefulness/struct-pattern-match-useless.stderr @@ -4,7 +4,7 @@ error: unreachable pattern LL | Foo { x: _x, y: _y } => (), | -------------------- matches any value LL | Foo { .. } => () - | ^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/struct-pattern-match-useless.rs:1:9 diff --git a/tests/ui/pattern/usefulness/top-level-alternation.stderr b/tests/ui/pattern/usefulness/top-level-alternation.stderr index ad846f23155..7fc03143bc3 100644 --- a/tests/ui/pattern/usefulness/top-level-alternation.stderr +++ b/tests/ui/pattern/usefulness/top-level-alternation.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/top-level-alternation.rs:4:23 | LL | while let 0..=2 | 1 = 0 {} - | ----- ^ unreachable pattern + | ----- ^ no value can reach this | | - | matches all the values already + | matches all the relevant values | note: the lint level is defined here --> $DIR/top-level-alternation.rs:1:9 @@ -16,66 +16,66 @@ error: unreachable pattern --> $DIR/top-level-alternation.rs:5:20 | LL | if let 0..=2 | 1 = 0 {} - | ----- ^ unreachable pattern + | ----- ^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: unreachable pattern --> $DIR/top-level-alternation.rs:9:15 | LL | 0 - | - matches all the values already + | - matches all the relevant values LL | | 0 => {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/top-level-alternation.rs:14:15 | LL | Some(0) - | ------- matches all the values already + | ------- matches all the relevant values LL | | Some(0) => {} - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/top-level-alternation.rs:19:9 | LL | (0, _) | (_, 0) => {} - | --------------- matches all the values already + | --------------- matches all the relevant values LL | (0, 0) => {} - | ^^^^^^ unreachable pattern + | ^^^^^^ no value can reach this error: unreachable pattern --> $DIR/top-level-alternation.rs:39:9 | LL | None | Some(_) => {} - | -------------- matches all the values already + | -------------- matches all the relevant values LL | _ => {} - | ^ unreachable pattern + | ^ no value can reach this error: unreachable pattern --> $DIR/top-level-alternation.rs:43:9 | LL | None | Some(_) => {} - | -------------- matches all the values already + | -------------- matches all the relevant values LL | Some(_) => {} - | ^^^^^^^ unreachable pattern + | ^^^^^^^ no value can reach this error: unreachable pattern --> $DIR/top-level-alternation.rs:44:9 | LL | None | Some(_) => {} - | -------------- matches all the values already + | -------------- matches all the relevant values LL | Some(_) => {} LL | None => {} - | ^^^^ unreachable pattern + | ^^^^ no value can reach this error: unreachable pattern --> $DIR/top-level-alternation.rs:49:9 | LL | None | Some(_) => {} - | ^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^ no value can reach this | -note: these patterns collectively make the last one unreachable +note: multiple earlier patterns match some of the same values --> $DIR/top-level-alternation.rs:49:9 | LL | Some(_) => {} @@ -89,17 +89,17 @@ error: unreachable pattern --> $DIR/top-level-alternation.rs:53:9 | LL | 1 | 2 => {}, - | ----- matches all the values already + | ----- matches all the relevant values LL | 1..=2 => {}, - | ^^^^^ unreachable pattern + | ^^^^^ no value can reach this error: unreachable pattern --> $DIR/top-level-alternation.rs:56:14 | LL | let (0 | 0) = 0 else { return }; - | - ^ unreachable pattern + | - ^ no value can reach this | | - | matches all the values already + | matches all the relevant values error: aborting due to 11 previous errors diff --git a/tests/ui/reachable/unreachable-arm.stderr b/tests/ui/reachable/unreachable-arm.stderr index 79627404030..50c29b30c69 100644 --- a/tests/ui/reachable/unreachable-arm.stderr +++ b/tests/ui/reachable/unreachable-arm.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/unreachable-arm.rs:11:9 | LL | Foo::B(_) | Foo::A(box _, 1) => { } - | ---------------------------- matches all the values already + | ---------------------------- matches all the relevant values LL | Foo::A(_, 1) => { } - | ^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/unreachable-arm.rs:4:9 diff --git a/tests/ui/reachable/unreachable-loop-patterns.stderr b/tests/ui/reachable/unreachable-loop-patterns.stderr index 9b7c2ba4acd..03959ac1606 100644 --- a/tests/ui/reachable/unreachable-loop-patterns.stderr +++ b/tests/ui/reachable/unreachable-loop-patterns.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/unreachable-loop-patterns.rs:16:9 | LL | for _ in unimplemented!() as Void {} - | ^ + | ^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here --> $DIR/unreachable-loop-patterns.rs:3:9 | diff --git a/tests/ui/reachable/unreachable-try-pattern.stderr b/tests/ui/reachable/unreachable-try-pattern.stderr index bc1a6fffda6..b082bc11603 100644 --- a/tests/ui/reachable/unreachable-try-pattern.stderr +++ b/tests/ui/reachable/unreachable-try-pattern.stderr @@ -17,9 +17,9 @@ warning: unreachable pattern --> $DIR/unreachable-try-pattern.rs:19:24 | LL | let y = (match x { Ok(n) => Ok(n as u32), Err(e) => Err(e) })?; - | ^^^^^ + | ^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here --> $DIR/unreachable-try-pattern.rs:4:9 | @@ -30,9 +30,9 @@ warning: unreachable pattern --> $DIR/unreachable-try-pattern.rs:30:40 | LL | let y = (match x { Ok(n) => Ok(n), Err(e) => Err(e) })?; - | ^^^^^^ + | ^^^^^^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types warning: 3 warnings emitted diff --git a/tests/ui/regions/explicit-static-bound-on-trait.rs b/tests/ui/regions/explicit-static-bound-on-trait.rs new file mode 100644 index 00000000000..835da34d1bb --- /dev/null +++ b/tests/ui/regions/explicit-static-bound-on-trait.rs @@ -0,0 +1,13 @@ +struct Hello<'a> { + value: Box<dyn std::any::Any + 'a>, + //~^ ERROR lifetime bound not satisfied +} + +impl<'a> Hello<'a> { + fn new<T: 'a>(value: T) -> Self { + Self { value: Box::new(value) } + //~^ ERROR the parameter type `T` may not live long enough + } +} + +fn main() {} diff --git a/tests/ui/regions/explicit-static-bound-on-trait.stderr b/tests/ui/regions/explicit-static-bound-on-trait.stderr new file mode 100644 index 00000000000..30d39c6e86e --- /dev/null +++ b/tests/ui/regions/explicit-static-bound-on-trait.stderr @@ -0,0 +1,32 @@ +error[E0478]: lifetime bound not satisfied + --> $DIR/explicit-static-bound-on-trait.rs:2:12 + | +LL | value: Box<dyn std::any::Any + 'a>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'a` as defined here + --> $DIR/explicit-static-bound-on-trait.rs:1:14 + | +LL | struct Hello<'a> { + | ^^ +note: but lifetime parameter must outlive the static lifetime + --> $SRC_DIR/core/src/any.rs:LL:COL + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/explicit-static-bound-on-trait.rs:8:23 + | +LL | Self { value: Box::new(value) } + | ^^^^^^^^^^^^^^^ + | | + | the parameter type `T` must be valid for the static lifetime... + | ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn new<T: 'a + 'static>(value: T) -> Self { + | +++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0310, E0478. +For more information about an error, try `rustc --explain E0310`. diff --git a/tests/ui/repr/conflicting-repr-hints.stderr b/tests/ui/repr/conflicting-repr-hints.stderr index 4dcd8f4fc28..fbfa69e7fb1 100644 --- a/tests/ui/repr/conflicting-repr-hints.stderr +++ b/tests/ui/repr/conflicting-repr-hints.stderr @@ -81,3 +81,25 @@ error: aborting due to 12 previous errors Some errors have detailed explanations: E0566, E0587, E0634. For more information about an error, try `rustc --explain E0566`. +Future incompatibility report: Future breakage diagnostic: +error[E0566]: conflicting representation hints + --> $DIR/conflicting-repr-hints.rs:13:8 + | +LL | #[repr(C, u64)] + | ^ ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585> + = note: `#[deny(conflicting_repr_hints)]` on by default + +Future breakage diagnostic: +error[E0566]: conflicting representation hints + --> $DIR/conflicting-repr-hints.rs:19:8 + | +LL | #[repr(u32, u64)] + | ^^^ ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585> + = note: `#[deny(conflicting_repr_hints)]` on by default + diff --git a/tests/ui/repr/repr-transparent-non-exhaustive-transparent-in-prose.rs b/tests/ui/repr/repr-transparent-non-exhaustive-transparent-in-prose.rs new file mode 100644 index 00000000000..6ab34719f06 --- /dev/null +++ b/tests/ui/repr/repr-transparent-non-exhaustive-transparent-in-prose.rs @@ -0,0 +1,25 @@ +//@ check-pass + +#![feature(sync_unsafe_cell)] +#![allow(unused)] +#![deny(repr_transparent_external_private_fields)] + +// https://github.com/rust-lang/rust/issues/129470 + +struct ZST; + +#[repr(transparent)] +struct TransparentWithManuallyDropZST { + value: i32, + md: std::mem::ManuallyDrop<ZST>, + mu: std::mem::MaybeUninit<ZST>, + p: std::pin::Pin<ZST>, + pd: std::marker::PhantomData<ZST>, + pp: std::marker::PhantomPinned, + c: std::cell::Cell<ZST>, + uc: std::cell::UnsafeCell<ZST>, + suc: std::cell::SyncUnsafeCell<ZST>, + zst: ZST, +} + +fn main() {} diff --git a/tests/ui/resolve/local-shadows-inner-generic.rs b/tests/ui/resolve/local-shadows-inner-generic.rs new file mode 100644 index 00000000000..d9145b9fe2c --- /dev/null +++ b/tests/ui/resolve/local-shadows-inner-generic.rs @@ -0,0 +1,8 @@ +//@ check-pass + +#![allow(non_camel_case_types)] + +pub fn main() { + let a = 1; + struct Foo<a> { field: a, }; +} diff --git a/tests/ui/return/return-from-residual-sugg-issue-125997.fixed b/tests/ui/return/return-from-residual-sugg-issue-125997.fixed index a5a13399825..43a9907a9b4 100644 --- a/tests/ui/return/return-from-residual-sugg-issue-125997.fixed +++ b/tests/ui/return/return-from-residual-sugg-issue-125997.fixed @@ -9,7 +9,6 @@ use std::io::prelude::*; fn test1() -> Result<(), Box<dyn std::error::Error>> { let mut _file = File::create("foo.txt")?; //~^ ERROR the `?` operator can only be used in a function - Ok(()) } @@ -17,7 +16,6 @@ fn test2() -> Result<(), Box<dyn std::error::Error>> { let mut _file = File::create("foo.txt")?; //~^ ERROR the `?` operator can only be used in a function println!(); - Ok(()) } @@ -27,9 +25,8 @@ macro_rules! mac { let mut _file = File::create("foo.txt")?; //~^ ERROR the `?` operator can only be used in a function println!(); - - Ok(()) -} + Ok(()) + } }; } @@ -39,23 +36,20 @@ impl A { fn test4(&self) -> Result<(), Box<dyn std::error::Error>> { let mut _file = File::create("foo.txt")?; //~^ ERROR the `?` operator can only be used in a method - - Ok(()) -} + Ok(()) + } fn test5(&self) -> Result<(), Box<dyn std::error::Error>> { let mut _file = File::create("foo.txt")?; //~^ ERROR the `?` operator can only be used in a method println!(); - - Ok(()) -} + Ok(()) + } } fn main() -> Result<(), Box<dyn std::error::Error>> { let mut _file = File::create("foo.txt")?; //~^ ERROR the `?` operator can only be used in a function mac!(); - Ok(()) } diff --git a/tests/ui/return/return-from-residual-sugg-issue-125997.stderr b/tests/ui/return/return-from-residual-sugg-issue-125997.stderr index a59f38c2ec6..e22f33fd242 100644 --- a/tests/ui/return/return-from-residual-sugg-issue-125997.stderr +++ b/tests/ui/return/return-from-residual-sugg-issue-125997.stderr @@ -12,9 +12,7 @@ help: consider adding return type LL ~ fn test1() -> Result<(), Box<dyn std::error::Error>> { LL | let mut _file = File::create("foo.txt")?; LL | -LL + LL + Ok(()) -LL + } | error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) @@ -32,9 +30,7 @@ LL ~ fn test2() -> Result<(), Box<dyn std::error::Error>> { LL | let mut _file = File::create("foo.txt")?; LL | LL | println!(); -LL + LL + Ok(()) -LL + } | error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`) @@ -51,9 +47,8 @@ help: consider adding return type LL ~ fn test4(&self) -> Result<(), Box<dyn std::error::Error>> { LL | let mut _file = File::create("foo.txt")?; LL | -LL ~ -LL + Ok(()) -LL + } +LL ~ Ok(()) +LL ~ } | error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`) @@ -71,9 +66,8 @@ LL ~ fn test5(&self) -> Result<(), Box<dyn std::error::Error>> { LL | let mut _file = File::create("foo.txt")?; LL | LL | println!(); -LL ~ -LL + Ok(()) -LL + } +LL ~ Ok(()) +LL ~ } | error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) @@ -91,9 +85,7 @@ LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> { LL | let mut _file = File::create("foo.txt")?; LL | LL | mac!(); -LL + LL + Ok(()) -LL + } | error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) @@ -115,9 +107,8 @@ LL ~ fn test3() -> Result<(), Box<dyn std::error::Error>> { LL | let mut _file = File::create("foo.txt")?; LL | LL | println!(); -LL ~ -LL + Ok(()) -LL + } +LL ~ Ok(()) +LL ~ } | error: aborting due to 6 previous errors diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr index 79b640d9f41..6b3f303eeab 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/unreachable.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/unreachable.rs:14:9 | LL | Err(!), - | ^^^^^^ + | ^^^^^^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here --> $DIR/unreachable.rs:4:9 | @@ -15,41 +15,41 @@ error: unreachable pattern --> $DIR/unreachable.rs:17:19 | LL | let (Ok(_x) | Err(!)) = res_void; - | ^^^^^^ + | ^^^^^^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/unreachable.rs:19:12 | LL | if let Err(!) = res_void {} - | ^^^^^^ + | ^^^^^^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/unreachable.rs:21:24 | LL | if let (Ok(true) | Err(!)) = res_void {} - | ^^^^^^ + | ^^^^^^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/unreachable.rs:23:23 | LL | for (Ok(mut _x) | Err(!)) in [res_void] {} - | ^^^^^^ + | ^^^^^^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/unreachable.rs:27:18 | LL | fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {} - | ^^^^^^ + | ^^^^^^ matches no values because `Void` is uninhabited | - = note: this pattern matches no values because `Void` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: aborting due to 6 previous errors diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr index d5f58e436c5..dfd7f9d6300 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/enum_same_crate_empty_match.rs:28:9 | LL | _ => {} - | ^ + | ^ matches no values because `EmptyNonExhaustiveEnum` is uninhabited | - = note: this pattern matches no values because `EmptyNonExhaustiveEnum` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here --> $DIR/enum_same_crate_empty_match.rs:1:9 | diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr index 4ec4ec9705a..956725fc10e 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/issue-65157-repeated-match-arm.rs:15:9 | LL | PartiallyInhabitedVariants::Struct { .. } => {}, - | ----------------------------------------- matches all the values already + | ----------------------------------------- matches all the relevant values LL | PartiallyInhabitedVariants::Struct { .. } => {}, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this | note: the lint level is defined here --> $DIR/issue-65157-repeated-match-arm.rs:2:9 diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr index c399bb9083f..7e7dc802e7f 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/patterns_same_crate.rs:51:9 | LL | Some(_x) => (), - | ^^^^^^^^ + | ^^^^^^^^ matches no values because `UninhabitedEnum` is uninhabited | - = note: this pattern matches no values because `UninhabitedEnum` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here --> $DIR/patterns_same_crate.rs:1:9 | @@ -15,33 +15,33 @@ error: unreachable pattern --> $DIR/patterns_same_crate.rs:56:9 | LL | Some(_x) => (), - | ^^^^^^^^ + | ^^^^^^^^ matches no values because `UninhabitedVariants` is uninhabited | - = note: this pattern matches no values because `UninhabitedVariants` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/patterns_same_crate.rs:60:15 | LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ matches no values because `!` is uninhabited | - = note: this pattern matches no values because `!` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/patterns_same_crate.rs:64:15 | LL | while let Some(_x) = uninhabited_struct() { - | ^^^^^^^^ + | ^^^^^^^^ matches no values because `UninhabitedStruct` is uninhabited | - = note: this pattern matches no values because `UninhabitedStruct` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/patterns_same_crate.rs:67:15 | LL | while let Some(_x) = uninhabited_tuple_struct() { - | ^^^^^^^^ + | ^^^^^^^^ matches no values because `UninhabitedTupleStruct` is uninhabited | - = note: this pattern matches no values because `UninhabitedTupleStruct` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: aborting due to 5 previous errors diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr index 8d0874fa900..693a06a2297 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr @@ -16,9 +16,9 @@ error: unreachable pattern --> $DIR/warns.rs:15:25 | LL | x if let None | None = x => {} - | ---- ^^^^ unreachable pattern + | ---- ^^^^ no value can reach this | | - | matches all the values already + | matches all the relevant values | note: the lint level is defined here --> $DIR/warns.rs:12:8 diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs index 637a24f53bc..6c320c0462e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs @@ -1,4 +1,4 @@ -//@ check-pass +//~ ERROR the trait bound //@ compile-flags: -Znext-solver #![allow(incomplete_features)] @@ -17,6 +17,6 @@ impl Foo for S { } impl const Bar for S {} -//FIXME ~^ ERROR the trait bound +// FIXME(effects) bad span fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr new file mode 100644 index 00000000000..9a907bbee0a --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `Maybe: TyCompat<<(Foo::{synthetic#0},) as std::marker::effects::Intersection>::Output>` is not satisfied + | +note: required by a bound in `Bar::{synthetic#0}` + --> $DIR/super-traits-fail.rs:11:1 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ required by this bound in `Bar::{synthetic#0}` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/sanitizer/cfi/transparent-has-regions.rs b/tests/ui/sanitizer/cfi/transparent-has-regions.rs new file mode 100644 index 00000000000..b70e1ea1791 --- /dev/null +++ b/tests/ui/sanitizer/cfi/transparent-has-regions.rs @@ -0,0 +1,18 @@ +//@ needs-sanitizer-cfi +//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ no-prefer-dynamic +//@ only-x86_64-unknown-linux-gnu +//@ build-pass + +pub trait Trait {} + +impl Trait for i32 {} + +#[repr(transparent)] +struct BoxedTrait(Box<dyn Trait + 'static>); + +fn hello(x: BoxedTrait) {} + +fn main() { + hello(BoxedTrait(Box::new(1))); +} diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index e04ec8bb3bc..216b7053488 100644 --- a/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -7,10 +7,10 @@ LL | async fn f(self: Pin<&Self>) -> impl Clone { self } | | opaque type defined here | hidden type `Pin<&Foo>` captures the anonymous lifetime defined here | -help: to declare that `impl Clone` captures `'_`, you can add an explicit `'_` lifetime bound +help: add a `use<...>` bound to explicitly capture `'_` | -LL | async fn f(self: Pin<&Self>) -> impl Clone + '_ { self } - | ++++ +LL | async fn f(self: Pin<&Self>) -> impl Clone + use<'_> { self } + | +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index a2964881d58..7a2ce110a38 100644 --- a/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -7,10 +7,10 @@ LL | fn f(self: Pin<&Self>) -> impl Clone { self } | | opaque type defined here | hidden type `Pin<&Foo>` captures the anonymous lifetime defined here | -help: to declare that `impl Clone` captures `'_`, you can add an explicit `'_` lifetime bound +help: add a `use<...>` bound to explicitly capture `'_` | -LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } - | ++++ +LL | fn f(self: Pin<&Self>) -> impl Clone + use<'_> { self } + | +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/sized/unsized-binding.stderr b/tests/ui/sized/unsized-binding.stderr index 7c3276032c2..8de236cd0b6 100644 --- a/tests/ui/sized/unsized-binding.stderr +++ b/tests/ui/sized/unsized-binding.stderr @@ -7,6 +7,11 @@ LL | let x = *""; = help: the trait `Sized` is not implemented for `str` = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let x = *""; +LL + let x = ""; + | error: aborting due to 1 previous error diff --git a/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs new file mode 100644 index 00000000000..35abbb80d99 --- /dev/null +++ b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs @@ -0,0 +1,30 @@ +fn foo() -> impl Sized { +//~^ ERROR the size for values of type `str` cannot be known at compilation time +//~| HELP the trait `Sized` is not implemented for `str` + *"" //~ HELP consider not dereferencing the expression +} +fn bar(_: impl Sized) {} +struct S; + +impl S { + fn baz(&self, _: impl Sized) {} +} + +fn main() { + let _ = foo(); + let x = *""; + //~^ ERROR the size for values of type `str` cannot be known at compilation time + //~| HELP consider not dereferencing the expression + //~| HELP the trait `Sized` is not implemented for `str` + //~| HELP unsized locals are gated as an unstable feature + bar(x); + S.baz(x); + bar(*""); + //~^ ERROR the size for values of type `str` cannot be known at compilation time + //~| HELP consider not dereferencing the expression + //~| HELP the trait `Sized` is not implemented for `str` + S.baz(*""); + //~^ ERROR the size for values of type `str` cannot be known at compilation time + //~| HELP consider not dereferencing the expression + //~| HELP the trait `Sized` is not implemented for `str` +} diff --git a/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr new file mode 100644 index 00000000000..9b7258aff12 --- /dev/null +++ b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr @@ -0,0 +1,74 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:1:13 + | +LL | fn foo() -> impl Sized { + | ^^^^^^^^^^ doesn't have a size known at compile-time +... +LL | *"" + | --- return type was inferred to be `str` here + | + = help: the trait `Sized` is not implemented for `str` +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - *"" +LL + "" + | + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:15:9 + | +LL | let x = *""; + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let x = *""; +LL + let x = ""; + | + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:22:9 + | +LL | bar(*""); + | --- ^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `str` +note: required by a bound in `bar` + --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:6:16 + | +LL | fn bar(_: impl Sized) {} + | ^^^^^ required by this bound in `bar` +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - bar(*""); +LL + bar(""); + | + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:26:11 + | +LL | S.baz(*""); + | --- ^^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `str` +note: required by a bound in `S::baz` + --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:10:27 + | +LL | fn baz(&self, _: impl Sized) {} + | ^^^^^ required by this bound in `S::baz` +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - S.baz(*""); +LL + S.baz(""); + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.rs b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.rs index fb962ad24bf..858fba2132a 100644 --- a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.rs +++ b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.rs @@ -14,5 +14,6 @@ struct Wrapper<const C: <i32 as Trait>::Type> {} impl<const C: usize> Wrapper<C> {} //~^ ERROR the constant `C` is not of type `<i32 as Trait>::Type` +//~| ERROR: mismatched types fn main() {} diff --git a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr index 7094ee8c67c..71d4277275f 100644 --- a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr +++ b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr @@ -20,5 +20,17 @@ note: required by a const generic parameter in `Wrapper` LL | struct Wrapper<const C: <i32 as Trait>::Type> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `Wrapper` -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/default-proj-ty-as-type-of-const-issue-125757.rs:15:30 + | +LL | impl<const C: usize> Wrapper<C> {} + | ^ expected associated type, found `usize` + | + = note: expected associated type `<i32 as Trait>::Type` + found type `usize` + = help: consider constraining the associated type `<i32 as Trait>::Type` to `usize` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs index a0ee7714417..f89a463bc58 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs @@ -6,6 +6,7 @@ struct S<const L: usize>; impl<const N: i32> Copy for S<N> {} +//~^ ERROR: mismatched types impl<const M: usize> Copy for S<M> {} //~^ ERROR: conflicting implementations of trait `Copy` for type `S<_>` diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr index 2953bc95917..1dac58e1f69 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr @@ -1,11 +1,19 @@ error[E0119]: conflicting implementations of trait `Copy` for type `S<_>` - --> $DIR/bad-const-wf-doesnt-specialize.rs:9:1 + --> $DIR/bad-const-wf-doesnt-specialize.rs:10:1 | LL | impl<const N: i32> Copy for S<N> {} | -------------------------------- first implementation here +LL | LL | impl<const M: usize> Copy for S<M> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>` -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/bad-const-wf-doesnt-specialize.rs:8:31 + | +LL | impl<const N: i32> Copy for S<N> {} + | ^ expected `usize`, found `i32` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0119`. +Some errors have detailed explanations: E0119, E0308. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/suggestions/issue-84973-blacklist.stderr b/tests/ui/suggestions/issue-84973-blacklist.stderr index 4fd063e4692..c1ef1cd428e 100644 --- a/tests/ui/suggestions/issue-84973-blacklist.stderr +++ b/tests/ui/suggestions/issue-84973-blacklist.stderr @@ -66,6 +66,11 @@ note: required by a bound in `f_sized` | LL | fn f_sized<T: Sized>(t: T) {} | ^^^^^ required by this bound in `f_sized` +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - f_sized(*ref_cl); +LL + f_sized(ref_cl); + | error[E0277]: `Rc<{integer}>` cannot be sent between threads safely --> $DIR/issue-84973-blacklist.rs:27:12 diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 64af17c830e..88a18e9d06d 100644 --- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -20,10 +20,10 @@ LL | | *dest = g.get(); LL | | } | |_____^ | -help: to declare that `impl FnOnce()` captures `'_`, you can add an explicit `'_` lifetime bound +help: add a `use<...>` bound to explicitly capture `'_` | -LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ++++ +LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + use<'_, G, T> + | +++++++++++++++ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:30:5 diff --git a/tests/ui/traits/object/pretty.rs b/tests/ui/traits/object/pretty.rs index 8958871ed5d..6660ff040f7 100644 --- a/tests/ui/traits/object/pretty.rs +++ b/tests/ui/traits/object/pretty.rs @@ -18,6 +18,10 @@ trait FixedHrtb: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> {} trait AnyDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super {} trait FixedDifferentBinders: for<'a> SuperGeneric<'a, Assoc2 = &'a u8> + Super<Assoc = u8> {} +trait HasGat<Outer> { + type Assoc<Inner> where Self: Sized; +} + fn dyn_super(x: &dyn Super<Assoc = u8>) { x } //~ERROR mismatched types fn dyn_any(x: &dyn Any<Assoc = u8>) { x } //~ERROR mismatched types fn dyn_fixed(x: &dyn Fixed) { x } //~ERROR mismatched types @@ -34,4 +38,7 @@ fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } //~ERROR mismatched types fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x } //~ERROR mismatched types fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x } //~ERROR mismatched types +fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x } //~ERROR mismatched types +//~^ WARN unnecessary associated type bound + fn main() {} diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr index bc645e5f967..6964d97c08e 100644 --- a/tests/ui/traits/object/pretty.stderr +++ b/tests/ui/traits/object/pretty.stderr @@ -1,5 +1,14 @@ +warning: unnecessary associated type bound for not object safe associated type + --> $DIR/pretty.rs:41:35 + | +LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x } + | ^^^^^^^^^^^^^^^^ help: remove this bound + | + = note: this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized` + = note: `#[warn(unused_associated_type_bounds)]` on by default + error[E0308]: mismatched types - --> $DIR/pretty.rs:21:43 + --> $DIR/pretty.rs:25:43 | LL | fn dyn_super(x: &dyn Super<Assoc = u8>) { x } | - ^ expected `()`, found `&dyn Super<Assoc = u8>` @@ -10,7 +19,7 @@ LL | fn dyn_super(x: &dyn Super<Assoc = u8>) { x } found reference `&dyn Super<Assoc = u8>` error[E0308]: mismatched types - --> $DIR/pretty.rs:22:39 + --> $DIR/pretty.rs:26:39 | LL | fn dyn_any(x: &dyn Any<Assoc = u8>) { x } | - ^ expected `()`, found `&dyn Any<Assoc = u8>` @@ -21,7 +30,7 @@ LL | fn dyn_any(x: &dyn Any<Assoc = u8>) { x } found reference `&dyn Any<Assoc = u8>` error[E0308]: mismatched types - --> $DIR/pretty.rs:23:31 + --> $DIR/pretty.rs:27:31 | LL | fn dyn_fixed(x: &dyn Fixed) { x } | - ^ expected `()`, found `&dyn Fixed` @@ -32,7 +41,7 @@ LL | fn dyn_fixed(x: &dyn Fixed) { x } found reference `&dyn Fixed` error[E0308]: mismatched types - --> $DIR/pretty.rs:24:50 + --> $DIR/pretty.rs:28:50 | LL | fn dyn_fixed_multi(x: &dyn Fixed<Assoc = u16>) { x } | - ^ expected `()`, found `&dyn Fixed<Assoc = u16>` @@ -43,7 +52,7 @@ LL | fn dyn_fixed_multi(x: &dyn Fixed<Assoc = u16>) { x } found reference `&dyn Fixed<Assoc = u16>` error[E0308]: mismatched types - --> $DIR/pretty.rs:25:38 + --> $DIR/pretty.rs:29:38 | LL | fn dyn_fixed_sub(x: &dyn FixedSub) { x } | - ^ expected `()`, found `&dyn FixedSub` @@ -54,7 +63,7 @@ LL | fn dyn_fixed_sub(x: &dyn FixedSub) { x } found reference `&dyn FixedSub` error[E0308]: mismatched types - --> $DIR/pretty.rs:26:44 + --> $DIR/pretty.rs:30:44 | LL | fn dyn_fixed_static(x: &dyn FixedStatic) { x } | - ^ expected `()`, found `&dyn FixedStatic` @@ -65,7 +74,7 @@ LL | fn dyn_fixed_static(x: &dyn FixedStatic) { x } found reference `&dyn FixedStatic` error[E0308]: mismatched types - --> $DIR/pretty.rs:28:75 + --> $DIR/pretty.rs:32:75 | LL | fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x } | - ^ expected `()`, found `&dyn SuperGeneric<'a, Assoc2 = &u8>` @@ -76,7 +85,7 @@ LL | fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x found reference `&dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>` error[E0308]: mismatched types - --> $DIR/pretty.rs:29:71 + --> $DIR/pretty.rs:33:71 | LL | fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } | - ^ expected `()`, found `&dyn AnyGeneric<'a, Assoc2 = &u8>` @@ -87,7 +96,7 @@ LL | fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } found reference `&dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>` error[E0308]: mismatched types - --> $DIR/pretty.rs:30:60 + --> $DIR/pretty.rs:34:60 | LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } | - ^ expected `()`, found `&dyn FixedGeneric1<'a>` @@ -98,7 +107,7 @@ LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } found reference `&dyn for<'a> FixedGeneric1<'a>` error[E0308]: mismatched types - --> $DIR/pretty.rs:31:60 + --> $DIR/pretty.rs:35:60 | LL | fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } | - ^ expected `()`, found `&dyn FixedGeneric2<'a>` @@ -109,7 +118,7 @@ LL | fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } found reference `&dyn for<'a> FixedGeneric2<'a>` error[E0308]: mismatched types - --> $DIR/pretty.rs:32:79 + --> $DIR/pretty.rs:36:79 | LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } | - ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = ...>` @@ -120,7 +129,7 @@ LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) found reference `&dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>` error[E0308]: mismatched types - --> $DIR/pretty.rs:33:40 + --> $DIR/pretty.rs:37:40 | LL | fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } | - ^ expected `()`, found `&dyn FixedHrtb` @@ -131,7 +140,7 @@ LL | fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } found reference `&dyn FixedHrtb` error[E0308]: mismatched types - --> $DIR/pretty.rs:34:73 + --> $DIR/pretty.rs:38:73 | LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x } | - ^ expected `()`, found `&dyn AnyDifferentBinders<Assoc = ...>` @@ -142,7 +151,7 @@ LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x } found reference `&dyn AnyDifferentBinders<Assoc = u8>` error[E0308]: mismatched types - --> $DIR/pretty.rs:35:65 + --> $DIR/pretty.rs:39:65 | LL | fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x } | - ^ expected `()`, found `&dyn FixedDifferentBinders` @@ -152,6 +161,17 @@ LL | fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x } = note: expected unit type `()` found reference `&dyn FixedDifferentBinders` -error: aborting due to 14 previous errors +error[E0308]: mismatched types + --> $DIR/pretty.rs:41:56 + | +LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x } + | - ^ expected `()`, found `&dyn HasGat<u8, Assoc<bool> = ()>` + | | + | help: try adding a return type: `-> &dyn HasGat<u8, Assoc<bool> = ()>` + | + = note: expected unit type `()` + found reference `&dyn HasGat<u8, Assoc<bool> = ()>` + +error: aborting due to 15 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/transmutability/arrays/huge-len.stderr b/tests/ui/transmutability/arrays/huge-len.stderr index 3fc652f47c1..37160c5c959 100644 --- a/tests/ui/transmutability/arrays/huge-len.stderr +++ b/tests/ui/transmutability/arrays/huge-len.stderr @@ -2,7 +2,7 @@ error[E0277]: `()` cannot be safely transmuted into `ExplicitlyPadded` --> $DIR/huge-len.rs:21:41 | LL | assert::is_maybe_transmutable::<(), ExplicitlyPadded>(); - | ^^^^^^^^^^^^^^^^ analyzing the transmutability of `ExplicitlyPadded` is not yet supported + | ^^^^^^^^^^^^^^^^ values of the type `ExplicitlyPadded` are too big for the current architecture | note: required by a bound in `is_maybe_transmutable` --> $DIR/huge-len.rs:8:14 @@ -17,7 +17,7 @@ error[E0277]: `ExplicitlyPadded` cannot be safely transmuted into `()` --> $DIR/huge-len.rs:24:55 | LL | assert::is_maybe_transmutable::<ExplicitlyPadded, ()>(); - | ^^ analyzing the transmutability of `ExplicitlyPadded` is not yet supported + | ^^ values of the type `ExplicitlyPadded` are too big for the current architecture | note: required by a bound in `is_maybe_transmutable` --> $DIR/huge-len.rs:8:14 diff --git a/tests/ui/transmutability/issue-101739-1.rs b/tests/ui/transmutability/issue-101739-1.rs index 20bd7917e53..81a9038fdb5 100644 --- a/tests/ui/transmutability/issue-101739-1.rs +++ b/tests/ui/transmutability/issue-101739-1.rs @@ -6,7 +6,8 @@ mod assert { pub fn is_transmutable<Src, const ASSUME_ALIGNMENT: bool>() where Dst: BikeshedIntrinsicFrom<Src, ASSUME_ALIGNMENT>, //~ ERROR cannot find type `Dst` in this scope - //~^ the constant `ASSUME_ALIGNMENT` is not of type `Assume` + //~| the constant `ASSUME_ALIGNMENT` is not of type `Assume` + //~| ERROR: mismatched types { } } diff --git a/tests/ui/transmutability/issue-101739-1.stderr b/tests/ui/transmutability/issue-101739-1.stderr index ba18a980f4d..6f79bf7b424 100644 --- a/tests/ui/transmutability/issue-101739-1.stderr +++ b/tests/ui/transmutability/issue-101739-1.stderr @@ -13,6 +13,13 @@ LL | Dst: BikeshedIntrinsicFrom<Src, ASSUME_ALIGNMENT>, note: required by a const generic parameter in `BikeshedIntrinsicFrom` --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/issue-101739-1.rs:8:41 + | +LL | Dst: BikeshedIntrinsicFrom<Src, ASSUME_ALIGNMENT>, + | ^^^^^^^^^^^^^^^^ expected `Assume`, found `bool` + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0308, E0412. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/transmutability/issue-101739-2.rs b/tests/ui/transmutability/issue-101739-2.rs index 8b36bf3dcb1..6dfde06d6b3 100644 --- a/tests/ui/transmutability/issue-101739-2.rs +++ b/tests/ui/transmutability/issue-101739-2.rs @@ -14,19 +14,23 @@ mod assert { const ASSUME_VISIBILITY: bool, >() where - Dst: BikeshedIntrinsicFrom< //~ ERROR trait takes at most 2 generic arguments but 5 generic arguments were supplied - Src, - ASSUME_ALIGNMENT, - ASSUME_LIFETIMES, - ASSUME_VALIDITY, - ASSUME_VISIBILITY, - >, - {} + Dst: BikeshedIntrinsicFrom< + //~^ ERROR trait takes at most 2 generic arguments but 5 generic arguments were supplied + Src, + ASSUME_ALIGNMENT, //~ ERROR: mismatched types + ASSUME_LIFETIMES, + ASSUME_VALIDITY, + ASSUME_VISIBILITY, + >, + { + } } fn via_const() { - #[repr(C)] struct Src; - #[repr(C)] struct Dst; + #[repr(C)] + struct Src; + #[repr(C)] + struct Dst; const FALSE: bool = false; diff --git a/tests/ui/transmutability/issue-101739-2.stderr b/tests/ui/transmutability/issue-101739-2.stderr index 6b0a36a414b..11e8fa1d8c5 100644 --- a/tests/ui/transmutability/issue-101739-2.stderr +++ b/tests/ui/transmutability/issue-101739-2.stderr @@ -3,14 +3,21 @@ error[E0107]: trait takes at most 2 generic arguments but 5 generic arguments we | LL | Dst: BikeshedIntrinsicFrom< | ^^^^^^^^^^^^^^^^^^^^^ expected at most 2 generic arguments -LL | Src, -LL | ASSUME_ALIGNMENT, - | _____________________________- -LL | | ASSUME_LIFETIMES, -LL | | ASSUME_VALIDITY, -LL | | ASSUME_VISIBILITY, - | |_____________________________- help: remove the unnecessary generic arguments +... +LL | ASSUME_ALIGNMENT, + | _________________________________- +LL | | ASSUME_LIFETIMES, +LL | | ASSUME_VALIDITY, +LL | | ASSUME_VISIBILITY, + | |_________________________________- help: remove the unnecessary generic arguments -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/issue-101739-2.rs:20:17 + | +LL | ASSUME_ALIGNMENT, + | ^^^^^^^^^^^^^^^^ expected `Assume`, found `bool` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0107, E0308. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.rs b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.rs new file mode 100644 index 00000000000..8c18de11196 --- /dev/null +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.rs @@ -0,0 +1,26 @@ +// An unknown destination type should be gracefully handled. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(incomplete_features)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src> + {} +} + +fn should_gracefully_handle_unknown_dst_field() { + #[repr(C)] struct Src; + #[repr(C)] struct Dst(Missing); //~ cannot find type + assert::is_transmutable::<Src, Dst>(); //~ ERROR cannot be safely transmuted +} + +fn should_gracefully_handle_unknown_dst_ref_field() { + #[repr(C)] struct Src(&'static Src); + #[repr(C)] struct Dst(&'static Missing); //~ cannot find type + assert::is_transmutable::<Src, Dst>(); //~ ERROR cannot be safely transmuted +} diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.stderr new file mode 100644 index 00000000000..df10919f6d3 --- /dev/null +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_dst_field.stderr @@ -0,0 +1,46 @@ +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/unknown_dst_field.rs:18:27 + | +LL | #[repr(C)] struct Dst(Missing); + | ^^^^^^^ not found in this scope + +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/unknown_dst_field.rs:24:36 + | +LL | #[repr(C)] struct Dst(&'static Missing); + | ^^^^^^^ not found in this scope + +error[E0277]: `should_gracefully_handle_unknown_dst_field::Src` cannot be safely transmuted into `should_gracefully_handle_unknown_dst_field::Dst` + --> $DIR/unknown_dst_field.rs:19:36 + | +LL | assert::is_transmutable::<Src, Dst>(); + | ^^^ `should_gracefully_handle_unknown_dst_field::Dst` has an unknown layout + | +note: required by a bound in `is_transmutable` + --> $DIR/unknown_dst_field.rs:12:14 + | +LL | pub fn is_transmutable<Src, Dst>() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `should_gracefully_handle_unknown_dst_ref_field::Src` cannot be safely transmuted into `should_gracefully_handle_unknown_dst_ref_field::Dst` + --> $DIR/unknown_dst_field.rs:25:36 + | +LL | assert::is_transmutable::<Src, Dst>(); + | ^^^ `should_gracefully_handle_unknown_dst_ref_field::Dst` has an unknown layout + | +note: required by a bound in `is_transmutable` + --> $DIR/unknown_dst_field.rs:12:14 + | +LL | pub fn is_transmutable<Src, Dst>() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0412. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs index 58c16d773e1..1da16e67223 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs @@ -13,8 +13,14 @@ mod assert { {} } -fn should_gracefully_handle_unknown_dst_field() { - #[repr(C)] struct Src; - #[repr(C)] struct Dst(Missing); //~ cannot find type +fn should_gracefully_handle_unknown_src_field() { + #[repr(C)] struct Src(Missing); //~ cannot find type + #[repr(C)] struct Dst(); + assert::is_transmutable::<Src, Dst>(); //~ ERROR cannot be safely transmuted +} + +fn should_gracefully_handle_unknown_src_ref_field() { + #[repr(C)] struct Src(&'static Missing); //~ cannot find type + #[repr(C)] struct Dst(&'static Dst); assert::is_transmutable::<Src, Dst>(); //~ ERROR cannot be safely transmuted } diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr index cabc7bcfef7..6ec66e17061 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr @@ -1,14 +1,35 @@ error[E0412]: cannot find type `Missing` in this scope - --> $DIR/unknown_src_field.rs:18:27 + --> $DIR/unknown_src_field.rs:17:27 | -LL | #[repr(C)] struct Dst(Missing); +LL | #[repr(C)] struct Src(Missing); | ^^^^^^^ not found in this scope -error[E0277]: `Src` cannot be safely transmuted into `Dst` +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/unknown_src_field.rs:23:36 + | +LL | #[repr(C)] struct Src(&'static Missing); + | ^^^^^^^ not found in this scope + +error[E0277]: `should_gracefully_handle_unknown_src_field::Src` cannot be safely transmuted into `should_gracefully_handle_unknown_src_field::Dst` --> $DIR/unknown_src_field.rs:19:36 | LL | assert::is_transmutable::<Src, Dst>(); - | ^^^ analyzing the transmutability of `Dst` is not yet supported + | ^^^ `should_gracefully_handle_unknown_src_field::Src` has an unknown layout + | +note: required by a bound in `is_transmutable` + --> $DIR/unknown_src_field.rs:12:14 + | +LL | pub fn is_transmutable<Src, Dst>() + | --------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `should_gracefully_handle_unknown_src_ref_field::Src` cannot be safely transmuted into `should_gracefully_handle_unknown_src_ref_field::Dst` + --> $DIR/unknown_src_field.rs:25:36 + | +LL | assert::is_transmutable::<Src, Dst>(); + | ^^^ `should_gracefully_handle_unknown_src_ref_field::Src` has an unknown layout | note: required by a bound in `is_transmutable` --> $DIR/unknown_src_field.rs:12:14 @@ -19,7 +40,7 @@ LL | where LL | Dst: BikeshedIntrinsicFrom<Src> | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0412. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs index 64110753832..4c285a616b3 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs @@ -22,5 +22,4 @@ fn should_pad_explicitly_packed_field() { //~^ ERROR: recursive type assert::is_maybe_transmutable::<ExplicitlyPadded, ()>(); - //~^ ERROR: cannot be safely transmuted } diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr index ebfb5361143..7fb051f6625 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr @@ -15,22 +15,7 @@ error[E0391]: cycle detected when computing layout of `should_pad_explicitly_pac = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::BikeshedIntrinsicFrom<should_pad_explicitly_packed_field::ExplicitlyPadded, core::mem::transmutability::Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0277]: `ExplicitlyPadded` cannot be safely transmuted into `()` - --> $DIR/transmute_infinitely_recursive_type.rs:24:55 - | -LL | assert::is_maybe_transmutable::<ExplicitlyPadded, ()>(); - | ^^ analyzing the transmutability of `ExplicitlyPadded` is not yet supported - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/transmute_infinitely_recursive_type.rs:14:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0072, E0277, E0391. +Some errors have detailed explanations: E0072, E0391. For more information about an error, try `rustc --explain E0072`. diff --git a/tests/ui/try-trait/try-operator-on-main.stderr b/tests/ui/try-trait/try-operator-on-main.stderr index d22117165c1..311e8076ed4 100644 --- a/tests/ui/try-trait/try-operator-on-main.stderr +++ b/tests/ui/try-trait/try-operator-on-main.stderr @@ -14,9 +14,7 @@ LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> { LL | // error for a `Try` type on a non-`Try` fn ... LL | try_trait_generic::<()>(); -LL + LL + Ok(()) -LL + } | error[E0277]: the `?` operator can only be applied to values that implement `Try` diff --git a/tests/ui/type-alias-impl-trait/different_args_considered_equal2.stderr b/tests/ui/type-alias-impl-trait/different_args_considered_equal2.stderr index 1104c2c498a..213272f5f34 100644 --- a/tests/ui/type-alias-impl-trait/different_args_considered_equal2.stderr +++ b/tests/ui/type-alias-impl-trait/different_args_considered_equal2.stderr @@ -9,11 +9,6 @@ LL | fn get_one<'a>(a: *mut &'a str) -> impl IntoIterator<Item = Opaque<'a>> { ... LL | None::<Opaque<'static>> | ^^^^^^^^^^^^^^^^^^^^^^^ - | -help: to declare that `impl IntoIterator<Item = Opaque<'a>>` captures `'a`, you can add an explicit `'a` lifetime bound - | -LL | fn get_one<'a>(a: *mut &'a str) -> impl IntoIterator<Item = Opaque<'a>> + 'a { - | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.stderr b/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.stderr index 9bffa94fda1..0bf9dccfad8 100644 --- a/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.stderr +++ b/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.stderr @@ -8,10 +8,10 @@ LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne { LL | <&'a mut i32 as Callable>::call(y) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: to declare that `impl PlusOne` captures `'a`, you can add an explicit `'a` lifetime bound +help: add a `use<...>` bound to explicitly capture `'a` | -LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne + 'a { - | ++++ +LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne + use<'a> { + | +++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/variance.rs b/tests/ui/type-alias-impl-trait/variance.rs index ba52eaa0359..113f6a4cc44 100644 --- a/tests/ui/type-alias-impl-trait/variance.rs +++ b/tests/ui/type-alias-impl-trait/variance.rs @@ -5,21 +5,21 @@ trait Captures<'a> {} impl<T> Captures<'_> for T {} -type NotCapturedEarly<'a> = impl Sized; //~ [*, o] +type NotCapturedEarly<'a> = impl Sized; //~ ['a: *, 'a: o] //~^ ERROR: unconstrained opaque type -type CapturedEarly<'a> = impl Sized + Captures<'a>; //~ [*, o] +type CapturedEarly<'a> = impl Sized + Captures<'a>; //~ ['a: *, 'a: o] //~^ ERROR: unconstrained opaque type -type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>; //~ [*, o, o] +type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>; //~ ['a: *, 'b: o, 'a: o] //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type //~| ERROR: unconstrained opaque type -type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>; //~ [*, o, o] +type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>; //~ ['a: *, 'b: o, 'a: o] //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type //~| ERROR: unconstrained opaque type -type Bar<'a, 'b: 'b, T> = impl Sized; //~ ERROR [*, *, o, o, o] +type Bar<'a, 'b: 'b, T> = impl Sized; //~ ERROR ['a: *, 'b: *, T: o, 'a: o, 'b: o] //~^ ERROR: unconstrained opaque type trait Foo<'i> { @@ -31,24 +31,24 @@ trait Foo<'i> { } impl<'i> Foo<'i> for &'i () { - type ImplicitCapture<'a> = impl Sized; //~ [*, *, o, o] + type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'a: o, 'i: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ [*, *, o, o] + type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'a: o, 'i: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ [*, *, o, o] + type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'a: o, 'i: o] //~^ ERROR: unconstrained opaque type } impl<'i> Foo<'i> for () { - type ImplicitCapture<'a> = impl Sized; //~ [*, *, o, o] + type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'a: o, 'i: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ [*, *, o, o] + type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'a: o, 'i: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ [*, *, o, o] + type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'a: o, 'i: o] //~^ ERROR: unconstrained opaque type } @@ -59,15 +59,15 @@ impl<'a> Nesting<'a> for &'a () { type Output = &'a (); } type NestedDeeply<'a> = - impl Nesting< //~ [*, o] + impl Nesting< //~ ['a: *, 'a: o] 'a, - Output = impl Nesting< //~ [*, o] + Output = impl Nesting< //~ ['a: *, 'a: o] 'a, - Output = impl Nesting< //~ [*, o] + Output = impl Nesting< //~ ['a: *, 'a: o] 'a, - Output = impl Nesting< //~ [*, o] + Output = impl Nesting< //~ ['a: *, 'a: o] 'a, - Output = impl Nesting<'a> //~ [*, o] + Output = impl Nesting<'a> //~ ['a: *, 'a: o] > >, >, diff --git a/tests/ui/type-alias-impl-trait/variance.stderr b/tests/ui/type-alias-impl-trait/variance.stderr index e5ced7a4981..489dfe03d44 100644 --- a/tests/ui/type-alias-impl-trait/variance.stderr +++ b/tests/ui/type-alias-impl-trait/variance.stderr @@ -110,73 +110,73 @@ LL | type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; | = note: `ExplicitCaptureFromGat` must be used in combination with a concrete type within the same impl -error: [*, o] +error: ['a: *, 'a: o] --> $DIR/variance.rs:8:29 | LL | type NotCapturedEarly<'a> = impl Sized; | ^^^^^^^^^^ -error: [*, o] +error: ['a: *, 'a: o] --> $DIR/variance.rs:11:26 | LL | type CapturedEarly<'a> = impl Sized + Captures<'a>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [*, o, o] +error: ['a: *, 'b: o, 'a: o] --> $DIR/variance.rs:14:56 | LL | type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>; | ^^^^^^^^^^ -error: [*, o, o] +error: ['a: *, 'b: o, 'a: o] --> $DIR/variance.rs:18:49 | LL | type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [*, *, o, o, o] +error: ['a: *, 'b: *, T: o, 'a: o, 'b: o] --> $DIR/variance.rs:22:27 | LL | type Bar<'a, 'b: 'b, T> = impl Sized; | ^^^^^^^^^^ -error: [*, *, o, o] +error: ['i: *, 'a: *, 'a: o, 'i: o] --> $DIR/variance.rs:34:32 | LL | type ImplicitCapture<'a> = impl Sized; | ^^^^^^^^^^ -error: [*, *, o, o] +error: ['i: *, 'a: *, 'a: o, 'i: o] --> $DIR/variance.rs:37:42 | LL | type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [*, *, o, o] +error: ['i: *, 'a: *, 'a: o, 'i: o] --> $DIR/variance.rs:40:39 | LL | type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [*, *, o, o] +error: ['i: *, 'a: *, 'a: o, 'i: o] --> $DIR/variance.rs:45:32 | LL | type ImplicitCapture<'a> = impl Sized; | ^^^^^^^^^^ -error: [*, *, o, o] +error: ['i: *, 'a: *, 'a: o, 'i: o] --> $DIR/variance.rs:48:42 | LL | type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [*, *, o, o] +error: ['i: *, 'a: *, 'a: o, 'i: o] --> $DIR/variance.rs:51:39 | LL | type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [*, o] +error: ['a: *, 'a: o] --> $DIR/variance.rs:62:5 | LL | / impl Nesting< @@ -188,7 +188,7 @@ LL | | >, LL | | >; | |_____^ -error: [*, o] +error: ['a: *, 'a: o] --> $DIR/variance.rs:64:18 | LL | Output = impl Nesting< @@ -201,7 +201,7 @@ LL | | >, LL | | >, | |_________^ -error: [*, o] +error: ['a: *, 'a: o] --> $DIR/variance.rs:66:22 | LL | Output = impl Nesting< @@ -214,7 +214,7 @@ LL | | > LL | | >, | |_____________^ -error: [*, o] +error: ['a: *, 'a: o] --> $DIR/variance.rs:68:26 | LL | Output = impl Nesting< @@ -224,7 +224,7 @@ LL | | Output = impl Nesting<'a> LL | | > | |_________________^ -error: [*, o] +error: ['a: *, 'a: o] --> $DIR/variance.rs:70:30 | LL | Output = impl Nesting<'a> diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs index 9fc249198d0..92c1999e154 100644 --- a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs +++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs @@ -3,16 +3,18 @@ // of an impl fn produces a type mismatch error instead of triggering // a const eval cycle - trait Trait { - fn func<const N: u32>() -> [ (); N ]; //~ ERROR the constant `N` is not of type `usize` + fn func<const N: u32>() -> [(); N]; + //~^ ERROR: the constant `N` is not of type `usize` + //~| ERROR: mismatched types } struct S {} #[allow(unused_braces)] impl Trait for S { - fn func<const N: u32>() -> [ (); { () }] { //~ ERROR mismatched types + fn func<const N: u32>() -> [(); { () }] { + //~^ ERROR mismatched types N } } diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr index bff926a2081..bb8025d47a1 100644 --- a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr +++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr @@ -1,15 +1,21 @@ error[E0308]: mismatched types - --> $DIR/const-in-impl-fn-return-type.rs:15:40 + --> $DIR/const-in-impl-fn-return-type.rs:16:39 | -LL | fn func<const N: u32>() -> [ (); { () }] { - | ^^ expected `usize`, found `()` +LL | fn func<const N: u32>() -> [(); { () }] { + | ^^ expected `usize`, found `()` error: the constant `N` is not of type `usize` - --> $DIR/const-in-impl-fn-return-type.rs:8:32 + --> $DIR/const-in-impl-fn-return-type.rs:7:32 | -LL | fn func<const N: u32>() -> [ (); N ]; - | ^^^^^^^^^ expected `usize`, found `u32` +LL | fn func<const N: u32>() -> [(); N]; + | ^^^^^^^ expected `usize`, found `u32` -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/const-in-impl-fn-return-type.rs:7:37 + | +LL | fn func<const N: u32>() -> [(); N]; + | ^ expected `usize`, found `u32` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/uninhabited/uninhabited-patterns.stderr b/tests/ui/uninhabited/uninhabited-patterns.stderr index 4e4aaa93f80..0e1c9d31a73 100644 --- a/tests/ui/uninhabited/uninhabited-patterns.stderr +++ b/tests/ui/uninhabited/uninhabited-patterns.stderr @@ -2,9 +2,9 @@ error: unreachable pattern --> $DIR/uninhabited-patterns.rs:29:9 | LL | Ok(box _) => (), - | ^^^^^^^^^ + | ^^^^^^^^^ matches no values because `NotSoSecretlyEmpty` is uninhabited | - = note: this pattern matches no values because `NotSoSecretlyEmpty` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types note: the lint level is defined here --> $DIR/uninhabited-patterns.rs:3:9 | @@ -15,17 +15,17 @@ error: unreachable pattern --> $DIR/uninhabited-patterns.rs:38:9 | LL | Err(Ok(_y)) => (), - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ matches no values because `NotSoSecretlyEmpty` is uninhabited | - = note: this pattern matches no values because `NotSoSecretlyEmpty` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: unreachable pattern --> $DIR/uninhabited-patterns.rs:41:15 | LL | while let Some(_y) = foo() { - | ^^^^^^^^ + | ^^^^^^^^ matches no values because `NotSoSecretlyEmpty` is uninhabited | - = note: this pattern matches no values because `NotSoSecretlyEmpty` is uninhabited + = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types error: aborting due to 3 previous errors diff --git a/tests/ui/unsized/unsized6.stderr b/tests/ui/unsized/unsized6.stderr index 56e7f60f9ff..d406120efc5 100644 --- a/tests/ui/unsized/unsized6.stderr +++ b/tests/ui/unsized/unsized6.stderr @@ -123,6 +123,11 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized` LL - fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) { LL + fn f3<X>(x1: Box<X>, x2: Box<X>, x3: Box<X>) { | +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let y = *x2; +LL + let y = x2; + | error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:26:10 @@ -177,6 +182,11 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized` LL - fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) { LL + fn f4<X: T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) { | +help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression + | +LL - let y = *x2; +LL + let y = x2; + | error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:34:10 diff --git a/tests/ui/variance/variance-associated-consts.rs b/tests/ui/variance/variance-associated-consts.rs index 6a44a94df3f..97edb7e266a 100644 --- a/tests/ui/variance/variance-associated-consts.rs +++ b/tests/ui/variance/variance-associated-consts.rs @@ -10,7 +10,7 @@ trait Trait { } #[rustc_variance] -struct Foo<T: Trait> { //~ ERROR [o] +struct Foo<T: Trait> { //~ ERROR [T: o] field: [u8; <T as Trait>::Const] //~^ ERROR: unconstrained generic constant } diff --git a/tests/ui/variance/variance-associated-consts.stderr b/tests/ui/variance/variance-associated-consts.stderr index b955a7686c2..5c3ed93464a 100644 --- a/tests/ui/variance/variance-associated-consts.stderr +++ b/tests/ui/variance/variance-associated-consts.stderr @@ -9,7 +9,7 @@ help: try adding a `where` bound LL | struct Foo<T: Trait> where [(); <T as Trait>::Const]: { | ++++++++++++++++++++++++++++++++ -error: [o] +error: [T: o] --> $DIR/variance-associated-consts.rs:13:1 | LL | struct Foo<T: Trait> { diff --git a/tests/ui/variance/variance-associated-types.rs b/tests/ui/variance/variance-associated-types.rs index ecb0821827d..07ff41062e8 100644 --- a/tests/ui/variance/variance-associated-types.rs +++ b/tests/ui/variance/variance-associated-types.rs @@ -10,12 +10,12 @@ trait Trait<'a> { } #[rustc_variance] -struct Foo<'a, T : Trait<'a>> { //~ ERROR [+, +] +struct Foo<'a, T : Trait<'a>> { //~ ERROR ['a: +, T: +] field: (T, &'a ()) } #[rustc_variance] -struct Bar<'a, T : Trait<'a>> { //~ ERROR [o, o] +struct Bar<'a, T : Trait<'a>> { //~ ERROR ['a: o, T: o] field: <T as Trait<'a>>::Type } diff --git a/tests/ui/variance/variance-associated-types.stderr b/tests/ui/variance/variance-associated-types.stderr index 70cb246f6e9..ca010b7e7ef 100644 --- a/tests/ui/variance/variance-associated-types.stderr +++ b/tests/ui/variance/variance-associated-types.stderr @@ -1,10 +1,10 @@ -error: [+, +] +error: ['a: +, T: +] --> $DIR/variance-associated-types.rs:13:1 | LL | struct Foo<'a, T : Trait<'a>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o, o] +error: ['a: o, T: o] --> $DIR/variance-associated-types.rs:18:1 | LL | struct Bar<'a, T : Trait<'a>> { diff --git a/tests/ui/variance/variance-object-types.rs b/tests/ui/variance/variance-object-types.rs index 6ded24cd1e9..fd03dec9824 100644 --- a/tests/ui/variance/variance-object-types.rs +++ b/tests/ui/variance/variance-object-types.rs @@ -4,7 +4,7 @@ // For better or worse, associated types are invariant, and hence we // get an invariant result for `'a`. #[rustc_variance] -struct Foo<'a> { //~ ERROR [o] +struct Foo<'a> { //~ ERROR ['a: o] x: Box<dyn Fn(i32) -> &'a i32 + 'static> } diff --git a/tests/ui/variance/variance-object-types.stderr b/tests/ui/variance/variance-object-types.stderr index 963f3454e1b..a6fb9b2403a 100644 --- a/tests/ui/variance/variance-object-types.stderr +++ b/tests/ui/variance/variance-object-types.stderr @@ -1,4 +1,4 @@ -error: [o] +error: ['a: o] --> $DIR/variance-object-types.rs:7:1 | LL | struct Foo<'a> { diff --git a/tests/ui/variance/variance-regions-direct.rs b/tests/ui/variance/variance-regions-direct.rs index f1763c403f1..2bcacec33ea 100644 --- a/tests/ui/variance/variance-regions-direct.rs +++ b/tests/ui/variance/variance-regions-direct.rs @@ -6,7 +6,7 @@ // Regions that just appear in normal spots are contravariant: #[rustc_variance] -struct Test2<'a, 'b, 'c> { //~ ERROR [+, +, +] +struct Test2<'a, 'b, 'c> { //~ ERROR ['a: +, 'b: +, 'c: +] x: &'a isize, y: &'b [isize], c: &'c str @@ -15,7 +15,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR [+, +, +] // Those same annotations in function arguments become covariant: #[rustc_variance] -struct Test3<'a, 'b, 'c> { //~ ERROR [-, -, -] +struct Test3<'a, 'b, 'c> { //~ ERROR ['a: -, 'b: -, 'c: -] x: extern "Rust" fn(&'a isize), y: extern "Rust" fn(&'b [isize]), c: extern "Rust" fn(&'c str), @@ -24,7 +24,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR [-, -, -] // Mutability induces invariance: #[rustc_variance] -struct Test4<'a, 'b:'a> { //~ ERROR [+, o] +struct Test4<'a, 'b:'a> { //~ ERROR ['a: +, 'b: o] x: &'a mut &'b isize, } @@ -32,7 +32,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR [+, o] // contravariant context: #[rustc_variance] -struct Test5<'a, 'b:'a> { //~ ERROR [-, o] +struct Test5<'a, 'b:'a> { //~ ERROR ['a: -, 'b: o] x: extern "Rust" fn(&'a mut &'b isize), } @@ -42,14 +42,14 @@ struct Test5<'a, 'b:'a> { //~ ERROR [-, o] // argument list occurs in an invariant context. #[rustc_variance] -struct Test6<'a, 'b:'a> { //~ ERROR [+, o] +struct Test6<'a, 'b:'a> { //~ ERROR ['a: +, 'b: o] x: &'a mut extern "Rust" fn(&'b isize), } // No uses at all is bivariant: #[rustc_variance] -struct Test7<'a> { //~ ERROR [*] +struct Test7<'a> { //~ ERROR ['a: *] //~^ ERROR: `'a` is never used x: isize } @@ -57,7 +57,7 @@ struct Test7<'a> { //~ ERROR [*] // Try enums too. #[rustc_variance] -enum Test8<'a, 'b, 'c:'b> { //~ ERROR [-, +, o] +enum Test8<'a, 'b, 'c:'b> { //~ ERROR ['a: -, 'b: +, 'c: o] Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), Test8C(&'b mut &'c str), diff --git a/tests/ui/variance/variance-regions-direct.stderr b/tests/ui/variance/variance-regions-direct.stderr index edfc888f656..45ce0303fb2 100644 --- a/tests/ui/variance/variance-regions-direct.stderr +++ b/tests/ui/variance/variance-regions-direct.stderr @@ -6,43 +6,43 @@ LL | struct Test7<'a> { | = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` -error: [+, +, +] +error: ['a: +, 'b: +, 'c: +] --> $DIR/variance-regions-direct.rs:9:1 | LL | struct Test2<'a, 'b, 'c> { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: [-, -, -] +error: ['a: -, 'b: -, 'c: -] --> $DIR/variance-regions-direct.rs:18:1 | LL | struct Test3<'a, 'b, 'c> { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: [+, o] +error: ['a: +, 'b: o] --> $DIR/variance-regions-direct.rs:27:1 | LL | struct Test4<'a, 'b:'a> { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: [-, o] +error: ['a: -, 'b: o] --> $DIR/variance-regions-direct.rs:35:1 | LL | struct Test5<'a, 'b:'a> { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: [+, o] +error: ['a: +, 'b: o] --> $DIR/variance-regions-direct.rs:45:1 | LL | struct Test6<'a, 'b:'a> { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: [*] +error: ['a: *] --> $DIR/variance-regions-direct.rs:52:1 | LL | struct Test7<'a> { | ^^^^^^^^^^^^^^^^ -error: [-, +, o] +error: ['a: -, 'b: +, 'c: o] --> $DIR/variance-regions-direct.rs:60:1 | LL | enum Test8<'a, 'b, 'c:'b> { diff --git a/tests/ui/variance/variance-regions-indirect.rs b/tests/ui/variance/variance-regions-indirect.rs index 31e25641d8c..aaa4d3f8779 100644 --- a/tests/ui/variance/variance-regions-indirect.rs +++ b/tests/ui/variance/variance-regions-indirect.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] #[rustc_variance] -enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [-, +, o, *] +enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR ['a: -, 'b: +, 'c: o, 'd: *] //~^ ERROR: `'d` is never used Test8A(extern "Rust" fn(&'a isize)), Test8B(&'b [isize]), @@ -13,25 +13,25 @@ enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [-, +, o, *] } #[rustc_variance] -struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, +, -] +struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR ['w: *, 'x: o, 'y: +, 'z: -] //~^ ERROR: `'w` is never used f: Base<'z, 'y, 'x, 'w> } #[rustc_variance] // Combine - and + to yield o -struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *] +struct Derived2<'a, 'b:'a, 'c> { //~ ERROR ['a: o, 'b: o, 'c: *] //~^ ERROR: `'c` is never used f: Base<'a, 'a, 'b, 'c> } #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) -struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, +, *] +struct Derived3<'a:'b, 'b, 'c> { //~ ERROR ['a: o, 'b: +, 'c: *] //~^ ERROR: `'c` is never used f: Base<'a, 'b, 'a, 'c> } #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) -struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [-, +, o] +struct Derived4<'a, 'b, 'c:'b> { //~ ERROR ['a: -, 'b: +, 'c: o] f: Base<'a, 'b, 'c, 'a> } diff --git a/tests/ui/variance/variance-regions-indirect.stderr b/tests/ui/variance/variance-regions-indirect.stderr index 901ec0c6a76..ed839b32350 100644 --- a/tests/ui/variance/variance-regions-indirect.stderr +++ b/tests/ui/variance/variance-regions-indirect.stderr @@ -30,31 +30,31 @@ LL | struct Derived3<'a:'b, 'b, 'c> { | = help: consider removing `'c`, referring to it in a field, or using a marker such as `PhantomData` -error: [-, +, o, *] +error: ['a: -, 'b: +, 'c: o, 'd: *] --> $DIR/variance-regions-indirect.rs:8:1 | LL | enum Base<'a, 'b, 'c:'b, 'd> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [*, o, +, -] +error: ['w: *, 'x: o, 'y: +, 'z: -] --> $DIR/variance-regions-indirect.rs:16:1 | LL | struct Derived1<'w, 'x:'y, 'y, 'z> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o, o, *] +error: ['a: o, 'b: o, 'c: *] --> $DIR/variance-regions-indirect.rs:22:1 | LL | struct Derived2<'a, 'b:'a, 'c> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o, +, *] +error: ['a: o, 'b: +, 'c: *] --> $DIR/variance-regions-indirect.rs:28:1 | LL | struct Derived3<'a:'b, 'b, 'c> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [-, +, o] +error: ['a: -, 'b: +, 'c: o] --> $DIR/variance-regions-indirect.rs:34:1 | LL | struct Derived4<'a, 'b, 'c:'b> { diff --git a/tests/ui/variance/variance-trait-bounds.rs b/tests/ui/variance/variance-trait-bounds.rs index 25a01b160dd..f86fa2bbef7 100644 --- a/tests/ui/variance/variance-trait-bounds.rs +++ b/tests/ui/variance/variance-trait-bounds.rs @@ -13,24 +13,24 @@ trait Setter<T> { } #[rustc_variance] -struct TestStruct<U,T:Setter<U>> { //~ ERROR [+, +] +struct TestStruct<U,T:Setter<U>> { //~ ERROR [U: +, T: +] t: T, u: U } #[rustc_variance] -enum TestEnum<U,T:Setter<U>> { //~ ERROR [*, +] +enum TestEnum<U,T:Setter<U>> { //~ ERROR [U: *, T: +] //~^ ERROR: `U` is never used Foo(T) } #[rustc_variance] -struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [*, +] +struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [U: *, T: +] //~^ ERROR: `U` is never used t: T } #[rustc_variance] -struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [*, +] +struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [U: *, T: +] //~^ ERROR: `U` is never used t: T } diff --git a/tests/ui/variance/variance-trait-bounds.stderr b/tests/ui/variance/variance-trait-bounds.stderr index 95ed18c1ad2..49cee3cbeca 100644 --- a/tests/ui/variance/variance-trait-bounds.stderr +++ b/tests/ui/variance/variance-trait-bounds.stderr @@ -25,25 +25,25 @@ LL | struct TestBox<U,T:Getter<U>+Setter<U>> { = help: consider removing `U`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `U` to be a const parameter, use `const U: /* Type */` instead -error: [+, +] +error: [U: +, T: +] --> $DIR/variance-trait-bounds.rs:16:1 | LL | struct TestStruct<U,T:Setter<U>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [*, +] +error: [U: *, T: +] --> $DIR/variance-trait-bounds.rs:21:1 | LL | enum TestEnum<U,T:Setter<U>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [*, +] +error: [U: *, T: +] --> $DIR/variance-trait-bounds.rs:27:1 | LL | struct TestContraStruct<U,T:Setter<U>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [*, +] +error: [U: *, T: +] --> $DIR/variance-trait-bounds.rs:33:1 | LL | struct TestBox<U,T:Getter<U>+Setter<U>> { diff --git a/tests/ui/variance/variance-trait-object-bound.rs b/tests/ui/variance/variance-trait-object-bound.rs index 11303c46520..ca80c6b6dce 100644 --- a/tests/ui/variance/variance-trait-object-bound.rs +++ b/tests/ui/variance/variance-trait-object-bound.rs @@ -11,7 +11,7 @@ use std::mem; trait T { fn foo(&self); } #[rustc_variance] -struct TOption<'a> { //~ ERROR [+] +struct TOption<'a> { //~ ERROR ['a: +] v: Option<Box<dyn T + 'a>>, } diff --git a/tests/ui/variance/variance-trait-object-bound.stderr b/tests/ui/variance/variance-trait-object-bound.stderr index f0471a34619..0af21ec12cc 100644 --- a/tests/ui/variance/variance-trait-object-bound.stderr +++ b/tests/ui/variance/variance-trait-object-bound.stderr @@ -1,4 +1,4 @@ -error: [+] +error: ['a: +] --> $DIR/variance-trait-object-bound.rs:14:1 | LL | struct TOption<'a> { diff --git a/tests/ui/variance/variance-types-bounds.rs b/tests/ui/variance/variance-types-bounds.rs index d1814dd97a0..f4738a2dae1 100644 --- a/tests/ui/variance/variance-types-bounds.rs +++ b/tests/ui/variance/variance-types-bounds.rs @@ -4,24 +4,24 @@ #![feature(rustc_attrs)] #[rustc_variance] -struct TestImm<A, B> { //~ ERROR [+, +] +struct TestImm<A, B> { //~ ERROR [A: +, B: +] x: A, y: B, } #[rustc_variance] -struct TestMut<A, B:'static> { //~ ERROR [+, o] +struct TestMut<A, B:'static> { //~ ERROR [A: +, B: o] x: A, y: &'static mut B, } #[rustc_variance] -struct TestIndirect<A:'static, B:'static> { //~ ERROR [+, o] +struct TestIndirect<A:'static, B:'static> { //~ ERROR [A: +, B: o] m: TestMut<A, B> } #[rustc_variance] -struct TestIndirect2<A:'static, B:'static> { //~ ERROR [o, o] +struct TestIndirect2<A:'static, B:'static> { //~ ERROR [A: o, B: o] n: TestMut<A, B>, m: TestMut<B, A> } @@ -35,7 +35,7 @@ trait Setter<A> { } #[rustc_variance] -struct TestObject<A, R> { //~ ERROR [o, o] +struct TestObject<A, R> { //~ ERROR [A: o, R: o] n: Box<dyn Setter<A>+Send>, m: Box<dyn Getter<R>+Send>, } diff --git a/tests/ui/variance/variance-types-bounds.stderr b/tests/ui/variance/variance-types-bounds.stderr index bb816443476..408c2ae8d36 100644 --- a/tests/ui/variance/variance-types-bounds.stderr +++ b/tests/ui/variance/variance-types-bounds.stderr @@ -1,28 +1,28 @@ -error: [+, +] +error: [A: +, B: +] --> $DIR/variance-types-bounds.rs:7:1 | LL | struct TestImm<A, B> { | ^^^^^^^^^^^^^^^^^^^^ -error: [+, o] +error: [A: +, B: o] --> $DIR/variance-types-bounds.rs:13:1 | LL | struct TestMut<A, B:'static> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [+, o] +error: [A: +, B: o] --> $DIR/variance-types-bounds.rs:19:1 | LL | struct TestIndirect<A:'static, B:'static> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o, o] +error: [A: o, B: o] --> $DIR/variance-types-bounds.rs:24:1 | LL | struct TestIndirect2<A:'static, B:'static> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o, o] +error: [A: o, R: o] --> $DIR/variance-types-bounds.rs:38:1 | LL | struct TestObject<A, R> { diff --git a/tests/ui/variance/variance-types.rs b/tests/ui/variance/variance-types.rs index cfc03b75473..aa336d1b424 100644 --- a/tests/ui/variance/variance-types.rs +++ b/tests/ui/variance/variance-types.rs @@ -7,32 +7,32 @@ use std::cell::Cell; // not considered bivariant. #[rustc_variance] -struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [+, o, o] +struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR ['a: +, A: o, B: o] t: &'a mut (A,B) } #[rustc_variance] -struct InvariantCell<A> { //~ ERROR [o] +struct InvariantCell<A> { //~ ERROR [A: o] t: Cell<A> } #[rustc_variance] -struct InvariantIndirect<A> { //~ ERROR [o] +struct InvariantIndirect<A> { //~ ERROR [A: o] t: InvariantCell<A> } #[rustc_variance] -struct Covariant<A> { //~ ERROR [+] +struct Covariant<A> { //~ ERROR [A: +] t: A, u: fn() -> A } #[rustc_variance] -struct Contravariant<A> { //~ ERROR [-] +struct Contravariant<A> { //~ ERROR [A: -] t: fn(A) } #[rustc_variance] -enum Enum<A,B,C> { //~ ERROR [+, -, o] +enum Enum<A,B,C> { //~ ERROR [A: +, B: -, C: o] Foo(Covariant<A>), Bar(Contravariant<B>), Zed(Covariant<C>,Contravariant<C>) diff --git a/tests/ui/variance/variance-types.stderr b/tests/ui/variance/variance-types.stderr index 0fda4b8036e..f2a67949425 100644 --- a/tests/ui/variance/variance-types.stderr +++ b/tests/ui/variance/variance-types.stderr @@ -1,34 +1,34 @@ -error: [+, o, o] +error: ['a: +, A: o, B: o] --> $DIR/variance-types.rs:10:1 | LL | struct InvariantMut<'a,A:'a,B:'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [o] +error: [A: o] --> $DIR/variance-types.rs:15:1 | LL | struct InvariantCell<A> { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: [o] +error: [A: o] --> $DIR/variance-types.rs:20:1 | LL | struct InvariantIndirect<A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [+] +error: [A: +] --> $DIR/variance-types.rs:25:1 | LL | struct Covariant<A> { | ^^^^^^^^^^^^^^^^^^^ -error: [-] +error: [A: -] --> $DIR/variance-types.rs:30:1 | LL | struct Contravariant<A> { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: [+, -, o] +error: [A: +, B: -, C: o] --> $DIR/variance-types.rs:35:1 | LL | enum Enum<A,B,C> { diff --git a/triagebot.toml b/triagebot.toml index 161fe98fca9..d7bc60e6c6f 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -913,7 +913,7 @@ cc = ["@kobzol"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514", "jhpratt", "oli-obk"] +users_on_vacation = ["jyn514", "jhpratt", "oli-obk", "kobzol"] [assign.adhoc_groups] compiler-team = [ @@ -951,6 +951,7 @@ libs = [ "@joboet", "@jhpratt", "@tgross35", + "@thomcc", ] bootstrap = [ "@Mark-Simulacrum", |
