diff --git a/Cargo.lock b/Cargo.lock index ee6726eae514d..5a8914b2cadc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3699,6 +3699,9 @@ dependencies = [ [[package]] name = "rustc_fs_util" version = "0.0.0" +dependencies = [ + "tempfile", +] [[package]] name = "rustc_graphviz" @@ -3753,7 +3756,6 @@ dependencies = [ "rustc_middle", "rustc_session", "rustc_span", - "rustc_target", "rustc_trait_selection", "smallvec", "tracing", @@ -3792,6 +3794,7 @@ dependencies = [ "rustc_middle", "rustc_session", "rustc_span", + "rustc_target", "rustc_trait_selection", "smallvec", "tracing", @@ -4011,7 +4014,6 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", - "tempfile", "tracing", ] @@ -4915,15 +4917,6 @@ dependencies = [ "color-eyre", ] -[[package]] -name = "spdx" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b69356da67e2fc1f542c71ea7e654a361a79c938e4424392ecf4fa065d2193" -dependencies = [ - "smallvec", -] - [[package]] name = "spdx-expression" version = "0.5.2" @@ -5743,9 +5736,9 @@ dependencies = [ [[package]] name = "wasi-preview1-component-adapter-provider" -version = "29.0.1" +version = "31.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcd9f21bbde82ba59e415a8725e6ad0d0d7e9e460b1a3ccbca5bdee952c1a324" +checksum = "86fabda09a0d89ffd1615b297b4a5d4b4d99df9598aeb24685837e63019e927b" [[package]] name = "wasm-bindgen" @@ -5807,9 +5800,9 @@ dependencies = [ [[package]] name = "wasm-component-ld" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "580305a8e3f1b7a79859a8db897de643533b2851c5eb080fe5800233f16dec88" +checksum = "a60a07a994a3538b57d8c5f8caba19f4793fb4c7156276e5e90e90acbb829e20" dependencies = [ "anyhow", "clap", @@ -5817,7 +5810,7 @@ dependencies = [ "libc", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.223.1", + "wasmparser 0.229.0", "wat", "windows-sys 0.59.0", "winsplit", @@ -5844,39 +5837,24 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.223.1" +version = "0.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0a96fdeaee8fbeb4bd917fb8157d48c0d61c3b1f4ee4c363c8e8d68b2f4fe8" -dependencies = [ - "leb128", - "wasmparser 0.223.1", -] - -[[package]] -name = "wasm-encoder" -version = "0.228.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d30290541f2d4242a162bbda76b8f2d8b1ac59eab3568ed6f2327d52c9b2c4" +checksum = "38ba1d491ecacb085a2552025c10a675a6fddcbd03b1fc9b36c536010ce265d2" dependencies = [ "leb128fmt", - "wasmparser 0.228.0", + "wasmparser 0.229.0", ] [[package]] name = "wasm-metadata" -version = "0.223.1" +version = "0.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7e37883181704d96b89dbd8f1291be13694c71cd0663aebb94b46d235a377" +checksum = "78fdb7d29a79191ab363dc90c1ddd3a1e880ffd5348d92d48482393a9e6c5f4d" dependencies = [ "anyhow", "indexmap", - "serde", - "serde_derive", - "serde_json", - "spdx", - "url", - "wasm-encoder 0.223.1", - "wasmparser 0.223.1", + "wasm-encoder 0.229.0", + "wasmparser 0.229.0", ] [[package]] @@ -5900,9 +5878,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.223.1" +version = "0.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664b980991ed9a8c834eb528a8979ab1109edcf52dc05dd5751e2cc3fb31035d" +checksum = "0cc3b1f053f5d41aa55640a1fa9b6d1b8a9e4418d118ce308d20e24ff3575a8c" dependencies = [ "bitflags", "hashbrown", @@ -5911,35 +5889,24 @@ dependencies = [ "serde", ] -[[package]] -name = "wasmparser" -version = "0.228.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4abf1132c1fdf747d56bbc1bb52152400c70f336870f968b85e89ea422198ae3" -dependencies = [ - "bitflags", - "indexmap", - "semver", -] - [[package]] name = "wast" -version = "228.0.0" +version = "229.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5aae124478cb51439f6587f074a3a5e835afd22751c59a87b2e2a882727c97" +checksum = "63fcaff613c12225696bb163f79ca38ffb40e9300eff0ff4b8aa8b2f7eadf0d9" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width 0.2.0", - "wasm-encoder 0.228.0", + "wasm-encoder 0.229.0", ] [[package]] name = "wat" -version = "1.228.0" +version = "1.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec29c89a8d055df988de7236483bf569988ac3d6905899f6af5ef920f9385ad" +checksum = "4189bad08b70455a9e9e67dc126d2dcf91fac143a80f1046747a5dde6d4c33e0" dependencies = [ "wast", ] @@ -6398,9 +6365,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.223.1" +version = "0.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fc2fcc52a79f6f010a89c867e53e06d4227f86c58984add3e37f32b8e7af5f0" +checksum = "7f550067740e223bfe6c4878998e81cdbe2529dd9a793dc49248dd6613394e8b" dependencies = [ "anyhow", "bitflags", @@ -6409,17 +6376,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.223.1", + "wasm-encoder 0.229.0", "wasm-metadata", - "wasmparser 0.223.1", + "wasmparser 0.229.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.223.1" +version = "0.229.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "263fde17f1fbe55a413f16eb59094bf751795c6da469a05c3d45ea6c77df6b40" +checksum = "459c6ba62bf511d6b5f2a845a2a736822e38059c1cfa0b644b467bbbfae4efa6" dependencies = [ "anyhow", "id-arena", @@ -6430,7 +6397,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.223.1", + "wasmparser 0.229.0", ] [[package]] diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 34c84c64070d2..1e1bdfb5977af 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -13,9 +13,9 @@ use object::read::archive::ArchiveFile; use object::read::macho::FatArch; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::Mmap; +use rustc_fs_util::TempDirBuilder; use rustc_session::Session; use rustc_span::Symbol; -use tempfile::Builder as TempFileBuilder; use tracing::trace; use super::metadata::search_for_section; @@ -501,7 +501,7 @@ impl<'a> ArArchiveBuilder<'a> { // it creates. We need it to be the default mode for back compat reasons however. (See // #107495) To handle this we are telling tempfile to create a temporary directory instead // and then inside this directory create a file using File::create. - let archive_tmpdir = TempFileBuilder::new() + let archive_tmpdir = TempDirBuilder::new() .suffix(".temp-archive") .tempdir_in(output.parent().unwrap_or_else(|| Path::new(""))) .map_err(|err| { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index f0c47ac41e8a0..323538969d73b 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{DiagCtxtHandle, LintDiagnostic}; -use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize}; +use rustc_fs_util::{TempDirBuilder, fix_windows_verbatim_for_gcc, try_canonicalize}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_macros::LintDiagnostic; use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file}; @@ -48,7 +48,6 @@ use rustc_target::spec::{ LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, }; -use tempfile::Builder as TempFileBuilder; use tracing::{debug, info, warn}; use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; @@ -100,7 +99,7 @@ pub fn link_binary( }); if outputs.outputs.should_link() { - let tmpdir = TempFileBuilder::new() + let tmpdir = TempDirBuilder::new() .prefix("rustc") .tempdir() .unwrap_or_else(|error| sess.dcx().emit_fatal(errors::CreateTempDir { error })); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 76270cad48f39..43ba67e7dc63b 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -918,6 +918,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes, "#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers." ), + rustc_attr!( + rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, + "`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument." + ), rustc_attr!( rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No, "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`." diff --git a/compiler/rustc_fs_util/Cargo.toml b/compiler/rustc_fs_util/Cargo.toml index baca3bc7d49eb..90a6acade8b03 100644 --- a/compiler/rustc_fs_util/Cargo.toml +++ b/compiler/rustc_fs_util/Cargo.toml @@ -5,4 +5,5 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +tempfile = "3.7.1" # tidy-alphabetical-end diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 0df1b243d697e..7a883a13b72da 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -1,6 +1,8 @@ -use std::ffi::CString; +use std::ffi::{CString, OsStr}; use std::path::{Path, PathBuf, absolute}; -use std::{fs, io}; +use std::{env, fs, io}; + +use tempfile::TempDir; // Unfortunately, on windows, it looks like msvcrt.dll is silently translating // verbatim paths under the hood to non-verbatim paths! This manifests itself as @@ -102,3 +104,43 @@ pub fn path_to_c_string(p: &Path) -> CString { pub fn try_canonicalize>(path: P) -> io::Result { fs::canonicalize(&path).or_else(|_| absolute(&path)) } + +pub struct TempDirBuilder<'a, 'b> { + builder: tempfile::Builder<'a, 'b>, +} + +impl<'a, 'b> TempDirBuilder<'a, 'b> { + pub fn new() -> Self { + Self { builder: tempfile::Builder::new() } + } + + pub fn prefix + ?Sized>(&mut self, prefix: &'a S) -> &mut Self { + self.builder.prefix(prefix); + self + } + + pub fn suffix + ?Sized>(&mut self, suffix: &'b S) -> &mut Self { + self.builder.suffix(suffix); + self + } + + pub fn tempdir_in>(&self, dir: P) -> io::Result { + let dir = dir.as_ref(); + // On Windows in CI, we had been getting fairly frequent "Access is denied" + // errors when creating temporary directories. + // So this implements a simple retry with backoff loop. + #[cfg(windows)] + for wait in 1..11 { + match self.builder.tempdir_in(dir) { + Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {} + t => return t, + } + std::thread::sleep(std::time::Duration::from_millis(1 << wait)); + } + self.builder.tempdir_in(dir) + } + + pub fn tempdir(&self) -> io::Result { + self.tempdir_in(env::temp_dir()) + } +} diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index e5017794d8f29..58213c4f4e462 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -26,7 +26,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 92701e3328e92..277bb7bd3e15c 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -450,9 +450,6 @@ hir_analysis_recursive_generic_parameter = {$param_def_kind} `{$param_name}` is hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}` .note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}` -hir_analysis_register_type_unstable = - type `{$ty}` cannot be used with this register class in stable - hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}` hir_analysis_return_type_notation_equality_bound = diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4f338c6a19e69..f92b2aea160a1 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -730,7 +730,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { .is_ok() { check_impl_items_against_trait(tcx, def_id, impl_trait_header); - check_on_unimplemented(tcx, def_id); } } } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 5fbd771976bbb..fad8abf5fae85 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -67,7 +67,6 @@ mod check; mod compare_impl_item; mod entry; pub mod intrinsic; -pub mod intrinsicck; mod region; pub mod wfcheck; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 508970cf2554d..2b1661aaac8f0 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1675,14 +1675,6 @@ pub(crate) struct CmseEntryGeneric { pub span: Span, } -#[derive(Diagnostic)] -#[diag(hir_analysis_register_type_unstable)] -pub(crate) struct RegisterTypeUnstable<'a> { - #[primary_span] - pub span: Span, - pub ty: Ty<'a>, -} - #[derive(LintDiagnostic)] #[diag(hir_analysis_supertrait_item_shadowing)] pub(crate) struct SupertraitItemShadowing { diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index b2b90cb29e36f..f00125c3e090a 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -22,6 +22,7 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 9e1b70f5767b4..23309102c4da5 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -179,6 +179,9 @@ hir_typeck_ptr_cast_add_auto_to_object = cannot add {$traits_len -> .help = use `transmute` if you're sure this is sound .label = unsupported cast +hir_typeck_register_type_unstable = + type `{$ty}` cannot be used with this register class in stable + hir_typeck_remove_semi_for_coerce = you might have meant to return the `match` expression hir_typeck_remove_semi_for_coerce_expr = this could be implicitly returned but it is a statement, not a tail expression hir_typeck_remove_semi_for_coerce_ret = the `match` arms can conform to this return type diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 9e7305430e5f5..732795535087e 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -963,3 +963,11 @@ pub(crate) enum SupertraitItemShadowee { traits: DiagSymbolList, }, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_register_type_unstable)] +pub(crate) struct RegisterTypeUnstable<'a> { + #[primary_span] + pub span: Span, + pub ty: Ty<'a>, +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 8b2d9ab297905..e70aa1a70645e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -8,7 +8,6 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirId, Node, QPath}; -use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_index::IndexVec; @@ -33,6 +32,7 @@ use crate::errors::SuggestPtrNullMut; use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx}; use crate::fn_ctxt::infer::FnCall; use crate::gather_locals::Declaration; +use crate::inline_asm::InlineAsmCtxt; use crate::method::MethodCallee; use crate::method::probe::IsSuggestion; use crate::method::probe::Mode::MethodCall; @@ -98,13 +98,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len()); for (asm, hir_id) in deferred_asm_checks.drain(..) { let enclosing_id = self.tcx.hir_enclosing_body_owner(hir_id); - InlineAsmCtxt::new( - enclosing_id, - &self.infcx, - self.typing_env(self.param_env), - &*self.typeck_results.borrow(), - ) - .check_asm(asm); + InlineAsmCtxt::new(self, enclosing_id).check_asm(asm); } } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs similarity index 89% rename from compiler/rustc_hir_analysis/src/check/intrinsicck.rs rename to compiler/rustc_hir_typeck/src/inline_asm.rs index 32a582aadc1ca..6399f0a78ae2f 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -3,25 +3,22 @@ use rustc_ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem}; -use rustc_infer::infer::InferCtxt; use rustc_middle::bug; -use rustc_middle::ty::{ - self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, TypeckResults, UintTy, -}; +use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; -use rustc_span::{Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::asm::{ InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo, }; +use rustc_trait_selection::infer::InferCtxtExt; +use crate::FnCtxt; use crate::errors::RegisterTypeUnstable; -pub struct InlineAsmCtxt<'a, 'tcx> { - typing_env: ty::TypingEnv<'tcx>, +pub(crate) struct InlineAsmCtxt<'a, 'tcx> { target_features: &'tcx FxIndexSet, - infcx: &'a InferCtxt<'tcx>, - typeck_results: &'a TypeckResults<'tcx>, + fcx: &'a FnCtxt<'a, 'tcx>, } enum NonAsmTypeReason<'tcx> { @@ -33,27 +30,17 @@ enum NonAsmTypeReason<'tcx> { } impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { - pub fn new( - def_id: LocalDefId, - infcx: &'a InferCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - typeck_results: &'a TypeckResults<'tcx>, - ) -> Self { - InlineAsmCtxt { - typing_env, - target_features: infcx.tcx.asm_target_features(def_id), - infcx, - typeck_results, - } + pub(crate) fn new(fcx: &'a FnCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self { + InlineAsmCtxt { target_features: fcx.tcx.asm_target_features(def_id), fcx } } fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx + self.fcx.tcx } fn expr_ty(&self, expr: &hir::Expr<'tcx>) -> Ty<'tcx> { - let ty = self.typeck_results.expr_ty_adjusted(expr); - let ty = self.infcx.resolve_vars_if_possible(ty); + let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted(expr); + let ty = self.fcx.try_structurally_resolve_type(expr.span, ty); if ty.has_non_region_infer() { Ty::new_misc_error(self.tcx()) } else { @@ -62,19 +49,23 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()` - fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool { + fn is_thin_ptr_ty(&self, span: Span, ty: Ty<'tcx>) -> bool { // Type still may have region variables, but `Sized` does not depend // on those, so just erase them before querying. - if ty.is_sized(self.tcx(), self.typing_env) { + if self.fcx.type_is_sized_modulo_regions(self.fcx.param_env, ty) { return true; } - if let ty::Foreign(..) = ty.kind() { + if let ty::Foreign(..) = self.fcx.try_structurally_resolve_type(span, ty).kind() { return true; } false } - fn get_asm_ty(&self, ty: Ty<'tcx>) -> Result> { + fn get_asm_ty( + &self, + span: Span, + ty: Ty<'tcx>, + ) -> Result> { let asm_ty_isize = match self.tcx().sess.target.pointer_width { 16 => InlineAsmType::I16, 32 => InlineAsmType::I32, @@ -95,7 +86,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Float(FloatTy::F128) => Ok(InlineAsmType::F128), ty::FnPtr(..) => Ok(asm_ty_isize), ty::RawPtr(elem_ty, _) => { - if self.is_thin_ptr_ty(elem_ty) { + if self.is_thin_ptr_ty(span, elem_ty) { Ok(asm_ty_isize) } else { Err(NonAsmTypeReason::NotSizedPtr(ty)) @@ -109,11 +100,20 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { let field = &fields[FieldIdx::ZERO]; let elem_ty = field.ty(self.tcx(), args); - let (size, ty) = match elem_ty.kind() { + let (size, ty) = match *elem_ty.kind() { ty::Array(ty, len) => { - let len = self.tcx().normalize_erasing_regions(self.typing_env, *len); + // FIXME: `try_structurally_resolve_const` doesn't eval consts + // in the old solver. + let len = if self.fcx.next_trait_solver() { + self.fcx.try_structurally_resolve_const(span, len) + } else { + self.fcx.tcx.normalize_erasing_regions( + self.fcx.typing_env(self.fcx.param_env), + len, + ) + }; if let Some(len) = len.try_to_target_usize(self.tcx()) { - (len, *ty) + (len, ty) } else { return Err(NonAsmTypeReason::UnevaluatedSIMDArrayLength( field.did, len, @@ -183,9 +183,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ); let fields = &ty.non_enum_variant().fields; let ty = fields[FieldIdx::ZERO].ty(self.tcx(), args); - self.get_asm_ty(ty) + self.get_asm_ty(expr.span, ty) } - _ => self.get_asm_ty(ty), + _ => self.get_asm_ty(expr.span, ty), }; let asm_ty = match asm_ty { Ok(asm_ty) => asm_ty, @@ -193,7 +193,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { match reason { NonAsmTypeReason::UnevaluatedSIMDArrayLength(did, len) => { let msg = format!("cannot evaluate SIMD vector length `{len}`"); - self.infcx + self.fcx .dcx() .struct_span_err(self.tcx().def_span(did), msg) .with_span_note( @@ -204,7 +204,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } NonAsmTypeReason::Invalid(ty) => { let msg = format!("cannot use value of type `{ty}` for inline assembly"); - self.infcx.dcx().struct_span_err(expr.span, msg).with_note( + self.fcx.dcx().struct_span_err(expr.span, msg).with_note( "only integers, floats, SIMD vectors, pointers and function pointers \ can be used as arguments for inline assembly", ).emit(); @@ -213,7 +213,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { let msg = format!( "cannot use value of unsized pointer type `{ty}` for inline assembly" ); - self.infcx + self.fcx .dcx() .struct_span_err(expr.span, msg) .with_note("only sized pointers can be used in inline assembly") @@ -223,7 +223,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { let msg = format!( "cannot use SIMD vector with element type `{ty}` for inline assembly" ); - self.infcx.dcx() + self.fcx.dcx() .struct_span_err(self.tcx().def_span(did), msg).with_span_note( expr.span, "only integers, floats, SIMD vectors, pointers and function pointers \ @@ -232,7 +232,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } NonAsmTypeReason::EmptySIMDArray(ty) => { let msg = format!("use of empty SIMD vector `{ty}`"); - self.infcx.dcx().struct_span_err(expr.span, msg).emit(); + self.fcx.dcx().struct_span_err(expr.span, msg).emit(); } } return None; @@ -241,9 +241,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // Check that the type implements Copy. The only case where this can // possibly fail is for SIMD types which don't #[derive(Copy)]. - if !self.tcx().type_is_copy_modulo_regions(self.typing_env, ty) { + if !self.fcx.type_is_copy_modulo_regions(self.fcx.param_env, ty) { let msg = "arguments for inline assembly must be copyable"; - self.infcx + self.fcx .dcx() .struct_span_err(expr.span, msg) .with_note(format!("`{ty}` does not implement the Copy trait")) @@ -263,7 +263,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if in_asm_ty != asm_ty { let msg = "incompatible types for asm inout argument"; let in_expr_ty = self.expr_ty(in_expr); - self.infcx + self.fcx .dcx() .struct_span_err(vec![in_expr.span, expr.span], msg) .with_span_label(in_expr.span, format!("type `{in_expr_ty}`")) @@ -296,7 +296,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ) } else { let msg = format!("type `{ty}` cannot be used with this register class"); - let mut err = self.infcx.dcx().struct_span_err(expr.span, msg); + let mut err = self.fcx.dcx().struct_span_err(expr.span, msg); let supported_tys: Vec<_> = supported_tys.iter().map(|(t, _)| t.to_string()).collect(); err.note(format!( @@ -326,7 +326,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if let Some(feature) = feature { if !self.target_features.contains(feature) { let msg = format!("`{feature}` target feature is not enabled"); - self.infcx + self.fcx .dcx() .struct_span_err(expr.span, msg) .with_note(format!( @@ -384,9 +384,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { Some(asm_ty) } - pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) { + pub(crate) fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) { let Some(asm_arch) = self.tcx().sess.asm_arch else { - self.infcx.dcx().delayed_bug("target architecture does not support asm"); + self.fcx.dcx().delayed_bug("target architecture does not support asm"); return; }; let allow_experimental_reg = self.tcx().features().asm_experimental_reg(); @@ -418,7 +418,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { op.is_clobber(), ) { let msg = format!("cannot use register `{}`: {}", reg.name(), msg); - self.infcx.dcx().span_err(op_sp, msg); + self.fcx.dcx().span_err(op_sp, msg); continue; } } @@ -458,7 +458,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { reg_class.name(), feature ); - self.infcx.dcx().span_err(op_sp, msg); + self.fcx.dcx().span_err(op_sp, msg); // register isn't enabled, don't do more checks continue; } @@ -472,7 +472,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { .intersperse(", ") .collect::(), ); - self.infcx.dcx().span_err(op_sp, msg); + self.fcx.dcx().span_err(op_sp, msg); // register isn't enabled, don't do more checks continue; } @@ -512,7 +512,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Error(_) => {} _ if ty.is_integral() => {} _ => { - self.infcx + self.fcx .dcx() .struct_span_err(op_sp, "invalid type for `const` operand") .with_span_label( @@ -531,7 +531,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::FnDef(..) => {} ty::Error(_) => {} _ => { - self.infcx + self.fcx .dcx() .struct_span_err(op_sp, "invalid `sym` operand") .with_span_label( diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index c3717b4efa47f..d861a4f81b0e0 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -23,6 +23,7 @@ mod diverges; mod errors; mod expectation; mod expr; +mod inline_asm; // Used by clippy; pub mod expr_use_visitor; mod fallback; diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 60c183bd56b1f..a6499b07fe26c 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -360,6 +360,10 @@ lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than pos lint_impl_trait_redundant_captures = all possible in-scope parameters are already captured, so `use<...>` syntax is redundant .suggestion = remove the `use<...>` syntax +lint_implicit_unsafe_autorefs = implicit autoref creates a reference to the dereference of a raw pointer + .note = creating a reference requires the pointer target to be valid and imposes aliasing requirements + .suggestion = try using a raw pointer method instead; or if this reference is intentional, make it explicit + lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe .label = not FFI-safe .note = the type is defined here diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs new file mode 100644 index 0000000000000..5dd26854c9570 --- /dev/null +++ b/compiler/rustc_lint/src/autorefs.rs @@ -0,0 +1,153 @@ +use rustc_ast::{BorrowKind, UnOp}; +use rustc_hir::{Expr, ExprKind, Mutability}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, OverloadedDeref}; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::sym; + +use crate::lints::{ImplicitUnsafeAutorefsDiag, ImplicitUnsafeAutorefsSuggestion}; +use crate::{LateContext, LateLintPass, LintContext}; + +declare_lint! { + /// The `dangerous_implicit_autorefs` lint checks for implicitly taken references + /// to dereferences of raw pointers. + /// + /// ### Example + /// + /// ```rust + /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { + /// &raw mut (*ptr)[..16] + /// // ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`, + /// // implicitly creating a reference + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When working with raw pointers it's usually undesirable to create references, + /// since they inflict additional safety requirements. Unfortunately, it's possible + /// to take a reference to the dereference of a raw pointer implicitly, which inflicts + /// the usual reference requirements. + /// + /// If you are sure that you can soundly take a reference, then you can take it explicitly: + /// + /// ```rust + /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { + /// &raw mut (&mut *ptr)[..16] + /// } + /// ``` + /// + /// Otherwise try to find an alternative way to achive your goals using only raw pointers: + /// + /// ```rust + /// use std::slice; + /// + /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { + /// slice::from_raw_parts_mut(ptr.cast(), 16) + /// } + /// ``` + pub DANGEROUS_IMPLICIT_AUTOREFS, + Warn, + "implicit reference to a dereference of a raw pointer", + report_in_external_macro +} + +declare_lint_pass!(ImplicitAutorefs => [DANGEROUS_IMPLICIT_AUTOREFS]); + +impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + // This logic has mostly been taken from + // + + // 5. Either of the following: + // a. A deref followed by any non-deref place projection (that intermediate + // deref will typically be auto-inserted). + // b. A method call annotated with `#[rustc_no_implicit_refs]`. + // c. A deref followed by a `&raw const` or `&raw mut`. + let mut is_coming_from_deref = false; + let inner = match expr.kind { + ExprKind::AddrOf(BorrowKind::Raw, _, inner) => match inner.kind { + ExprKind::Unary(UnOp::Deref, inner) => { + is_coming_from_deref = true; + inner + } + _ => return, + }, + ExprKind::Index(base, _, _) => base, + ExprKind::MethodCall(_, inner, _, _) + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) => + { + inner + } + ExprKind::Field(inner, _) => inner, + _ => return, + }; + + let typeck = cx.typeck_results(); + let adjustments_table = typeck.adjustments(); + + if let Some(adjustments) = adjustments_table.get(inner.hir_id) + // 4. Any number of automatically inserted deref/derefmut calls. + && let adjustments = peel_derefs_adjustments(&**adjustments) + // 3. An automatically inserted reference (might come from a deref). + && let [adjustment] = adjustments + && let Some(borrow_mutbl) = has_implicit_borrow(adjustment) + && let ExprKind::Unary(UnOp::Deref, dereferenced) = + // 2. Any number of place projections. + peel_place_mappers(inner).kind + // 1. Deref of a raw pointer. + && typeck.expr_ty(dereferenced).is_raw_ptr() + { + cx.emit_span_lint( + DANGEROUS_IMPLICIT_AUTOREFS, + expr.span.source_callsite(), + ImplicitUnsafeAutorefsDiag { + suggestion: ImplicitUnsafeAutorefsSuggestion { + mutbl: borrow_mutbl.ref_prefix_str(), + deref: if is_coming_from_deref { "*" } else { "" }, + start_span: inner.span.shrink_to_lo(), + end_span: inner.span.shrink_to_hi(), + }, + }, + ) + } + } +} + +/// Peels expressions from `expr` that can map a place. +fn peel_place_mappers<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { + loop { + match expr.kind { + ExprKind::Index(base, _idx, _) => expr = &base, + ExprKind::Field(e, _) => expr = &e, + _ => break expr, + } + } +} + +/// Peel derefs adjustments until the last last element. +fn peel_derefs_adjustments<'a>(mut adjs: &'a [Adjustment<'a>]) -> &'a [Adjustment<'a>] { + while let [Adjustment { kind: Adjust::Deref(_), .. }, end @ ..] = adjs + && !end.is_empty() + { + adjs = end; + } + adjs +} + +/// Test if some adjustment has some implicit borrow. +/// +/// Returns `Some(mutability)` if the argument adjustment has implicit borrow in it. +fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option { + match kind { + &Adjust::Deref(Some(OverloadedDeref { mutbl, .. })) => Some(mutbl), + &Adjust::Borrow(AutoBorrow::Ref(mutbl)) => Some(mutbl.into()), + Adjust::NeverToAny + | Adjust::Pointer(..) + | Adjust::ReborrowPin(..) + | Adjust::Deref(None) + | Adjust::Borrow(AutoBorrow::RawPtr(..)) => None, + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 96705e79e0a41..b910d6a138e11 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -36,6 +36,7 @@ mod async_closures; mod async_fn_in_trait; +mod autorefs; pub mod builtin; mod context; mod dangling; @@ -83,6 +84,7 @@ mod utils; use async_closures::AsyncClosureUsage; use async_fn_in_trait::AsyncFnInTrait; +use autorefs::*; use builtin::*; use dangling::*; use default_could_be_derived::DefaultCouldBeDerived; @@ -200,6 +202,7 @@ late_lint_methods!( PathStatements: PathStatements, LetUnderscore: LetUnderscore, InvalidReferenceCasting: InvalidReferenceCasting, + ImplicitAutorefs: ImplicitAutorefs, // Depends on referenced function signatures in expressions UnusedResults: UnusedResults, UnitBindings: UnitBindings, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 8ab64fbd127af..487184b836a43 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -55,6 +55,26 @@ pub(crate) enum ShadowedIntoIterDiagSub { }, } +// autorefs.rs +#[derive(LintDiagnostic)] +#[diag(lint_implicit_unsafe_autorefs)] +#[note] +pub(crate) struct ImplicitUnsafeAutorefsDiag { + #[subdiagnostic] + pub suggestion: ImplicitUnsafeAutorefsSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(lint_suggestion, applicability = "maybe-incorrect")] +pub(crate) struct ImplicitUnsafeAutorefsSuggestion { + pub mutbl: &'static str, + pub deref: &'static str, + #[suggestion_part(code = "({mutbl}{deref}")] + pub start_span: Span, + #[suggestion_part(code = ")")] + pub end_span: Span, +} + // builtin.rs #[derive(LintDiagnostic)] #[diag(lint_builtin_while_true)] diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 68058250a2671..ed5edeef1617d 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -229,6 +229,7 @@ pub fn initialize_available_targets() { LLVMInitializeXtensaTargetInfo, LLVMInitializeXtensaTarget, LLVMInitializeXtensaTargetMC, + LLVMInitializeXtensaAsmPrinter, LLVMInitializeXtensaAsmParser ); init_target!( diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 08dcc3d519a2b..b11f9260be7c0 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -26,7 +26,6 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -tempfile = "3.2" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs index c4e1e0f1d1a99..e57534b847ef0 100644 --- a/compiler/rustc_metadata/src/fs.rs +++ b/compiler/rustc_metadata/src/fs.rs @@ -2,11 +2,11 @@ use std::path::{Path, PathBuf}; use std::{fs, io}; use rustc_data_structures::temp_dir::MaybeTempDir; +use rustc_fs_util::TempDirBuilder; use rustc_middle::ty::TyCtxt; use rustc_session::config::{CrateType, OutFileName, OutputType}; use rustc_session::output::filename_for_metadata; use rustc_session::{MetadataKind, Session}; -use tempfile::Builder as TempFileBuilder; use crate::errors::{ BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile, @@ -45,7 +45,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { // final destination, with an `fs::rename` call. In order for the rename to // always succeed, the temporary file needs to be on the same filesystem, // which is why we create it inside the output directory specifically. - let metadata_tmpdir = TempFileBuilder::new() + let metadata_tmpdir = TempDirBuilder::new() .prefix("rmeta") .tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new(""))) .unwrap_or_else(|err| tcx.dcx().emit_fatal(FailedCreateTempdir { err })); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 98057a25f04c7..e8dad1e056cbd 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -590,6 +590,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.defaultness(def_id).has_value() } + fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool { + self.specializes((impl_def_id, victim_def_id)) + } + fn impl_is_default(self, impl_def_id: DefId) -> bool { self.defaultness(impl_def_id).is_default() } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index ecb57cc0ad71b..381a732b8dee9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -10,6 +10,7 @@ use rustc_type_ir::{ }; use tracing::{debug, instrument}; +use super::has_only_region_constraints; use super::trait_goals::TraitGoalProvenVia; use crate::delegate::SolverDelegate; use crate::solve::inspect::ProbeKind; @@ -771,6 +772,69 @@ where } }) } +} + +pub(super) enum AllowInferenceConstraints { + Yes, + No, +} + +impl EvalCtxt<'_, D> +where + D: SolverDelegate, + I: Interner, +{ + /// Check whether we can ignore impl candidates due to specialization. + /// + /// This is only necessary for `feature(specialization)` and seems quite ugly. + pub(super) fn filter_specialized_impls( + &mut self, + allow_inference_constraints: AllowInferenceConstraints, + candidates: &mut Vec>, + ) { + match self.typing_mode() { + TypingMode::Coherence => return, + TypingMode::Analysis { .. } + | TypingMode::Borrowck { .. } + | TypingMode::PostBorrowckAnalysis { .. } + | TypingMode::PostAnalysis => {} + } + + let mut i = 0; + 'outer: while i < candidates.len() { + let CandidateSource::Impl(victim_def_id) = candidates[i].source else { + i += 1; + continue; + }; + + for (j, c) in candidates.iter().enumerate() { + if i == j { + continue; + } + + let CandidateSource::Impl(other_def_id) = c.source else { + continue; + }; + + // See if we can toss out `victim` based on specialization. + // + // While this requires us to know *for sure* that the `lhs` impl applies + // we still use modulo regions here. This is fine as specialization currently + // assumes that specializing impls have to be always applicable, meaning that + // the only allowed region constraints may be constraints also present on the default impl. + if matches!(allow_inference_constraints, AllowInferenceConstraints::Yes) + || has_only_region_constraints(c.result) + { + if self.cx().impl_specializes(other_def_id, victim_def_id) { + candidates.remove(i); + continue 'outer; + } + } + } + + i += 1; + } + } /// Assemble and merge candidates for goals which are related to an underlying trait /// goal. Right now, this is normalizes-to and host effect goals. @@ -857,7 +921,7 @@ where } } TraitGoalProvenVia::Misc => { - let candidates = + let mut candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All); // Prefer "orphaned" param-env normalization predicates, which are used @@ -871,6 +935,13 @@ where return Ok(response); } + // We drop specialized impls to allow normalization via a final impl here. In case + // the specializing impl has different inference constraints from the specialized + // impl, proving the trait goal is already ambiguous, so we never get here. This + // means we can just ignore inference constraints and don't have to special-case + // constraining the normalized-to `term`. + self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates); + let responses: Vec<_> = candidates.iter().map(|c| c.result).collect(); if let Some(response) = self.try_merge_responses(&responses) { Ok(response) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 27ca8787db5c5..19fb2b00fcb3a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -16,6 +16,7 @@ use rustc_type_ir::{ }; use tracing::{instrument, trace}; +use super::has_only_region_constraints; use crate::coherence; use crate::delegate::SolverDelegate; use crate::solve::inspect::{self, ProofTreeBuilder}; @@ -476,13 +477,8 @@ where Ok(response) => response, }; - let has_changed = if !response.value.var_values.is_identity_modulo_regions() - || !response.value.external_constraints.opaque_types.is_empty() - { - HasChanged::Yes - } else { - HasChanged::No - }; + let has_changed = + if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No }; let (normalization_nested_goals, certainty) = self.instantiate_and_apply_query_response(goal.param_env, orig_values, response); diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 0695c5acdcab3..d9cf84787a036 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -70,6 +70,17 @@ fn has_no_inference_or_external_constraints( && normalization_nested_goals.is_empty() } +fn has_only_region_constraints(response: ty::Canonical>) -> bool { + let ExternalConstraintsData { + region_constraints: _, + ref opaque_types, + ref normalization_nested_goals, + } = *response.value.external_constraints; + response.value.var_values.is_identity_modulo_regions() + && opaque_types.is_empty() + && normalization_nested_goals.is_empty() +} + impl<'a, D, I> EvalCtxt<'a, D> where D: SolverDelegate, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 9466901683e21..119d197de134f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -213,9 +213,6 @@ where ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }; - // In case the associated item is hidden due to specialization, we have to - // return ambiguity this would otherwise be incomplete, resulting in - // unsoundness during coherence (#105782). let target_item_def_id = match ecx.fetch_eligible_assoc_item( goal_trait_ref, goal.predicate.def_id(), @@ -223,8 +220,28 @@ where ) { Ok(Some(target_item_def_id)) => target_item_def_id, Ok(None) => { - return ecx - .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + match ecx.typing_mode() { + // In case the associated item is hidden due to specialization, we have to + // return ambiguity this would otherwise be incomplete, resulting in + // unsoundness during coherence (#105782). + ty::TypingMode::Coherence => { + return ecx.evaluate_added_goals_and_make_canonical_response( + Certainty::AMBIGUOUS, + ); + } + // Outside of coherence, we treat the associated item as rigid instead. + ty::TypingMode::Analysis { .. } + | ty::TypingMode::Borrowck { .. } + | ty::TypingMode::PostBorrowckAnalysis { .. } + | ty::TypingMode::PostAnalysis => { + ecx.structurally_instantiate_normalizes_to_term( + goal, + goal.predicate.alias, + ); + return ecx + .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + } + }; } Err(guar) => return error_response(ecx, guar), }; diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 3404c47bba2a3..24657496df6a5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -13,7 +13,7 @@ use tracing::{instrument, trace}; use crate::delegate::SolverDelegate; use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; -use crate::solve::assembly::{self, AssembleCandidatesFrom, Candidate}; +use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidatesFrom, Candidate}; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, @@ -1338,6 +1338,8 @@ where }; } + self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates); + // If there are *only* global where bounds, then make sure to return that this // is still reported as being proven-via the param-env so that rigid projections // operate correctly. Otherwise, drop all global where-bounds before merging the diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index ae9143486eea3..ac4f7ed64e22f 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -675,6 +675,8 @@ parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns ar parse_nul_in_c_str = null characters in C string literals are not supported +parse_or_in_let_chain = `||` operators are not supported in let chain conditions + parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings parse_out_of_range_hex_escape = out of range hex escape diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 35cf4c1b00d4b..6a6fb0eb9b5ba 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -478,6 +478,13 @@ pub(crate) struct ExpectedExpressionFoundLet { pub comparison: Option, } +#[derive(Diagnostic)] +#[diag(parse_or_in_let_chain)] +pub(crate) struct OrInLetChain { + #[primary_span] + pub span: Span, +} + #[derive(Subdiagnostic, Clone, Copy)] #[multipart_suggestion( parse_maybe_missing_let, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 370eb3f402d93..f3b53971b2957 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4073,14 +4073,18 @@ impl MutVisitor for CondChecker<'_> { match e.kind { ExprKind::Let(_, _, _, ref mut recovered @ Recovered::No) => { if let Some(reason) = self.forbid_let_reason { - *recovered = Recovered::Yes(self.parser.dcx().emit_err( - errors::ExpectedExpressionFoundLet { + let error = match reason { + NotSupportedOr(or_span) => { + self.parser.dcx().emit_err(errors::OrInLetChain { span: or_span }) + } + _ => self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet { span, reason, missing_let: self.missing_let, comparison: self.comparison, - }, - )); + }), + }; + *recovered = Recovered::Yes(error); } else if self.depth > 1 { // Top level `let` is always allowed; only gate chains match self.let_chains_policy { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7a27bc5c38738..a61d446a3a93b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -179,6 +179,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::rustc_as_ptr, ..] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } + [sym::rustc_no_implicit_autorefs, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } [sym::rustc_never_returns_null_ptr, ..] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 32a5aff0cb327..9ddeef6c462d9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1830,6 +1830,7 @@ symbols! { rustc_must_implement_one_of, rustc_never_returns_null_ptr, rustc_never_type_options, + rustc_no_implicit_autorefs, rustc_no_mir_inline, rustc_nonnull_optimization_guaranteed, rustc_nounwind, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 848d0646d009f..1f4fa5aac102a 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -163,15 +163,15 @@ where fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); let mut errors = Vec::new(); - for i in 0.. { - if !infcx.tcx.recursion_limit().value_within_limit(i) { - self.obligations.on_fulfillment_overflow(infcx); - // Only return true errors that we have accumulated while processing. - return errors; - } - + loop { let mut has_changed = false; - for obligation in self.obligations.drain_pending(|_| true) { + for mut obligation in self.obligations.drain_pending(|_| true) { + if !infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) { + self.obligations.on_fulfillment_overflow(infcx); + // Only return true errors that we have accumulated while processing. + return errors; + } + let goal = obligation.as_goal(); let result = <&SolverDelegate<'tcx>>::from(infcx) .evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span) @@ -189,6 +189,13 @@ where }; if changed == HasChanged::Yes { + // We increment the recursion depth here to track the number of times + // this goal has resulted in inference progress. This doesn't precisely + // model the way that we track recursion depth in the old solver due + // to the fact that we only process root obligations, but it is a good + // approximation and should only result in fulfillment overflow in + // pathological cases. + obligation.recursion_depth += 1; has_changed = true; } diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs index d555ea702a9fe..4d5f630ae229e 100644 --- a/compiler/rustc_transmute/src/layout/mod.rs +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -65,7 +65,12 @@ impl fmt::Debug for Byte { } } -#[cfg(test)] +impl From> for Byte { + fn from(src: RangeInclusive) -> Self { + Self::new(src) + } +} + impl From for Byte { fn from(src: u8) -> Self { Self::from_val(src) diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 6a09be18ef944..7cf712ce9e977 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -1,4 +1,4 @@ -use std::ops::ControlFlow; +use std::ops::{ControlFlow, RangeInclusive}; use super::{Byte, Def, Ref}; @@ -32,6 +32,22 @@ where Byte(Byte), } +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub(crate) enum Endian { + Little, + Big, +} + +#[cfg(feature = "rustc")] +impl From for Endian { + fn from(order: rustc_abi::Endian) -> Endian { + match order { + rustc_abi::Endian::Little => Endian::Little, + rustc_abi::Endian::Big => Endian::Big, + } + } +} + impl Tree where D: Def, @@ -59,22 +75,60 @@ where /// A `Tree` representing the layout of `bool`. pub(crate) fn bool() -> Self { - Self::Byte(Byte::new(0x00..=0x01)) + Self::byte(0x00..=0x01) } /// A `Tree` whose layout matches that of a `u8`. pub(crate) fn u8() -> Self { - Self::Byte(Byte::new(0x00..=0xFF)) + Self::byte(0x00..=0xFF) + } + + /// A `Tree` whose layout matches that of a `char`. + pub(crate) fn char(order: Endian) -> Self { + // `char`s can be in the following ranges: + // - [0, 0xD7FF] + // - [0xE000, 10FFFF] + // + // All other `char` values are illegal. We can thus represent a `char` + // as a union of three possible layouts: + // - 00 00 [00, D7] XX + // - 00 00 [E0, FF] XX + // - 00 [01, 10] XX XX + + const _0: RangeInclusive = 0..=0; + const BYTE: RangeInclusive = 0x00..=0xFF; + let x = Self::from_big_endian(order, [_0, _0, 0x00..=0xD7, BYTE]); + let y = Self::from_big_endian(order, [_0, _0, 0xE0..=0xFF, BYTE]); + let z = Self::from_big_endian(order, [_0, 0x01..=0x10, BYTE, BYTE]); + Self::alt([x, y, z]) } - /// A `Tree` whose layout accepts exactly the given bit pattern. - pub(crate) fn from_bits(bits: u8) -> Self { - Self::Byte(Byte::from_val(bits)) + /// A `Tree` whose layout matches `std::num::NonZeroXxx`. + #[allow(dead_code)] + pub(crate) fn nonzero(width_in_bytes: u64) -> Self { + const BYTE: RangeInclusive = 0x00..=0xFF; + const NONZERO: RangeInclusive = 0x01..=0xFF; + + (0..width_in_bytes) + .map(|nz_idx| { + (0..width_in_bytes) + .map(|pos| Self::byte(if pos == nz_idx { NONZERO } else { BYTE })) + .fold(Self::unit(), Self::then) + }) + .fold(Self::uninhabited(), Self::or) + } + + pub(crate) fn bytes>(bytes: [B; N]) -> Self { + Self::seq(bytes.map(B::into).map(Self::Byte)) + } + + pub(crate) fn byte(byte: impl Into) -> Self { + Self::Byte(byte.into()) } /// A `Tree` whose layout is a number of the given width. - pub(crate) fn number(width_in_bytes: usize) -> Self { - Self::Seq(vec![Self::u8(); width_in_bytes]) + pub(crate) fn number(width_in_bytes: u64) -> Self { + Self::Seq(vec![Self::u8(); width_in_bytes.try_into().unwrap()]) } /// A `Tree` whose layout is entirely padding of the given width. @@ -125,13 +179,35 @@ where Self::Byte(..) | Self::Ref(..) | Self::Def(..) => true, } } -} -impl Tree -where - D: Def, - R: Ref, -{ + /// Produces a `Tree` which represents a sequence of bytes stored in + /// `order`. + /// + /// `bytes` is taken to be in big-endian byte order, and its order will be + /// swapped if `order == Endian::Little`. + pub(crate) fn from_big_endian>( + order: Endian, + mut bytes: [B; N], + ) -> Self { + if order == Endian::Little { + (&mut bytes[..]).reverse(); + } + + Self::bytes(bytes) + } + + /// Produces a `Tree` where each of the trees in `trees` are sequenced one + /// after another. + pub(crate) fn seq(trees: [Tree; N]) -> Self { + trees.into_iter().fold(Tree::unit(), Self::then) + } + + /// Produces a `Tree` where each of the trees in `trees` are accepted as + /// alternative layouts. + pub(crate) fn alt(trees: [Tree; N]) -> Self { + trees.into_iter().fold(Tree::uninhabited(), Self::or) + } + /// Produces a new `Tree` where `other` is sequenced after `self`. pub(crate) fn then(self, other: Self) -> Self { match (self, other) { @@ -222,17 +298,17 @@ pub(crate) mod rustc { ty::Float(nty) => { let width = nty.bit_width() / 8; - Ok(Self::number(width as _)) + Ok(Self::number(width.try_into().unwrap())) } ty::Int(nty) => { let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8; - Ok(Self::number(width as _)) + Ok(Self::number(width.try_into().unwrap())) } ty::Uint(nty) => { let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8; - Ok(Self::number(width as _)) + Ok(Self::number(width.try_into().unwrap())) } ty::Tuple(members) => Self::from_tuple((ty, layout), members, cx), @@ -249,11 +325,33 @@ pub(crate) mod rustc { .fold(Tree::unit(), |tree, elt| tree.then(elt))) } - ty::Adt(adt_def, _args_ref) if !ty.is_box() => match adt_def.adt_kind() { - AdtKind::Struct => Self::from_struct((ty, layout), *adt_def, cx), - AdtKind::Enum => Self::from_enum((ty, layout), *adt_def, cx), - AdtKind::Union => Self::from_union((ty, layout), *adt_def, cx), - }, + ty::Adt(adt_def, _args_ref) if !ty.is_box() => { + let (lo, hi) = cx.tcx().layout_scalar_valid_range(adt_def.did()); + + use core::ops::Bound::*; + let is_transparent = adt_def.repr().transparent(); + match (adt_def.adt_kind(), lo, hi) { + (AdtKind::Struct, Unbounded, Unbounded) => { + Self::from_struct((ty, layout), *adt_def, cx) + } + (AdtKind::Struct, Included(1), Included(_hi)) if is_transparent => { + // FIXME(@joshlf): Support `NonZero` types: + // - Check to make sure that the first field is + // numerical + // - Check to make sure that the upper bound is the + // maximum value for the field's type + // - Construct `Self::nonzero` + Err(Err::NotYetSupported) + } + (AdtKind::Enum, Unbounded, Unbounded) => { + Self::from_enum((ty, layout), *adt_def, cx) + } + (AdtKind::Union, Unbounded, Unbounded) => { + Self::from_union((ty, layout), *adt_def, cx) + } + _ => Err(Err::NotYetSupported), + } + } ty::Ref(lifetime, ty, mutability) => { let layout = layout_of(cx, *ty)?; @@ -268,6 +366,8 @@ pub(crate) mod rustc { })) } + ty::Char => Ok(Self::char(cx.tcx().data_layout.endian.into())), + _ => Err(Err::NotYetSupported), } } @@ -450,7 +550,7 @@ pub(crate) mod rustc { &bytes[bytes.len() - size.bytes_usize()..] } }; - Self::Seq(bytes.iter().map(|&b| Self::from_bits(b)).collect()) + Self::Seq(bytes.iter().map(|&b| Self::byte(b)).collect()) } /// Constructs a `Tree` from a union. diff --git a/compiler/rustc_transmute/src/layout/tree/tests.rs b/compiler/rustc_transmute/src/layout/tree/tests.rs index 44f50a25c939a..8c3dbbe37ab21 100644 --- a/compiler/rustc_transmute/src/layout/tree/tests.rs +++ b/compiler/rustc_transmute/src/layout/tree/tests.rs @@ -20,23 +20,18 @@ mod prune { #[test] fn seq_1() { - let layout: Tree = - Tree::def(Def::NoSafetyInvariants).then(Tree::from_bits(0x00)); - assert_eq!( - layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), - Tree::from_bits(0x00) - ); + let layout: Tree = Tree::def(Def::NoSafetyInvariants).then(Tree::byte(0x00)); + assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::byte(0x00)); } #[test] fn seq_2() { - let layout: Tree = Tree::from_bits(0x00) - .then(Tree::def(Def::NoSafetyInvariants)) - .then(Tree::from_bits(0x01)); + let layout: Tree = + Tree::byte(0x00).then(Tree::def(Def::NoSafetyInvariants)).then(Tree::byte(0x01)); assert_eq!( layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), - Tree::from_bits(0x00).then(Tree::from_bits(0x01)) + Tree::byte(0x00).then(Tree::byte(0x01)) ); } } @@ -66,7 +61,7 @@ mod prune { #[test] fn invisible_def_in_seq_len_3() { let layout: Tree = Tree::def(Def::NoSafetyInvariants) - .then(Tree::from_bits(0x00)) + .then(Tree::byte(0x00)) .then(Tree::def(Def::HasSafetyInvariants)); assert_eq!( layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), @@ -94,12 +89,9 @@ mod prune { #[test] fn visible_def_in_seq_len_3() { let layout: Tree = Tree::def(Def::NoSafetyInvariants) - .then(Tree::from_bits(0x00)) + .then(Tree::byte(0x00)) .then(Tree::def(Def::NoSafetyInvariants)); - assert_eq!( - layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), - Tree::from_bits(0x00) - ); + assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::byte(0x00)); } } } diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index 24e2a1acadd68..992fcb7cc4c81 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -177,9 +177,9 @@ mod bool { #[test] fn should_permit_validity_expansion_and_reject_contraction() { - let b0 = layout::Tree::::from_bits(0); - let b1 = layout::Tree::::from_bits(1); - let b2 = layout::Tree::::from_bits(2); + let b0 = layout::Tree::::byte(0); + let b1 = layout::Tree::::byte(1); + let b2 = layout::Tree::::byte(2); let alts = [b0, b1, b2]; @@ -279,8 +279,8 @@ mod alt { fn should_permit_identity_transmutation() { type Tree = layout::Tree; - let x = Tree::Seq(vec![Tree::from_bits(0), Tree::from_bits(0)]); - let y = Tree::Seq(vec![Tree::bool(), Tree::from_bits(1)]); + let x = Tree::Seq(vec![Tree::byte(0), Tree::byte(0)]); + let y = Tree::Seq(vec![Tree::bool(), Tree::byte(1)]); let layout = Tree::Alt(vec![x, y]); let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( @@ -323,6 +323,76 @@ mod union { } } +mod char { + use super::*; + use crate::layout::tree::Endian; + + #[test] + fn should_permit_valid_transmutation() { + for order in [Endian::Big, Endian::Little] { + use Answer::*; + let char_layout = layout::Tree::::char(order); + + // `char`s can be in the following ranges: + // - [0, 0xD7FF] + // - [0xE000, 10FFFF] + // + // This loop synthesizes a singleton-validity type for the extremes + // of each range, and for one past the end of the extremes of each + // range. + let no = No(Reason::DstIsBitIncompatible); + for (src, answer) in [ + (0u32, Yes), + (0xD7FF, Yes), + (0xD800, no.clone()), + (0xDFFF, no.clone()), + (0xE000, Yes), + (0x10FFFF, Yes), + (0x110000, no.clone()), + (0xFFFF0000, no.clone()), + (0xFFFFFFFF, no), + ] { + let src_layout = + layout::tree::Tree::::from_big_endian(order, src.to_be_bytes()); + + let a = is_transmutable(&src_layout, &char_layout, Assume::default()); + assert_eq!(a, answer, "endian:{order:?},\nsrc:{src:x}"); + } + } + } +} + +mod nonzero { + use super::*; + use crate::{Answer, Reason}; + + const NONZERO_BYTE_WIDTHS: [u64; 5] = [1, 2, 4, 8, 16]; + + #[test] + fn should_permit_identity_transmutation() { + for width in NONZERO_BYTE_WIDTHS { + let layout = layout::Tree::::nonzero(width); + assert_eq!(is_transmutable(&layout, &layout, Assume::default()), Answer::Yes); + } + } + + #[test] + fn should_permit_valid_transmutation() { + for width in NONZERO_BYTE_WIDTHS { + use Answer::*; + + let num = layout::Tree::::number(width); + let nz = layout::Tree::::nonzero(width); + + let a = is_transmutable(&num, &nz, Assume::default()); + assert_eq!(a, No(Reason::DstIsBitIncompatible), "width:{width}"); + + let a = is_transmutable(&nz, &num, Assume::default()); + assert_eq!(a, Yes, "width:{width}"); + } + } +} + mod r#ref { use super::*; @@ -330,7 +400,7 @@ mod r#ref { fn should_permit_identity_transmutation() { type Tree = crate::layout::Tree; - let layout = Tree::Seq(vec![Tree::from_bits(0), Tree::Ref([()])]); + let layout = Tree::Seq(vec![Tree::byte(0x00), Tree::Ref([()])]); let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( layout.clone(), diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index ab38556589e03..9758cecaf6ac7 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -286,6 +286,8 @@ pub trait Interner: fn has_item_definition(self, def_id: Self::DefId) -> bool; + fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool; + fn impl_is_default(self, impl_def_id: Self::DefId) -> bool; fn impl_trait_ref(self, impl_def_id: Self::DefId) -> ty::EarlyBinder>; diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 9a161d057db09..cd9e04a915aa2 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1832,6 +1832,7 @@ impl String { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] #[rustc_confusables("length", "size")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] pub const fn len(&self) -> usize { self.vec.len() } @@ -1851,6 +1852,7 @@ impl String { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] pub const fn is_empty(&self) -> bool { self.len() == 0 } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 68e4add30e5d0..65a83cb98ba6a 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2588,7 +2588,7 @@ impl Vec { #[inline] #[track_caller] unsafe fn append_elements(&mut self, other: *const [T]) { - let count = unsafe { (*other).len() }; + let count = other.len(); self.reserve(count); let len = self.len(); unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) }; diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index 37d9a28fb99c0..8106c088f0ba2 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -67,6 +67,7 @@ pub trait Index { /// /// May panic if the index is out of bounds. #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[track_caller] fn index(&self, index: Idx) -> &Self::Output; } @@ -171,6 +172,7 @@ pub trait IndexMut: Index { /// /// May panic if the index is out of bounds. #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[track_caller] fn index_mut(&mut self, index: Idx) -> &mut Self::Output; } diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 9e6acf04bf722..dd1c2f2c28513 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -676,7 +676,7 @@ //! let data_ptr = unpinned_src.data.as_ptr() as *const u8; //! let slice_ptr = unpinned_src.slice.as_ptr() as *const u8; //! let offset = slice_ptr.offset_from(data_ptr) as usize; -//! let len = (*unpinned_src.slice.as_ptr()).len(); +//! let len = unpinned_src.slice.as_ptr().len(); //! //! unpinned_self.slice = NonNull::from(&mut unpinned_self.data[offset..offset+len]); //! } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 1ae0849db5b56..fbfa4d874158b 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -109,6 +109,7 @@ impl [T] { #[lang = "slice_len_fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[inline] #[must_use] pub const fn len(&self) -> usize { @@ -128,6 +129,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_is_empty", since = "1.39.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[inline] #[must_use] pub const fn is_empty(&self) -> bool { @@ -562,6 +564,7 @@ impl [T] { /// assert_eq!(None, v.get(0..4)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[inline] #[must_use] pub fn get(&self, index: I) -> Option<&I::Output> @@ -587,6 +590,7 @@ impl [T] { /// assert_eq!(x, &[0, 42, 2]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[inline] #[must_use] pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> @@ -624,6 +628,7 @@ impl [T] { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[inline] #[must_use] pub unsafe fn get_unchecked(&self, index: I) -> &I::Output @@ -666,6 +671,7 @@ impl [T] { /// assert_eq!(x, &[1, 13, 4]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[inline] #[must_use] pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 79b4953fcc11a..2099327d2f14a 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -134,6 +134,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_len", since = "1.39.0")] #[rustc_diagnostic_item = "str_len"] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[must_use] #[inline] pub const fn len(&self) -> usize { @@ -153,6 +154,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_is_empty", since = "1.39.0")] + #[cfg_attr(not(bootstrap), rustc_no_implicit_autorefs)] #[must_use] #[inline] pub const fn is_empty(&self) -> bool { diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index c46dcebedcab8..36a1c57b02012 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -513,13 +513,13 @@ impl Span { } /// Creates an empty span pointing to directly before this span. - #[unstable(feature = "proc_macro_span", issue = "54725")] + #[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")] pub fn start(&self) -> Span { Span(self.0.start()) } /// Creates an empty span pointing to directly after this span. - #[unstable(feature = "proc_macro_span", issue = "54725")] + #[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")] pub fn end(&self) -> Span { Span(self.0.end()) } @@ -527,7 +527,7 @@ impl Span { /// The one-indexed line of the source file where the span starts. /// /// To obtain the line of the span's end, use `span.end().line()`. - #[unstable(feature = "proc_macro_span", issue = "54725")] + #[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")] pub fn line(&self) -> usize { self.0.line() } @@ -535,7 +535,7 @@ impl Span { /// The one-indexed column of the source file where the span starts. /// /// To obtain the column of the span's end, use `span.end().column()`. - #[unstable(feature = "proc_macro_span", issue = "54725")] + #[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")] pub fn column(&self) -> usize { self.0.column() } diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 91701576130e6..c9595b051e207 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -388,11 +388,15 @@ mod enum_keyword {} /// lazy_static;`. The other use is in foreign function interfaces (FFI). /// /// `extern` is used in two different contexts within FFI. The first is in the form of external -/// blocks, for declaring function interfaces that Rust code can call foreign code by. +/// blocks, for declaring function interfaces that Rust code can call foreign code by. This use +/// of `extern` is unsafe, since we are asserting to the compiler that all function declarations +/// are correct. If they are not, using these items may lead to undefined behavior. /// /// ```rust ignore +/// // SAFETY: The function declarations given below are in +/// // line with the header files of `my_c_library`. /// #[link(name = "my_c_library")] -/// extern "C" { +/// unsafe extern "C" { /// fn my_c_function(x: i32) -> bool; /// } /// ``` diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index d5c965f7053e0..e41a06aff3036 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -407,16 +407,23 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { is_extern_crate = check_item(&item, &mut info, crate_name); } - StmtKind::Expr(ref expr) if matches!(expr.kind, ast::ExprKind::Err(_)) => { - reset_error_count(&psess); - return Err(()); + StmtKind::Expr(ref expr) => { + if matches!(expr.kind, ast::ExprKind::Err(_)) { + reset_error_count(&psess); + return Err(()); + } + has_non_items = true; } + // We assume that the macro calls will expand to item(s) even though they could + // expand to statements and expressions. And the simple fact that we're trying + // to retrieve a `main` function inside it is a terrible idea. StmtKind::MacCall(ref mac_call) if !info.has_main_fn => { let mut iter = mac_call.mac.args.tokens.iter(); @@ -437,7 +444,9 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result {} + _ => { + has_non_items = true; + } } // Weirdly enough, the `Stmt` span doesn't include its attributes, so we need to @@ -462,6 +471,11 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { diff --git a/src/tools/miri/tests/pass/dst-raw.rs b/src/tools/miri/tests/pass/dst-raw.rs index f26191a1d5998..3d0b843b3da22 100644 --- a/src/tools/miri/tests/pass/dst-raw.rs +++ b/src/tools/miri/tests/pass/dst-raw.rs @@ -1,5 +1,7 @@ // Test DST raw pointers +#![allow(dangerous_implicit_autorefs)] + trait Trait { fn foo(&self) -> isize; } diff --git a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs b/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs index 830e9c33847cf..e86cb3711acb0 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,3 +1,5 @@ +#![allow(dangerous_implicit_autorefs)] + use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; use std::mem::{self, MaybeUninit}; diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml index f8ae91f9e6f1b..642d48b9952ed 100644 --- a/src/tools/wasm-component-ld/Cargo.toml +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -10,4 +10,4 @@ name = "wasm-component-ld" path = "src/main.rs" [dependencies] -wasm-component-ld = "0.5.12" +wasm-component-ld = "0.5.13" diff --git a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs index 508faadcf6729..ca5dd78746789 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs +++ b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs @@ -4,12 +4,12 @@ //@ compile-flags:--test //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" -//@ failure-status: 101 +//@ check-pass /// /// /// ```rust -/// struct S {}; // unexpected semicolon after struct def +/// struct S {}; /// /// fn main() { /// assert_eq!(0, 1); diff --git a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout index 9eb8b391e7809..1068b98cb0fbb 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout +++ b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout @@ -1,29 +1,6 @@ running 1 test -test $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) ... FAILED +test $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) ... ok -failures: - ----- $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) stdout ---- -error: expected item, found `;` - --> $DIR/failed-doctest-extra-semicolon-on-item.rs:12:12 - | -LL | struct S {}; // unexpected semicolon after struct def - | ^ - | - = help: braced struct declarations are not followed by a semicolon -help: remove this semicolon - | -LL - struct S {}; // unexpected semicolon after struct def -LL + struct S {} // unexpected semicolon after struct def - | - -error: aborting due to 1 previous error - -Couldn't compile the test. - -failures: - $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) - -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs new file mode 100644 index 0000000000000..ee2299c0fd87e --- /dev/null +++ b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs @@ -0,0 +1,22 @@ +// This test ensures that if there is an expression alongside a `main` +// function, it will not consider the entire code to be part of the `main` +// function and will generate its own function to wrap everything. +// +// This is a regression test for: +// * +// * +//@ compile-flags:--test +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass + +#![crate_name = "foo"] + +//! ``` +//! # if cfg!(miri) { return; } +//! use std::ops::Deref; +//! +//! fn main() { +//! println!("Hi!"); +//! } +//! ``` diff --git a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout new file mode 100644 index 0000000000000..90d7c3546bf10 --- /dev/null +++ b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/test-main-alongside-exprs.rs - (line 15) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/ui/asm/named_const_simd_vec_len.rs b/tests/ui/asm/named_const_simd_vec_len.rs index 7df4d922d5c91..7fedeb7d4d122 100644 --- a/tests/ui/asm/named_const_simd_vec_len.rs +++ b/tests/ui/asm/named_const_simd_vec_len.rs @@ -3,6 +3,9 @@ //@ only-x86_64 //@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver #![feature(repr_simd)] diff --git a/tests/ui/asm/normalizable-asm-ty.rs b/tests/ui/asm/normalizable-asm-ty.rs new file mode 100644 index 0000000000000..ad76fb0f4298a --- /dev/null +++ b/tests/ui/asm/normalizable-asm-ty.rs @@ -0,0 +1,15 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +fn invoke(pc_section: &[usize]) { + unsafe { + std::arch::asm!( + "/* {} */", + in(reg) pc_section[0] + ); + } +} + +fn main() {} diff --git a/tests/ui/coroutine/dont-drop-stalled-generators.rs b/tests/ui/coroutine/dont-drop-stalled-generators.rs new file mode 100644 index 0000000000000..8e0c45a9773b3 --- /dev/null +++ b/tests/ui/coroutine/dont-drop-stalled-generators.rs @@ -0,0 +1,25 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass +//@ edition: 2024 + +// This test previously used the `is_copy_raw` query during +// HIR typeck, dropping the list of generators from the current +// body. This then caused a query cycle. + +struct W(*const T); + +impl Clone for W { + fn clone(&self) -> Self { W(self.0) } +} + +impl Copy for W {} + +fn main() { + let coro = async {}; + let x = W(&raw const coro); + let c = || { + let x = x; + }; +} diff --git a/tests/ui/dynamically-sized-types/dst-raw.rs b/tests/ui/dynamically-sized-types/dst-raw.rs index 111848c5a7f05..935f0f11ca61f 100644 --- a/tests/ui/dynamically-sized-types/dst-raw.rs +++ b/tests/ui/dynamically-sized-types/dst-raw.rs @@ -1,6 +1,8 @@ //@ run-pass // Test DST raw pointers +#![allow(dangerous_implicit_autorefs)] + trait Trait { fn foo(&self) -> isize; } diff --git a/tests/ui/lint/implicit_autorefs.fixed b/tests/ui/lint/implicit_autorefs.fixed new file mode 100644 index 0000000000000..96a617b20c918 --- /dev/null +++ b/tests/ui/lint/implicit_autorefs.fixed @@ -0,0 +1,99 @@ +//@ check-pass +//@ run-rustfix + +#![allow(dead_code)] // For the rustfix-ed code. + +use std::mem::ManuallyDrop; +use std::ops::Deref; + +unsafe fn test_const(ptr: *const [u8]) { + let _ = (&(*ptr))[..16]; + //~^ WARN implicit autoref +} + +struct Test { + field: [u8], +} + +unsafe fn test_field(ptr: *const Test) -> *const [u8] { + let l = (&(*ptr).field).len(); + //~^ WARN implicit autoref + + &raw const (&(*ptr).field)[..l - 1] + //~^ WARN implicit autoref +} + +unsafe fn test_builtin_index(a: *mut [String]) { + _ = (&(*a)[0]).len(); + //~^ WARN implicit autoref + + _ = (&(&(*a))[..1][0]).len(); + //~^ WARN implicit autoref + //~^^ WARN implicit autoref +} + +unsafe fn test_overloaded_deref_const(ptr: *const ManuallyDrop) { + let _ = (&(*ptr)).field; + //~^ WARN implicit autoref + let _ = &raw const (&(*ptr)).field; + //~^ WARN implicit autoref +} + +unsafe fn test_overloaded_deref_mut(ptr: *mut ManuallyDrop) { + let _ = (&(*ptr)).field; + //~^ WARN implicit autoref +} + +unsafe fn test_double_overloaded_deref_const(ptr: *const ManuallyDrop>) { + let _ = (&(*ptr)).field; + //~^ WARN implicit autoref +} + +unsafe fn test_manually_overloaded_deref() { + struct W(T); + + impl Deref for W { + type Target = T; + fn deref(&self) -> &T { &self.0 } + } + + let w: W = W(5); + let w = &raw const w; + let _p: *const i32 = &raw const *(&**w); + //~^ WARN implicit autoref +} + +struct Test2 { + // Derefs to `[u8]`. + field: &'static [u8] +} + +fn test_more_manual_deref(ptr: *const Test2) -> usize { + unsafe { (&(*ptr).field).len() } + //~^ WARN implicit autoref +} + +unsafe fn test_no_attr(ptr: *mut ManuallyDrop) { + ptr.write(ManuallyDrop::new(1)); // Should not warn, as `ManuallyDrop::write` is not + // annotated with `#[rustc_no_implicit_auto_ref]` +} + +unsafe fn test_vec_get(ptr: *mut Vec) { + let _ = (&(*ptr)).get(0); + //~^ WARN implicit autoref + let _ = (&(*ptr)).get_unchecked(0); + //~^ WARN implicit autoref + let _ = (&mut (*ptr)).get_mut(0); + //~^ WARN implicit autoref + let _ = (&mut (*ptr)).get_unchecked_mut(0); + //~^ WARN implicit autoref +} + +unsafe fn test_string(ptr: *mut String) { + let _ = (&(*ptr)).len(); + //~^ WARN implicit autoref + let _ = (&(*ptr)).is_empty(); + //~^ WARN implicit autoref +} + +fn main() {} diff --git a/tests/ui/lint/implicit_autorefs.rs b/tests/ui/lint/implicit_autorefs.rs new file mode 100644 index 0000000000000..61dd0ac50ce75 --- /dev/null +++ b/tests/ui/lint/implicit_autorefs.rs @@ -0,0 +1,99 @@ +//@ check-pass +//@ run-rustfix + +#![allow(dead_code)] // For the rustfix-ed code. + +use std::mem::ManuallyDrop; +use std::ops::Deref; + +unsafe fn test_const(ptr: *const [u8]) { + let _ = (*ptr)[..16]; + //~^ WARN implicit autoref +} + +struct Test { + field: [u8], +} + +unsafe fn test_field(ptr: *const Test) -> *const [u8] { + let l = (*ptr).field.len(); + //~^ WARN implicit autoref + + &raw const (*ptr).field[..l - 1] + //~^ WARN implicit autoref +} + +unsafe fn test_builtin_index(a: *mut [String]) { + _ = (*a)[0].len(); + //~^ WARN implicit autoref + + _ = (*a)[..1][0].len(); + //~^ WARN implicit autoref + //~^^ WARN implicit autoref +} + +unsafe fn test_overloaded_deref_const(ptr: *const ManuallyDrop) { + let _ = (*ptr).field; + //~^ WARN implicit autoref + let _ = &raw const (*ptr).field; + //~^ WARN implicit autoref +} + +unsafe fn test_overloaded_deref_mut(ptr: *mut ManuallyDrop) { + let _ = (*ptr).field; + //~^ WARN implicit autoref +} + +unsafe fn test_double_overloaded_deref_const(ptr: *const ManuallyDrop>) { + let _ = (*ptr).field; + //~^ WARN implicit autoref +} + +unsafe fn test_manually_overloaded_deref() { + struct W(T); + + impl Deref for W { + type Target = T; + fn deref(&self) -> &T { &self.0 } + } + + let w: W = W(5); + let w = &raw const w; + let _p: *const i32 = &raw const **w; + //~^ WARN implicit autoref +} + +struct Test2 { + // Derefs to `[u8]`. + field: &'static [u8] +} + +fn test_more_manual_deref(ptr: *const Test2) -> usize { + unsafe { (*ptr).field.len() } + //~^ WARN implicit autoref +} + +unsafe fn test_no_attr(ptr: *mut ManuallyDrop) { + ptr.write(ManuallyDrop::new(1)); // Should not warn, as `ManuallyDrop::write` is not + // annotated with `#[rustc_no_implicit_auto_ref]` +} + +unsafe fn test_vec_get(ptr: *mut Vec) { + let _ = (*ptr).get(0); + //~^ WARN implicit autoref + let _ = (*ptr).get_unchecked(0); + //~^ WARN implicit autoref + let _ = (*ptr).get_mut(0); + //~^ WARN implicit autoref + let _ = (*ptr).get_unchecked_mut(0); + //~^ WARN implicit autoref +} + +unsafe fn test_string(ptr: *mut String) { + let _ = (*ptr).len(); + //~^ WARN implicit autoref + let _ = (*ptr).is_empty(); + //~^ WARN implicit autoref +} + +fn main() {} diff --git a/tests/ui/lint/implicit_autorefs.stderr b/tests/ui/lint/implicit_autorefs.stderr new file mode 100644 index 0000000000000..6dd1ac65ada98 --- /dev/null +++ b/tests/ui/lint/implicit_autorefs.stderr @@ -0,0 +1,219 @@ +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:10:13 + | +LL | let _ = (*ptr)[..16]; + | ^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements + = note: `#[warn(dangerous_implicit_autorefs)]` on by default +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&(*ptr))[..16]; + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:19:13 + | +LL | let l = (*ptr).field.len(); + | ^^^^^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let l = (&(*ptr).field).len(); + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:22:16 + | +LL | &raw const (*ptr).field[..l - 1] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | &raw const (&(*ptr).field)[..l - 1] + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:27:9 + | +LL | _ = (*a)[0].len(); + | ^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | _ = (&(*a)[0]).len(); + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:30:9 + | +LL | _ = (*a)[..1][0].len(); + | ^^^^^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | _ = (&(*a)[..1][0]).len(); + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:30:9 + | +LL | _ = (*a)[..1][0].len(); + | ^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | _ = (&(*a))[..1][0].len(); + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:36:13 + | +LL | let _ = (*ptr).field; + | ^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&(*ptr)).field; + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:38:24 + | +LL | let _ = &raw const (*ptr).field; + | ^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = &raw const (&(*ptr)).field; + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:43:13 + | +LL | let _ = (*ptr).field; + | ^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&(*ptr)).field; + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:48:13 + | +LL | let _ = (*ptr).field; + | ^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&(*ptr)).field; + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:62:26 + | +LL | let _p: *const i32 = &raw const **w; + | ^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _p: *const i32 = &raw const *(&**w); + | +++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:72:14 + | +LL | unsafe { (*ptr).field.len() } + | ^^^^^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | unsafe { (&(*ptr).field).len() } + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:82:13 + | +LL | let _ = (*ptr).get(0); + | ^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&(*ptr)).get(0); + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:84:13 + | +LL | let _ = (*ptr).get_unchecked(0); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&(*ptr)).get_unchecked(0); + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:86:13 + | +LL | let _ = (*ptr).get_mut(0); + | ^^^^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&mut (*ptr)).get_mut(0); + | +++++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:88:13 + | +LL | let _ = (*ptr).get_unchecked_mut(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&mut (*ptr)).get_unchecked_mut(0); + | +++++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:93:13 + | +LL | let _ = (*ptr).len(); + | ^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&(*ptr)).len(); + | ++ + + +warning: implicit autoref creates a reference to the dereference of a raw pointer + --> $DIR/implicit_autorefs.rs:95:13 + | +LL | let _ = (*ptr).is_empty(); + | ^^^^^^^^^^^^^^^^^ + | + = note: creating a reference requires the pointer target to be valid and imposes aliasing requirements +help: try using a raw pointer method instead; or if this reference is intentional, make it explicit + | +LL | let _ = (&(*ptr)).is_empty(); + | ++ + + +warning: 18 warnings emitted + diff --git a/tests/ui/parser/or-in-let-chain.edition2021.stderr b/tests/ui/parser/or-in-let-chain.edition2021.stderr new file mode 100644 index 0000000000000..a97095cc3b82e --- /dev/null +++ b/tests/ui/parser/or-in-let-chain.edition2021.stderr @@ -0,0 +1,28 @@ +error: `||` operators are not supported in let chain conditions + --> $DIR/or-in-let-chain.rs:6:24 + | +LL | if let true = true || false {} + | ^^ + +error: expected expression, found `let` statement + --> $DIR/or-in-let-chain.rs:9:9 + | +LL | if (let true = true) || false {} + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `||` operators are not supported in let chain conditions + --> $DIR/or-in-let-chain.rs:12:24 + | +LL | if let true = true || false || true {} + | ^^ + +error: `||` operators are not supported in let chain conditions + --> $DIR/or-in-let-chain.rs:15:33 + | +LL | if let true = true && false || true {} + | ^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/parser/or-in-let-chain.edition2024.stderr b/tests/ui/parser/or-in-let-chain.edition2024.stderr new file mode 100644 index 0000000000000..a97095cc3b82e --- /dev/null +++ b/tests/ui/parser/or-in-let-chain.edition2024.stderr @@ -0,0 +1,28 @@ +error: `||` operators are not supported in let chain conditions + --> $DIR/or-in-let-chain.rs:6:24 + | +LL | if let true = true || false {} + | ^^ + +error: expected expression, found `let` statement + --> $DIR/or-in-let-chain.rs:9:9 + | +LL | if (let true = true) || false {} + | ^^^^^^^^^^^^^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions + +error: `||` operators are not supported in let chain conditions + --> $DIR/or-in-let-chain.rs:12:24 + | +LL | if let true = true || false || true {} + | ^^ + +error: `||` operators are not supported in let chain conditions + --> $DIR/or-in-let-chain.rs:15:33 + | +LL | if let true = true && false || true {} + | ^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/parser/or-in-let-chain.rs b/tests/ui/parser/or-in-let-chain.rs new file mode 100644 index 0000000000000..4c4372bb00f0f --- /dev/null +++ b/tests/ui/parser/or-in-let-chain.rs @@ -0,0 +1,17 @@ +//@ revisions: edition2021 edition2024 +//@ [edition2021] edition: 2021 +//@ [edition2024] edition: 2024 + +fn main() { + if let true = true || false {} + //~^ ERROR `||` operators are not supported in let chain conditions + // With parentheses + if (let true = true) || false {} + //~^ ERROR expected expression, found `let` statement + // Multiple || operators + if let true = true || false || true {} + //~^ ERROR `||` operators are not supported in let chain conditions + // Mixed operators (should still show error for ||) + if let true = true && false || true {} + //~^ ERROR `||` operators are not supported in let chain conditions +} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs index ae13f7c76badd..ed461af66aaf9 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs @@ -3,7 +3,7 @@ fn let_or_guard(x: Result, ()>) { match x { Ok(opt) if let Some(4) = opt || false => {} - //~^ ERROR expected expression, found `let` statement + //~^ ERROR `||` operators are not supported in let chain conditions _ => {} } } diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.stderr index 4b85fdd505057..0566d96fddc31 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.stderr @@ -1,11 +1,4 @@ -error: expected expression, found `let` statement - --> $DIR/ast-validate-guards.rs:5:20 - | -LL | Ok(opt) if let Some(4) = opt || false => {} - | ^^^^^^^^^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `||` operators are not supported in let chain expressions +error: `||` operators are not supported in let chain conditions --> $DIR/ast-validate-guards.rs:5:38 | LL | Ok(opt) if let Some(4) = opt || false => {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr index 817e226bc45d5..141a6d255d086 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr @@ -272,14 +272,7 @@ LL | if (let 0 = 0)? {} | = note: only supported directly in conditions of `if` and `while` expressions -error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:121:16 - | -LL | if true || let 0 = 0 {} - | ^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `||` operators are not supported in let chain expressions +error: `||` operators are not supported in let chain conditions --> $DIR/disallowed-positions.rs:121:13 | LL | if true || let 0 = 0 {} @@ -485,14 +478,7 @@ LL | while (let 0 = 0)? {} | = note: only supported directly in conditions of `if` and `while` expressions -error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:212:19 - | -LL | while true || let 0 = 0 {} - | ^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `||` operators are not supported in let chain expressions +error: `||` operators are not supported in let chain conditions --> $DIR/disallowed-positions.rs:212:16 | LL | while true || let 0 = 0 {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr index bab50c22c0308..dda09de4c5344 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr @@ -272,14 +272,7 @@ LL | if (let 0 = 0)? {} | = note: only supported directly in conditions of `if` and `while` expressions -error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:121:16 - | -LL | if true || let 0 = 0 {} - | ^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `||` operators are not supported in let chain expressions +error: `||` operators are not supported in let chain conditions --> $DIR/disallowed-positions.rs:121:13 | LL | if true || let 0 = 0 {} @@ -485,14 +478,7 @@ LL | while (let 0 = 0)? {} | = note: only supported directly in conditions of `if` and `while` expressions -error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:212:19 - | -LL | while true || let 0 = 0 {} - | ^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `||` operators are not supported in let chain expressions +error: `||` operators are not supported in let chain conditions --> $DIR/disallowed-positions.rs:212:16 | LL | while true || let 0 = 0 {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr index 943956feb4e07..5b53691cbf546 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr @@ -272,14 +272,7 @@ LL | if (let 0 = 0)? {} | = note: only supported directly in conditions of `if` and `while` expressions -error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:121:16 - | -LL | if true || let 0 = 0 {} - | ^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `||` operators are not supported in let chain expressions +error: `||` operators are not supported in let chain conditions --> $DIR/disallowed-positions.rs:121:13 | LL | if true || let 0 = 0 {} @@ -485,14 +478,7 @@ LL | while (let 0 = 0)? {} | = note: only supported directly in conditions of `if` and `while` expressions -error: expected expression, found `let` statement - --> $DIR/disallowed-positions.rs:212:19 - | -LL | while true || let 0 = 0 {} - | ^^^^^^^^^ - | - = note: only supported directly in conditions of `if` and `while` expressions -note: `||` operators are not supported in let chain expressions +error: `||` operators are not supported in let chain conditions --> $DIR/disallowed-positions.rs:212:16 | LL | while true || let 0 = 0 {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs index 0b0abe6ec1754..65beccf2214fd 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs @@ -119,7 +119,7 @@ fn nested_within_if_expr() { //~^ ERROR expected expression, found `let` statement if true || let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement + //~^ ERROR `||` operators are not supported in let chain conditions if (true || let 0 = 0) {} //~^ ERROR expected expression, found `let` statement if true && (true || let 0 = 0) {} @@ -210,7 +210,7 @@ fn nested_within_while_expr() { //~^ ERROR expected expression, found `let` statement while true || let 0 = 0 {} - //~^ ERROR expected expression, found `let` statement + //~^ ERROR `||` operators are not supported in let chain conditions while (true || let 0 = 0) {} //~^ ERROR expected expression, found `let` statement while true && (true || let 0 = 0) {} diff --git a/tests/ui/specialization/prefer-specializing-impl-over-default.current.stderr b/tests/ui/specialization/prefer-specializing-impl-over-default.current.stderr new file mode 100644 index 0000000000000..7e3df0c83f9f3 --- /dev/null +++ b/tests/ui/specialization/prefer-specializing-impl-over-default.current.stderr @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/prefer-specializing-impl-over-default.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/specialization/prefer-specializing-impl-over-default.next.stderr b/tests/ui/specialization/prefer-specializing-impl-over-default.next.stderr new file mode 100644 index 0000000000000..7e3df0c83f9f3 --- /dev/null +++ b/tests/ui/specialization/prefer-specializing-impl-over-default.next.stderr @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/prefer-specializing-impl-over-default.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/specialization/prefer-specializing-impl-over-default.rs b/tests/ui/specialization/prefer-specializing-impl-over-default.rs new file mode 100644 index 0000000000000..af6837b30cafa --- /dev/null +++ b/tests/ui/specialization/prefer-specializing-impl-over-default.rs @@ -0,0 +1,29 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass +#![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete + +trait WithAssoc: 'static { + type Assoc; +} +impl WithAssoc for (T,) { + type Assoc = (); +} + +struct GenericArray(U::Assoc); + +trait AbiExample { + fn example(); +} +impl AbiExample for GenericArray { + fn example() {} +} +impl AbiExample for T { + default fn example() {} +} + +fn main() { + let _ = GenericArray::<((),)>::example(); +} diff --git a/tests/ui/specialization/specialization-default-projection.stderr b/tests/ui/specialization/specialization-default-projection.current.stderr similarity index 91% rename from tests/ui/specialization/specialization-default-projection.stderr rename to tests/ui/specialization/specialization-default-projection.current.stderr index b8b81876d8131..038c379c43e13 100644 --- a/tests/ui/specialization/specialization-default-projection.stderr +++ b/tests/ui/specialization/specialization-default-projection.current.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-default-projection.rs:1:12 + --> $DIR/specialization-default-projection.rs:5:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | #![feature(specialization)] = note: `#[warn(incomplete_features)]` on by default error[E0308]: mismatched types - --> $DIR/specialization-default-projection.rs:21:5 + --> $DIR/specialization-default-projection.rs:25:5 | LL | fn generic() -> ::Assoc { | ----------------- expected `::Assoc` because of return type @@ -23,7 +23,7 @@ LL | () = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types - --> $DIR/specialization-default-projection.rs:28:5 + --> $DIR/specialization-default-projection.rs:32:5 | LL | fn monomorphic() -> () { | -- expected `()` because of return type diff --git a/tests/ui/specialization/specialization-default-projection.next.stderr b/tests/ui/specialization/specialization-default-projection.next.stderr new file mode 100644 index 0000000000000..9111f173a9c87 --- /dev/null +++ b/tests/ui/specialization/specialization-default-projection.next.stderr @@ -0,0 +1,43 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-default-projection.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/specialization-default-projection.rs:25:5 + | +LL | fn generic() -> ::Assoc { + | ----------------- expected `::Assoc` because of return type +... +LL | () + | ^^ types differ + | + = note: expected associated type `::Assoc` + found unit type `()` + = help: consider constraining the associated type `::Assoc` to `()` or calling a method that returns `::Assoc` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0308]: mismatched types + --> $DIR/specialization-default-projection.rs:32:5 + | +LL | fn monomorphic() -> () { + | -- expected `()` because of return type +... +LL | generic::<()>() + | ^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;` + | | + | types differ + | + = note: expected unit type `()` + found associated type `<() as Foo>::Assoc` + = help: consider constraining the associated type `<() as Foo>::Assoc` to `()` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/specialization/specialization-default-projection.rs b/tests/ui/specialization/specialization-default-projection.rs index 7f3ae951287ca..4f69ccb59746b 100644 --- a/tests/ui/specialization/specialization-default-projection.rs +++ b/tests/ui/specialization/specialization-default-projection.rs @@ -1,3 +1,7 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + #![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Make sure we can't project defaulted associated types diff --git a/tests/ui/specialization/specialization-default-types.stderr b/tests/ui/specialization/specialization-default-types.current.stderr similarity index 91% rename from tests/ui/specialization/specialization-default-types.stderr rename to tests/ui/specialization/specialization-default-types.current.stderr index 774ac9536175d..67477f9a6d537 100644 --- a/tests/ui/specialization/specialization-default-types.stderr +++ b/tests/ui/specialization/specialization-default-types.current.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-default-types.rs:5:12 + --> $DIR/specialization-default-types.rs:9:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | #![feature(specialization)] = note: `#[warn(incomplete_features)]` on by default error[E0308]: mismatched types - --> $DIR/specialization-default-types.rs:15:9 + --> $DIR/specialization-default-types.rs:19:9 | LL | default type Output = Box; | ----------------------------- associated type is `default` and may be overridden @@ -22,7 +22,7 @@ LL | Box::new(self) found struct `Box` error[E0308]: mismatched types - --> $DIR/specialization-default-types.rs:25:5 + --> $DIR/specialization-default-types.rs:29:5 | LL | fn trouble(t: T) -> Box { | ------ expected `Box` because of return type diff --git a/tests/ui/specialization/specialization-default-types.next.stderr b/tests/ui/specialization/specialization-default-types.next.stderr new file mode 100644 index 0000000000000..4f7c47654460e --- /dev/null +++ b/tests/ui/specialization/specialization-default-types.next.stderr @@ -0,0 +1,39 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-default-types.rs:9:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/specialization-default-types.rs:19:9 + | +LL | default type Output = Box; + | ----------------------------- associated type is `default` and may be overridden +LL | default fn generate(self) -> Self::Output { + | ------------ expected `::Output` because of return type +LL | Box::new(self) + | ^^^^^^^^^^^^^^ types differ + | + = note: expected associated type `::Output` + found struct `Box` + +error[E0308]: mismatched types + --> $DIR/specialization-default-types.rs:29:5 + | +LL | fn trouble(t: T) -> Box { + | ------ expected `Box` because of return type +LL | Example::generate(t) + | ^^^^^^^^^^^^^^^^^^^^ types differ + | + = note: expected struct `Box` + found associated type `::Output` + = help: consider constraining the associated type `::Output` to `Box` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/specialization/specialization-default-types.rs b/tests/ui/specialization/specialization-default-types.rs index 346471f11e4a8..77817abea127c 100644 --- a/tests/ui/specialization/specialization-default-types.rs +++ b/tests/ui/specialization/specialization-default-types.rs @@ -1,3 +1,7 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + // It should not be possible to use the concrete value of a defaulted // associated type in the impl defining it -- otherwise, what happens // if it's overridden? diff --git a/tests/ui/traits/next-solver/coerce-depth.rs b/tests/ui/traits/next-solver/coerce-depth.rs new file mode 100644 index 0000000000000..c8fc3fcab59d8 --- /dev/null +++ b/tests/ui/traits/next-solver/coerce-depth.rs @@ -0,0 +1,31 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +// Ensure that a stack of coerce predicates doesn't end up overflowing when they get procesed +// in *reverse* order, which may require O(N) iterations of the fulfillment loop. + +#![recursion_limit = "16"] + +fn main() { + match 0 { + 0 => None, + 1 => None, + 2 => None, + 3 => None, + 4 => None, + 5 => None, + 6 => None, + 7 => None, + 8 => None, + 9 => None, + 10 => None, + 11 => None, + 12 => None, + 13 => None, + 14 => None, + 15 => None, + 16 => None, + 17 => None, + _ => Some(1u32), + }; +} diff --git a/tests/ui/traits/next-solver/specialization-transmute.rs b/tests/ui/traits/next-solver/specialization-transmute.rs index 376fa22ae1923..f1447cd6a9e2e 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.rs +++ b/tests/ui/traits/next-solver/specialization-transmute.rs @@ -10,11 +10,8 @@ trait Default { impl Default for T { default type Id = T; - // This will be fixed by #111994 fn intu(&self) -> &Self::Id { - //~^ ERROR type annotations needed - //~| ERROR cannot normalize `::Id: '_` - self //~ ERROR cannot satisfy + self //~ ERROR mismatched types } } @@ -25,6 +22,7 @@ fn transmute, U: Copy>(t: T) -> U { use std::num::NonZero; fn main() { - let s = transmute::>>(0); //~ ERROR cannot satisfy + let s = transmute::>>(0); + //~^ ERROR type mismatch resolving `::Id == Option>` assert_eq!(s, None); } diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr index eeb101911c435..8bd290ea19707 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.stderr +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -8,37 +8,32 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default -error: cannot normalize `::Id: '_` - --> $DIR/specialization-transmute.rs:14:5 +error[E0308]: mismatched types + --> $DIR/specialization-transmute.rs:14:9 | LL | fn intu(&self) -> &Self::Id { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0282]: type annotations needed - --> $DIR/specialization-transmute.rs:14:23 - | -LL | fn intu(&self) -> &Self::Id { - | ^^^^^^^^^ cannot infer type for reference `&::Id` - -error[E0284]: type annotations needed: cannot satisfy `::Id normalizes-to T` - --> $DIR/specialization-transmute.rs:17:9 - | + | --------- expected `&::Id` because of return type LL | self - | ^^^^ cannot satisfy `::Id normalizes-to T` + | ^^^^ types differ + | + = note: expected reference `&::Id` + found reference `&T` -error[E0284]: type annotations needed: cannot satisfy `::Id normalizes-to Option>` - --> $DIR/specialization-transmute.rs:28:13 +error[E0271]: type mismatch resolving `::Id == Option>` + --> $DIR/specialization-transmute.rs:25:50 | LL | let s = transmute::>>(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `::Id normalizes-to Option>` + | ------------------------------------ ^ types differ + | | + | required by a bound introduced by this call | note: required by a bound in `transmute` - --> $DIR/specialization-transmute.rs:21:25 + --> $DIR/specialization-transmute.rs:18:25 | LL | fn transmute, U: Copy>(t: T) -> U { | ^^^^^^ required by this bound in `transmute` -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted -Some errors have detailed explanations: E0282, E0284. -For more information about an error, try `rustc --explain E0282`. +Some errors have detailed explanations: E0271, E0308. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.rs b/tests/ui/traits/next-solver/specialization-unconstrained.rs index 2bbe784011071..6835c0764d6c8 100644 --- a/tests/ui/traits/next-solver/specialization-unconstrained.rs +++ b/tests/ui/traits/next-solver/specialization-unconstrained.rs @@ -18,5 +18,5 @@ fn test, U>() {} fn main() { test::(); - //~^ ERROR cannot satisfy `::Id normalizes-to ()` + //~^ ERROR type mismatch resolving `::Id == ()` } diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.stderr b/tests/ui/traits/next-solver/specialization-unconstrained.stderr index e1d785b554bd3..1bcf5eddb5bca 100644 --- a/tests/ui/traits/next-solver/specialization-unconstrained.stderr +++ b/tests/ui/traits/next-solver/specialization-unconstrained.stderr @@ -8,11 +8,11 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default -error[E0284]: type annotations needed: cannot satisfy `::Id normalizes-to ()` - --> $DIR/specialization-unconstrained.rs:20:5 +error[E0271]: type mismatch resolving `::Id == ()` + --> $DIR/specialization-unconstrained.rs:20:12 | LL | test::(); - | ^^^^^^^^^^^^^^^^^ cannot satisfy `::Id normalizes-to ()` + | ^^^ types differ | note: required by a bound in `test` --> $DIR/specialization-unconstrained.rs:17:20 @@ -22,4 +22,4 @@ LL | fn test, U>() {} error: aborting due to 1 previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/transmutability/char.rs b/tests/ui/transmutability/char.rs new file mode 100644 index 0000000000000..55a6153732955 --- /dev/null +++ b/tests/ui/transmutability/char.rs @@ -0,0 +1,41 @@ +#![feature(never_type)] +#![feature(transmutability)] + +use std::mem::{Assume, TransmuteFrom}; + +pub fn is_transmutable() +where + Dst: TransmuteFrom, +{ +} + +fn main() { + is_transmutable::(); + + // `char`s can be in the following ranges: + // - [0, 0xD7FF] + // - [0xE000, 10FFFF] + // + // `Char` has variants whose tags are in the top and bottom of each range. + // It also has generic variants which are out of bounds of these ranges, but + // are generic on types which may be set to `!` to "disable" them in the + // transmutability analysis. + #[repr(u32)] + enum Char { + A = 0, + B = 0xD7FF, + OverB(B) = 0xD800, + UnderC(C) = 0xDFFF, + C = 0xE000, + D = 0x10FFFF, + OverD(D) = 0x110000, + } + + is_transmutable::, char>(); + is_transmutable::, char>(); + //~^ ERROR cannot be safely transmuted into `char` + is_transmutable::, char>(); + //~^ ERROR cannot be safely transmuted into `char` + is_transmutable::, char>(); + //~^ ERROR cannot be safely transmuted into `char` +} diff --git a/tests/ui/transmutability/char.stderr b/tests/ui/transmutability/char.stderr new file mode 100644 index 0000000000000..98e7ae9c0d49c --- /dev/null +++ b/tests/ui/transmutability/char.stderr @@ -0,0 +1,48 @@ +error[E0277]: `main::Char<(), !, !>` cannot be safely transmuted into `char` + --> $DIR/char.rs:35:39 + | +LL | is_transmutable::, char>(); + | ^^^^ at least one value of `main::Char<(), !, !>` isn't a bit-valid value of `char` + | +note: required by a bound in `is_transmutable` + --> $DIR/char.rs:8:10 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: TransmuteFrom, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `main::Char` cannot be safely transmuted into `char` + --> $DIR/char.rs:37:39 + | +LL | is_transmutable::, char>(); + | ^^^^ at least one value of `main::Char` isn't a bit-valid value of `char` + | +note: required by a bound in `is_transmutable` + --> $DIR/char.rs:8:10 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: TransmuteFrom, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: `main::Char` cannot be safely transmuted into `char` + --> $DIR/char.rs:39:39 + | +LL | is_transmutable::, char>(); + | ^^^^ at least one value of `main::Char` isn't a bit-valid value of `char` + | +note: required by a bound in `is_transmutable` + --> $DIR/char.rs:8:10 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this function +LL | where +LL | Dst: TransmuteFrom, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`.