diff options
| author | The Miri Cronjob Bot <miri@cron.bot> | 2025-07-01 05:05:50 +0000 |
|---|---|---|
| committer | The Miri Cronjob Bot <miri@cron.bot> | 2025-07-01 05:05:50 +0000 |
| commit | e6371c9379b63cb18aea2acb0c1b76e828150f0b (patch) | |
| tree | 8ef29ca518789e149c0b2e6c4d8e45d96264cde7 | |
| parent | 0c3c9e4438379bb49d45961122e4deaacdb0fa4b (diff) | |
| parent | c3fb7d1d1c3d05be8ed3abdfd01196782f6c7821 (diff) | |
| download | rust-e6371c9379b63cb18aea2acb0c1b76e828150f0b.tar.gz rust-e6371c9379b63cb18aea2acb0c1b76e828150f0b.zip | |
Merge from rustc
344 files changed, 4266 insertions, 2475 deletions
diff --git a/.mailmap b/.mailmap index 2a53cbf9eff..90533e81b39 100644 --- a/.mailmap +++ b/.mailmap @@ -690,6 +690,7 @@ Xinye Tao <xy.tao@outlook.com> Xuefeng Wu <benewu@gmail.com> Xuefeng Wu <xfwu@thoughtworks.com> Xuefeng Wu <benewu@gmail.com> XuefengWu <benewu@gmail.com> York Xiang <bombless@126.com> +Yotam Ofek <yotam.ofek@gmail.com> <yotamofek@microsoft.com> Youngsoo Son <ysson83@gmail.com> <ysoo.son@samsung.com> Youngsuk Kim <joseph942010@gmail.com> Yuki Okushi <jtitor@2k36.org> diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 5eb1931152d..85a4f1c6765 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -256,6 +256,9 @@ pub enum AttributeKind { /// Represents `#[link_name]`. LinkName { name: Symbol, span: Span }, + /// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute) + LinkSection { name: Symbol, span: Span }, + /// Represents `#[loop_match]`. LoopMatch(Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 0d6ee77c718..3c55f62cc80 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -24,6 +24,7 @@ impl AttributeKind { DocComment { .. } => Yes, ExportName { .. } => Yes, Inline(..) => No, + LinkSection { .. } => No, MacroTransparency(..) => Yes, Repr(..) => No, Stability { .. } => Yes, diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 39652335f55..9ad46a83f50 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -99,6 +99,8 @@ attr_parsing_non_ident_feature = attr_parsing_null_on_export = `export_name` may not contain null characters +attr_parsing_null_on_link_section = `link_section` may not contain null characters + attr_parsing_repr_ident = meta item in `repr` must be an identifier diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 740222178ed..e298053ab76 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -1,11 +1,12 @@ use rustc_attr_data_structures::AttributeKind; -use rustc_attr_data_structures::AttributeKind::LinkName; +use rustc_attr_data_structures::AttributeKind::{LinkName, LinkSection}; use rustc_feature::{AttributeTemplate, template}; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; +use crate::session_diagnostics::NullOnLinkSection; pub(crate) struct LinkNameParser; @@ -28,3 +29,31 @@ impl<S: Stage> SingleAttributeParser<S> for LinkNameParser { Some(LinkName { name, span: cx.attr_span }) } } + +pub(crate) struct LinkSectionParser; + +impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser { + const PATH: &[Symbol] = &[sym::link_section]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + let Some(name) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + if name.as_str().contains('\0') { + // `#[link_section = ...]` will be converted to a null-terminated string, + // so it may not contain any null characters. + cx.emit_err(NullOnLinkSection { span: cx.attr_span }); + return None; + } + + Some(LinkSection { name, span: cx.attr_span }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 1ac41b9c7e8..eee6d860550 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -22,7 +22,7 @@ use crate::attributes::codegen_attrs::{ use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; -use crate::attributes::link_attrs::LinkNameParser; +use crate::attributes::link_attrs::{LinkNameParser, LinkSectionParser}; use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser}; use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; use crate::attributes::must_use::MustUseParser; @@ -123,6 +123,7 @@ attribute_parsers!( Single<ExportNameParser>, Single<InlineParser>, Single<LinkNameParser>, + Single<LinkSectionParser>, Single<LoopMatchParser>, Single<MayDangleParser>, Single<MustUseParser>, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 7cfce579979..53aafaa714f 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -453,6 +453,13 @@ pub(crate) struct NullOnExport { } #[derive(Diagnostic)] +#[diag(attr_parsing_null_on_link_section, code = E0648)] +pub(crate) struct NullOnLinkSection { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(attr_parsing_stability_outside_std, code = E0734)] pub(crate) struct StabilityOutsideStd { #[primary_span] diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 524ebde1c74..2f53bbf8b79 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -660,7 +660,7 @@ pub mod intrinsics { #[rustc_intrinsic] pub unsafe fn ctlz_nonzero<T>(x: T) -> u32; #[rustc_intrinsic] - pub fn needs_drop<T: ?::Sized>() -> bool; + pub const fn needs_drop<T: ?::Sized>() -> bool; #[rustc_intrinsic] pub fn bitreverse<T>(x: T) -> T; #[rustc_intrinsic] diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 1499f948deb..246bd3104ec 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -1,4 +1,13 @@ -#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)] +#![feature( + no_core, + lang_items, + never_type, + linkage, + extern_types, + thread_local, + repr_simd, + rustc_private +)] #![no_core] #![allow(dead_code, non_camel_case_types, internal_features)] @@ -207,10 +216,14 @@ fn main() { assert_eq!(intrinsics::align_of::<u16>() as u8, 2); assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); - assert!(!intrinsics::needs_drop::<u8>()); - assert!(!intrinsics::needs_drop::<[u8]>()); - assert!(intrinsics::needs_drop::<NoisyDrop>()); - assert!(intrinsics::needs_drop::<NoisyDropUnsized>()); + let u8_needs_drop = const { intrinsics::needs_drop::<u8>() }; + assert!(!u8_needs_drop); + let slice_needs_drop = const { intrinsics::needs_drop::<[u8]>() }; + assert!(!slice_needs_drop); + let noisy_drop = const { intrinsics::needs_drop::<NoisyDrop>() }; + assert!(noisy_drop); + let noisy_unsized_drop = const { intrinsics::needs_drop::<NoisyDropUnsized>() }; + assert!(noisy_unsized_drop); Unique { pointer: NonNull(1 as *mut &str), _marker: PhantomData } as Unique<dyn SomeTrait>; diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 3a62cd52a9d..ee43eb736e6 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -133,7 +133,7 @@ pub(crate) fn codegen_const_value<'tcx>( } } Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative + let (prov, offset) = ptr.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); let base_addr = match fx.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index df5748c34d1..4ff5773a06c 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -812,21 +812,6 @@ fn codegen_regular_intrinsic_call<'tcx>( dest.write_cvalue(fx, val); } - sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => { - intrinsic_args!(fx, args => (); intrinsic); - - let const_val = fx - .tcx - .const_eval_instance( - ty::TypingEnv::fully_monomorphized(), - instance, - source_info.span, - ) - .unwrap(); - let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty); - ret.write_cvalue(fx, val); - } - sym::ptr_offset_from | sym::ptr_offset_from_unsigned => { intrinsic_args!(fx, args => (ptr, base); intrinsic); let ptr = ptr.load_scalar(fx); diff --git a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml index 931f6097abc..29a3bcec304 100644 --- a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml +++ b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml @@ -6,6 +6,7 @@ resolver = "2" [dependencies] core = { path = "./sysroot_src/library/core" } +compiler_builtins = { path = "./sysroot_src/library/compiler-builtins/compiler-builtins" } alloc = { path = "./sysroot_src/library/alloc" } std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] } test = { path = "./sysroot_src/library/test" } diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index f1f31f83ca2..cbb0f949383 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -9,8 +9,8 @@ use crate::build; use crate::config::{Channel, ConfigInfo}; use crate::utils::{ create_dir, get_sysroot_dir, get_toolchain, git_clone, git_clone_root_dir, remove_file, - run_command, run_command_with_env, run_command_with_output, run_command_with_output_and_env, - rustc_version_info, split_args, walk_dir, + run_command, run_command_with_env, run_command_with_output_and_env, rustc_version_info, + split_args, walk_dir, }; type Env = HashMap<String, String>; @@ -485,30 +485,6 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> { run_command_with_output_and_env(&[&"git", &"checkout"], rust_dir, Some(env))?; } - let mut patches = Vec::new(); - walk_dir( - "patches/tests", - &mut |_| Ok(()), - &mut |file_path: &Path| { - patches.push(file_path.to_path_buf()); - Ok(()) - }, - false, - )?; - patches.sort(); - // TODO: remove duplication with prepare.rs by creating a apply_patch function in the utils - // module. - for file_path in patches { - println!("[GIT] apply `{}`", file_path.display()); - let path = Path::new("../..").join(file_path); - run_command_with_output(&[&"git", &"apply", &path], rust_dir)?; - run_command_with_output(&[&"git", &"add", &"-A"], rust_dir)?; - run_command_with_output( - &[&"git", &"commit", &"--no-gpg-sign", &"-m", &format!("Patch {}", path.display())], - rust_dir, - )?; - } - let cargo = String::from_utf8( run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout, ) diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index c3bd62e5897..6b6f71edaf8 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -6,6 +6,7 @@ )] #![no_core] #![allow(dead_code, internal_features, non_camel_case_types)] +#![rustfmt::skip] extern crate mini_core; @@ -197,10 +198,10 @@ fn main() { assert_eq!(intrinsics::align_of::<u16>() as u8, 2); assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); - assert!(!intrinsics::needs_drop::<u8>()); - assert!(!intrinsics::needs_drop::<[u8]>()); - assert!(intrinsics::needs_drop::<NoisyDrop>()); - assert!(intrinsics::needs_drop::<NoisyDropUnsized>()); + assert!(!const { intrinsics::needs_drop::<u8>() }); + assert!(!const { intrinsics::needs_drop::<[u8]>() }); + assert!(const { intrinsics::needs_drop::<NoisyDrop>() }); + assert!(const { intrinsics::needs_drop::<NoisyDropUnsized>() }); Unique { pointer: 0 as *const &str, diff --git a/compiler/rustc_codegen_gcc/patches/tests/0001-Workaround-to-make-a-run-make-test-pass.patch b/compiler/rustc_codegen_gcc/patches/tests/0001-Workaround-to-make-a-run-make-test-pass.patch deleted file mode 100644 index a329d09a95e..00000000000 --- a/compiler/rustc_codegen_gcc/patches/tests/0001-Workaround-to-make-a-run-make-test-pass.patch +++ /dev/null @@ -1,25 +0,0 @@ -From a131c69e54b5c02fe3b517e8f3ad23d4f784ffc8 Mon Sep 17 00:00:00 2001 -From: Antoni Boucher <bouanto@zoho.com> -Date: Fri, 13 Jun 2025 20:25:33 -0400 -Subject: [PATCH] Workaround to make a run-make test pass - ---- - tests/run-make/linker-warning/rmake.rs | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs -index bc21739fefc..0946a7e2a48 100644 ---- a/tests/run-make/linker-warning/rmake.rs -+++ b/tests/run-make/linker-warning/rmake.rs -@@ -55,7 +55,7 @@ fn main() { - diff() - .expected_file("short-error.txt") - .actual_text("(linker error)", out.stderr()) -- .normalize(r#"/rustc[^/]*/"#, "/rustc/") -+ .normalize(r#"/tmp/rustc[^/]*/"#, "/tmp/rustc/") - .normalize( - regex::escape(run_make_support::build_root().to_str().unwrap()), - "/build-root", --- -2.49.0 - diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain index 8be204c1581..bccbc6cd2c5 100644 --- a/compiler/rustc_codegen_gcc/rust-toolchain +++ b/compiler/rustc_codegen_gcc/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-06-02" +channel = "nightly-2025-06-28" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 08f3d281904..0b359f1c5c8 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -1,7 +1,9 @@ #[cfg(feature = "master")] use gccjit::FnAttribute; use gccjit::{ToLValue, ToRValue, Type}; -use rustc_abi::{ArmCall, CanonAbi, InterruptKind, Reg, RegKind, X86Call}; +#[cfg(feature = "master")] +use rustc_abi::{ArmCall, CanonAbi, InterruptKind, X86Call}; +use rustc_abi::{Reg, RegKind}; use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeCodegenMethods}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 1fce547ad1b..b1785af444a 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -538,11 +538,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn ret(&mut self, mut value: RValue<'gcc>) { - if self.structs_as_pointer.borrow().contains(&value) { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - value = value.dereference(self.location).to_rvalue(); - } let expected_return_type = self.current_func().get_return_type(); if !expected_return_type.is_compatible_with(value.get_type()) { // NOTE: due to opaque pointers now being used, we need to cast here. @@ -700,7 +695,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let a = self.gcc_int_cast(a, a_type); let b_type = b.get_type().to_unsigned(self); let b = self.gcc_int_cast(b, b_type); - a / b + self.gcc_udiv(a, b) } fn sdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -712,8 +707,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they // should be the same. let typ = a.get_type().to_signed(self); - let b = self.context.new_cast(self.location, b, typ); - a / b + let b = self.gcc_int_cast(b, typ); + self.gcc_sdiv(a, b) } fn fdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -1119,13 +1114,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo) } - fn store(&mut self, mut val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { - if self.structs_as_pointer.borrow().contains(&val) { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - val = val.dereference(self.location).to_rvalue(); - } - + fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { self.store_with_flags(val, ptr, align, MemFlags::empty()) } @@ -1508,16 +1497,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { element.get_address(self.location) } else if value_type.dyncast_vector().is_some() { panic!(); - } else if let Some(pointer_type) = value_type.get_pointee() { - if let Some(struct_type) = pointer_type.is_struct() { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - aggregate_value - .dereference_field(self.location, struct_type.get_field(idx as i32)) - .to_rvalue() - } else { - panic!("Unexpected type {:?}", value_type); - } } else if let Some(struct_type) = value_type.is_struct() { aggregate_value .access_field(self.location, struct_type.get_field(idx as i32)) @@ -1537,21 +1516,18 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { assert_eq!(idx as usize as u64, idx); let value_type = aggregate_value.get_type(); + let new_val = self.current_func().new_local(None, value_type, "aggregate_value"); + self.block.add_assignment(None, new_val, aggregate_value); + let lvalue = if value_type.dyncast_array().is_some() { let index = self .context .new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); - self.context.new_array_access(self.location, aggregate_value, index) + self.context.new_array_access(self.location, new_val, index) } else if value_type.dyncast_vector().is_some() { panic!(); - } else if let Some(pointer_type) = value_type.get_pointee() { - if let Some(struct_type) = pointer_type.is_struct() { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - aggregate_value.dereference_field(self.location, struct_type.get_field(idx as i32)) - } else { - panic!("Unexpected type {:?}", value_type); - } + } else if let Some(struct_type) = value_type.is_struct() { + new_val.access_field(None, struct_type.get_field(idx as i32)) } else { panic!("Unexpected type {:?}", value_type); }; @@ -1568,7 +1544,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.llbb().add_assignment(self.location, lvalue, value); - aggregate_value + new_val.to_rvalue() } fn set_personality_fn(&mut self, _personality: Function<'gcc>) { diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index fdd47821b51..dd582834fac 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -117,15 +117,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> { let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined"); - if typ.is_struct().is_some() { - // NOTE: hack to workaround a limitation of the rustc API: see comment on - // CodegenCx.structs_as_pointer - let pointer = local.get_address(None); - self.structs_as_pointer.borrow_mut().insert(pointer); - pointer - } else { - local.to_rvalue() - } + local.to_rvalue() } fn const_poison(&self, typ: Type<'gcc>) -> RValue<'gcc> { @@ -248,7 +240,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { } } Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative + let (prov, offset) = ptr.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); let base_addr = match self.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 1d029811dfe..665cf22ddba 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -124,14 +124,6 @@ pub struct CodegenCx<'gcc, 'tcx> { pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>, - /// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such, - /// `const_undef()` returns struct as pointer so that they can later be assigned a value (in - /// e.g. Builder::insert_value). - /// As such, this set remembers which of these pointers were returned by this function so that - /// they can be dereferenced later. - /// FIXME(antoyo): fix the rustc API to avoid having this hack. - pub structs_as_pointer: RefCell<FxHashSet<RValue<'gcc>>>, - #[cfg(feature = "master")] pub cleanup_blocks: RefCell<FxHashSet<Block<'gcc>>>, /// The alignment of a u128/i128 type. @@ -304,7 +296,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { #[cfg(feature = "master")] rust_try_fn: Cell::new(None), pointee_infos: Default::default(), - structs_as_pointer: Default::default(), #[cfg(feature = "master")] cleanup_blocks: Default::default(), }; diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs index f0352c5e6e5..915ed875e32 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs @@ -1,9 +1,9 @@ // File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py` // DO NOT EDIT IT! /// Translate a given LLVM intrinsic name to an equivalent GCC one. -fn map_arch_intrinsic(name: &str) -> &str { - let Some(name) = name.strip_prefix("llvm.") else { - unimplemented!("***** unsupported LLVM intrinsic {}", name) +fn map_arch_intrinsic(full_name: &str) -> &'static str { + let Some(name) = full_name.strip_prefix("llvm.") else { + unimplemented!("***** unsupported LLVM intrinsic {}", full_name) }; let Some((arch, name)) = name.split_once('.') else { unimplemented!("***** unsupported LLVM intrinsic {}", name) @@ -11,7 +11,7 @@ fn map_arch_intrinsic(name: &str) -> &str { match arch { "AMDGPU" => { #[allow(non_snake_case)] - fn AMDGPU(name: &str) -> &str { + fn AMDGPU(name: &str, full_name: &str) -> &'static str { match name { // AMDGPU "div.fixup.f32" => "__builtin_amdgpu_div_fixup", @@ -42,14 +42,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "trig.preop.f64" => "__builtin_amdgpu_trig_preop", "trig.preop.v2f64" => "__builtin_amdgpu_trig_preop", "trig.preop.v4f32" => "__builtin_amdgpu_trig_preop", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - AMDGPU(name) + AMDGPU(name, full_name) } "aarch64" => { #[allow(non_snake_case)] - fn aarch64(name: &str) -> &str { + fn aarch64(name: &str, full_name: &str) -> &'static str { match name { // aarch64 "chkfeat" => "__builtin_arm_chkfeat", @@ -75,14 +75,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "tcommit" => "__builtin_arm_tcommit", "tstart" => "__builtin_arm_tstart", "ttest" => "__builtin_arm_ttest", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - aarch64(name) + aarch64(name, full_name) } "amdgcn" => { #[allow(non_snake_case)] - fn amdgcn(name: &str) -> &str { + fn amdgcn(name: &str, full_name: &str) -> &'static str { match name { // amdgcn "alignbyte" => "__builtin_amdgcn_alignbyte", @@ -99,6 +99,8 @@ fn map_arch_intrinsic(name: &str) -> &str { "cvt.f32.fp8" => "__builtin_amdgcn_cvt_f32_fp8", "cvt.off.f32.i4" => "__builtin_amdgcn_cvt_off_f32_i4", "cvt.pk.bf8.f32" => "__builtin_amdgcn_cvt_pk_bf8_f32", + "cvt.pk.f16.bf8" => "__builtin_amdgcn_cvt_pk_f16_bf8", + "cvt.pk.f16.fp8" => "__builtin_amdgcn_cvt_pk_f16_fp8", "cvt.pk.f32.bf8" => "__builtin_amdgcn_cvt_pk_f32_bf8", "cvt.pk.f32.fp8" => "__builtin_amdgcn_cvt_pk_f32_fp8", "cvt.pk.fp8.f32" => "__builtin_amdgcn_cvt_pk_fp8_f32", @@ -292,6 +294,7 @@ fn map_arch_intrinsic(name: &str) -> &str { "s.sendmsg" => "__builtin_amdgcn_s_sendmsg", "s.sendmsghalt" => "__builtin_amdgcn_s_sendmsghalt", "s.setprio" => "__builtin_amdgcn_s_setprio", + "s.setprio.inc.wg" => "__builtin_amdgcn_s_setprio_inc_wg", "s.setreg" => "__builtin_amdgcn_s_setreg", "s.sleep" => "__builtin_amdgcn_s_sleep", "s.sleep.var" => "__builtin_amdgcn_s_sleep_var", @@ -356,14 +359,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "workitem.id.x" => "__builtin_amdgcn_workitem_id_x", "workitem.id.y" => "__builtin_amdgcn_workitem_id_y", "workitem.id.z" => "__builtin_amdgcn_workitem_id_z", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - amdgcn(name) + amdgcn(name, full_name) } "arm" => { #[allow(non_snake_case)] - fn arm(name: &str) -> &str { + fn arm(name: &str, full_name: &str) -> &'static str { match name { // arm "cdp" => "__builtin_arm_cdp", @@ -465,14 +468,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "usub8" => "__builtin_arm_usub8", "uxtab16" => "__builtin_arm_uxtab16", "uxtb16" => "__builtin_arm_uxtb16", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - arm(name) + arm(name, full_name) } "bpf" => { #[allow(non_snake_case)] - fn bpf(name: &str) -> &str { + fn bpf(name: &str, full_name: &str) -> &'static str { match name { // bpf "btf.type.id" => "__builtin_bpf_btf_type_id", @@ -487,25 +490,25 @@ fn map_arch_intrinsic(name: &str) -> &str { "preserve.field.info" => "__builtin_bpf_preserve_field_info", "preserve.type.info" => "__builtin_bpf_preserve_type_info", "pseudo" => "__builtin_bpf_pseudo", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - bpf(name) + bpf(name, full_name) } "cuda" => { #[allow(non_snake_case)] - fn cuda(name: &str) -> &str { + fn cuda(name: &str, full_name: &str) -> &'static str { match name { // cuda "syncthreads" => "__syncthreads", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - cuda(name) + cuda(name, full_name) } "hexagon" => { #[allow(non_snake_case)] - fn hexagon(name: &str) -> &str { + fn hexagon(name: &str, full_name: &str) -> &'static str { match name { // hexagon "A2.abs" => "__builtin_HEXAGON_A2_abs", @@ -2479,14 +2482,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "prefetch" => "__builtin_HEXAGON_prefetch", "vmemcpy" => "__builtin_hexagon_vmemcpy", "vmemset" => "__builtin_hexagon_vmemset", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - hexagon(name) + hexagon(name, full_name) } "loongarch" => { #[allow(non_snake_case)] - fn loongarch(name: &str) -> &str { + fn loongarch(name: &str, full_name: &str) -> &'static str { match name { // loongarch "asrtgt.d" => "__builtin_loongarch_asrtgt_d", @@ -3988,14 +3991,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "movfcsr2gr" => "__builtin_loongarch_movfcsr2gr", "movgr2fcsr" => "__builtin_loongarch_movgr2fcsr", "syscall" => "__builtin_loongarch_syscall", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - loongarch(name) + loongarch(name, full_name) } "mips" => { #[allow(non_snake_case)] - fn mips(name: &str) -> &str { + fn mips(name: &str, full_name: &str) -> &'static str { match name { // mips "absq.s.ph" => "__builtin_mips_absq_s_ph", @@ -4669,14 +4672,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "wrdsp" => "__builtin_mips_wrdsp", "xor.v" => "__builtin_msa_xor_v", "xori.b" => "__builtin_msa_xori_b", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - mips(name) + mips(name, full_name) } "nvvm" => { #[allow(non_snake_case)] - fn nvvm(name: &str) -> &str { + fn nvvm(name: &str, full_name: &str) -> &'static str { match name { // nvvm "abs.i" => "__nvvm_abs_i", @@ -5024,6 +5027,7 @@ fn map_arch_intrinsic(name: &str) -> &str { "nanosleep" => "__nvvm_nanosleep", "neg.bf16" => "__nvvm_neg_bf16", "neg.bf16x2" => "__nvvm_neg_bf16x2", + "pm.event.mask" => "__nvvm_pm_event_mask", "popc.i" => "__nvvm_popc_i", "popc.ll" => "__nvvm_popc_ll", "prmt" => "__nvvm_prmt", @@ -5448,14 +5452,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "vote.ballot.sync" => "__nvvm_vote_ballot_sync", "vote.uni" => "__nvvm_vote_uni", "vote.uni.sync" => "__nvvm_vote_uni_sync", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - nvvm(name) + nvvm(name, full_name) } "ppc" => { #[allow(non_snake_case)] - fn ppc(name: &str) -> &str { + fn ppc(name: &str, full_name: &str) -> &'static str { match name { // ppc "addex" => "__builtin_ppc_addex", @@ -5842,7 +5846,10 @@ fn map_arch_intrinsic(name: &str) -> &str { "mulhdu" => "__builtin_ppc_mulhdu", "mulhw" => "__builtin_ppc_mulhw", "mulhwu" => "__builtin_ppc_mulhwu", + "national2packed" => "__builtin_ppc_national2packed", "pack.longdouble" => "__builtin_pack_longdouble", + "packed2national" => "__builtin_ppc_packed2national", + "packed2zoned" => "__builtin_ppc_packed2zoned", "pdepd" => "__builtin_pdepd", "pextd" => "__builtin_pextd", "qpx.qvfabs" => "__builtin_qpx_qvfabs", @@ -6035,14 +6042,15 @@ fn map_arch_intrinsic(name: &str) -> &str { "vsx.xxinsertw" => "__builtin_vsx_xxinsertw", "vsx.xxleqv" => "__builtin_vsx_xxleqv", "vsx.xxpermx" => "__builtin_vsx_xxpermx", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + "zoned2packed" => "__builtin_ppc_zoned2packed", + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - ppc(name) + ppc(name, full_name) } "ptx" => { #[allow(non_snake_case)] - fn ptx(name: &str) -> &str { + fn ptx(name: &str, full_name: &str) -> &'static str { match name { // ptx "bar.sync" => "__builtin_ptx_bar_sync", @@ -6063,14 +6071,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "read.pm3" => "__builtin_ptx_read_pm3", "read.smid" => "__builtin_ptx_read_smid", "read.warpid" => "__builtin_ptx_read_warpid", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - ptx(name) + ptx(name, full_name) } "r600" => { #[allow(non_snake_case)] - fn r600(name: &str) -> &str { + fn r600(name: &str, full_name: &str) -> &'static str { match name { // r600 "group.barrier" => "__builtin_r600_group_barrier", @@ -6088,14 +6096,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "read.tidig.x" => "__builtin_r600_read_tidig_x", "read.tidig.y" => "__builtin_r600_read_tidig_y", "read.tidig.z" => "__builtin_r600_read_tidig_z", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - r600(name) + r600(name, full_name) } "riscv" => { #[allow(non_snake_case)] - fn riscv(name: &str) -> &str { + fn riscv(name: &str, full_name: &str) -> &'static str { match name { // riscv "aes32dsi" => "__builtin_riscv_aes32dsi", @@ -6119,14 +6127,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "sha512sum0r" => "__builtin_riscv_sha512sum0r", "sha512sum1" => "__builtin_riscv_sha512sum1", "sha512sum1r" => "__builtin_riscv_sha512sum1r", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - riscv(name) + riscv(name, full_name) } "s390" => { #[allow(non_snake_case)] - fn s390(name: &str) -> &str { + fn s390(name: &str, full_name: &str) -> &'static str { match name { // s390 "bdepg" => "__builtin_s390_bdepg", @@ -6313,14 +6321,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "vupllf" => "__builtin_s390_vupllf", "vupllg" => "__builtin_s390_vupllg", "vupllh" => "__builtin_s390_vupllh", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - s390(name) + s390(name, full_name) } "ve" => { #[allow(non_snake_case)] - fn ve(name: &str) -> &str { + fn ve(name: &str, full_name: &str) -> &'static str { match name { // ve "vl.andm.MMM" => "__builtin_ve_vl_andm_MMM", @@ -7586,14 +7594,14 @@ fn map_arch_intrinsic(name: &str) -> &str { "vl.vxor.vvvvl" => "__builtin_ve_vl_vxor_vvvvl", "vl.xorm.MMM" => "__builtin_ve_vl_xorm_MMM", "vl.xorm.mmm" => "__builtin_ve_vl_xorm_mmm", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - ve(name) + ve(name, full_name) } "x86" => { #[allow(non_snake_case)] - fn x86(name: &str) -> &str { + fn x86(name: &str, full_name: &str) -> &'static str { match name { // x86 "aadd32" => "__builtin_ia32_aadd32", @@ -10154,25 +10162,25 @@ fn map_arch_intrinsic(name: &str) -> &str { "xresldtrk" => "__builtin_ia32_xresldtrk", "xsusldtrk" => "__builtin_ia32_xsusldtrk", "xtest" => "__builtin_ia32_xtest", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - x86(name) + x86(name, full_name) } "xcore" => { #[allow(non_snake_case)] - fn xcore(name: &str) -> &str { + fn xcore(name: &str, full_name: &str) -> &'static str { match name { // xcore "bitrev" => "__builtin_bitrev", "getid" => "__builtin_getid", "getps" => "__builtin_getps", "setps" => "__builtin_setps", - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"), } } - xcore(name) + xcore(name, full_name) } - _ => unimplemented!("***** unsupported LLVM intrinsic {}", name), + _ => unimplemented!("***** unsupported LLVM architecture {arch}, intrinsic:{full_name}"), } } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs index 0b77694f115..39dba28b24c 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs @@ -648,6 +648,11 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( new_args.push(handle); args = new_args.into(); } + "__builtin_ia32_rdtscp" => { + let result = builder.current_func().new_local(None, builder.u32_type, "result"); + let new_args = vec![result.get_address(None).to_rvalue()]; + args = new_args.into(); + } _ => (), } } else { @@ -764,6 +769,14 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( new_args.swap(0, 1); args = new_args.into(); } + "__builtin_ia32_dpps256" => { + let mut new_args = args.to_vec(); + // NOTE: without this cast to u8 (and it needs to be a u8 to fix the issue), we + // would get the following error: + // the last argument must be an 8-bit immediate + new_args[2] = builder.context.new_cast(None, new_args[2], builder.cx.type_u8()); + args = new_args.into(); + } _ => (), } } @@ -935,6 +948,19 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>( ); return_value = result.to_rvalue(); } + "__builtin_ia32_rdtscp" => { + let field1 = builder.context.new_field(None, return_value.get_type(), "rdtscpField1"); + let return2 = args[0].dereference(None).to_rvalue(); + let field2 = builder.context.new_field(None, return2.get_type(), "rdtscpField2"); + let struct_type = + builder.context.new_struct_type(None, "rdtscpResult", &[field1, field2]); + return_value = builder.context.new_struct_constructor( + None, + struct_type.as_type(), + None, + &[return_value, return2], + ); + } _ => (), } @@ -1529,6 +1555,17 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.aesdecwide128kl" => "__builtin_ia32_aesdecwide128kl_u8", "llvm.x86.aesencwide256kl" => "__builtin_ia32_aesencwide256kl_u8", "llvm.x86.aesdecwide256kl" => "__builtin_ia32_aesdecwide256kl_u8", + "llvm.x86.avx512.uitofp.round.v8f16.v8i16" => "__builtin_ia32_vcvtuw2ph128_mask", + "llvm.x86.avx512.uitofp.round.v16f16.v16i16" => "__builtin_ia32_vcvtuw2ph256_mask", + "llvm.x86.avx512.uitofp.round.v32f16.v32i16" => "__builtin_ia32_vcvtuw2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f16.v8i32" => "__builtin_ia32_vcvtudq2ph256_mask", + "llvm.x86.avx512.uitofp.round.v16f16.v16i32" => "__builtin_ia32_vcvtudq2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f16.v8i64" => "__builtin_ia32_vcvtuqq2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f64.v8i64" => "__builtin_ia32_cvtuqq2pd512_mask", + "llvm.x86.avx512.uitofp.round.v2f64.v2i64" => "__builtin_ia32_cvtuqq2pd128_mask", + "llvm.x86.avx512.uitofp.round.v4f64.v4i64" => "__builtin_ia32_cvtuqq2pd256_mask", + "llvm.x86.avx512.uitofp.round.v8f32.v8i64" => "__builtin_ia32_cvtuqq2ps512_mask", + "llvm.x86.avx512.uitofp.round.v4f32.v4i64" => "__builtin_ia32_cvtuqq2ps256_mask", // TODO: support the tile builtins: "llvm.x86.ldtilecfg" => "__builtin_trap", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 4c10380fe74..497605978fe 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -114,7 +114,6 @@ fn get_simple_intrinsic<'gcc, 'tcx>( } sym::copysignf32 => "copysignf", sym::copysignf64 => "copysign", - sym::copysignf128 => "copysignl", sym::floorf32 => "floorf", sym::floorf64 => "floor", sym::ceilf32 => "ceilf", @@ -238,6 +237,7 @@ fn get_simple_function_f128_2args<'gcc, 'tcx>( let func_name = match name { sym::maxnumf128 => "fmaxf128", sym::minnumf128 => "fminf128", + sym::copysignf128 => "copysignf128", _ => return None, }; Some(cx.context.new_function( @@ -261,6 +261,7 @@ fn f16_builtin<'gcc, 'tcx>( let f32_type = cx.type_f32(); let builtin_name = match name { sym::ceilf16 => "__builtin_ceilf", + sym::copysignf16 => "__builtin_copysignf", sym::floorf16 => "__builtin_floorf", sym::fmaf16 => "fmaf", sym::maxnumf16 => "__builtin_fmaxf", @@ -330,6 +331,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc ) } sym::ceilf16 + | sym::copysignf16 | sym::floorf16 | sym::fmaf16 | sym::maxnumf16 diff --git a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py index ed0ebf00719..88927f39b93 100644 --- a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py +++ b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py @@ -176,14 +176,14 @@ def update_intrinsics(llvm_path, llvmint, llvmint2): out.write("// File generated by `rustc_codegen_gcc/tools/generate_intrinsics.py`\n") out.write("// DO NOT EDIT IT!\n") out.write("/// Translate a given LLVM intrinsic name to an equivalent GCC one.\n") - out.write("fn map_arch_intrinsic(name:&str)->&str{\n") - out.write('let Some(name) = name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n') + out.write("fn map_arch_intrinsic(full_name:&str)->&'static str{\n") + out.write('let Some(name) = full_name.strip_prefix("llvm.") else { unimplemented!("***** unsupported LLVM intrinsic {}", full_name) };\n') out.write('let Some((arch, name)) = name.split_once(\'.\') else { unimplemented!("***** unsupported LLVM intrinsic {}", name) };\n') out.write("match arch {\n") for arch in archs: if len(intrinsics[arch]) == 0: continue - out.write("\"{}\" => {{ #[allow(non_snake_case)] fn {}(name: &str) -> &str {{ match name {{".format(arch,arch)) + out.write("\"{}\" => {{ #[allow(non_snake_case)] fn {}(name: &str,full_name:&str) -> &'static str {{ match name {{".format(arch,arch)) intrinsics[arch].sort(key=lambda x: (x[0], x[2])) out.write(' // {}\n'.format(arch)) for entry in intrinsics[arch]: @@ -196,9 +196,9 @@ def update_intrinsics(llvm_path, llvmint, llvmint2): out.write(' // [INVALID CONVERSION]: "{}" => "{}",\n'.format(llvm_name, entry[1])) else: out.write(' "{}" => "{}",\n'.format(llvm_name, entry[1])) - out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {}", name),\n') - out.write("}} }} {}(name) }}\n,".format(arch)) - out.write(' _ => unimplemented!("***** unsupported LLVM architecture {}", name),\n') + out.write(' _ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),\n') + out.write("}} }} {}(name,full_name) }}\n,".format(arch)) + out.write(' _ => unimplemented!("***** unsupported LLVM architecture {arch}, intrinsic:{full_name}"),\n') out.write("}\n}") subprocess.call(["rustfmt", output_file]) print("Done!") diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index ae5add59322..7cfab25bc50 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -268,7 +268,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { } } Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.prov_and_relative_offset(); let global_alloc = self.tcx.global_alloc(prov.alloc_id()); let base_addr = match global_alloc { GlobalAlloc::Memory(alloc) => { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 7680f8e1074..a87c26f43f9 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -124,6 +124,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name), + AttributeKind::LinkSection { name, .. } => { + codegen_fn_attrs.link_section = Some(*name) + } AttributeKind::NoMangle(attr_span) => { if tcx.opt_item_name(did.to_def_id()).is_some() { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; @@ -253,16 +256,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } } - sym::link_section => { - if let Some(val) = attr.value_str() { - if val.as_str().bytes().any(|b| b == 0) { - let msg = format!("illegal null byte in link_section value: `{val}`"); - tcx.dcx().span_err(attr.span(), msg); - } else { - codegen_fn_attrs.link_section = Some(val); - } - } - } sym::link_ordinal => { link_ordinal_span = Some(attr.span()); if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 27fcab8ed2d..fc95f62b4a4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -1,7 +1,7 @@ use rustc_abi::WrappingRange; -use rustc_middle::bug; use rustc_middle::mir::SourceInfo; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::sym; @@ -98,6 +98,27 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { discr.to_atomic_ordering() }; + if args.is_empty() { + match name { + sym::abort + | sym::unreachable + | sym::cold_path + | sym::breakpoint + | sym::assert_zero_valid + | sym::assert_mem_uninitialized_valid + | sym::assert_inhabited + | sym::ub_checks + | sym::contract_checks + | sym::atomic_fence + | sym::atomic_singlethreadfence + | sym::caller_location => {} + _ => { + span_bug!(span, "nullary intrinsic {name} must either be in a const block or explicitly opted out because it is inherently a runtime intrinsic +"); + } + } + } + let llval = match name { sym::abort => { bx.abort(); @@ -150,10 +171,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } value } - sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => { - let value = bx.tcx().const_eval_instance(bx.typing_env(), instance, span).unwrap(); - OperandRef::from_const(bx, value, result.layout.ty).immediate_or_packed_pair(bx) - } sym::arith_offset => { let ty = fn_args.type_at(0); let layout = bx.layout_of(ty); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 66c4af4c935..10b44a1faf0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -354,15 +354,15 @@ fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let destination_block = target.unwrap(); - bb.statements.push(mir::Statement { - source_info: bb.terminator().source_info, - kind: mir::StatementKind::Assign(Box::new(( + bb.statements.push(mir::Statement::new( + bb.terminator().source_info, + mir::StatementKind::Assign(Box::new(( *destination, mir::Rvalue::Use(mir::Operand::Copy( arg_place.project_deeper(&[mir::ProjectionElem::Deref], tcx), )), ))), - }); + )); bb.terminator_mut().kind = mir::TerminatorKind::Goto { target: destination_block }; } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 2a2c3e6aee2..22a1894ee72 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -263,9 +263,6 @@ const_eval_non_const_try_block_from_output = const_eval_not_enough_caller_args = calling a function with fewer arguments than it requires -const_eval_nullary_intrinsic_fail = - could not evaluate nullary intrinsic - const_eval_offset_from_different_allocations = `{$name}` called on two different pointers that are not both derived from the same allocation const_eval_offset_from_out_of_bounds = diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 569a07c3a01..08e1877f0eb 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -20,7 +20,7 @@ use crate::const_eval::CheckAlignment; use crate::interpret::{ CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpErrorKind, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, create_static_alloc, - eval_nullary_intrinsic, intern_const_alloc_recursive, interp_ok, throw_exhaust, + intern_const_alloc_recursive, interp_ok, throw_exhaust, }; use crate::{CTRL_C_RECEIVED, errors}; @@ -209,9 +209,9 @@ pub(super) fn op_to_const<'tcx>( match immediate { Left(ref mplace) => { - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (prov, offset) = mplace.ptr().into_parts(); - let alloc_id = prov.expect("cannot have `fake` place for non-ZST type").alloc_id(); + let (prov, offset) = + mplace.ptr().into_pointer_or_addr().unwrap().prov_and_relative_offset(); + let alloc_id = prov.alloc_id(); ConstValue::Indirect { alloc_id, offset } } // see comment on `let force_as_immediate` above @@ -232,9 +232,10 @@ pub(super) fn op_to_const<'tcx>( imm.layout.ty, ); let msg = "`op_to_const` on an immediate scalar pair must only be used on slice references to the beginning of an actual allocation"; - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (prov, offset) = a.to_pointer(ecx).expect(msg).into_parts(); - let alloc_id = prov.expect(msg).alloc_id(); + let ptr = a.to_pointer(ecx).expect(msg); + let (prov, offset) = + ptr.into_pointer_or_addr().expect(msg).prov_and_relative_offset(); + let alloc_id = prov.alloc_id(); let data = ecx.tcx.global_alloc(alloc_id).unwrap_memory(); assert!(offset == abi::Size::ZERO, "{}", msg); let meta = b.to_target_usize(ecx).expect(msg); @@ -280,34 +281,6 @@ pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { - // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. - // Catch such calls and evaluate them instead of trying to load a constant's MIR. - if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def { - let ty = key.value.instance.ty(tcx, key.typing_env); - let ty::FnDef(_, args) = ty.kind() else { - bug!("intrinsic with type {:?}", ty); - }; - return eval_nullary_intrinsic(tcx, key.typing_env, def_id, args).report_err().map_err( - |error| { - let span = tcx.def_span(def_id); - - // FIXME(oli-obk): why don't we have any tests for this code path? - super::report( - tcx, - error.into_kind(), - span, - || (span, vec![]), - |diag, span, _| { - diag.span_label( - span, - crate::fluent_generated::const_eval_nullary_intrinsic_fail, - ); - }, - ) - }, - ); - } - tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 14abdd8c98c..9133a5fc8ef 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -574,7 +574,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { if addr != 0 { diag.arg( "pointer", - Pointer::<Option<CtfeProvenance>>::from_addr_invalid(addr).to_string(), + Pointer::<Option<CtfeProvenance>>::without_provenance(addr).to_string(), ); } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index b29c5c7c7d7..d7cede71293 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -6,10 +6,9 @@ use std::assert_matches::assert_matches; use rustc_abi::Size; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; -use rustc_hir::def_id::DefId; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; use rustc_middle::ty::layout::{TyAndLayout, ValidityRequirement}; -use rustc_middle::ty::{GenericArgsRef, Ty, TyCtxt}; +use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::{bug, ty}; use rustc_span::{Symbol, sym}; use tracing::trace; @@ -17,8 +16,8 @@ use tracing::trace; use super::memory::MemoryKind; use super::util::ensure_monomorphic_enough; use super::{ - Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, Machine, - OpTy, PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom, + Allocation, CheckInAllocMsg, ConstAllocation, ImmTy, InterpCx, InterpResult, Machine, OpTy, + PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom, err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format, }; use crate::fluent_generated as fluent; @@ -30,73 +29,6 @@ pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAll tcx.mk_const_alloc(alloc) } -/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated -/// inside an `InterpCx` and instead have their value computed directly from rustc internal info. -pub(crate) fn eval_nullary_intrinsic<'tcx>( - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - def_id: DefId, - args: GenericArgsRef<'tcx>, -) -> InterpResult<'tcx, ConstValue<'tcx>> { - let tp_ty = args.type_at(0); - let name = tcx.item_name(def_id); - interp_ok(match name { - sym::type_name => { - ensure_monomorphic_enough(tcx, tp_ty)?; - let alloc = alloc_type_name(tcx, tp_ty); - ConstValue::Slice { data: alloc, meta: alloc.inner().size().bytes() } - } - sym::needs_drop => { - ensure_monomorphic_enough(tcx, tp_ty)?; - ConstValue::from_bool(tp_ty.needs_drop(tcx, typing_env)) - } - sym::type_id => { - ensure_monomorphic_enough(tcx, tp_ty)?; - ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128()) - } - sym::variant_count => match match tp_ty.kind() { - // Pattern types have the same number of variants as their base type. - // Even if we restrict e.g. which variants are valid, the variants are essentially just uninhabited. - // And `Result<(), !>` still has two variants according to `variant_count`. - ty::Pat(base, _) => *base, - _ => tp_ty, - } - .kind() - { - // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. - ty::Adt(adt, _) => ConstValue::from_target_usize(adt.variants().len() as u64, &tcx), - ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => { - throw_inval!(TooGeneric) - } - ty::Pat(..) => unreachable!(), - ty::Bound(_, _) => bug!("bound ty during ctfe"), - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Foreign(_) - | ty::Str - | ty::Array(_, _) - | ty::Slice(_) - | ty::RawPtr(_, _) - | ty::Ref(_, _, _) - | ty::FnDef(_, _) - | ty::FnPtr(..) - | ty::Dynamic(_, _, _) - | ty::Closure(_, _) - | ty::CoroutineClosure(_, _) - | ty::Coroutine(_, _) - | ty::CoroutineWitness(..) - | ty::UnsafeBinder(_) - | ty::Never - | ty::Tuple(_) - | ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx), - }, - other => bug!("`{}` is not a zero arg intrinsic", other), - }) -} - impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Returns `true` if emulation happened. /// Here we implement the intrinsics that are common to all Miri instances; individual machines can add their own @@ -110,8 +42,77 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, bool> { let instance_args = instance.args; let intrinsic_name = self.tcx.item_name(instance.def_id()); + let tcx = self.tcx.tcx; match intrinsic_name { + sym::type_name => { + let tp_ty = instance.args.type_at(0); + ensure_monomorphic_enough(tcx, tp_ty)?; + let alloc = alloc_type_name(tcx, tp_ty); + let val = ConstValue::Slice { data: alloc, meta: alloc.inner().size().bytes() }; + let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?; + self.copy_op(&val, dest)?; + } + sym::needs_drop => { + let tp_ty = instance.args.type_at(0); + ensure_monomorphic_enough(tcx, tp_ty)?; + let val = ConstValue::from_bool(tp_ty.needs_drop(tcx, self.typing_env)); + let val = self.const_val_to_op(val, tcx.types.bool, Some(dest.layout))?; + self.copy_op(&val, dest)?; + } + sym::type_id => { + let tp_ty = instance.args.type_at(0); + ensure_monomorphic_enough(tcx, tp_ty)?; + let val = ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128()); + let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?; + self.copy_op(&val, dest)?; + } + sym::variant_count => { + let tp_ty = instance.args.type_at(0); + let ty = match tp_ty.kind() { + // Pattern types have the same number of variants as their base type. + // Even if we restrict e.g. which variants are valid, the variants are essentially just uninhabited. + // And `Result<(), !>` still has two variants according to `variant_count`. + ty::Pat(base, _) => *base, + _ => tp_ty, + }; + let val = match ty.kind() { + // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. + ty::Adt(adt, _) => { + ConstValue::from_target_usize(adt.variants().len() as u64, &tcx) + } + ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => { + throw_inval!(TooGeneric) + } + ty::Pat(..) => unreachable!(), + ty::Bound(_, _) => bug!("bound ty during ctfe"), + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(..) + | ty::Dynamic(_, _, _) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(..) + | ty::UnsafeBinder(_) + | ty::Never + | ty::Tuple(_) + | ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx), + }; + let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?; + self.copy_op(&val, dest)?; + } + sym::caller_location => { let span = self.find_closest_untracked_caller_location(); let val = self.tcx.span_as_caller_location(span); @@ -137,21 +138,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_scalar(Scalar::from_target_usize(result, self), dest)?; } - sym::needs_drop | sym::type_id | sym::type_name | sym::variant_count => { - let gid = GlobalId { instance, promoted: None }; - let ty = self - .tcx - .fn_sig(instance.def_id()) - .instantiate(self.tcx.tcx, instance.args) - .output() - .no_bound_vars() - .unwrap(); - let val = self - .ctfe_query(|tcx| tcx.const_eval_global_id(self.typing_env, gid, tcx.span))?; - let val = self.const_val_to_op(val, ty, Some(dest.layout))?; - self.copy_op(&val, dest)?; - } - sym::fadd_algebraic | sym::fsub_algebraic | sym::fmul_algebraic diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index d6d230fbd17..35ec303f961 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -747,7 +747,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { // Allow these casts, but make the pointer not dereferenceable. // (I.e., they behave like transmutation.) // This is correct because no pointers can ever be exposed in compile-time evaluation. - interp_ok(Pointer::from_addr_invalid(addr)) + interp_ok(Pointer::without_provenance(addr)) } #[inline(always)] @@ -756,8 +756,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { ptr: Pointer<CtfeProvenance>, _size: i64, ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> { - // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.prov_and_relative_offset(); Some((prov.alloc_id(), offset, prov.immutable())) } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 69fceb02ff9..3b36bb85985 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1596,7 +1596,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Some((alloc_id, offset, extra)) => Ok((alloc_id, offset, extra)), None => { assert!(M::Provenance::OFFSET_IS_ADDR); - let (_, addr) = ptr.into_parts(); + // Offset is absolute, as we just asserted. + let (_, addr) = ptr.into_raw_parts(); Err(addr.bytes()) } }, diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index f5792aba207..f8b3c92debb 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -29,7 +29,6 @@ pub use self::intern::{ HasStaticRootDefId, InternKind, InternResult, intern_const_alloc_for_constprop, intern_const_alloc_recursive, }; -pub(crate) use self::intrinsics::eval_nullary_intrinsic; pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine}; pub use self::memory::{AllocInfo, AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; use self::operand::Operand; diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 3028568dd8f..a3cd35ff0bb 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -118,7 +118,7 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { pub fn fake_alloc_zst(layout: TyAndLayout<'tcx>) -> Self { assert!(layout.is_zst()); let align = layout.align.abi; - let ptr = Pointer::from_addr_invalid(align.bytes()); // no provenance, absolute address + let ptr = Pointer::without_provenance(align.bytes()); // no provenance, absolute address MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::None, misaligned: None }, layout } } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 998ef3729ea..72680019380 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -518,7 +518,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance { ptr_kind, // FIXME this says "null pointer" when null but we need translate - pointer: format!("{}", Pointer::<Option<AllocId>>::from_addr_invalid(i)) + pointer: format!("{}", Pointer::<Option<AllocId>>::without_provenance(i)) }, Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds { ptr_kind @@ -868,7 +868,9 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { fn add_data_range(&mut self, ptr: Pointer<Option<M::Provenance>>, size: Size) { if let Some(data_bytes) = self.data_bytes.as_mut() { // We only have to store the offset, the rest is the same for all pointers here. - let (_prov, offset) = ptr.into_parts(); + // The logic is agnostic to wether the offset is relative or absolute as long as + // it is consistent. + let (_prov, offset) = ptr.into_raw_parts(); // Add this. data_bytes.add_range(offset, size); }; @@ -894,7 +896,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { .as_mplace_or_imm() .expect_left("place must be in memory") .ptr(); - let (_prov, offset) = ptr.into_parts(); + let (_prov, offset) = ptr.into_raw_parts(); offset } @@ -903,7 +905,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // Our value must be in memory, otherwise we would not have set up `data_bytes`. let mplace = self.ecx.force_allocation(place)?; // Determine starting offset and size. - let (_prov, start_offset) = mplace.ptr().into_parts(); + let (_prov, start_offset) = mplace.ptr().into_raw_parts(); let (size, _align) = self .ecx .size_and_align_of_val(&mplace)? diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 4855fc58d03..18490385455 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1112,7 +1112,9 @@ fn get_backend_from_raw_matches( matches: &Matches, ) -> Box<dyn CodegenBackend> { let debug_flags = matches.opt_strs("Z"); - let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); + let backend_name = debug_flags + .iter() + .find_map(|x| x.strip_prefix("codegen-backend=").or(x.strip_prefix("codegen_backend="))); let target = parse_target_triple(early_dcx, matches); let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from)); let target = config::build_target_config(early_dcx, &target, sysroot.path()); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6fa473d177d..57d3c5da873 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -278,8 +278,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { /// fall back to subtyping (`unify_and`). fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b); - assert!(a.is_ty_var() && self.shallow_resolve(a) == a); - assert!(self.shallow_resolve(b) == b); + debug_assert!(a.is_ty_var() && self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); if b.is_ty_var() { // Two unresolved type variables: create a `Coerce` predicate. @@ -323,6 +323,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { mutbl_b: hir::Mutability, ) -> CoerceResult<'tcx> { debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); + debug_assert!(self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); // If we have a parameter of type `&M T_a` and the value // provided is `expr`, we will be adding an implicit borrow, @@ -514,10 +516,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { /// /// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions) #[instrument(skip(self), level = "debug")] - fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> { - source = self.shallow_resolve(source); - target = self.shallow_resolve(target); + fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tcx> { debug!(?source, ?target); + debug_assert!(self.shallow_resolve(source) == source); + debug_assert!(self.shallow_resolve(target) == target); // We don't apply any coercions incase either the source or target // aren't sufficiently well known but tend to instead just equate @@ -531,6 +533,54 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(TypeError::Mismatch); } + // This is an optimization because coercion is one of the most common + // operations that we do in typeck, since it happens at every assignment + // and call arg (among other positions). + // + // These targets are known to never be RHS in `LHS: CoerceUnsized<RHS>`. + // That's because these are built-in types for which a core-provided impl + // doesn't exist, and for which a user-written impl is invalid. + // + // This is technically incomplete when users write impossible bounds like + // `where T: CoerceUnsized<usize>`, for example, but that trait is unstable + // and coercion is allowed to be incomplete. The only case where this matters + // is impossible bounds. + // + // Note that some of these types implement `LHS: Unsize<RHS>`, but they + // do not implement *`CoerceUnsized`* which is the root obligation of the + // check below. + match target.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::FnDef(_, _) + | ty::FnPtr(_, _) + | ty::Dynamic(_, _, _) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(_, _) + | ty::Never + | ty::Tuple(_) => return Err(TypeError::Mismatch), + _ => {} + } + // Additionally, we ignore `&str -> &str` coercions, which happen very + // commonly since strings are one of the most used argument types in Rust, + // we do coercions when type checking call expressions. + if let ty::Ref(_, source_pointee, ty::Mutability::Not) = *source.kind() + && source_pointee.is_str() + && let ty::Ref(_, target_pointee, ty::Mutability::Not) = *target.kind() + && target_pointee.is_str() + { + return Err(TypeError::Mismatch); + } + let traits = (self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait()); let (Some(unsize_did), Some(coerce_unsized_did)) = traits else { @@ -800,6 +850,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { /// - `Pin<Box<T>>` as `Pin<&mut T>` #[instrument(skip(self), level = "trace")] fn coerce_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + debug_assert!(self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); + // We need to make sure the two types are compatible for coercion. // Then we will build a ReborrowPin adjustment and return that as an InferOk. @@ -848,6 +901,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { b: Ty<'tcx>, adjustment: Option<Adjust>, ) -> CoerceResult<'tcx> { + debug_assert!(self.shallow_resolve(b) == b); + self.commit_if_ok(|snapshot| { let outer_universe = self.infcx.universe(); @@ -888,24 +943,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { fn_ty_a: ty::PolyFnSig<'tcx>, b: Ty<'tcx>, ) -> CoerceResult<'tcx> { - //! Attempts to coerce from the type of a Rust function item - //! into a closure or a `proc`. - //! - - let b = self.shallow_resolve(b); debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer"); + debug_assert!(self.shallow_resolve(b) == b); self.coerce_from_safe_fn(fn_ty_a, b, None) } fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - //! Attempts to coerce from the type of a Rust function item - //! into a closure or a `proc`. + debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); + debug_assert!(self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); - let b = self.shallow_resolve(b); let InferOk { value: b, mut obligations } = self.at(&self.cause, self.param_env).normalize(b); - debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); match b.kind() { ty::FnPtr(_, b_hdr) => { @@ -955,6 +1005,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } + /// Attempts to coerce from the type of a non-capturing closure + /// into a function pointer. fn coerce_closure_to_fn( &self, a: Ty<'tcx>, @@ -962,11 +1014,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { args_a: GenericArgsRef<'tcx>, b: Ty<'tcx>, ) -> CoerceResult<'tcx> { - //! Attempts to coerce from the type of a non-capturing closure - //! into a function pointer. - //! - - let b = self.shallow_resolve(b); + debug_assert!(self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); match b.kind() { // At this point we haven't done capture analysis, which means @@ -1010,6 +1059,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { mutbl_b: hir::Mutability, ) -> CoerceResult<'tcx> { debug!("coerce_raw_ptr(a={:?}, b={:?})", a, b); + debug_assert!(self.shallow_resolve(a) == a); + debug_assert!(self.shallow_resolve(b) == b); let (is_ref, mt_a) = match *a.kind() { ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }), diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index d0a48872f75..df1ee0e79c2 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3055,7 +3055,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn note_unmet_impls_on_type( &self, err: &mut Diag<'_>, - errors: Vec<FulfillmentError<'tcx>>, + errors: &[FulfillmentError<'tcx>], suggest_derive: bool, ) { let preds: Vec<_> = errors diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index b9d24506986..87a7cd62ae5 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -322,7 +322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_expr.span, format!("cannot use `{}` on type `{}`", s, lhs_ty_str), ); - self.note_unmet_impls_on_type(&mut err, errors, false); + self.note_unmet_impls_on_type(&mut err, &errors, false); (err, None) } Op::BinOp(bin_op) => { @@ -382,7 +382,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(rhs_expr.span, rhs_ty_str); } let suggest_derive = self.can_eq(self.param_env, lhs_ty, rhs_ty); - self.note_unmet_impls_on_type(&mut err, errors, suggest_derive); + self.note_unmet_impls_on_type(&mut err, &errors, suggest_derive); (err, output_def_id) } }; @@ -582,22 +582,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted } else if lhs_ty.has_non_region_param() { - // Look for a TraitPredicate in the Fulfillment errors, - // and use it to generate a suggestion. - // - // Note that lookup_op_method must be called again but - // with a specific rhs_ty instead of a placeholder so - // the resulting predicate generates a more specific - // suggestion for the user. - let errors = self - .lookup_op_method( - (lhs_expr, lhs_ty), - Some((rhs_expr, rhs_ty)), - lang_item_for_binop(self.tcx, op), - op.span(), - expected, - ) - .unwrap_err(); if !errors.is_empty() { for error in errors { if let Some(trait_pred) = @@ -946,7 +930,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Str | ty::Never | ty::Char | ty::Tuple(_) | ty::Array(_, _) => {} ty::Ref(_, lty, _) if *lty.kind() == ty::Str => {} _ => { - self.note_unmet_impls_on_type(&mut err, errors, true); + self.note_unmet_impls_on_type(&mut err, &errors, true); } } } diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index cae674165f0..ddc0b116806 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -110,17 +110,16 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r.kind() { - ty::ReBound(..) => { - // leave bound regions alone - r - } + // Leave bound regions alone, since they affect selection via the leak check. + ty::ReBound(..) => r, + // Leave error regions alone, since they affect selection b/c of incompleteness. + ty::ReError(_) => r, ty::ReEarlyParam(..) | ty::ReLateParam(_) | ty::ReVar(_) | ty::RePlaceholder(..) | ty::ReStatic - | ty::ReError(_) | ty::ReErased => self.cx().lifetimes.re_erased, } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index edfb05e2ccd..3fe7c5e4286 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -298,6 +298,16 @@ fn configure_and_expand( fn print_macro_stats(ecx: &ExtCtxt<'_>) { use std::fmt::Write; + let crate_name = ecx.ecfg.crate_name.as_str(); + let crate_name = if crate_name == "build_script_build" { + // This is a build script. Get the package name from the environment. + let pkg_name = + std::env::var("CARGO_PKG_NAME").unwrap_or_else(|_| "<unknown crate>".to_string()); + format!("{pkg_name} build script") + } else { + crate_name.to_string() + }; + // No instability because we immediately sort the produced vector. #[allow(rustc::potential_query_instability)] let mut macro_stats: Vec<_> = ecx @@ -327,7 +337,7 @@ fn print_macro_stats(ecx: &ExtCtxt<'_>) { // non-interleaving, though. let mut s = String::new(); _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w)); - _ = writeln!(s, "{prefix} MACRO EXPANSION STATS: {}", ecx.ecfg.crate_name); + _ = writeln!(s, "{prefix} MACRO EXPANSION STATS: {}", crate_name); _ = writeln!( s, "{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}", @@ -341,20 +351,30 @@ fn print_macro_stats(ecx: &ExtCtxt<'_>) { } for (bytes, lines, uses, name, kind) in macro_stats { let mut name = ExpnKind::Macro(kind, *name).descr(); + let uses_with_underscores = thousands::usize_with_underscores(uses); let avg_lines = lines as f64 / uses as f64; let avg_bytes = bytes as f64 / uses as f64; - if name.len() >= name_w { - // If the name is long, print it on a line by itself, then - // set the name to empty and print things normally, to show the - // stats on the next line. + + // Ensure the "Macro Name" and "Uses" columns are as compact as possible. + let mut uses_w = uses_w; + if name.len() + uses_with_underscores.len() >= name_w + uses_w { + // The name would abut or overlap the uses value. Print the name + // on a line by itself, then set the name to empty and print things + // normally, to show the stats on the next line. _ = writeln!(s, "{prefix} {:<name_w$}", name); name = String::new(); - } + } else if name.len() >= name_w { + // The name won't abut or overlap with the uses value, but it does + // overlap with the empty part of the uses column. Shrink the width + // of the uses column to account for the excess name length. + uses_w = uses_with_underscores.len() + 1 + }; + _ = writeln!( s, "{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}", name, - thousands::usize_with_underscores(uses), + uses_with_underscores, thousands::usize_with_underscores(lines), thousands::f64p1_with_underscores(avg_lines), thousands::usize_with_underscores(bytes), diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 2b2ffa71628..16edc240544 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -168,8 +168,9 @@ impl<'tcx> ConstValue<'tcx> { return Some(&[]); } // Non-empty slice, must have memory. We know this is a relative pointer. - let (inner_prov, offset) = ptr.into_parts(); - let data = tcx.global_alloc(inner_prov?.alloc_id()).unwrap_memory(); + let (inner_prov, offset) = + ptr.into_pointer_or_addr().ok()?.prov_and_relative_offset(); + let data = tcx.global_alloc(inner_prov.alloc_id()).unwrap_memory(); (data, offset.bytes(), offset.bytes() + len) } }; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index dd55d039794..4198b198ab1 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -526,7 +526,7 @@ impl Allocation { let ptr_bytes = &mut bytes[idx..idx + ptr_size]; let bits = read_target_uint(endian, ptr_bytes).unwrap(); let (ptr_prov, ptr_offset) = - adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_parts(); + adjust_ptr(Pointer::new(alloc_id, Size::from_bytes(bits)))?.into_raw_parts(); write_target_uint(endian, ptr_bytes, ptr_offset.bytes().into()).unwrap(); new_provenance.push((offset, ptr_prov)); } @@ -769,7 +769,7 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> // as-is into memory. This also double-checks that `val.size()` matches `range.size`. let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size)? { Right(ptr) => { - let (provenance, offset) = ptr.into_parts(); + let (provenance, offset) = ptr.into_raw_parts(); (u128::from(offset.bytes()), Some(provenance)) } Left(data) => (data, None), diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 25c7c26ddd9..0ff14f15c13 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -288,7 +288,7 @@ impl From<CtfeProvenance> for Pointer { impl<Prov> From<Pointer<Prov>> for Pointer<Option<Prov>> { #[inline(always)] fn from(ptr: Pointer<Prov>) -> Self { - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.into_raw_parts(); Pointer::new(Some(prov), offset) } } @@ -314,19 +314,17 @@ impl<Prov> Pointer<Option<Prov>> { assert!(Prov::OFFSET_IS_ADDR); self.offset } -} -impl<Prov> Pointer<Option<Prov>> { /// Creates a pointer to the given address, with invalid provenance (i.e., cannot be used for /// any memory access). #[inline(always)] - pub fn from_addr_invalid(addr: u64) -> Self { + pub fn without_provenance(addr: u64) -> Self { Pointer { provenance: None, offset: Size::from_bytes(addr) } } #[inline(always)] pub fn null() -> Self { - Pointer::from_addr_invalid(0) + Pointer::without_provenance(0) } } @@ -336,11 +334,11 @@ impl<Prov> Pointer<Prov> { Pointer { provenance, offset } } - /// Obtain the constituents of this pointer. Not that the meaning of the offset depends on the type `Prov`! - /// This function must only be used in the implementation of `Machine::ptr_get_alloc`, - /// and when a `Pointer` is taken apart to be stored efficiently in an `Allocation`. + /// Obtain the constituents of this pointer. Note that the meaning of the offset depends on the + /// type `Prov`! This is a low-level function that should only be used when absolutely + /// necessary. Prefer `prov_and_relative_offset` if possible. #[inline(always)] - pub fn into_parts(self) -> (Prov, Size) { + pub fn into_raw_parts(self) -> (Prov, Size) { (self.provenance, self.offset) } @@ -361,3 +359,12 @@ impl<Prov> Pointer<Prov> { self.wrapping_offset(Size::from_bytes(i as u64), cx) } } + +impl Pointer<CtfeProvenance> { + /// Return the provenance and relative offset stored in this pointer. Safer alternative to + /// `into_raw_parts` since the type ensures that the offset is indeed relative. + #[inline(always)] + pub fn prov_and_relative_offset(self) -> (CtfeProvenance, Size) { + (self.provenance, self.offset) + } +} diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 7ba0e5b5e07..8092f634dc8 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -109,7 +109,7 @@ impl<Prov> Scalar<Prov> { /// Create a Scalar from a pointer with an `Option<_>` provenance (where `None` represents a /// plain integer / "invalid" pointer). pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self { - match ptr.into_parts() { + match ptr.into_raw_parts() { (Some(prov), offset) => Scalar::from_pointer(Pointer::new(prov, offset), cx), (None, offset) => { Scalar::Int(ScalarInt::try_from_uint(offset.bytes(), cx.pointer_size()).unwrap()) @@ -276,7 +276,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> { Right(ptr) => interp_ok(ptr.into()), Left(bits) => { let addr = u64::try_from(bits).unwrap(); - interp_ok(Pointer::from_addr_invalid(addr)) + interp_ok(Pointer::without_provenance(addr)) } } } @@ -299,7 +299,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> { Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap()) } else { // We know `offset` is relative, since `OFFSET_IS_ADDR == false`. - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.into_raw_parts(); // Because `OFFSET_IS_ADDR == false`, this unwrap can never fail. Err(Scalar::Ptr(Pointer::new(prov.get_alloc_id().unwrap(), offset), sz)) } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index adc100941a3..9f39908c3b2 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1359,7 +1359,15 @@ pub struct BasicBlockData<'tcx> { impl<'tcx> BasicBlockData<'tcx> { pub fn new(terminator: Option<Terminator<'tcx>>, is_cleanup: bool) -> BasicBlockData<'tcx> { - BasicBlockData { statements: vec![], terminator, is_cleanup } + BasicBlockData::new_stmts(Vec::new(), terminator, is_cleanup) + } + + pub fn new_stmts( + statements: Vec<Statement<'tcx>>, + terminator: Option<Terminator<'tcx>>, + is_cleanup: bool, + ) -> BasicBlockData<'tcx> { + BasicBlockData { statements, terminator, is_cleanup } } /// Accessor for terminator. diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index d98b40f0fcf..d16477adb77 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -16,12 +16,16 @@ pub struct Statement<'tcx> { pub kind: StatementKind<'tcx>, } -impl Statement<'_> { +impl<'tcx> Statement<'tcx> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. pub fn make_nop(&mut self) { self.kind = StatementKind::Nop } + + pub fn new(source_info: SourceInfo, kind: StatementKind<'tcx>) -> Self { + Statement { source_info, kind } + } } impl<'tcx> StatementKind<'tcx> { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1392d1d08fc..bee490b3648 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1755,7 +1755,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ) -> Result<(), PrintError> { define_scoped_cx!(self); - let (prov, offset) = ptr.into_parts(); + let (prov, offset) = ptr.prov_and_relative_offset(); match ty.kind() { // Byte strings (&[u8; N]) ty::Ref(_, inner, _) => { diff --git a/compiler/rustc_mir_build/src/builder/cfg.rs b/compiler/rustc_mir_build/src/builder/cfg.rs index 082cdc2e2a4..2faccc43247 100644 --- a/compiler/rustc_mir_build/src/builder/cfg.rs +++ b/compiler/rustc_mir_build/src/builder/cfg.rs @@ -42,7 +42,7 @@ impl<'tcx> CFG<'tcx> { ) { self.push( block, - Statement { source_info, kind: StatementKind::Assign(Box::new((place, rvalue))) }, + Statement::new(source_info, StatementKind::Assign(Box::new((place, rvalue)))), ); } @@ -88,7 +88,7 @@ impl<'tcx> CFG<'tcx> { place: Place<'tcx>, ) { let kind = StatementKind::FakeRead(Box::new((cause, place))); - let stmt = Statement { source_info, kind }; + let stmt = Statement::new(source_info, kind); self.push(block, stmt); } @@ -99,7 +99,7 @@ impl<'tcx> CFG<'tcx> { place: Place<'tcx>, ) { let kind = StatementKind::PlaceMention(Box::new(place)); - let stmt = Statement { source_info, kind }; + let stmt = Statement::new(source_info, kind); self.push(block, stmt); } @@ -110,7 +110,7 @@ impl<'tcx> CFG<'tcx> { /// syntax (e.g. `continue` or `if !`) that would otherwise not appear in MIR. pub(crate) fn push_coverage_span_marker(&mut self, block: BasicBlock, source_info: SourceInfo) { let kind = StatementKind::Coverage(coverage::CoverageKind::SpanMarker); - let stmt = Statement { source_info, kind }; + let stmt = Statement::new(source_info, kind); self.push(block, stmt); } diff --git a/compiler/rustc_mir_build/src/builder/coverageinfo.rs b/compiler/rustc_mir_build/src/builder/coverageinfo.rs index a80bd4f3c80..aa43b273cff 100644 --- a/compiler/rustc_mir_build/src/builder/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/builder/coverageinfo.rs @@ -61,10 +61,10 @@ impl BlockMarkerGen { block: BasicBlock, ) -> BlockMarkerId { let id = self.next_block_marker_id(); - let marker_statement = mir::Statement { + let marker_statement = mir::Statement::new( source_info, - kind: mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }), - }; + mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }), + ); cfg.push(block, marker_statement); id diff --git a/compiler/rustc_mir_build/src/builder/custom/parse.rs b/compiler/rustc_mir_build/src/builder/custom/parse.rs index 91e284604b6..10154461c33 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse.rs @@ -315,10 +315,8 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let stmt = self.statement_as_expr(*stmt_id)?; let span = self.thir[stmt].span; let statement = self.parse_statement(stmt)?; - data.statements.push(Statement { - source_info: SourceInfo { span, scope: self.source_scope }, - kind: statement, - }); + data.statements + .push(Statement::new(SourceInfo { span, scope: self.source_scope }, statement)); } let Some(trailing) = block.expr else { return Err(self.expr_error(expr_id, "terminator")) }; diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 99148504a87..7c851ec465b 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -489,16 +489,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = place_builder.to_place(this); this.cfg.push( block, - Statement { - source_info: ty_source_info, - kind: StatementKind::AscribeUserType( + Statement::new( + ty_source_info, + StatementKind::AscribeUserType( Box::new(( place, UserTypeProjection { base: annotation_index, projs: vec![] }, )), Variance::Invariant, ), - }, + ), ); } block.and(place_builder) @@ -518,16 +518,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }); this.cfg.push( block, - Statement { - source_info: ty_source_info, - kind: StatementKind::AscribeUserType( + Statement::new( + ty_source_info, + StatementKind::AscribeUserType( Box::new(( Place::from(temp), UserTypeProjection { base: annotation_index, projs: vec![] }, )), Variance::Invariant, ), - }, + ), ); } block.and(PlaceBuilder::from(temp)) diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index 9e07dd5da7e..975226bb642 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -175,10 +175,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // and therefore is not considered during coroutine auto-trait // determination. See the comment about `box` at `yield_in_scope`. let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span)); - this.cfg.push( - block, - Statement { source_info, kind: StatementKind::StorageLive(result) }, - ); + this.cfg + .push(block, Statement::new(source_info, StatementKind::StorageLive(result))); if let Some(scope) = scope.temp_lifetime { // schedule a shallow free of that memory, lest we unwind: this.schedule_drop_storage_and_value(expr_span, scope, result); @@ -278,12 +276,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; this.cfg.push( block, - Statement { + Statement::new( source_info, - kind: StatementKind::Intrinsic(Box::new( - NonDivergingIntrinsic::Assume(Operand::Move(assert_place)), - )), - }, + StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume( + Operand::Move(assert_place), + ))), + ), ); } @@ -789,7 +787,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = this.source_info(upvar_span); let temp = this.local_decls.push(LocalDecl::new(upvar_ty, upvar_span)); - this.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) }); + this.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(temp))); let arg_place_builder = unpack!(block = this.as_place_builder(block, arg)); diff --git a/compiler/rustc_mir_build/src/builder/expr/as_temp.rs b/compiler/rustc_mir_build/src/builder/expr/as_temp.rs index 0bd61168fba..b0ce3527d8b 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_temp.rs @@ -102,8 +102,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Block { expr: None, targeted_by_break: false, .. } = this.thir[block] && expr_ty.is_never() => {} _ => { - this.cfg - .push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) }); + this.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(temp))); // In constants, `temp_lifetime` is `None` for temporaries that // live for the `'static` lifetime. Thus we do not drop these diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 270a7d4b154..9600067a85f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -646,9 +646,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let base = self.canonical_user_type_annotations.push(annotation.clone()); self.cfg.push( block, - Statement { - source_info: ty_source_info, - kind: StatementKind::AscribeUserType( + Statement::new( + ty_source_info, + StatementKind::AscribeUserType( Box::new((place, UserTypeProjection { base, projs: Vec::new() })), // We always use invariant as the variance here. This is because the // variance field from the ascription refers to the variance to use @@ -666,7 +666,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // `<expr>`. ty::Invariant, ), - }, + ), ); self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); @@ -828,7 +828,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> Place<'tcx> { let local_id = self.var_local_id(var, for_guard); let source_info = self.source_info(span); - self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) }); + self.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(local_id))); // Although there is almost always scope for given variable in corner cases // like #92893 we might get variable with no scope. if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) @@ -2578,16 +2578,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let base = self.canonical_user_type_annotations.push(ascription.annotation); self.cfg.push( block, - Statement { + Statement::new( source_info, - kind: StatementKind::AscribeUserType( + StatementKind::AscribeUserType( Box::new(( ascription.source, UserTypeProjection { base, projs: Vec::new() }, )), ascription.variance, ), - }, + ), ); } } diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 1d15e7e126f..405d47c7c79 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -431,13 +431,13 @@ impl DropTree { cfg.terminate(block, drop_node.data.source_info, terminator); } DropKind::ForLint => { - let stmt = Statement { - source_info: drop_node.data.source_info, - kind: StatementKind::BackwardIncompatibleDropHint { + let stmt = Statement::new( + drop_node.data.source_info, + StatementKind::BackwardIncompatibleDropHint { place: Box::new(drop_node.data.local.into()), reason: BackwardIncompatibleDropReason::Edition2024, }, - }; + ); cfg.push(block, stmt); let target = blocks[drop_node.next].unwrap(); if target != block { @@ -454,10 +454,10 @@ impl DropTree { // Root nodes don't correspond to a drop. DropKind::Storage if drop_idx == ROOT_NODE => {} DropKind::Storage => { - let stmt = Statement { - source_info: drop_node.data.source_info, - kind: StatementKind::StorageDead(drop_node.data.local), - }; + let stmt = Statement::new( + drop_node.data.source_info, + StatementKind::StorageDead(drop_node.data.local), + ); cfg.push(block, stmt); let target = blocks[drop_node.next].unwrap(); if target != block { @@ -1124,13 +1124,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { DropKind::ForLint => { self.cfg.push( block, - Statement { + Statement::new( source_info, - kind: StatementKind::BackwardIncompatibleDropHint { + StatementKind::BackwardIncompatibleDropHint { place: Box::new(local.into()), reason: BackwardIncompatibleDropReason::Edition2024, }, - }, + ), ); } DropKind::Storage => { @@ -1138,7 +1138,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { assert!(local.index() > self.arg_count); self.cfg.push( block, - Statement { source_info, kind: StatementKind::StorageDead(local) }, + Statement::new(source_info, StatementKind::StorageDead(local)), ); } } @@ -1880,13 +1880,13 @@ where cfg.push( block, - Statement { + Statement::new( source_info, - kind: StatementKind::BackwardIncompatibleDropHint { + StatementKind::BackwardIncompatibleDropHint { place: Box::new(local.into()), reason: BackwardIncompatibleDropReason::Edition2024, }, - }, + ), ); } DropKind::Storage => { @@ -1910,7 +1910,7 @@ where } // Only temps and vars need their storage dead. assert!(local.index() > arg_count); - cfg.push(block, Statement { source_info, kind: StatementKind::StorageDead(local) }); + cfg.push(block, Statement::new(source_info, StatementKind::StorageDead(local))); } } } diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 8602bb55765..23e28a11a45 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -17,13 +17,13 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { let mut blocks = IndexVec::new(); let mut block = |n, kind| { - let nop = mir::Statement { source_info, kind: mir::StatementKind::Nop }; + let nop = mir::Statement::new(source_info, mir::StatementKind::Nop); - blocks.push(mir::BasicBlockData { - statements: std::iter::repeat(&nop).cloned().take(n).collect(), - terminator: Some(mir::Terminator { source_info, kind }), - is_cleanup: false, - }) + blocks.push(mir::BasicBlockData::new_stmts( + std::iter::repeat(&nop).cloned().take(n).collect(), + Some(mir::Terminator { source_info, kind }), + false, + )) }; let dummy_place = mir::Place { local: mir::RETURN_PLACE, projection: ty::List::empty() }; diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs index bacff287859..26839ebf61e 100644 --- a/compiler/rustc_mir_transform/src/add_call_guards.rs +++ b/compiler/rustc_mir_transform/src/add_call_guards.rs @@ -44,11 +44,10 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards { let cur_len = body.basic_blocks.len(); let mut new_block = |source_info: SourceInfo, is_cleanup: bool, target: BasicBlock| { - let block = BasicBlockData { - statements: vec![], + let block = BasicBlockData::new( + Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), is_cleanup, - terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), - }; + ); let idx = cur_len + new_blocks.len(); new_blocks.push(block); BasicBlock::new(idx) diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs index a414d120e68..7ae2ebaf4ff 100644 --- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs +++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs @@ -93,11 +93,11 @@ fn add_move_for_packed_drop<'tcx>( let ty = place.ty(body, tcx).ty; let temp = patch.new_temp(ty, source_info.span); - let storage_dead_block = patch.new_block(BasicBlockData { - statements: vec![Statement { source_info, kind: StatementKind::StorageDead(temp) }], - terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), + let storage_dead_block = patch.new_block(BasicBlockData::new_stmts( + vec![Statement::new(source_info, StatementKind::StorageDead(temp))], + Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), is_cleanup, - }); + )); patch.add_statement(loc, StatementKind::StorageLive(temp)); patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place))); diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index e5a28d1b66c..3c29d4624b7 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -81,9 +81,11 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag { // Emit their retags. basic_blocks[START_BLOCK].statements.splice( 0..0, - places.map(|(place, source_info)| Statement { - source_info, - kind: StatementKind::Retag(RetagKind::FnEntry, Box::new(place)), + places.map(|(place, source_info)| { + Statement::new( + source_info, + StatementKind::Retag(RetagKind::FnEntry, Box::new(place)), + ) }), ); } @@ -113,10 +115,10 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag { for (source_info, dest_place, dest_block) in returns { basic_blocks[dest_block].statements.insert( 0, - Statement { + Statement::new( source_info, - kind: StatementKind::Retag(RetagKind::Default, Box::new(dest_place)), - }, + StatementKind::Retag(RetagKind::Default, Box::new(dest_place)), + ), ); } @@ -174,10 +176,7 @@ impl<'tcx> crate::MirPass<'tcx> for AddRetag { let source_info = block_data.statements[i].source_info; block_data.statements.insert( i + 1, - Statement { - source_info, - kind: StatementKind::Retag(retag_kind, Box::new(place)), - }, + Statement::new(source_info, StatementKind::Retag(retag_kind, Box::new(place))), ); } } diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index 8f88613b79f..989787504b7 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -51,22 +51,18 @@ fn insert_alignment_check<'tcx>( let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit); let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr); let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into(); - stmts - .push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) }); + stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((thin_ptr, rvalue))))); // Transmute the pointer to a usize (equivalent to `ptr.addr()`). let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize); let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) }); + stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((addr, rvalue))))); // Get the alignment of the pointee let alignment = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); let rvalue = Rvalue::NullaryOp(NullOp::AlignOf, pointee_ty); - stmts.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new((alignment, rvalue))), - }); + stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((alignment, rvalue))))); // Subtract 1 from the alignment to get the alignment mask let alignment_mask = @@ -76,13 +72,13 @@ fn insert_alignment_check<'tcx>( user_ty: None, const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize), })); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( alignment_mask, Rvalue::BinaryOp(BinOp::Sub, Box::new((Operand::Copy(alignment), one))), ))), - }); + )); // If this target does not have reliable alignment, further limit the mask by anding it with // the mask for the highest reliable alignment. @@ -99,31 +95,31 @@ fn insert_alignment_check<'tcx>( tcx.types.usize, ), })); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( alignment_mask, Rvalue::BinaryOp( BinOp::BitAnd, Box::new((Operand::Copy(alignment_mask), max_mask)), ), ))), - }); + )); } // BitAnd the alignment mask with the pointer let alignment_bits = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( alignment_bits, Rvalue::BinaryOp( BinOp::BitAnd, Box::new((Operand::Copy(addr), Operand::Copy(alignment_mask))), ), ))), - }); + )); // Check if the alignment bits are all zero let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); @@ -132,13 +128,13 @@ fn insert_alignment_check<'tcx>( user_ty: None, const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize), })); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( is_ok, Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(alignment_bits), zero.clone()))), ))), - }); + )); // Emit a check that asserts on the alignment and otherwise triggers a // AssertKind::MisalignedPointerDereference. diff --git a/compiler/rustc_mir_transform/src/check_null.rs b/compiler/rustc_mir_transform/src/check_null.rs index ad74e335bd9..e365d36580a 100644 --- a/compiler/rustc_mir_transform/src/check_null.rs +++ b/compiler/rustc_mir_transform/src/check_null.rs @@ -41,13 +41,12 @@ fn insert_null_check<'tcx>( let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit); let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr); let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into(); - stmts - .push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) }); + stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((thin_ptr, rvalue))))); // Transmute the pointer to a usize (equivalent to `ptr.addr()`). let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize); let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) }); + stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((addr, rvalue))))); let zero = Operand::Constant(Box::new(ConstOperand { span: source_info.span, @@ -71,24 +70,24 @@ fn insert_null_check<'tcx>( let rvalue = Rvalue::NullaryOp(NullOp::SizeOf, pointee_ty); let sizeof_pointee = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new((sizeof_pointee, rvalue))), - }); + StatementKind::Assign(Box::new((sizeof_pointee, rvalue))), + )); // Check that the pointee is not a ZST. let is_pointee_not_zst = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( is_pointee_not_zst, Rvalue::BinaryOp( BinOp::Ne, Box::new((Operand::Copy(sizeof_pointee), zero.clone())), ), ))), - }); + )); // Pointer needs to be checked only if pointee is not a ZST. Operand::Copy(is_pointee_not_zst) @@ -97,38 +96,38 @@ fn insert_null_check<'tcx>( // Check whether the pointer is null. let is_null = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( is_null, Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(addr), zero))), ))), - }); + )); // We want to throw an exception if the pointer is null and the pointee is not unconditionally // allowed (which for all non-borrow place uses, is when the pointee is ZST). let should_throw_exception = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( should_throw_exception, Rvalue::BinaryOp( BinOp::BitAnd, Box::new((Operand::Copy(is_null), pointee_should_be_checked)), ), ))), - }); + )); // The final condition whether this pointer usage is ok or not. let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); - stmts.push(Statement { + stmts.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( is_ok, Rvalue::UnaryOp(UnOp::Not, Operand::Copy(should_throw_exception)), ))), - }); + )); // Emit a PointerCheck that asserts on the condition and otherwise triggers // a AssertKind::NullPointerDereference. diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs index bf94f1aad24..4f913c1fca0 100644 --- a/compiler/rustc_mir_transform/src/check_pointers.rs +++ b/compiler/rustc_mir_transform/src/check_pointers.rs @@ -235,11 +235,11 @@ fn split_block( let block_data = &mut basic_blocks[location.block]; // Drain every statement after this one and move the current terminator to a new basic block. - let new_block = BasicBlockData { - statements: block_data.statements.split_off(location.statement_index), - terminator: block_data.terminator.take(), - is_cleanup: block_data.is_cleanup, - }; + let new_block = BasicBlockData::new_stmts( + block_data.statements.split_off(location.statement_index), + block_data.terminator.take(), + block_data.is_cleanup, + ); basic_blocks.push(new_block) } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 06c6b46a9c2..761d5461a99 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -252,16 +252,16 @@ impl<'tcx> TransformVisitor<'tcx> { } }; - let statements = vec![Statement { - kind: StatementKind::Assign(Box::new((Place::return_place(), none_value))), + let statements = vec![Statement::new( source_info, - }]; + StatementKind::Assign(Box::new((Place::return_place(), none_value))), + )]; - body.basic_blocks_mut().push(BasicBlockData { + body.basic_blocks_mut().push(BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }); + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + )); block } @@ -342,10 +342,10 @@ impl<'tcx> TransformVisitor<'tcx> { } }; - statements.push(Statement { - kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))), + statements.push(Statement::new( source_info, - }); + StatementKind::Assign(Box::new((Place::return_place(), rvalue))), + )); } // Create a Place referencing a coroutine struct field @@ -361,13 +361,13 @@ impl<'tcx> TransformVisitor<'tcx> { // Create a statement which changes the discriminant fn set_discr(&self, state_disc: VariantIdx, source_info: SourceInfo) -> Statement<'tcx> { let self_place = Place::from(SELF_ARG); - Statement { + Statement::new( source_info, - kind: StatementKind::SetDiscriminant { + StatementKind::SetDiscriminant { place: Box::new(self_place), variant_index: state_disc, }, - } + ) } // Create a statement which reads the discriminant into a temporary @@ -377,10 +377,10 @@ impl<'tcx> TransformVisitor<'tcx> { let temp = Place::from(local_decls_len); let self_place = Place::from(SELF_ARG); - let assign = Statement { - source_info: SourceInfo::outermost(body.span), - kind: StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))), - }; + let assign = Statement::new( + SourceInfo::outermost(body.span), + StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))), + ); (assign, temp) } } @@ -450,7 +450,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { && !self.always_live_locals.contains(l); if needs_storage_dead { data.statements - .push(Statement { source_info, kind: StatementKind::StorageDead(l) }); + .push(Statement::new(source_info, StatementKind::StorageDead(l))); } } @@ -596,10 +596,8 @@ fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local let local = arg.node.place().unwrap().local; let arg = Rvalue::Use(arg.node); - let assign = Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new((destination, arg))), - }; + let assign = + Statement::new(terminator.source_info, StatementKind::Assign(Box::new((destination, arg)))); bb_data.statements.push(assign); bb_data.terminator = Some(Terminator { source_info: terminator.source_info, @@ -1075,11 +1073,11 @@ fn insert_switch<'tcx>( let source_info = SourceInfo::outermost(body.span); body.basic_blocks_mut().raw.insert( 0, - BasicBlockData { - statements: vec![assign], - terminator: Some(Terminator { source_info, kind: switch }), - is_cleanup: false, - }, + BasicBlockData::new_stmts( + vec![assign], + Some(Terminator { source_info, kind: switch }), + false, + ), ); for b in body.basic_blocks_mut().iter_mut() { @@ -1089,11 +1087,7 @@ fn insert_switch<'tcx>( fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock { let source_info = SourceInfo::outermost(body.span); - body.basic_blocks_mut().push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { source_info, kind }), - is_cleanup: false, - }) + body.basic_blocks_mut().push(BasicBlockData::new(Some(Terminator { source_info, kind }), false)) } fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) -> Statement<'tcx> { @@ -1109,19 +1103,16 @@ fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) -> Box::new(AggregateKind::Adt(poll_def_id, VariantIdx::from_usize(0), args, None, None)), IndexVec::from_raw(vec![val]), ); - Statement { - kind: StatementKind::Assign(Box::new((Place::return_place(), ready_val))), - source_info, - } + Statement::new(source_info, StatementKind::Assign(Box::new((Place::return_place(), ready_val)))) } fn insert_poll_ready_block<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> BasicBlock { let source_info = SourceInfo::outermost(body.span); - body.basic_blocks_mut().push(BasicBlockData { - statements: [return_poll_ready_assign(tcx, source_info)].to_vec(), - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }) + body.basic_blocks_mut().push(BasicBlockData::new_stmts( + [return_poll_ready_assign(tcx, source_info)].to_vec(), + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + )) } fn insert_panic_block<'tcx>( @@ -1205,13 +1196,11 @@ fn generate_poison_block_and_redirect_unwinds_there<'tcx>( body: &mut Body<'tcx>, ) { let source_info = SourceInfo::outermost(body.span); - let poison_block = body.basic_blocks_mut().push(BasicBlockData { - statements: vec![ - transform.set_discr(VariantIdx::new(CoroutineArgs::POISONED), source_info), - ], - terminator: Some(Terminator { source_info, kind: TerminatorKind::UnwindResume }), - is_cleanup: true, - }); + let poison_block = body.basic_blocks_mut().push(BasicBlockData::new_stmts( + vec![transform.set_discr(VariantIdx::new(CoroutineArgs::POISONED), source_info)], + Some(Terminator { source_info, kind: TerminatorKind::UnwindResume }), + true, + )); for (idx, block) in body.basic_blocks_mut().iter_enumerated_mut() { let source_info = block.terminator().source_info; @@ -1345,32 +1334,28 @@ fn create_cases<'tcx>( && !transform.remap.contains(l) && !transform.always_live_locals.contains(l); if needs_storage_live { - statements - .push(Statement { source_info, kind: StatementKind::StorageLive(l) }); + statements.push(Statement::new(source_info, StatementKind::StorageLive(l))); } } if operation == Operation::Resume { // Move the resume argument to the destination place of the `Yield` terminator let resume_arg = CTX_ARG; - statements.push(Statement { + statements.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( point.resume_arg, Rvalue::Use(Operand::Move(resume_arg.into())), ))), - }); + )); } // Then jump to the real target - let block = body.basic_blocks_mut().push(BasicBlockData { + let block = body.basic_blocks_mut().push(BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { - source_info, - kind: TerminatorKind::Goto { target }, - }), - is_cleanup: false, - }); + Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), + false, + )); (point.state, block) }) @@ -1540,13 +1525,13 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { let stmts = &mut body.basic_blocks_mut()[START_BLOCK].statements; stmts.insert( 0, - Statement { + Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( old_resume_local.into(), Rvalue::Use(Operand::Move(resume_local.into())), ))), - }, + ), ); let always_live_locals = always_storage_live_locals(body); diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index dc68629ec0d..406575c4f43 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -87,12 +87,11 @@ fn build_pin_fut<'tcx>( const_: Const::zero_sized(pin_fut_new_unchecked_fn), })); - let storage_live = - Statement { source_info, kind: StatementKind::StorageLive(fut_pin_place.local) }; + let storage_live = Statement::new(source_info, StatementKind::StorageLive(fut_pin_place.local)); - let fut_ref_assign = Statement { + let fut_ref_assign = Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( fut_ref_place, Rvalue::Ref( tcx.lifetimes.re_erased, @@ -100,12 +99,12 @@ fn build_pin_fut<'tcx>( fut_place, ), ))), - }; + ); // call Pin<FutTy>::new_unchecked(&mut fut) - let pin_fut_bb = body.basic_blocks_mut().push(BasicBlockData { - statements: [storage_live, fut_ref_assign].to_vec(), - terminator: Some(Terminator { + let pin_fut_bb = body.basic_blocks_mut().push(BasicBlockData::new_stmts( + [storage_live, fut_ref_assign].to_vec(), + Some(Terminator { source_info, kind: TerminatorKind::Call { func: pin_fut_new_unchecked_fn, @@ -117,8 +116,8 @@ fn build_pin_fut<'tcx>( fn_span: span, }, }), - is_cleanup: false, - }); + false, + )); (pin_fut_bb, fut_pin_place) } @@ -156,19 +155,15 @@ fn build_poll_switch<'tcx>( let source_info = SourceInfo::outermost(body.span); let poll_discr_place = Place::from(body.local_decls.push(LocalDecl::new(poll_discr_ty, source_info.span))); - let discr_assign = Statement { + let discr_assign = Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( - poll_discr_place, - Rvalue::Discriminant(*poll_unit_place), - ))), - }; - let storage_dead = - Statement { source_info, kind: StatementKind::StorageDead(fut_pin_place.local) }; + StatementKind::Assign(Box::new((poll_discr_place, Rvalue::Discriminant(*poll_unit_place)))), + ); + let storage_dead = Statement::new(source_info, StatementKind::StorageDead(fut_pin_place.local)); let unreachable_block = insert_term_block(body, TerminatorKind::Unreachable); - body.basic_blocks_mut().push(BasicBlockData { - statements: [storage_dead, discr_assign].to_vec(), - terminator: Some(Terminator { + body.basic_blocks_mut().push(BasicBlockData::new_stmts( + [storage_dead, discr_assign].to_vec(), + Some(Terminator { source_info, kind: TerminatorKind::SwitchInt { discr: Operand::Move(poll_discr_place), @@ -179,8 +174,8 @@ fn build_poll_switch<'tcx>( ), }, }), - is_cleanup: false, - }) + false, + )) } // Gather blocks, reachable through 'drop' targets of Yield and Drop terminators (chained) @@ -330,10 +325,10 @@ pub(super) fn expand_async_drops<'tcx>( let context_ref_place = Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span))); let arg = Rvalue::Use(Operand::Move(Place::from(CTX_ARG))); - body[bb].statements.push(Statement { + body[bb].statements.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new((context_ref_place, arg))), - }); + StatementKind::Assign(Box::new((context_ref_place, arg))), + )); let yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield let (pin_bb, fut_pin_place) = build_pin_fut(tcx, body, fut_place.clone(), UnwindAction::Continue); @@ -551,11 +546,8 @@ pub(super) fn insert_clean_drop<'tcx>( }; // Create a block to destroy an unresumed coroutines. This can only destroy upvars. - body.basic_blocks_mut().push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { source_info, kind: term }), - is_cleanup: false, - }) + body.basic_blocks_mut() + .push(BasicBlockData::new(Some(Terminator { source_info, kind: term }), false)) } pub(super) fn create_coroutine_drop_shim<'tcx>( @@ -734,11 +726,7 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>( body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info); // call coroutine_drop() - let call_bb = body.basic_blocks_mut().push(BasicBlockData { - statements: Vec::new(), - terminator: None, - is_cleanup: false, - }); + let call_bb = body.basic_blocks_mut().push(BasicBlockData::new(None, false)); // return Poll::Ready() let ret_bb = insert_poll_ready_block(tcx, &mut body); diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 702c62eddc7..f253d1662ca 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -259,7 +259,7 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb debug!(" injecting statement {counter_kind:?} for {bb:?}"); let data = &mut mir_body[bb]; let source_info = data.terminator().source_info; - let statement = Statement { source_info, kind: StatementKind::Coverage(counter_kind) }; + let statement = Statement::new(source_info, StatementKind::Coverage(counter_kind)); data.statements.insert(0, statement); } diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 3c0053c610d..b0fc5e90f07 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -68,14 +68,13 @@ impl<'tcx> MockBlocks<'tcx> { BytePos(1) }; let next_hi = next_lo + BytePos(1); - self.blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + self.blocks.push(BasicBlockData::new( + Some(Terminator { source_info: SourceInfo::outermost(Span::with_root_ctxt(next_lo, next_hi)), kind, }), - is_cleanup: false, - }) + false, + )) } fn link(&mut self, from_block: BasicBlock, to_block: BasicBlock) { diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs index d0b313e149a..fb17cca30f4 100644 --- a/compiler/rustc_mir_transform/src/ctfe_limit.rs +++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs @@ -55,8 +55,8 @@ fn has_back_edge( } fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) { - basic_block_data.statements.push(Statement { - source_info: basic_block_data.terminator().source_info, - kind: StatementKind::ConstEvalCounter, - }); + basic_block_data.statements.push(Statement::new( + basic_block_data.terminator().source_info, + StatementKind::ConstEvalCounter, + )); } diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index c9bc52c6c7e..de96b1f255a 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -222,15 +222,14 @@ where let span = self.source_info.span; let pin_obj_bb = bb.unwrap_or_else(|| { - self.elaborator.patch().new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + self.elaborator.patch().new_block(BasicBlockData::new( + Some(Terminator { // Temporary terminator, will be replaced by patch source_info: self.source_info, kind: TerminatorKind::Return, }), - is_cleanup: false, - }) + false, + )) }); let (fut_ty, drop_fn_def_id, trait_args) = if call_destructor_only { @@ -366,10 +365,8 @@ where call_statements.push(self.assign(obj_ptr_place, addr)); obj_ptr_place }; - call_statements.push(Statement { - source_info: self.source_info, - kind: StatementKind::StorageLive(fut.local), - }); + call_statements + .push(Statement::new(self.source_info, StatementKind::StorageLive(fut.local))); let call_drop_bb = self.new_block_with_statements( unwind, @@ -732,17 +729,17 @@ where let do_drop_bb = self.drop_subpath(interior, interior_path, succ, unwind, dropline); - let setup_bbd = BasicBlockData { - statements: vec![self.assign( + let setup_bbd = BasicBlockData::new_stmts( + vec![self.assign( Place::from(ptr_local), Rvalue::Cast(CastKind::Transmute, Operand::Copy(nonnull_place), ptr_ty), )], - terminator: Some(Terminator { + Some(Terminator { kind: TerminatorKind::Goto { target: do_drop_bb }, source_info: self.source_info, }), - is_cleanup: unwind.is_cleanup(), - }; + unwind.is_cleanup(), + ); self.elaborator.patch().new_block(setup_bbd) } @@ -753,14 +750,13 @@ where args: GenericArgsRef<'tcx>, ) -> BasicBlock { if adt.variants().is_empty() { - return self.elaborator.patch().new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + return self.elaborator.patch().new_block(BasicBlockData::new( + Some(Terminator { source_info: self.source_info, kind: TerminatorKind::Unreachable, }), - is_cleanup: self.unwind.is_cleanup(), - }); + self.unwind.is_cleanup(), + )); } let skip_contents = adt.is_union() || adt.is_manually_drop(); @@ -927,9 +923,9 @@ where let discr_ty = adt.repr().discr_type().to_ty(self.tcx()); let discr = Place::from(self.new_temp(discr_ty)); let discr_rv = Rvalue::Discriminant(self.place); - let switch_block = BasicBlockData { - statements: vec![self.assign(discr, discr_rv)], - terminator: Some(Terminator { + let switch_block = BasicBlockData::new_stmts( + vec![self.assign(discr, discr_rv)], + Some(Terminator { source_info: self.source_info, kind: TerminatorKind::SwitchInt { discr: Operand::Move(discr), @@ -939,8 +935,8 @@ where ), }, }), - is_cleanup: unwind.is_cleanup(), - }; + unwind.is_cleanup(), + ); let switch_block = self.elaborator.patch().new_block(switch_block); self.drop_flag_test_block(switch_block, succ, unwind) } @@ -956,8 +952,8 @@ where let ref_place = self.new_temp(ref_ty); let unit_temp = Place::from(self.new_temp(tcx.types.unit)); - let result = BasicBlockData { - statements: vec![self.assign( + let result = BasicBlockData::new_stmts( + vec![self.assign( Place::from(ref_place), Rvalue::Ref( tcx.lifetimes.re_erased, @@ -965,7 +961,7 @@ where self.place, ), )], - terminator: Some(Terminator { + Some(Terminator { kind: TerminatorKind::Call { func: Operand::function_handle( tcx, @@ -983,8 +979,8 @@ where }, source_info: self.source_info, }), - is_cleanup: unwind.is_cleanup(), - }; + unwind.is_cleanup(), + ); let destructor_block = self.elaborator.patch().new_block(result); @@ -1047,8 +1043,8 @@ where let can_go = Place::from(self.new_temp(tcx.types.bool)); let one = self.constant_usize(1); - let drop_block = BasicBlockData { - statements: vec![ + let drop_block = BasicBlockData::new_stmts( + vec![ self.assign( ptr, Rvalue::RawPtr(RawPtrKind::Mut, tcx.mk_place_index(self.place, cur)), @@ -1058,26 +1054,26 @@ where Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))), ), ], - is_cleanup: unwind.is_cleanup(), - terminator: Some(Terminator { + Some(Terminator { source_info: self.source_info, // this gets overwritten by drop elaboration. kind: TerminatorKind::Unreachable, }), - }; + unwind.is_cleanup(), + ); let drop_block = self.elaborator.patch().new_block(drop_block); - let loop_block = BasicBlockData { - statements: vec![self.assign( + let loop_block = BasicBlockData::new_stmts( + vec![self.assign( can_go, Rvalue::BinaryOp(BinOp::Eq, Box::new((copy(Place::from(cur)), copy(len.into())))), )], - is_cleanup: unwind.is_cleanup(), - terminator: Some(Terminator { + Some(Terminator { source_info: self.source_info, kind: TerminatorKind::if_(move_(can_go), succ, drop_block), }), - }; + unwind.is_cleanup(), + ); let loop_block = self.elaborator.patch().new_block(loop_block); let place = tcx.mk_place_deref(ptr); @@ -1187,8 +1183,8 @@ where let slice_ptr_ty = Ty::new_mut_ptr(tcx, slice_ty); let slice_ptr = self.new_temp(slice_ptr_ty); - let mut delegate_block = BasicBlockData { - statements: vec![ + let mut delegate_block = BasicBlockData::new_stmts( + vec![ self.assign(Place::from(array_ptr), Rvalue::RawPtr(RawPtrKind::Mut, self.place)), self.assign( Place::from(slice_ptr), @@ -1202,9 +1198,9 @@ where ), ), ], - is_cleanup: self.unwind.is_cleanup(), - terminator: None, - }; + None, + self.unwind.is_cleanup(), + ); let array_place = mem::replace( &mut self.place, @@ -1246,8 +1242,8 @@ where }; let zero = self.constant_usize(0); - let block = BasicBlockData { - statements: vec![ + let block = BasicBlockData::new_stmts( + vec![ self.assign( len.into(), Rvalue::UnaryOp( @@ -1257,12 +1253,12 @@ where ), self.assign(cur.into(), Rvalue::Use(zero)), ], - is_cleanup: unwind.is_cleanup(), - terminator: Some(Terminator { + Some(Terminator { source_info: self.source_info, kind: TerminatorKind::Goto { target: loop_block }, }), - }; + unwind.is_cleanup(), + ); let drop_block = self.elaborator.patch().new_block(block); // FIXME(#34708): handle partially-dropped array/slice elements. @@ -1308,14 +1304,13 @@ where self.source_info.span, "open drop for unsafe binder shouldn't be encountered", ); - self.elaborator.patch().new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + self.elaborator.patch().new_block(BasicBlockData::new( + Some(Terminator { source_info: self.source_info, kind: TerminatorKind::Unreachable, }), - is_cleanup: self.unwind.is_cleanup(), - }) + self.unwind.is_cleanup(), + )) } _ => span_bug!(self.source_info.span, "open drop from non-ADT `{:?}`", ty), @@ -1434,11 +1429,10 @@ where } fn new_block(&mut self, unwind: Unwind, k: TerminatorKind<'tcx>) -> BasicBlock { - self.elaborator.patch().new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { source_info: self.source_info, kind: k }), - is_cleanup: unwind.is_cleanup(), - }) + self.elaborator.patch().new_block(BasicBlockData::new( + Some(Terminator { source_info: self.source_info, kind: k }), + unwind.is_cleanup(), + )) } fn new_block_with_statements( @@ -1447,11 +1441,11 @@ where statements: Vec<Statement<'tcx>>, k: TerminatorKind<'tcx>, ) -> BasicBlock { - self.elaborator.patch().new_block(BasicBlockData { + self.elaborator.patch().new_block(BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { source_info: self.source_info, kind: k }), - is_cleanup: unwind.is_cleanup(), - }) + Some(Terminator { source_info: self.source_info, kind: k }), + unwind.is_cleanup(), + )) } fn new_temp(&mut self, ty: Ty<'tcx>) -> Local { @@ -1467,9 +1461,6 @@ where } fn assign(&self, lhs: Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> { - Statement { - source_info: self.source_info, - kind: StatementKind::Assign(Box::new((lhs, rhs))), - } + Statement::new(self.source_info, StatementKind::Assign(Box::new((lhs, rhs)))) } } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index b17b7f45000..335354c23b6 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1636,7 +1636,7 @@ fn op_to_prop_const<'tcx>( } let pointer = mplace.ptr().into_pointer_or_addr().ok()?; - let (prov, offset) = pointer.into_parts(); + let (prov, offset) = pointer.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); intern_const_alloc_for_constprop(ecx, alloc_id).discard_err()?; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index c27087fea11..7852bb7ae2f 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -900,10 +900,10 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( ); let dest_ty = dest.ty(caller_body, tcx); let temp = Place::from(new_call_temp(caller_body, callsite, dest_ty, return_block)); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::Assign(Box::new((temp, dest))), - }); + caller_body[callsite.block].statements.push(Statement::new( + callsite.source_info, + StatementKind::Assign(Box::new((temp, dest))), + )); tcx.mk_place_deref(temp) } else { destination @@ -947,10 +947,9 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( for local in callee_body.vars_and_temps_iter() { if integrator.always_live_locals.contains(local) { let new_local = integrator.map_local(local); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageLive(new_local), - }); + caller_body[callsite.block] + .statements + .push(Statement::new(callsite.source_info, StatementKind::StorageLive(new_local))); } } if let Some(block) = return_block { @@ -958,22 +957,22 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( // the slice once. let mut n = 0; if remap_destination { - caller_body[block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::Assign(Box::new(( + caller_body[block].statements.push(Statement::new( + callsite.source_info, + StatementKind::Assign(Box::new(( dest, Rvalue::Use(Operand::Move(destination_local.into())), ))), - }); + )); n += 1; } for local in callee_body.vars_and_temps_iter().rev() { if integrator.always_live_locals.contains(local) { let new_local = integrator.map_local(local); - caller_body[block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageDead(new_local), - }); + caller_body[block].statements.push(Statement::new( + callsite.source_info, + StatementKind::StorageDead(new_local), + )); n += 1; } } @@ -1126,10 +1125,10 @@ fn create_temp_if_necessary<'tcx, I: Inliner<'tcx>>( trace!("creating temp for argument {:?}", arg); let arg_ty = arg.ty(caller_body, inliner.tcx()); let local = new_call_temp(caller_body, callsite, arg_ty, return_block); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))), - }); + caller_body[callsite.block].statements.push(Statement::new( + callsite.source_info, + StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))), + )); local } @@ -1142,19 +1141,14 @@ fn new_call_temp<'tcx>( ) -> Local { let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span)); - caller_body[callsite.block].statements.push(Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageLive(local), - }); + caller_body[callsite.block] + .statements + .push(Statement::new(callsite.source_info, StatementKind::StorageLive(local))); if let Some(block) = return_block { - caller_body[block].statements.insert( - 0, - Statement { - source_info: callsite.source_info, - kind: StatementKind::StorageDead(local), - }, - ); + caller_body[block] + .statements + .insert(0, Statement::new(callsite.source_info, StatementKind::StorageDead(local))); } local diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 5f0c55ddc09..dbcaed20953 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -240,15 +240,15 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { let Some(arg_place) = arg.node.place() else { return }; - statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::Use(Operand::Copy( arg_place.project_deeper(&[ProjectionElem::Deref], self.tcx), )), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target: *destination_block }; } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index c4415294264..08f25276cec 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -259,13 +259,13 @@ fn remap_mir_for_const_eval_select<'tcx>( // (const generic stuff) so we just create a temporary and deconstruct // that. let local = body.local_decls.push(LocalDecl::new(ty, fn_span)); - bb.statements.push(Statement { - source_info: SourceInfo::outermost(fn_span), - kind: StatementKind::Assign(Box::new(( + bb.statements.push(Statement::new( + SourceInfo::outermost(fn_span), + StatementKind::Assign(Box::new(( local.into(), Rvalue::Use(tupled_args.node.clone()), ))), - }); + )); (Operand::Move, local.into()) } Operand::Move(place) => (Operand::Move, place), diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index fa29ab985b7..8dadce0d448 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -25,31 +25,31 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { } sym::ub_checks => { let target = target.unwrap(); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::NullaryOp(NullOp::UbChecks, tcx.types.bool), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::contract_checks => { let target = target.unwrap(); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::NullaryOp(NullOp::ContractChecks, tcx.types.bool), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::forget => { let target = target.unwrap(); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: terminator.source_info.span, @@ -57,7 +57,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { const_: Const::zero_sized(tcx.types.unit), }))), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::copy_nonoverlapping => { @@ -65,9 +65,9 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { let Ok([src, dst, count]) = take_array(args) else { bug!("Wrong arguments for copy_non_overlapping intrinsic"); }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Intrinsic(Box::new( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Intrinsic(Box::new( NonDivergingIntrinsic::CopyNonOverlapping( rustc_middle::mir::CopyNonOverlapping { src: src.node, @@ -76,7 +76,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { }, ), )), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::assume => { @@ -84,12 +84,12 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { let Ok([arg]) = take_array(args) else { bug!("Wrong arguments for assume intrinsic"); }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Intrinsic(Box::new( - NonDivergingIntrinsic::Assume(arg.node), - )), - }); + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume( + arg.node, + ))), + )); terminator.kind = TerminatorKind::Goto { target }; } sym::wrapping_add @@ -121,13 +121,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { sym::unchecked_shr => BinOp::ShrUnchecked, _ => bug!("unexpected intrinsic"), }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { @@ -141,13 +141,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { sym::mul_with_overflow => BinOp::MulWithOverflow, _ => bug!("unexpected intrinsic"), }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::size_of | sym::align_of => { @@ -158,13 +158,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { sym::align_of => NullOp::AlignOf, _ => bug!("unexpected intrinsic"), }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::NullaryOp(null_op, tp_ty), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::read_via_copy => { @@ -183,13 +183,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { }; // Add new statement at the end of the block that does the read, and patch // up the terminator. - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::Use(Operand::Copy(derefed_place)), ))), - }); + )); terminator.kind = match *target { None => { // No target means this read something uninhabited, @@ -217,13 +217,10 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { "Only passing a local is supported" ); }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( - derefed_place, - Rvalue::Use(val.node), - ))), - }); + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new((derefed_place, Rvalue::Use(val.node)))), + )); terminator.kind = TerminatorKind::Goto { target }; } sym::discriminant_value => { @@ -236,13 +233,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { }; let arg = arg.node.place().unwrap(); let arg = tcx.mk_place_deref(arg); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::Discriminant(arg), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::offset => { @@ -253,13 +250,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { "Wrong number of arguments for offset intrinsic", ); }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr.node, delta.node))), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::slice_get_unchecked => { @@ -302,10 +299,10 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { _ => bug!("Unknown return type {ret_ty:?}"), }; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new((*destination, rvalue))), - }); + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new((*destination, rvalue))), + )); terminator.kind = TerminatorKind::Goto { target }; } sym::transmute | sym::transmute_unchecked => { @@ -320,13 +317,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { // Always emit the cast, even if we transmute to an uninhabited type, // because that lets CTFE and codegen generate better error messages // when such a transmute actually ends up reachable. - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::Cast(CastKind::Transmute, arg.node, dst_ty), ))), - }); + )); if let Some(target) = *target { terminator.kind = TerminatorKind::Goto { target }; } else { @@ -351,13 +348,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { ); }; let fields = [data.node, meta.node]; - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::Aggregate(Box::new(kind), fields.into()), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } sym::ptr_metadata => { @@ -368,13 +365,13 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { ); }; let target = target.unwrap(); - block.statements.push(Statement { - source_info: terminator.source_info, - kind: StatementKind::Assign(Box::new(( + block.statements.push(Statement::new( + terminator.source_info, + StatementKind::Assign(Box::new(( *destination, Rvalue::UnaryOp(UnOp::PtrMetadata, ptr.node), ))), - }); + )); terminator.kind = TerminatorKind::Goto { target }; } _ => {} diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index aca80e36e33..79a9017de3e 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -56,8 +56,7 @@ fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_ite // make new RValue for Len let r_value = Rvalue::UnaryOp(UnOp::PtrMetadata, arg.node.clone()); let len_statement_kind = StatementKind::Assign(Box::new((*destination, r_value))); - let add_statement = - Statement { kind: len_statement_kind, source_info: terminator.source_info }; + let add_statement = Statement::new(terminator.source_info, len_statement_kind); // modify terminator into simple Goto let new_terminator_kind = TerminatorKind::Goto { target: *bb }; diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs index a872eae15f1..c781d1a5324 100644 --- a/compiler/rustc_mir_transform/src/patch.rs +++ b/compiler/rustc_mir_transform/src/patch.rs @@ -78,14 +78,13 @@ impl<'tcx> MirPatch<'tcx> { return bb; } - let bb = self.new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + let bb = self.new_block(BasicBlockData::new( + Some(Terminator { source_info: SourceInfo::outermost(self.body_span), kind: TerminatorKind::UnwindResume, }), - is_cleanup: true, - }); + true, + )); self.resume_block = Some(bb); bb } @@ -95,14 +94,13 @@ impl<'tcx> MirPatch<'tcx> { return bb; } - let bb = self.new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + let bb = self.new_block(BasicBlockData::new( + Some(Terminator { source_info: SourceInfo::outermost(self.body_span), kind: TerminatorKind::Unreachable, }), - is_cleanup: true, - }); + true, + )); self.unreachable_cleanup_block = Some(bb); bb } @@ -112,14 +110,13 @@ impl<'tcx> MirPatch<'tcx> { return bb; } - let bb = self.new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + let bb = self.new_block(BasicBlockData::new( + Some(Terminator { source_info: SourceInfo::outermost(self.body_span), kind: TerminatorKind::Unreachable, }), - is_cleanup: false, - }); + false, + )); self.unreachable_no_cleanup_block = Some(bb); bb } @@ -131,14 +128,13 @@ impl<'tcx> MirPatch<'tcx> { return cached_bb; } - let bb = self.new_block(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + let bb = self.new_block(BasicBlockData::new( + Some(Terminator { source_info: SourceInfo::outermost(self.body_span), kind: TerminatorKind::UnwindTerminate(reason), }), - is_cleanup: true, - }); + true, + )); self.terminate_block = Some((bb, reason)); bb } @@ -280,7 +276,7 @@ impl<'tcx> MirPatch<'tcx> { let source_info = Self::source_info_for_index(&body[loc.block], loc); body[loc.block] .statements - .insert(loc.statement_index, Statement { source_info, kind: stmt }); + .insert(loc.statement_index, Statement::new(source_info, stmt)); delta += 1; } } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 47d43830970..4e8f30e077b 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -731,23 +731,22 @@ struct Promoter<'a, 'tcx> { impl<'a, 'tcx> Promoter<'a, 'tcx> { fn new_block(&mut self) -> BasicBlock { let span = self.promoted.span; - self.promoted.basic_blocks_mut().push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + self.promoted.basic_blocks_mut().push(BasicBlockData::new( + Some(Terminator { source_info: SourceInfo::outermost(span), kind: TerminatorKind::Return, }), - is_cleanup: false, - }) + false, + )) } fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) { let last = self.promoted.basic_blocks.last_index().unwrap(); let data = &mut self.promoted[last]; - data.statements.push(Statement { - source_info: SourceInfo::outermost(span), - kind: StatementKind::Assign(Box::new((Place::from(dest), rvalue))), - }); + data.statements.push(Statement::new( + SourceInfo::outermost(span), + StatementKind::Assign(Box::new((Place::from(dest), rvalue))), + )); } fn is_temp_kind(&self, local: Local) -> bool { @@ -914,13 +913,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref); let promoted_operand = promoted_operand(ref_ty, span); - let promoted_ref_statement = Statement { - source_info: statement.source_info, - kind: StatementKind::Assign(Box::new(( + let promoted_ref_statement = Statement::new( + statement.source_info, + StatementKind::Assign(Box::new(( Place::from(promoted_ref), Rvalue::Use(Operand::Constant(Box::new(promoted_operand))), ))), - }; + ); self.extra_statements.push((loc, promoted_ref_statement)); ( diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 6d45bbc6e16..4083038cbb6 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -323,9 +323,7 @@ fn dropee_emit_retag<'tcx>( StatementKind::Retag(RetagKind::FnEntry, Box::new(dropee_ptr)), ]; for s in new_statements { - body.basic_blocks_mut()[START_BLOCK] - .statements - .push(Statement { source_info, kind: s }); + body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, s)); } } dropee_ptr @@ -350,11 +348,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) let return_block = BasicBlock::new(1); let mut blocks = IndexVec::with_capacity(2); let block = |blocks: &mut IndexVec<_, _>, kind| { - blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { source_info, kind }), - is_cleanup: false, - }) + blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false)) }; block(&mut blocks, TerminatorKind::Goto { target: return_block }); block(&mut blocks, TerminatorKind::Return); @@ -515,17 +509,17 @@ fn build_thread_local_shim<'tcx>( let span = tcx.def_span(def_id); let source_info = SourceInfo::outermost(span); - let blocks = IndexVec::from_raw(vec![BasicBlockData { - statements: vec![Statement { + let blocks = IndexVec::from_raw(vec![BasicBlockData::new_stmts( + vec![Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( Place::return_place(), Rvalue::ThreadLocalRef(def_id), ))), - }], - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }]); + )], + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + )]); new_body( MirSource::from_instance(instance), @@ -609,11 +603,11 @@ impl<'tcx> CloneShimBuilder<'tcx> { is_cleanup: bool, ) -> BasicBlock { let source_info = self.source_info(); - self.blocks.push(BasicBlockData { + self.blocks.push(BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { source_info, kind }), + Some(Terminator { source_info, kind }), is_cleanup, - }) + )) } /// Gives the index of an upcoming BasicBlock, with an offset. @@ -625,7 +619,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { } fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> { - Statement { source_info: self.source_info(), kind } + Statement::new(self.source_info(), kind) } fn copy_shim(&mut self) { @@ -901,13 +895,13 @@ fn build_call_shim<'tcx>( .immutable(), ); let borrow_kind = BorrowKind::Mut { kind: MutBorrowKind::Default }; - statements.push(Statement { + statements.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( Place::from(ref_rcvr), Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()), ))), - }); + )); Operand::Move(Place::from(ref_rcvr)) } }); @@ -956,11 +950,11 @@ fn build_call_shim<'tcx>( let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 }; let mut blocks = IndexVec::with_capacity(n_blocks); let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| { - blocks.push(BasicBlockData { + blocks.push(BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { source_info, kind }), + Some(Terminator { source_info, kind }), is_cleanup, - }) + )) }; // BB #0 @@ -1071,8 +1065,9 @@ pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { let kind = AggregateKind::Adt(adt_def.did(), variant_index, args, None, None); let variant = adt_def.variant(variant_index); - let statement = Statement { - kind: StatementKind::Assign(Box::new(( + let statement = Statement::new( + source_info, + StatementKind::Assign(Box::new(( Place::return_place(), Rvalue::Aggregate( Box::new(kind), @@ -1081,14 +1076,13 @@ pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { .collect(), ), ))), - source_info, - }; + ); - let start_block = BasicBlockData { - statements: vec![statement], - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }; + let start_block = BasicBlockData::new_stmts( + vec![statement], + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + ); let source = MirSource::item(ctor_id); let mut body = new_body( @@ -1130,16 +1124,16 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t Operand::Move(Place::from(Local::new(1))), Ty::new_imm_ptr(tcx, tcx.types.unit), ); - let stmt = Statement { + let stmt = Statement::new( source_info, - kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))), - }; + StatementKind::Assign(Box::new((Place::return_place(), rvalue))), + ); let statements = vec![stmt]; - let start_block = BasicBlockData { + let start_block = BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }; + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + ); let source = MirSource::from_instance(ty::InstanceKind::FnPtrAddrShim(def_id, self_ty)); new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span) } @@ -1230,16 +1224,16 @@ fn build_construct_coroutine_by_move_shim<'tcx>( Box::new(AggregateKind::Coroutine(coroutine_def_id, coroutine_args)), IndexVec::from_raw(fields), ); - let stmt = Statement { + let stmt = Statement::new( source_info, - kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))), - }; + StatementKind::Assign(Box::new((Place::return_place(), rvalue))), + ); let statements = vec![stmt]; - let start_block = BasicBlockData { + let start_block = BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }; + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + ); let source = MirSource::from_instance(ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id, diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index fd7b7362cd9..18d09473c19 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -88,11 +88,7 @@ pub(super) fn build_async_drop_shim<'tcx>( let return_block = BasicBlock::new(1); let mut blocks = IndexVec::with_capacity(2); let block = |blocks: &mut IndexVec<_, _>, kind| { - blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { source_info, kind }), - is_cleanup: false, - }) + blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false)) }; block( &mut blocks, @@ -133,7 +129,7 @@ pub(super) fn build_async_drop_shim<'tcx>( dropee_ptr, Rvalue::Use(Operand::Move(coroutine_layout_dropee)), ))); - body.basic_blocks_mut()[START_BLOCK].statements.push(Statement { source_info, kind: st_kind }); + body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, st_kind)); dropee_ptr = dropee_emit_retag(tcx, &mut body, dropee_ptr, span); let dropline = body.basic_blocks.last_index(); @@ -240,13 +236,13 @@ fn build_adrop_for_coroutine_shim<'tcx>( .project_deeper(&[PlaceElem::Field(FieldIdx::ZERO, proxy_ref)], tcx); body.basic_blocks_mut()[START_BLOCK].statements.insert( idx, - Statement { + Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( Place::from(proxy_ref_local), Rvalue::CopyForDeref(proxy_ref_place), ))), - }, + ), ); idx += 1; let mut cor_ptr_local = proxy_ref_local; @@ -261,13 +257,13 @@ fn build_adrop_for_coroutine_shim<'tcx>( // _cor_ptr = _proxy.0.0 (... .0) body.basic_blocks_mut()[START_BLOCK].statements.insert( idx, - Statement { + Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( Place::from(cor_ptr_local), Rvalue::CopyForDeref(impl_ptr_place), ))), - }, + ), ); idx += 1; } @@ -281,10 +277,10 @@ fn build_adrop_for_coroutine_shim<'tcx>( ); body.basic_blocks_mut()[START_BLOCK].statements.insert( idx, - Statement { + Statement::new( source_info, - kind: StatementKind::Assign(Box::new((Place::from(cor_ref_local), reborrow))), - }, + StatementKind::Assign(Box::new((Place::from(cor_ref_local), reborrow))), + ), ); } body @@ -334,13 +330,13 @@ fn build_adrop_for_adrop_shim<'tcx>( let mut statements = Vec::new(); - statements.push(Statement { + statements.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( Place::from(proxy_ref_local), Rvalue::CopyForDeref(proxy_ref_place), ))), - }); + )); let mut cor_ptr_local = proxy_ref_local; proxy_ty.find_async_drop_impl_coroutine(tcx, |ty| { @@ -350,13 +346,13 @@ fn build_adrop_for_adrop_shim<'tcx>( .project_deeper(&[PlaceElem::Deref, PlaceElem::Field(FieldIdx::ZERO, ty_ptr)], tcx); cor_ptr_local = locals.push(LocalDecl::new(ty_ptr, span)); // _cor_ptr = _proxy.0.0 (... .0) - statements.push(Statement { + statements.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new(( + StatementKind::Assign(Box::new(( Place::from(cor_ptr_local), Rvalue::CopyForDeref(impl_ptr_place), ))), - }); + )); } }); @@ -367,10 +363,10 @@ fn build_adrop_for_adrop_shim<'tcx>( tcx.mk_place_deref(Place::from(cor_ptr_local)), ); let cor_ref_place = Place::from(locals.push(LocalDecl::new(cor_ref, span))); - statements.push(Statement { + statements.push(Statement::new( source_info, - kind: StatementKind::Assign(Box::new((cor_ref_place, reborrow))), - }); + StatementKind::Assign(Box::new((cor_ref_place, reborrow))), + )); // cor_pin_ty = `Pin<&mut cor_ref>` let cor_pin_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[cor_ref.into()])); @@ -378,9 +374,9 @@ fn build_adrop_for_adrop_shim<'tcx>( let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, span); // call Pin<FutTy>::new_unchecked(&mut impl_cor) - blocks.push(BasicBlockData { + blocks.push(BasicBlockData::new_stmts( statements, - terminator: Some(Terminator { + Some(Terminator { source_info, kind: TerminatorKind::Call { func: Operand::function_handle(tcx, pin_fn, [cor_ref.into()], span), @@ -392,15 +388,14 @@ fn build_adrop_for_adrop_shim<'tcx>( fn_span: span, }, }), - is_cleanup: false, - }); + false, + )); // When dropping async drop coroutine, we continue its execution: // we call impl::poll (impl_layout, ctx) let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, span); let resume_ctx = Place::from(Local::new(2)); - blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { + blocks.push(BasicBlockData::new( + Some(Terminator { source_info, kind: TerminatorKind::Call { func: Operand::function_handle(tcx, poll_fn, [impl_ty.into()], span), @@ -416,13 +411,12 @@ fn build_adrop_for_adrop_shim<'tcx>( fn_span: span, }, }), - is_cleanup: false, - }); - blocks.push(BasicBlockData { - statements: vec![], - terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), - is_cleanup: false, - }); + false, + )); + blocks.push(BasicBlockData::new( + Some(Terminator { source_info, kind: TerminatorKind::Return }), + false, + )); let source = MirSource::from_instance(instance); let mut body = new_body(source, blocks, locals, sig.inputs().len(), span); diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index bd008230731..c60eb566521 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -115,10 +115,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { for bb_idx in new_targets.all_targets() { storage_deads_to_insert.push(( *bb_idx, - Statement { - source_info: terminator.source_info, - kind: StatementKind::StorageDead(opt.to_switch_on.local), - }, + Statement::new( + terminator.source_info, + StatementKind::StorageDead(opt.to_switch_on.local), + ), )); } } 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 a300558c0c9..c281ef216c7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -383,10 +383,10 @@ where let mut candidates = vec![]; - if let TypingMode::Coherence = self.typing_mode() { - if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) { - return vec![candidate]; - } + if let TypingMode::Coherence = self.typing_mode() + && let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) + { + return vec![candidate]; } self.assemble_alias_bound_candidates(goal, &mut candidates); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 5b6f9785272..73bb1508de9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -997,12 +997,12 @@ where } fn try_fold_ty(&mut self, ty: I::Ty) -> Result<I::Ty, Ambiguous> { - if let ty::Alias(ty::Projection, alias_ty) = ty.kind() { - if let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())? { - return Ok(term.expect_ty()); - } + if let ty::Alias(ty::Projection, alias_ty) = ty.kind() + && let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())? + { + Ok(term.expect_ty()) + } else { + ty.try_super_fold_with(self) } - - ty.try_super_fold_with(self) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 0547eb77f8d..42264f58bcd 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -42,20 +42,18 @@ where goal: Goal<I, Self>, assumption: I::Clause, ) -> Result<(), NoSolution> { - if let Some(host_clause) = assumption.as_host_effect_clause() { - if host_clause.def_id() == goal.predicate.def_id() - && host_clause.constness().satisfies(goal.predicate.constness) - { - if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( - goal.predicate.trait_ref.args, - host_clause.skip_binder().trait_ref.args, - ) { - return Ok(()); - } - } + if let Some(host_clause) = assumption.as_host_effect_clause() + && host_clause.def_id() == goal.predicate.def_id() + && host_clause.constness().satisfies(goal.predicate.constness) + && DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( + goal.predicate.trait_ref.args, + host_clause.skip_binder().trait_ref.args, + ) + { + Ok(()) + } else { + Err(NoSolution) } - - Err(NoSolution) } fn match_assumption( 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 dd9ccadf6cf..b42587618b5 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 @@ -429,22 +429,21 @@ where // If we have run this goal before, and it was stalled, check that any of the goal's // args have changed. Otherwise, we don't need to re-run the goal because it'll remain // stalled, since it'll canonicalize the same way and evaluation is pure. - if let Some(stalled_on) = stalled_on { - if !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value)) - && !self - .delegate - .opaque_types_storage_num_entries() - .needs_reevaluation(stalled_on.num_opaques) - { - return Ok(( - NestedNormalizationGoals::empty(), - GoalEvaluation { - certainty: Certainty::Maybe(stalled_on.stalled_cause), - has_changed: HasChanged::No, - stalled_on: Some(stalled_on), - }, - )); - } + if let Some(stalled_on) = stalled_on + && !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value)) + && !self + .delegate + .opaque_types_storage_num_entries() + .needs_reevaluation(stalled_on.num_opaques) + { + return Ok(( + NestedNormalizationGoals::empty(), + GoalEvaluation { + certainty: Certainty::Maybe(stalled_on.stalled_cause), + has_changed: HasChanged::No, + stalled_on: Some(stalled_on), + }, + )); } let (orig_values, canonical_goal) = self.canonicalize_goal(goal); @@ -833,14 +832,11 @@ where match t.kind() { ty::Infer(ty::TyVar(vid)) => { - if let ty::TermKind::Ty(term) = self.term.kind() { - if let ty::Infer(ty::TyVar(term_vid)) = term.kind() { - if self.delegate.root_ty_var(vid) - == self.delegate.root_ty_var(term_vid) - { - return ControlFlow::Break(()); - } - } + if let ty::TermKind::Ty(term) = self.term.kind() + && let ty::Infer(ty::TyVar(term_vid)) = term.kind() + && self.delegate.root_ty_var(vid) == self.delegate.root_ty_var(term_vid) + { + return ControlFlow::Break(()); } self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?; @@ -860,15 +856,12 @@ where fn visit_const(&mut self, c: I::Const) -> Self::Result { match c.kind() { ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - if let ty::TermKind::Const(term) = self.term.kind() { - if let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() - { - if self.delegate.root_const_var(vid) - == self.delegate.root_const_var(term_vid) - { - return ControlFlow::Break(()); - } - } + if let ty::TermKind::Const(term) = self.term.kind() + && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() + && self.delegate.root_const_var(vid) + == self.delegate.root_const_var(term_vid) + { + return ControlFlow::Break(()); } self.check_nameable(self.delegate.universe_of_ct(vid).unwrap()) 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 d51c87fe68e..edb354b4a84 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 @@ -112,18 +112,17 @@ where goal: Goal<I, Self>, assumption: I::Clause, ) -> Result<(), NoSolution> { - if let Some(projection_pred) = assumption.as_projection_clause() { - if projection_pred.item_def_id() == goal.predicate.def_id() { - if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( - goal.predicate.alias.args, - projection_pred.skip_binder().projection_term.args, - ) { - return Ok(()); - } - } + if let Some(projection_pred) = assumption.as_projection_clause() + && projection_pred.item_def_id() == goal.predicate.def_id() + && DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( + goal.predicate.alias.args, + projection_pred.skip_binder().projection_term.args, + ) + { + Ok(()) + } else { + Err(NoSolution) } - - Err(NoSolution) } fn match_assumption( 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 8aaa8e9ca87..6c9fb63b579 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -127,33 +127,32 @@ where goal: Goal<I, Self>, assumption: I::Clause, ) -> Result<(), NoSolution> { - if let Some(trait_clause) = assumption.as_trait_clause() { - if trait_clause.polarity() != goal.predicate.polarity { - return Err(NoSolution); - } - - if trait_clause.def_id() == goal.predicate.def_id() { - if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( - goal.predicate.trait_ref.args, - trait_clause.skip_binder().trait_ref.args, - ) { - return Ok(()); - } - } - + fn trait_def_id_matches<I: Interner>( + cx: I, + clause_def_id: I::DefId, + goal_def_id: I::DefId, + ) -> bool { + clause_def_id == goal_def_id // PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so - // check for a `Sized` subtrait when looking for `MetaSized`. `PointeeSized` bounds - // are syntactic sugar for a lack of bounds so don't need this. - if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized) - && ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized) - { - let meta_sized_clause = - trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id()); - return Self::fast_reject_assumption(ecx, goal, meta_sized_clause); - } + // check for a `MetaSized` supertrait being matched against a `Sized` assumption. + // + // `PointeeSized` bounds are syntactic sugar for a lack of bounds so don't need this. + || (cx.is_lang_item(clause_def_id, TraitSolverLangItem::Sized) + && cx.is_lang_item(goal_def_id, TraitSolverLangItem::MetaSized)) } - Err(NoSolution) + if let Some(trait_clause) = assumption.as_trait_clause() + && trait_clause.polarity() == goal.predicate.polarity + && trait_def_id_matches(ecx.cx(), trait_clause.def_id(), goal.predicate.def_id()) + && DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( + goal.predicate.trait_ref.args, + trait_clause.skip_binder().trait_ref.args, + ) + { + return Ok(()); + } else { + Err(NoSolution) + } } fn match_assumption( diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ae486a58062..34c76bd3f27 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -177,6 +177,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => { self.check_align(span, target, *align, *repr_span) } + Attribute::Parsed(AttributeKind::LinkSection { span: attr_span, .. }) => { + self.check_link_section(hir_id, *attr_span, span, target) + } Attribute::Parsed(AttributeKind::Naked(attr_span)) => { self.check_naked(hir_id, *attr_span, span, target) } @@ -286,7 +289,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target), [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target), [sym::link, ..] => self.check_link(hir_id, attr, span, target), - [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), [sym::macro_use, ..] | [sym::macro_escape, ..] => { self.check_macro_use(hir_id, attr, target) } @@ -1831,7 +1833,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[link_section]` is applied to a function or static. - fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_link_section(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { match target { Target::Static | Target::Fn | Target::Method(..) => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1839,7 +1841,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_section"); + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_section"); } _ => { // FIXME: #[link_section] was previously allowed on non-functions/statics and some @@ -1847,7 +1849,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::LinkSection { span }, ); } diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 177bad96595..7ffcf7b5d96 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -320,10 +320,10 @@ pub fn supertrait_def_ids<I: Interner>( let trait_def_id = stack.pop()?; for (predicate, _) in cx.explicit_super_predicates_of(trait_def_id).iter_identity() { - if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() { - if set.insert(data.def_id()) { - stack.push(data.def_id()); - } + if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() + && set.insert(data.def_id()) + { + stack.push(data.def_id()); } } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 2bc12d0a23b..8ba9e7105d6 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -117,12 +117,20 @@ impl<I: Interner> TypingMode<I> { } pub fn borrowck(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> { - TypingMode::Borrowck { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) } + let defining_opaque_types = cx.opaque_types_defined_by(body_def_id); + if defining_opaque_types.is_empty() { + TypingMode::non_body_analysis() + } else { + TypingMode::Borrowck { defining_opaque_types } + } } pub fn post_borrowck_analysis(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> { - TypingMode::PostBorrowckAnalysis { - defined_opaque_types: cx.opaque_types_defined_by(body_def_id), + let defined_opaque_types = cx.opaque_types_defined_by(body_def_id); + if defined_opaque_types.is_empty() { + TypingMode::non_body_analysis() + } else { + TypingMode::PostBorrowckAnalysis { defined_opaque_types } } } } diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index e42639c6807..79f6bc5dabb 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -284,12 +284,12 @@ where } // If they have no bound vars, relate normally. - if let Some(a_inner) = a.no_bound_vars() { - if let Some(b_inner) = b.no_bound_vars() { - self.relate(a_inner, b_inner)?; - return Ok(a); - } - }; + if let Some(a_inner) = a.no_bound_vars() + && let Some(b_inner) = b.no_bound_vars() + { + self.relate(a_inner, b_inner)?; + return Ok(a); + } match self.ambient_variance { // Checks whether `for<..> sub <: for<..> sup` holds. diff --git a/compiler/rustc_type_ir/src/search_graph/global_cache.rs b/compiler/rustc_type_ir/src/search_graph/global_cache.rs index 1b99cc820f1..eb56c1af408 100644 --- a/compiler/rustc_type_ir/src/search_graph/global_cache.rs +++ b/compiler/rustc_type_ir/src/search_graph/global_cache.rs @@ -80,31 +80,29 @@ impl<X: Cx> GlobalCache<X> { mut candidate_is_applicable: impl FnMut(&NestedGoals<X>) -> bool, ) -> Option<CacheData<'a, X>> { let entry = self.map.get(&input)?; - if let Some(Success { required_depth, ref nested_goals, ref result }) = entry.success { - if available_depth.cache_entry_is_applicable(required_depth) - && candidate_is_applicable(nested_goals) - { - return Some(CacheData { - result: cx.get_tracked(&result), - required_depth, - encountered_overflow: false, - nested_goals, - }); - } + if let Some(Success { required_depth, ref nested_goals, ref result }) = entry.success + && available_depth.cache_entry_is_applicable(required_depth) + && candidate_is_applicable(nested_goals) + { + return Some(CacheData { + result: cx.get_tracked(&result), + required_depth, + encountered_overflow: false, + nested_goals, + }); } let additional_depth = available_depth.0; if let Some(WithOverflow { nested_goals, result }) = entry.with_overflow.get(&additional_depth) + && candidate_is_applicable(nested_goals) { - if candidate_is_applicable(nested_goals) { - return Some(CacheData { - result: cx.get_tracked(result), - required_depth: additional_depth, - encountered_overflow: true, - nested_goals, - }); - } + return Some(CacheData { + result: cx.get_tracked(result), + required_depth: additional_depth, + encountered_overflow: true, + nested_goals, + }); } None diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 7aa3f3c6d74..01dce114592 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -742,7 +742,7 @@ impl TypeId { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] pub const fn of<T: ?Sized + 'static>() -> TypeId { - let t: u128 = intrinsics::type_id::<T>(); + let t: u128 = const { intrinsics::type_id::<T>() }; let t1 = (t >> 64) as u64; let t2 = t as u64; @@ -824,7 +824,7 @@ impl fmt::Debug for TypeId { #[stable(feature = "type_name", since = "1.38.0")] #[rustc_const_unstable(feature = "const_type_name", issue = "63084")] pub const fn type_name<T: ?Sized>() -> &'static str { - intrinsics::type_name::<T>() + const { intrinsics::type_name::<T>() } } /// Returns the type name of the pointed-to value as a string slice. diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index b5c3e91d046..4250de9fb2b 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -839,10 +839,10 @@ pub const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst; /// If the actual type neither requires drop glue nor implements /// `Copy`, then the return value of this function is unspecified. /// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. +/// Note that, unlike most intrinsics, this can only be called at compile-time +/// as backends do not have an implementation for it. The only caller (its +/// stable counterpart) wraps this intrinsic call in a `const` block so that +/// backends only see an evaluated constant. /// /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). #[rustc_intrinsic_const_stable_indirect] @@ -2655,10 +2655,10 @@ pub const fn align_of<T>() -> usize; /// Returns the number of variants of the type `T` cast to a `usize`; /// if `T` has no variants, returns `0`. Uninhabited variants will be counted. /// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. +/// Note that, unlike most intrinsics, this can only be called at compile-time +/// as backends do not have an implementation for it. The only caller (its +/// stable counterpart) wraps this intrinsic call in a `const` block so that +/// backends only see an evaluated constant. /// /// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`]. #[rustc_nounwind] @@ -2694,10 +2694,10 @@ pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize; /// Gets a static string slice containing the name of a type. /// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. +/// Note that, unlike most intrinsics, this can only be called at compile-time +/// as backends do not have an implementation for it. The only caller (its +/// stable counterpart) wraps this intrinsic call in a `const` block so that +/// backends only see an evaluated constant. /// /// The stabilized version of this intrinsic is [`core::any::type_name`]. #[rustc_nounwind] @@ -2709,10 +2709,10 @@ pub const fn type_name<T: ?Sized>() -> &'static str; /// function will return the same value for a type regardless of whichever /// crate it is invoked in. /// -/// Note that, unlike most intrinsics, this is safe to call; -/// it does not require an `unsafe` block. -/// Therefore, implementations must not require the user to uphold -/// any safety invariants. +/// Note that, unlike most intrinsics, this can only be called at compile-time +/// as backends do not have an implementation for it. The only caller (its +/// stable counterpart) wraps this intrinsic call in a `const` block so that +/// backends only see an evaluated constant. /// /// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. #[rustc_nounwind] diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index b93f854b9dc..c00585de064 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -616,7 +616,7 @@ pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize { #[rustc_const_stable(feature = "const_mem_needs_drop", since = "1.36.0")] #[rustc_diagnostic_item = "needs_drop"] pub const fn needs_drop<T: ?Sized>() -> bool { - intrinsics::needs_drop::<T>() + const { intrinsics::needs_drop::<T>() } } /// Returns the value of type `T` represented by the all-zero byte-pattern. @@ -1215,7 +1215,7 @@ pub const fn discriminant<T>(v: &T) -> Discriminant<T> { #[rustc_const_unstable(feature = "variant_count", issue = "73662")] #[rustc_diagnostic_item = "mem_variant_count"] pub const fn variant_count<T>() -> usize { - intrinsics::variant_count::<T>() + const { intrinsics::variant_count::<T>() } } /// Provides associated constants for various useful properties of types, diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 0ac887f99dc..98a3b784233 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -316,6 +316,11 @@ mod prim_bool {} #[unstable(feature = "never_type", issue = "35121")] mod prim_never {} +// Required to make auto trait impls render. +// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls +#[doc(hidden)] +impl ! {} + #[rustc_doc_primitive = "char"] #[allow(rustdoc::invalid_rust_codeblocks)] /// A character type. diff --git a/library/std/src/sys/fs/windows/remove_dir_all.rs b/library/std/src/sys/fs/windows/remove_dir_all.rs index 06734f9e309..c8b1a076768 100644 --- a/library/std/src/sys/fs/windows/remove_dir_all.rs +++ b/library/std/src/sys/fs/windows/remove_dir_all.rs @@ -33,7 +33,7 @@ use core::sync::atomic::{Atomic, AtomicU32, Ordering}; use super::{AsRawHandle, DirBuff, File, FromRawHandle}; use crate::sys::c; -use crate::sys::pal::api::WinError; +use crate::sys::pal::api::{UnicodeStrRef, WinError, unicode_str}; use crate::thread; // The maximum number of times to spin when waiting for deletes to complete. @@ -74,7 +74,7 @@ unsafe fn nt_open_file( /// `options` will be OR'd with `FILE_OPEN_REPARSE_POINT`. fn open_link_no_reparse( parent: &File, - path: &[u16], + path: UnicodeStrRef<'_>, access: u32, options: u32, ) -> Result<Option<File>, WinError> { @@ -90,9 +90,8 @@ fn open_link_no_reparse( static ATTRIBUTES: Atomic<u32> = AtomicU32::new(c::OBJ_DONT_REPARSE); let result = unsafe { - let mut path_str = c::UNICODE_STRING::from_ref(path); let mut object = c::OBJECT_ATTRIBUTES { - ObjectName: &mut path_str, + ObjectName: path.as_ptr(), RootDirectory: parent.as_raw_handle(), Attributes: ATTRIBUTES.load(Ordering::Relaxed), ..c::OBJECT_ATTRIBUTES::with_length() @@ -129,7 +128,7 @@ fn open_link_no_reparse( } } -fn open_dir(parent: &File, name: &[u16]) -> Result<Option<File>, WinError> { +fn open_dir(parent: &File, name: UnicodeStrRef<'_>) -> Result<Option<File>, WinError> { // Open the directory for synchronous directory listing. open_link_no_reparse( parent, @@ -140,7 +139,7 @@ fn open_dir(parent: &File, name: &[u16]) -> Result<Option<File>, WinError> { ) } -fn delete(parent: &File, name: &[u16]) -> Result<(), WinError> { +fn delete(parent: &File, name: UnicodeStrRef<'_>) -> Result<(), WinError> { // Note that the `delete` function consumes the opened file to ensure it's // dropped immediately. See module comments for why this is important. match open_link_no_reparse(parent, name, c::DELETE, 0) { @@ -179,8 +178,9 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> { 'outer: while let Some(dir) = dirlist.pop() { let more_data = dir.fill_dir_buff(&mut buffer, restart)?; for (name, is_directory) in buffer.iter() { + let name = unicode_str!(&name); if is_directory { - let Some(subdir) = open_dir(&dir, &name)? else { continue }; + let Some(subdir) = open_dir(&dir, name)? else { continue }; dirlist.push(dir); dirlist.push(subdir); continue 'outer; @@ -188,7 +188,7 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> { // Attempt to delete, retrying on sharing violation errors as these // can often be very temporary. E.g. if something takes just a // bit longer than expected to release a file handle. - retry(|| delete(&dir, &name), WinError::SHARING_VIOLATION)?; + retry(|| delete(&dir, name), WinError::SHARING_VIOLATION)?; } } if more_data { @@ -197,7 +197,8 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> { } else { // Attempt to delete, retrying on not empty errors because we may // need to wait some time for files to be removed from the filesystem. - retry(|| delete(&dir, &[]), WinError::DIR_NOT_EMPTY)?; + let name = unicode_str!(""); + retry(|| delete(&dir, name), WinError::DIR_NOT_EMPTY)?; restart = true; } } diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs index 773455c572f..25a6c2d7d8e 100644 --- a/library/std/src/sys/pal/windows/api.rs +++ b/library/std/src/sys/pal/windows/api.rs @@ -30,6 +30,7 @@ //! should go in sys/pal/windows/mod.rs rather than here. See `IoResult` as an example. use core::ffi::c_void; +use core::marker::PhantomData; use super::c; @@ -291,3 +292,75 @@ impl WinError { pub const TIMEOUT: Self = Self::new(c::ERROR_TIMEOUT); // tidy-alphabetical-end } + +/// A wrapper around a UNICODE_STRING that is equivalent to `&[u16]`. +/// +/// It is preferable to use the `unicode_str!` macro as that contains mitigations for #143078. +/// +/// If the MaximumLength field of the underlying UNICODE_STRING is greater than +/// the Length field then you can test if the string is null terminated by inspecting +/// the u16 directly after the string. You cannot otherwise depend on nul termination. +#[derive(Copy, Clone)] +pub struct UnicodeStrRef<'a> { + s: c::UNICODE_STRING, + lifetime: PhantomData<&'a [u16]>, +} + +static EMPTY_STRING_NULL_TERMINATED: &[u16] = &[0]; + +impl UnicodeStrRef<'_> { + const fn new(slice: &[u16], is_null_terminated: bool) -> Self { + let (len, max_len, ptr) = if slice.is_empty() { + (0, 2, EMPTY_STRING_NULL_TERMINATED.as_ptr().cast_mut()) + } else { + let len = slice.len() - (is_null_terminated as usize); + (len * 2, size_of_val(slice), slice.as_ptr().cast_mut()) + }; + Self { + s: c::UNICODE_STRING { Length: len as _, MaximumLength: max_len as _, Buffer: ptr }, + lifetime: PhantomData, + } + } + + pub const fn from_slice_with_nul(slice: &[u16]) -> Self { + if !slice.is_empty() { + debug_assert!(slice[slice.len() - 1] == 0); + } + Self::new(slice, true) + } + + pub const fn from_slice(slice: &[u16]) -> Self { + Self::new(slice, false) + } + + /// Returns a pointer to the underlying UNICODE_STRING + pub const fn as_ptr(&self) -> *const c::UNICODE_STRING { + &self.s + } +} + +/// Create a UnicodeStringRef from a literal str or a u16 array. +/// +/// To mitigate #143078, when using a literal str the created UNICODE_STRING +/// will be nul terminated. The MaximumLength field of the UNICODE_STRING will +/// be set greater than the Length field to indicate that a nul may be present. +/// +/// If using a u16 array, the array is used exactly as provided and you cannot +/// count on the string being nul terminated. +/// This should generally be used for strings that come from the OS. +/// +/// **NOTE:** we lack a UNICODE_STRING builder type as we don't currently have +/// a use for it. If needing to dynamically build a UNICODE_STRING, the builder +/// should try to ensure there's a nul one past the end of the string. +pub macro unicode_str { + ($str:literal) => {const { + crate::sys::pal::windows::api::UnicodeStrRef::from_slice_with_nul( + crate::sys::pal::windows::api::wide_str!($str), + ) + }}, + ($array:expr) => { + crate::sys::pal::windows::api::UnicodeStrRef::from_slice( + $array, + ) + } +} diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 53dec105d0c..eee169d410a 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -37,13 +37,6 @@ pub fn nt_success(status: NTSTATUS) -> bool { status >= 0 } -impl UNICODE_STRING { - pub fn from_ref(slice: &[u16]) -> Self { - let len = size_of_val(slice); - Self { Length: len as _, MaximumLength: len as _, Buffer: slice.as_ptr() as _ } - } -} - impl OBJECT_ATTRIBUTES { pub fn with_length() -> Self { Self { diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index bc5d05c4505..b5ccf037a4f 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -1,9 +1,8 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::ops::Neg; use crate::os::windows::prelude::*; -use crate::sys::api::utf16; -use crate::sys::c; use crate::sys::handle::Handle; +use crate::sys::{api, c}; use crate::sys_common::{FromInner, IntoInner}; use crate::{mem, ptr}; @@ -73,8 +72,8 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res // Open a handle to the pipe filesystem (`\??\PIPE\`). // This will be used when creating a new annon pipe. let pipe_fs = { - let path = c::UNICODE_STRING::from_ref(utf16!(r"\??\PIPE\")); - object_attributes.ObjectName = &path; + let path = api::unicode_str!(r"\??\PIPE\"); + object_attributes.ObjectName = path.as_ptr(); let mut pipe_fs = ptr::null_mut(); let status = c::NtOpenFile( &mut pipe_fs, @@ -93,8 +92,12 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res // From now on we're using handles instead of paths to create and open pipes. // So set the `ObjectName` to a zero length string. + // As a (perhaps overzealous) mitigation for #143078, we use the null pointer + // for empty.Buffer instead of unicode_str!(""). + // There's no difference to the OS itself but it's possible that third party + // DLLs which hook in to processes could be relying on the exact form of this string. let empty = c::UNICODE_STRING::default(); - object_attributes.ObjectName = ∅ + object_attributes.ObjectName = &raw const empty; // Create our side of the pipe for async access. let ours = { diff --git a/library/stdarch/crates/intrinsic-test/README.md b/library/stdarch/crates/intrinsic-test/README.md index 260d59fca80..bea95f91e9e 100644 --- a/library/stdarch/crates/intrinsic-test/README.md +++ b/library/stdarch/crates/intrinsic-test/README.md @@ -7,7 +7,7 @@ USAGE: intrinsic-test [FLAGS] [OPTIONS] <INPUT> FLAGS: - --a32 Run tests for A32 instrinsics instead of A64 + --a32 Run tests for A32 intrinsics instead of A64 --generate-only Regenerate test programs, but don't build or run them -h, --help Prints help information -V, --version Prints version information diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index a6ca699e282..2434a278d55 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -12,6 +12,15 @@ dependencies = [ ] [[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] name = "anstyle" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -62,8 +71,8 @@ dependencies = [ "toml", "tracing", "tracing-chrome", + "tracing-forest", "tracing-subscriber", - "tracing-tree", "walkdir", "windows", "xz2", @@ -450,15 +459,6 @@ dependencies = [ ] [[package]] -name = "nu-ansi-term" -version = "0.50.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] name = "objc2-core-foundation" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -776,6 +776,26 @@ dependencies = [ ] [[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "thread_local" version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -838,6 +858,19 @@ dependencies = [ ] [[package]] +name = "tracing-forest" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f" +dependencies = [ + "ansi_term", + "smallvec", + "thiserror", + "tracing", + "tracing-subscriber", +] + +[[package]] name = "tracing-log" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -855,7 +888,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", - "nu-ansi-term 0.46.0", + "nu-ansi-term", "once_cell", "regex", "sharded-slab", @@ -867,18 +900,6 @@ dependencies = [ ] [[package]] -name = "tracing-tree" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f459ca79f1b0d5f71c54ddfde6debfc59c8b6eeb46808ae492077f739dc7b49c" -dependencies = [ - "nu-ansi-term 0.50.1", - "tracing-core", - "tracing-log", - "tracing-subscriber", -] - -[[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 9785a306c9b..073cebdcae2 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -7,7 +7,7 @@ default-run = "bootstrap" [features] build-metrics = ["sysinfo"] -tracing = ["dep:tracing", "dep:tracing-chrome", "dep:tracing-subscriber", "dep:tracing-tree"] +tracing = ["dep:tracing", "dep:tracing-chrome", "dep:tracing-subscriber", "dep:tracing-forest"] [lib] path = "src/lib.rs" @@ -64,7 +64,7 @@ sysinfo = { version = "0.35.0", default-features = false, optional = true, featu tracing = { version = "0.1", optional = true, features = ["attributes"] } tracing-chrome = { version = "0.7", optional = true } tracing-subscriber = { version = "0.3", optional = true, features = ["env-filter", "fmt", "registry", "std"] } -tracing-tree = { version = "0.4.0", optional = true } +tracing-forest = { version = "0.1.6", optional = true, default-features = false, features = ["smallvec", "ansi", "env-filter"] } [target.'cfg(windows)'.dependencies.junction] version = "1.0.0" diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 833f8027951..e1862a451f2 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -217,12 +217,11 @@ fn check_version(config: &Config) -> Option<String> { // "tracing", instrument(..))]`. #[cfg(feature = "tracing")] fn setup_tracing() -> impl Drop { + use tracing_forest::ForestLayer; use tracing_subscriber::EnvFilter; use tracing_subscriber::layer::SubscriberExt; let filter = EnvFilter::from_env("BOOTSTRAP_TRACING"); - // cf. <https://docs.rs/tracing-tree/latest/tracing_tree/struct.HierarchicalLayer.html>. - let layer = tracing_tree::HierarchicalLayer::default().with_targets(true).with_indent_amount(2); let mut chrome_layer = tracing_chrome::ChromeLayerBuilder::new().include_args(true); @@ -233,7 +232,8 @@ fn setup_tracing() -> impl Drop { let (chrome_layer, _guard) = chrome_layer.build(); - let registry = tracing_subscriber::registry().with(filter).with(layer).with(chrome_layer); + let registry = + tracing_subscriber::registry().with(filter).with(ForestLayer::default()).with(chrome_layer); tracing::subscriber::set_global_default(registry).unwrap(); _guard diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 8200e154169..84064150738 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2241,7 +2241,7 @@ impl Step for Assemble { debug!("copying codegen backends to sysroot"); copy_codegen_backends_to_sysroot(builder, build_compiler, target_compiler); - if builder.config.lld_enabled && !builder.config.is_system_llvm(target_compiler.host) { + if builder.config.lld_enabled { builder.ensure(crate::core::build_steps::tool::LldWrapper { build_compiler, target_compiler, diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index d1ffdf24acd..0cdfbbdaf75 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1003,9 +1003,7 @@ impl Config { } if config.lld_enabled && config.is_system_llvm(config.host_target) { - eprintln!( - "Warning: LLD is enabled when using external llvm-config. LLD will not be built and copied to the sysroot." - ); + panic!("Cannot enable LLD with `rust.lld = true` when using external llvm-config."); } config.optimized_compiler_builtins = diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 7c588cfea8c..006c294d445 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -431,4 +431,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "It is no longer possible to `x build` with stage 0. All build commands have to be on stage 1+.", }, + ChangeInfo { + change_id: 143175, + severity: ChangeSeverity::Info, + summary: "It is no longer possible to combine `rust.lld = true` with configuring external LLVM using `llvm.llvm-config`.", + }, ]; diff --git a/src/doc/book b/src/doc/book -Subproject 8a6d44e45b7b564eeb6bae30507e1fbac439d72 +Subproject ef1ce8f87a8b18feb1b6a9cf9a4939a79bde679 diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject 10fa1e084365f23f24ad0000df541923385b73b +Subproject 41f688a598a5022b749e23d37f3c524f6a0b28e diff --git a/src/doc/reference b/src/doc/reference -Subproject 50fc1628f36563958399123829c73755fa7a842 +Subproject e9fc99f107840813916f62e16b3f6d9556e1f2d diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 05c7d8bae65f23a1837430c5a19be129d414f5e +Subproject 288b4e4948add43f387cad35adc7b1c54ca6fe1 diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index 09dc476d68e..f7e62e1eccf 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -499,7 +499,7 @@ This directive takes comma-separated issue numbers as arguments, or `"unknown"`: - `//@ known-bug: rust-lang/chalk#123456` (allows arbitrary text before the `#`, which is useful when the issue is on another repo) - `//@ known-bug: unknown` - (when there is no known issue yet; preferrably open one if it does not already exist) + (when there is no known issue yet; preferably open one if it does not already exist) Do not include [error annotations](#error-annotations) in a test with `known-bug`. The test should still include other normal directives and diff --git a/src/doc/unstable-book/src/language-features/type-alias-impl-trait.md b/src/doc/unstable-book/src/language-features/type-alias-impl-trait.md index a6fb25a55be..10464e500ec 100644 --- a/src/doc/unstable-book/src/language-features/type-alias-impl-trait.md +++ b/src/doc/unstable-book/src/language-features/type-alias-impl-trait.md @@ -64,7 +64,7 @@ struct HaveAlias { In this example, the concrete type referred to by `Alias` is guaranteed to be the same wherever `Alias` occurs. -> Orginally this feature included type aliases as an associated type of a trait. In [#110237] this was split off to [`impl_trait_in_assoc_type`]. +> Originally this feature included type aliases as an associated type of a trait. In [#110237] this was split off to [`impl_trait_in_assoc_type`]. ### `type_alias_impl_trait` in argument position. diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3cac55493f0..600c564d714 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -753,9 +753,12 @@ impl Item { .other_attrs .iter() .filter_map(|attr| { + if let hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) = attr { + Some(format!("#[link_section = \"{name}\"]")) + } // NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing. // It is also used by cargo-semver-checks. - if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr { + else if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr { Some("#[no_mangle]".to_string()) } else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr { diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 3b544d8b828..cdada5a2230 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -6,6 +6,10 @@ edition = "2024" [lib] doctest = false +[[bin]] +name = "compiletest" +path = "src/bin/main.rs" + [dependencies] # tidy-alphabetical-start anstyle-svg = "0.1.3" diff --git a/src/tools/compiletest/src/bin/main.rs b/src/tools/compiletest/src/bin/main.rs new file mode 100644 index 00000000000..1f777e71cf9 --- /dev/null +++ b/src/tools/compiletest/src/bin/main.rs @@ -0,0 +1,24 @@ +use std::env; +use std::io::IsTerminal; +use std::sync::Arc; + +use compiletest::{early_config_check, log_config, parse_config, run_tests}; + +fn main() { + tracing_subscriber::fmt::init(); + + // colored checks stdout by default, but for some reason only stderr is a terminal. + // compiletest *does* print many things to stdout, but it doesn't really matter. + if std::io::stderr().is_terminal() + && matches!(std::env::var("NO_COLOR").as_deref(), Err(_) | Ok("0")) + { + colored::control::set_override(true); + } + + let config = Arc::new(parse_config(env::args().collect())); + + early_config_check(&config); + + log_config(&config); + run_tests(config); +} diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 9b9d94bbead..cdce5d941d0 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -11,6 +11,7 @@ use serde::de::{Deserialize, Deserializer, Error as _}; pub use self::Mode::*; use crate::executor::{ColorConfig, OutputFormat}; +use crate::fatal; use crate::util::{Utf8PathBufExt, add_dylib_path}; macro_rules! string_enum { @@ -783,11 +784,13 @@ fn rustc_output(config: &Config, args: &[&str], envs: HashMap<String, String>) - let output = match command.output() { Ok(output) => output, - Err(e) => panic!("error: failed to run {command:?}: {e}"), + Err(e) => { + fatal!("failed to run {command:?}: {e}"); + } }; if !output.status.success() { - panic!( - "error: failed to run {command:?}\n--- stdout\n{}\n--- stderr\n{}", + fatal!( + "failed to run {command:?}\n--- stdout\n{}\n--- stderr\n{}", String::from_utf8(output.stdout).unwrap(), String::from_utf8(output.stderr).unwrap(), ); diff --git a/src/tools/compiletest/src/diagnostics.rs b/src/tools/compiletest/src/diagnostics.rs new file mode 100644 index 00000000000..207a6cb91d7 --- /dev/null +++ b/src/tools/compiletest/src/diagnostics.rs @@ -0,0 +1,46 @@ +//! Collection of diagnostics helpers for `compiletest` *itself*. + +#[macro_export] +macro_rules! fatal { + ($($arg:tt)*) => { + let status = ::colored::Colorize::bright_red("FATAL: "); + let status = ::colored::Colorize::bold(status); + eprint!("{status}"); + eprintln!($($arg)*); + // This intentionally uses a seemingly-redundant panic to include backtrace location. + // + // FIXME: in the long term, we should handle "logic bug in compiletest itself" vs "fatal + // user error" separately. + panic!("fatal error"); + }; +} + +#[macro_export] +macro_rules! error { + ($($arg:tt)*) => { + let status = ::colored::Colorize::red("ERROR: "); + let status = ::colored::Colorize::bold(status); + eprint!("{status}"); + eprintln!($($arg)*); + }; +} + +#[macro_export] +macro_rules! warning { + ($($arg:tt)*) => { + let status = ::colored::Colorize::yellow("WARNING: "); + let status = ::colored::Colorize::bold(status); + eprint!("{status}"); + eprintln!($($arg)*); + }; +} + +#[macro_export] +macro_rules! help { + ($($arg:tt)*) => { + let status = ::colored::Colorize::cyan("HELP: "); + let status = ::colored::Colorize::bold(status); + eprint!("{status}"); + eprintln!($($arg)*); + }; +} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 2b203bb309c..5636a146b0f 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -15,6 +15,7 @@ use crate::errors::ErrorKind; use crate::executor::{CollectedTestDesc, ShouldPanic}; use crate::header::auxiliary::{AuxProps, parse_and_update_aux}; use crate::header::needs::CachedNeedsConditions; +use crate::help; use crate::util::static_regex; pub(crate) mod auxiliary; @@ -920,9 +921,9 @@ fn iter_header( if !is_known_directive { *poisoned = true; - eprintln!( - "error: detected unknown compiletest test directive `{}` in {}:{}", - directive_line.raw_directive, testfile, line_number, + error!( + "{testfile}:{line_number}: detected unknown compiletest test directive `{}`", + directive_line.raw_directive, ); return; @@ -931,11 +932,11 @@ fn iter_header( if let Some(trailing_directive) = &trailing_directive { *poisoned = true; - eprintln!( - "error: detected trailing compiletest test directive `{}` in {}:{}\n \ - help: put the trailing directive in it's own line: `//@ {}`", - trailing_directive, testfile, line_number, trailing_directive, + error!( + "{testfile}:{line_number}: detected trailing compiletest test directive `{}`", + trailing_directive, ); + help!("put the trailing directive in it's own line: `//@ {}`", trailing_directive); return; } @@ -1031,10 +1032,9 @@ impl Config { }; let Some((regex, replacement)) = parse_normalize_rule(raw_value) else { - panic!( - "couldn't parse custom normalization rule: `{raw_directive}`\n\ - help: expected syntax is: `{directive_name}: \"REGEX\" -> \"REPLACEMENT\"`" - ); + error!("couldn't parse custom normalization rule: `{raw_directive}`"); + help!("expected syntax is: `{directive_name}: \"REGEX\" -> \"REPLACEMENT\"`"); + panic!("invalid normalization rule detected"); }; Some(NormalizeRule { kind, regex, replacement }) } @@ -1406,7 +1406,7 @@ pub(crate) fn make_test_description<R: Read>( ignore_message = Some(reason.into()); } IgnoreDecision::Error { message } => { - eprintln!("error: {}:{line_number}: {message}", path); + error!("{path}:{line_number}: {message}"); *poisoned = true; return; } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 0db4d3f6a41..09de3eb4c70 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -11,6 +11,7 @@ mod tests; pub mod common; pub mod compute_diff; mod debuggers; +pub mod diagnostics; pub mod errors; mod executor; pub mod header; @@ -33,7 +34,7 @@ use build_helper::git::{get_git_modified_files, get_git_untracked_files}; use camino::{Utf8Path, Utf8PathBuf}; use getopts::Options; use rayon::iter::{ParallelBridge, ParallelIterator}; -use tracing::*; +use tracing::debug; use walkdir::WalkDir; use self::header::{EarlyProps, make_test_description}; @@ -51,12 +52,6 @@ use crate::util::logv; /// some code here that inspects environment variables or even runs executables /// (e.g. when discovering debugger versions). pub fn parse_config(args: Vec<String>) -> Config { - if env::var("RUST_TEST_NOCAPTURE").is_ok() { - eprintln!( - "WARNING: RUST_TEST_NOCAPTURE is not supported. Use the `--no-capture` flag instead." - ); - } - let mut opts = Options::new(); opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") @@ -657,10 +652,7 @@ pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest> let common_inputs_stamp = common_inputs_stamp(&config); let modified_tests = modified_tests(&config, &config.src_test_suite_root).unwrap_or_else(|err| { - panic!( - "modified_tests got error from dir: {}, error: {}", - config.src_test_suite_root, err - ) + fatal!("modified_tests: {}: {err}", config.src_test_suite_root); }); let cache = HeadersCache::load(&config); @@ -1111,3 +1103,20 @@ fn check_for_overlapping_test_paths(found_path_stems: &HashSet<Utf8PathBuf>) { ); } } + +pub fn early_config_check(config: &Config) { + if !config.has_html_tidy && config.mode == Mode::Rustdoc { + warning!("`tidy` (html-tidy.org) is not installed; diffs will not be generated"); + } + + if !config.profiler_runtime && config.mode == Mode::CoverageRun { + let actioned = if config.bless { "blessed" } else { "checked" }; + warning!("profiler runtime is not available, so `.coverage` files won't be {actioned}"); + help!("try setting `profiler = true` in the `[build]` section of `bootstrap.toml`"); + } + + // `RUST_TEST_NOCAPTURE` is a libtest env var, but we don't callout to libtest. + if env::var("RUST_TEST_NOCAPTURE").is_ok() { + warning!("`RUST_TEST_NOCAPTURE` is not supported; use the `--no-capture` flag instead"); + } +} diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs deleted file mode 100644 index b9ae583581e..00000000000 --- a/src/tools/compiletest/src/main.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::env; -use std::io::IsTerminal; -use std::sync::Arc; - -use compiletest::common::Mode; -use compiletest::{log_config, parse_config, run_tests}; - -fn main() { - tracing_subscriber::fmt::init(); - - // colored checks stdout by default, but for some reason only stderr is a terminal. - // compiletest *does* print many things to stdout, but it doesn't really matter. - if std::io::stderr().is_terminal() - && matches!(std::env::var("NO_COLOR").as_deref(), Err(_) | Ok("0")) - { - colored::control::set_override(true); - } - - let config = Arc::new(parse_config(env::args().collect())); - - if !config.has_html_tidy && config.mode == Mode::Rustdoc { - eprintln!("warning: `tidy` (html-tidy.org) is not installed; diffs will not be generated"); - } - - if !config.profiler_runtime && config.mode == Mode::CoverageRun { - let actioned = if config.bless { "blessed" } else { "checked" }; - eprintln!( - r#" -WARNING: profiler runtime is not available, so `.coverage` files won't be {actioned} -help: try setting `profiler = true` in the `[build]` section of `bootstrap.toml`"# - ); - } - - log_config(&config); - run_tests(config); -} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 980e89889ab..53b5990d3cd 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -27,7 +27,7 @@ use crate::errors::{Error, ErrorKind, load_errors}; use crate::header::TestProps; use crate::read2::{Truncated, read2_abbreviated}; use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex}; -use crate::{ColorConfig, json, stamp_file_path}; +use crate::{ColorConfig, help, json, stamp_file_path, warning}; mod debugger; @@ -485,12 +485,15 @@ impl<'test> TestCx<'test> { .windows(2) .any(|args| args == cfg_arg || args[0] == arg || args[1] == arg) { - panic!( - "error: redundant cfg argument `{normalized_revision}` is already created by the revision" + error!( + "redundant cfg argument `{normalized_revision}` is already created by the \ + revision" ); + panic!("redundant cfg argument"); } if self.config.builtin_cfg_names().contains(&normalized_revision) { - panic!("error: revision `{normalized_revision}` collides with a builtin cfg"); + error!("revision `{normalized_revision}` collides with a built-in cfg"); + panic!("revision collides with built-in cfg"); } cmd.args(cfg_arg); } @@ -2167,9 +2170,10 @@ impl<'test> TestCx<'test> { println!("{}", String::from_utf8_lossy(&output.stdout)); eprintln!("{}", String::from_utf8_lossy(&output.stderr)); } else { - eprintln!("warning: no pager configured, falling back to unified diff"); - eprintln!( - "help: try configuring a git pager (e.g. `delta`) with `git config --global core.pager delta`" + warning!("no pager configured, falling back to unified diff"); + help!( + "try configuring a git pager (e.g. `delta`) with \ + `git config --global core.pager delta`" ); let mut out = io::stdout(); let mut diff = BufReader::new(File::open(&diff_filename).unwrap()); diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs index 8dfa8d18d1a..44ddcb1d288 100644 --- a/src/tools/compiletest/src/runtest/codegen_units.rs +++ b/src/tools/compiletest/src/runtest/codegen_units.rs @@ -1,8 +1,8 @@ use std::collections::HashSet; use super::{Emit, TestCx, WillExecute}; -use crate::errors; use crate::util::static_regex; +use crate::{errors, fatal}; impl TestCx<'_> { pub(super) fn run_codegen_units_test(&self) { @@ -100,7 +100,7 @@ impl TestCx<'_> { } if !(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty()) { - panic!(); + fatal!("!(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty())"); } #[derive(Clone, Eq, PartialEq)] diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 4a038fe6487..1796120cf8a 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -390,7 +390,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, interpret::Pointer<Provenance>> { let this = self.eval_context_ref(); - let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance) + let (prov, offset) = ptr.prov_and_relative_offset(); let alloc_id = prov.alloc_id(); // Get a pointer to the beginning of this allocation. @@ -447,7 +447,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> Option<(AllocId, Size)> { let this = self.eval_context_ref(); - let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) + let (tag, addr) = ptr.into_raw_parts(); // addr is absolute (Miri provenance) let alloc_id = if let Provenance::Concrete { alloc_id, .. } = tag { alloc_id diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index ec77a162cdb..ed1851a19ae 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -191,7 +191,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [f] = check_intrinsic_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; - let res = fixed_float_value(intrinsic_name, &[f]).unwrap_or_else(||{ + let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| { // Using host floats (but it's fine, these operations do not have // guaranteed precision). let host = f.to_host(); @@ -235,7 +235,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [f] = check_intrinsic_arg_count(args)?; let f = this.read_scalar(f)?.to_f64()?; - let res = fixed_float_value(intrinsic_name, &[f]).unwrap_or_else(||{ + let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| { // Using host floats (but it's fine, these operations do not have // guaranteed precision). let host = f.to_host(); @@ -312,7 +312,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let f1 = this.read_scalar(f1)?.to_f32()?; let f2 = this.read_scalar(f2)?.to_f32()?; - let res = fixed_float_value(intrinsic_name, &[f1, f2]).unwrap_or_else(|| { + let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| { // Using host floats (but it's fine, this operation does not have guaranteed precision). let res = f1.to_host().powf(f2.to_host()).to_soft(); @@ -330,7 +330,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let f1 = this.read_scalar(f1)?.to_f64()?; let f2 = this.read_scalar(f2)?.to_f64()?; - let res = fixed_float_value(intrinsic_name, &[f1, f2]).unwrap_or_else(|| { + let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| { // Using host floats (but it's fine, this operation does not have guaranteed precision). let res = f1.to_host().powf(f2.to_host()).to_soft(); @@ -349,7 +349,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let f = this.read_scalar(f)?.to_f32()?; let i = this.read_scalar(i)?.to_i32()?; - let res = fixed_powi_float_value(f, i).unwrap_or_else(|| { + let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| { // Using host floats (but it's fine, this operation does not have guaranteed precision). let res = f.to_host().powi(i).to_soft(); @@ -367,7 +367,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let f = this.read_scalar(f)?.to_f64()?; let i = this.read_scalar(i)?.to_i32()?; - let res = fixed_powi_float_value(f, i).unwrap_or_else(|| { + let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| { // Using host floats (but it's fine, this operation does not have guaranteed precision). let res = f.to_host().powi(i).to_soft(); @@ -496,52 +496,88 @@ fn apply_random_float_error_to_imm<'tcx>( /// - logf32, logf64, log2f32, log2f64, log10f32, log10f64 /// - powf32, powf64 /// +/// # Return +/// /// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard /// (specifically, C23 annex F.10) when given `args` as arguments. Outputs that are unaffected by a relative error /// (such as INF and zero) are not handled here, they are assumed to be handled by the underlying /// implementation. Returns `None` if no specific value is guaranteed. +/// +/// # Note +/// +/// For `powf*` operations of the form: +/// +/// - `(SNaN)^(±0)` +/// - `1^(SNaN)` +/// +/// The result is implementation-defined: +/// - musl returns for both `1.0` +/// - glibc returns for both `NaN` +/// +/// This discrepancy exists because SNaN handling is not consistently defined across platforms, +/// and the C standard leaves behavior for SNaNs unspecified. +/// +/// Miri chooses to adhere to both implementations and returns either one of them non-deterministically. fn fixed_float_value<S: Semantics>( + ecx: &mut MiriInterpCx<'_>, intrinsic_name: &str, args: &[IeeeFloat<S>], ) -> Option<IeeeFloat<S>> { let one = IeeeFloat::<S>::one(); - match (intrinsic_name, args) { + Some(match (intrinsic_name, args) { // cos(+- 0) = 1 - ("cosf32" | "cosf64", [input]) if input.is_zero() => Some(one), + ("cosf32" | "cosf64", [input]) if input.is_zero() => one, // e^0 = 1 - ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => Some(one), - - // 1^y = 1 for any y, even a NaN. - ("powf32" | "powf64", [base, _]) if *base == one => Some(one), + ("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => one, // (-1)^(±INF) = 1 - ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => Some(one), + ("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => one, + + // 1^y = 1 for any y, even a NaN + ("powf32" | "powf64", [base, exp]) if *base == one => { + let rng = ecx.machine.rng.get_mut(); + // SNaN exponents get special treatment: they might return 1, or a NaN. + let return_nan = exp.is_signaling() && ecx.machine.float_nondet && rng.random(); + // Handle both the musl and glibc cases non-deterministically. + if return_nan { ecx.generate_nan(args) } else { one } + } - // FIXME(#4286): The C ecosystem is inconsistent with handling sNaN's, some return 1 others propogate - // the NaN. We should return either 1 or the NaN non-deterministically here. - // But for now, just handle them all the same. // x^(±0) = 1 for any x, even a NaN - ("powf32" | "powf64", [_, exp]) if exp.is_zero() => Some(one), + ("powf32" | "powf64", [base, exp]) if exp.is_zero() => { + let rng = ecx.machine.rng.get_mut(); + // SNaN bases get special treatment: they might return 1, or a NaN. + let return_nan = base.is_signaling() && ecx.machine.float_nondet && rng.random(); + // Handle both the musl and glibc cases non-deterministically. + if return_nan { ecx.generate_nan(args) } else { one } + } - // There are a lot of cases for fixed outputs according to the C Standard, but these are mainly INF or zero - // which are not affected by the applied error. - _ => None, - } + // There are a lot of cases for fixed outputs according to the C Standard, but these are + // mainly INF or zero which are not affected by the applied error. + _ => return None, + }) } -/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the C standard -/// (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`. -fn fixed_powi_float_value<S: Semantics>(base: IeeeFloat<S>, exp: i32) -> Option<IeeeFloat<S>> { - match (base.category(), exp) { - // x^0 = 1, if x is not a Signaling NaN - // FIXME(#4286): The C ecosystem is inconsistent with handling sNaN's, some return 1 others propogate - // the NaN. We should return either 1 or the NaN non-deterministically here. - // But for now, just handle them all the same. - (_, 0) => Some(IeeeFloat::<S>::one()), - - _ => None, - } +/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the +/// C standard (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`. +fn fixed_powi_float_value<S: Semantics>( + ecx: &mut MiriInterpCx<'_>, + base: IeeeFloat<S>, + exp: i32, +) -> Option<IeeeFloat<S>> { + Some(match exp { + 0 => { + let one = IeeeFloat::<S>::one(); + let rng = ecx.machine.rng.get_mut(); + let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling(); + // For SNaN treatment, we are consistent with `powf`above. + // (We wouldn't have two, unlike powf all implementations seem to agree for powi, + // but for now we are maximally conservative.) + if return_nan { ecx.generate_nan(&[base]) } else { one } + } + + _ => return None, + }) } /// Given an floating-point operation and a floating-point value, clamps the result to the output diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 3a748c4c687..17c13a9e33c 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -285,7 +285,7 @@ impl interpret::Provenance for Provenance { } fn fmt(ptr: &interpret::Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (prov, addr) = ptr.into_parts(); // address is absolute + let (prov, addr) = ptr.into_raw_parts(); // offset is absolute address write!(f, "{:#x}", addr.bytes())?; if f.alternate() { write!(f, "{prov:#?}")?; diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs index b3d715db9cd..6adf1448648 100644 --- a/src/tools/miri/src/provenance_gc.rs +++ b/src/tools/miri/src/provenance_gc.rs @@ -68,15 +68,13 @@ impl VisitProvenance for Provenance { impl VisitProvenance for StrictPointer { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let (prov, _offset) = self.into_parts(); - prov.visit_provenance(visit); + self.provenance.visit_provenance(visit); } } impl VisitProvenance for Pointer { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let (prov, _offset) = self.into_parts(); - prov.visit_provenance(visit); + self.provenance.visit_provenance(visit); } } diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 416cb1ab55e..97070eb742f 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -411,7 +411,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { AlignFromBytesError::TooLarge(_) => Align::MAX, } }); - let (_, addr) = ptr.into_parts(); // we know the offset is absolute + let addr = ptr.addr(); // Cannot panic since `align` is a power of 2 and hence non-zero. if addr.bytes().strict_rem(align.bytes()) != 0 { throw_unsup_format!( diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index 4bbbbc69c08..1738de4dd4f 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -49,7 +49,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { && matches!(&*this.tcx.sess.target.os, "macos" | "solaris" | "illumos") && (flags & map_fixed) != 0 { - return interp_ok(Scalar::from_maybe_pointer(Pointer::from_addr_invalid(addr), this)); + return interp_ok(Scalar::from_maybe_pointer(Pointer::without_provenance(addr), this)); } let prot_read = this.eval_libc_i32("PROT_READ"); diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 383579198bb..0fec1fb15eb 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1066,17 +1066,6 @@ pub fn libm() { assert_eq!((-1f32).powf(f32::NEG_INFINITY), 1.0); assert_eq!((-1f64).powf(f64::NEG_INFINITY), 1.0); - // For pow (powf in rust) the C standard says: - // x^0 = 1 for all x even a sNaN - // FIXME(#4286): this does not match the behavior of all implementations. - assert_eq!(SNAN_F32.powf(0.0), 1.0); - assert_eq!(SNAN_F64.powf(0.0), 1.0); - - // For pown (powi in rust) the C standard says: - // x^0 = 1 for all x even a sNaN - // FIXME(#4286): this does not match the behavior of all implementations. - assert_eq!(SNAN_F32.powi(0), 1.0); - assert_eq!(SNAN_F64.powi(0), 1.0); assert_eq!(0f32.powi(10), 0.0); assert_eq!(0f64.powi(100), 0.0); @@ -1358,7 +1347,7 @@ fn test_min_max_nondet() { /// Ensure that if we call the closure often enough, we see both `true` and `false.` #[track_caller] fn ensure_both(f: impl Fn() -> bool) { - let rounds = 16; + let rounds = 32; let first = f(); for _ in 1..rounds { if f() != first { @@ -1500,4 +1489,18 @@ fn test_non_determinism() { test_operations_f32(12., 5.); test_operations_f64(19., 11.); test_operations_f128(25., 18.); + + + // SNaN^0 = (1 | NaN) + ensure_nondet(|| f32::powf(SNAN_F32, 0.0).is_nan()); + ensure_nondet(|| f64::powf(SNAN_F64, 0.0).is_nan()); + + // 1^SNaN = (1 | NaN) + ensure_nondet(|| f32::powf(1.0, SNAN_F32).is_nan()); + ensure_nondet(|| f64::powf(1.0, SNAN_F64).is_nan()); + + // same as powf (keep it consistent): + // x^SNaN = (1 | NaN) + ensure_nondet(|| f32::powi(SNAN_F32, 0).is_nan()); + ensure_nondet(|| f64::powi(SNAN_F64, 0).is_nan()); } diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs index cadbbd58af5..3ffdb6868ac 100644 --- a/src/tools/miri/tests/pass/float_nan.rs +++ b/src/tools/miri/tests/pass/float_nan.rs @@ -260,6 +260,7 @@ fn test_f32() { // Intrinsics let nan = F32::nan(Neg, Quiet, 0).as_f32(); + let snan = F32::nan(Neg, Signaling, 1).as_f32(); check_all_outcomes( HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), || F32::from(f32::min(nan, nan)), @@ -313,6 +314,18 @@ fn test_f32() { HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), || F32::from(nan.ln_gamma().0), ); + check_all_outcomes( + HashSet::from_iter([ + F32::from(1.0), + F32::nan(Pos, Quiet, 0), + F32::nan(Neg, Quiet, 0), + F32::nan(Pos, Quiet, 1), + F32::nan(Neg, Quiet, 1), + F32::nan(Pos, Signaling, 1), + F32::nan(Neg, Signaling, 1), + ]), + || F32::from(snan.powf(0.0)), + ); } fn test_f64() { @@ -376,6 +389,7 @@ fn test_f64() { // Intrinsics let nan = F64::nan(Neg, Quiet, 0).as_f64(); + let snan = F64::nan(Neg, Signaling, 1).as_f64(); check_all_outcomes( HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), || F64::from(f64::min(nan, nan)), @@ -433,6 +447,18 @@ fn test_f64() { HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), || F64::from(nan.ln_gamma().0), ); + check_all_outcomes( + HashSet::from_iter([ + F64::from(1.0), + F64::nan(Pos, Quiet, 0), + F64::nan(Neg, Quiet, 0), + F64::nan(Pos, Quiet, 1), + F64::nan(Neg, Quiet, 1), + F64::nan(Pos, Signaling, 1), + F64::nan(Neg, Signaling, 1), + ]), + || F64::from(snan.powf(0.0)), + ); } fn test_casts() { diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index 53ce772fa77..705a1750ae8 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -72,6 +72,8 @@ change-id = 115898 [rust] channel = "{channel}" verbose-tests = true +# rust-lld cannot be combined with an external LLVM +lld = false [build] rustc = "{rustc}" diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml index 79fb7a2d2ea..770652494f4 100644 --- a/src/tools/rust-analyzer/.github/workflows/ci.yaml +++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml @@ -17,6 +17,10 @@ env: RUST_BACKTRACE: short RUSTUP_MAX_RETRIES: 10 +defaults: + run: + shell: bash + jobs: changes: runs-on: ubuntu-latest @@ -80,6 +84,7 @@ jobs: CC: deny_c strategy: + fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] @@ -99,7 +104,7 @@ jobs: rustup toolchain install nightly --profile minimal --component rustfmt # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json - name: Install Rust Problem Matcher - if: matrix.os == 'ubuntu-latest' + if: matrix.os == 'macos-latest' run: echo "::add-matcher::.github/rust.json" # - name: Cache Dependencies @@ -116,23 +121,9 @@ jobs: if: matrix.os == 'ubuntu-latest' run: cargo codegen --check - - name: Compile tests - run: cargo test --no-run - - name: Run tests run: cargo nextest run --no-fail-fast --hide-progress-bar --status-level fail - - name: Cancel parallel jobs - if: failure() - run: | - # https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#cancel-a-workflow-run - curl -L \ - -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel - - name: Run Clippy if: matrix.os == 'macos-latest' run: cargo clippy --all-targets -- -D clippy::disallowed_macros -D clippy::dbg_macro -D clippy::todo -D clippy::print_stdout -D clippy::print_stderr @@ -333,3 +324,21 @@ jobs: jq -C <<< '${{ toJson(needs) }}' # Check if all jobs that we depend on (in the needs array) were successful (or have been skipped). jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}' + + cancel-if-matrix-failed: + needs: rust + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Cancel parallel jobs + run: | + if jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}'; then + exit 0 + fi + # https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#cancel-a-workflow-run + curl -L \ + -X POST \ + -H "Accept: application/vnd.github.v3+json" \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/cancel diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml index a758ecfd467..5bd90130f4c 100644 --- a/src/tools/rust-analyzer/.github/workflows/release.yaml +++ b/src/tools/rust-analyzer/.github/workflows/release.yaml @@ -134,13 +134,13 @@ jobs: - name: Run analysis-stats on rust-analyzer if: matrix.target == 'x86_64-unknown-linux-gnu' - run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats . + run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats . -q - name: Run analysis-stats on rust std library if: matrix.target == 'x86_64-unknown-linux-gnu' env: RUSTC_BOOTSTRAP: 1 - run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std + run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std -q - name: Upload artifacts uses: actions/upload-artifact@v4 diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 2c7b4641641..caa8f28d8e2 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -1458,7 +1458,7 @@ dependencies = [ "edition", "expect-test", "ra-ap-rustc_lexer", - "rustc-literal-escaper 0.0.3", + "rustc-literal-escaper 0.0.4", "stdx", "tracing", ] @@ -1927,9 +1927,9 @@ checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04" [[package]] name = "rustc-literal-escaper" -version = "0.0.3" +version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78744cd17f5d01c75b709e49807d1363e02a940ccee2e9e72435843fdb0d076e" +checksum = "ab03008eb631b703dd16978282ae36c73282e7922fe101a4bd072a40ecea7b8b" [[package]] name = "rustc-stable-hash" @@ -2207,7 +2207,7 @@ dependencies = [ "rayon", "rowan", "rustc-hash 2.1.1", - "rustc-literal-escaper 0.0.3", + "rustc-literal-escaper 0.0.4", "rustc_apfloat", "smol_str", "stdx", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 449c75859cf..0a8e6feb46e 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -143,7 +143,7 @@ serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } serde_json = "1.0.140" rustc-hash = "2.1.1" -rustc-literal-escaper = "0.0.3" +rustc-literal-escaper = "0.0.4" smallvec = { version = "1.15.1", features = [ "const_new", "union", diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index 3b423a86f97..ea06fd9c48f 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] la-arena.workspace = true diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml index d7764a16c04..ba349666145 100644 --- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml +++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] rustc-hash.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml index c6922eca49f..abb4819a767 100644 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] arrayvec.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 00408e95ae6..c67bb2422ac 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -25,11 +25,10 @@ use crate::{ import_map::ImportMap, item_tree::{ItemTree, file_item_tree_query}, lang_item::{self, LangItem}, - nameres::{assoc::TraitItems, crate_def_map, diagnostics::DefDiagnostics}, + nameres::crate_def_map, signatures::{ ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature, StructSignature, TraitAliasSignature, TraitSignature, TypeAliasSignature, UnionSignature, - VariantFields, }, tt, visibility::{self, Visibility}, @@ -113,24 +112,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { // region:data - #[salsa::invoke(VariantFields::query)] - fn variant_fields_with_source_map( - &self, - id: VariantId, - ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>); - - #[salsa::transparent] - #[salsa::invoke(TraitItems::trait_items_query)] - fn trait_items(&self, e: TraitId) -> Arc<TraitItems>; - - #[salsa::invoke(TraitItems::trait_items_with_diagnostics_query)] - fn trait_items_with_diagnostics(&self, tr: TraitId) -> (Arc<TraitItems>, DefDiagnostics); - - #[salsa::tracked] - fn variant_fields(&self, id: VariantId) -> Arc<VariantFields> { - self.variant_fields_with_source_map(id).0 - } - #[salsa::tracked] fn trait_signature(&self, trait_: TraitId) -> Arc<TraitSignature> { self.trait_signature_with_source_map(trait_).0 diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs index f617c3225ae..85bd193223f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs @@ -9,7 +9,10 @@ pub mod scope; #[cfg(test)] mod tests; -use std::ops::{Deref, Index}; +use std::{ + ops::{Deref, Index}, + sync::LazyLock, +}; use cfg::{CfgExpr, CfgOptions}; use either::Either; @@ -19,6 +22,7 @@ use rustc_hash::FxHashMap; use smallvec::SmallVec; use span::{Edition, SyntaxContext}; use syntax::{AstPtr, SyntaxNodePtr, ast}; +use triomphe::Arc; use tt::TextRange; use crate::{ @@ -220,6 +224,12 @@ impl ExpressionStoreBuilder { } impl ExpressionStore { + pub fn empty_singleton() -> Arc<Self> { + static EMPTY: LazyLock<Arc<ExpressionStore>> = + LazyLock::new(|| Arc::new(ExpressionStoreBuilder::default().finish())); + EMPTY.clone() + } + /// Returns an iterator over all block expressions in this store that define inner items. pub fn blocks<'a>( &'a self, @@ -636,6 +646,12 @@ impl Index<PathId> for ExpressionStore { // FIXME: Change `node_` prefix to something more reasonable. // Perhaps `expr_syntax` and `expr_id`? impl ExpressionStoreSourceMap { + pub fn empty_singleton() -> Arc<Self> { + static EMPTY: LazyLock<Arc<ExpressionStoreSourceMap>> = + LazyLock::new(|| Arc::new(ExpressionStoreSourceMap::default())); + EMPTY.clone() + } + pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> { match id { ExprOrPatId::ExprId(id) => self.expr_syntax(id), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index efa1374a446..c0e51b338b4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -2250,7 +2250,7 @@ impl ExprCollector<'_> { Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())), Some(ModuleDefId::EnumVariantId(variant)) // FIXME: This can cause a cycle if the user is writing invalid code - if self.db.variant_fields(variant.into()).shape != FieldsShape::Record => + if variant.fields(self.db).shape != FieldsShape::Record => { (None, Pat::Path(name.into())) } @@ -2825,14 +2825,7 @@ impl ExprCollector<'_> { let use_format_args_since_1_89_0 = fmt_args().is_some() && fmt_unsafe_arg().is_none(); let idx = if use_format_args_since_1_89_0 { - self.collect_format_args_impl( - syntax_ptr, - fmt, - hygiene, - argmap, - lit_pieces, - format_options, - ) + self.collect_format_args_impl(syntax_ptr, fmt, argmap, lit_pieces, format_options) } else { self.collect_format_args_before_1_89_0_impl( syntax_ptr, @@ -2962,7 +2955,6 @@ impl ExprCollector<'_> { &mut self, syntax_ptr: AstPtr<ast::Expr>, fmt: FormatArgs, - hygiene: HygieneId, argmap: FxIndexSet<(usize, ArgumentType)>, lit_pieces: ExprId, format_options: ExprId, @@ -2997,8 +2989,11 @@ impl ExprCollector<'_> { let args = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); let args_name = Name::new_symbol_root(sym::args); - let args_binding = - self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene); + let args_binding = self.alloc_binding( + args_name.clone(), + BindingAnnotation::Unannotated, + HygieneId::ROOT, + ); let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); self.add_definition_to_binding(args_binding, args_pat); // TODO: We don't have `super let` yet. @@ -3008,13 +3003,16 @@ impl ExprCollector<'_> { initializer: Some(args), else_branch: None, }; - (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(Path::from(args_name)))) + (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(args_name.into()))) } else { // Generate: // super let args = (&arg0, &arg1, &...); let args_name = Name::new_symbol_root(sym::args); - let args_binding = - self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene); + let args_binding = self.alloc_binding( + args_name.clone(), + BindingAnnotation::Unannotated, + HygieneId::ROOT, + ); let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); self.add_definition_to_binding(args_binding, args_pat); let elements = arguments @@ -3057,8 +3055,11 @@ impl ExprCollector<'_> { .collect(); let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args })); - let args_binding = - self.alloc_binding(args_name.clone(), BindingAnnotation::Unannotated, hygiene); + let args_binding = self.alloc_binding( + args_name.clone(), + BindingAnnotation::Unannotated, + HygieneId::ROOT, + ); let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None }); self.add_definition_to_binding(args_binding, args_pat); let let_stmt2 = Statement::Let { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs index 56c7655f9ea..87bcd33ed7b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs @@ -121,7 +121,7 @@ pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: E VariantId::UnionId(it) => format!("union {}", item_name(db, it, "<missing>")), }; - let fields = db.variant_fields(owner); + let fields = owner.fields(db); let mut p = Printer { db, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs index a9a0e36312c..94e683cb0f8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/generics.rs @@ -331,13 +331,13 @@ impl GenericParams { } #[inline] - pub fn no_predicates(&self) -> bool { + pub fn has_no_predicates(&self) -> bool { self.where_predicates.is_empty() } #[inline] - pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> { - self.where_predicates.iter() + pub fn where_predicates(&self) -> &[WherePredicate] { + &self.where_predicates } /// Iterator of type_or_consts field diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs index a6138fb6821..f31f355cfa5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs @@ -16,7 +16,7 @@ use crate::{ AssocItemId, AttrDefId, Complete, FxIndexMap, ModuleDefId, ModuleId, TraitId, db::DefDatabase, item_scope::{ImportOrExternCrate, ItemInNs}, - nameres::{DefMap, crate_def_map}, + nameres::{DefMap, assoc::TraitItems, crate_def_map}, visibility::Visibility, }; @@ -221,7 +221,7 @@ impl ImportMap { trait_import_info: &ImportInfo, ) { let _p = tracing::info_span!("collect_trait_assoc_items").entered(); - for &(ref assoc_item_name, item) in &db.trait_items(tr).items { + for &(ref assoc_item_name, item) in &TraitItems::query(db, tr).items { let module_def_id = match item { AssocItemId::FunctionId(f) => ModuleDefId::from(f), AssocItemId::ConstId(c) => ModuleDefId::from(c), @@ -482,7 +482,7 @@ mod tests { use expect_test::{Expect, expect}; use test_fixture::WithFixture; - use crate::{ItemContainerId, Lookup, test_db::TestDB}; + use crate::{ItemContainerId, Lookup, nameres::assoc::TraitItems, test_db::TestDB}; use super::*; @@ -580,7 +580,7 @@ mod tests { let trait_info = dependency_imports.import_info_for(ItemInNs::Types(trait_id.into()))?; - let trait_items = db.trait_items(trait_id); + let trait_items = TraitItems::query(db, trait_id); let (assoc_item_name, _) = trait_items .items .iter() diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index faff7d036a2..750308026ee 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -9,8 +9,10 @@ use triomphe::Arc; use crate::{ AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, ModuleDefId, - StaticId, StructId, TraitId, TypeAliasId, UnionId, db::DefDatabase, expr_store::path::Path, - nameres::crate_def_map, + StaticId, StructId, TraitId, TypeAliasId, UnionId, + db::DefDatabase, + expr_store::path::Path, + nameres::{assoc::TraitItems, crate_def_map}, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -113,14 +115,16 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt match def { ModuleDefId::TraitId(trait_) => { lang_items.collect_lang_item(db, trait_, LangItemTarget::Trait); - db.trait_items(trait_).items.iter().for_each(|&(_, assoc_id)| match assoc_id { - AssocItemId::FunctionId(f) => { - lang_items.collect_lang_item(db, f, LangItemTarget::Function); + TraitItems::query(db, trait_).items.iter().for_each(|&(_, assoc_id)| { + match assoc_id { + AssocItemId::FunctionId(f) => { + lang_items.collect_lang_item(db, f, LangItemTarget::Function); + } + AssocItemId::TypeAliasId(alias) => { + lang_items.collect_lang_item(db, alias, LangItemTarget::TypeAlias) + } + AssocItemId::ConstId(_) => {} } - AssocItemId::TypeAliasId(alias) => { - lang_items.collect_lang_item(db, alias, LangItemTarget::TypeAlias) - } - AssocItemId::ConstId(_) => {} }); } ModuleDefId::AdtId(AdtId::EnumId(e)) => { @@ -304,6 +308,8 @@ impl LangItem { language_item_table! { // Variant name, Name, Getter method name, Target Generic requirements; Sized, sym::sized, sized_trait, Target::Trait, GenericRequirement::Exact(0); + MetaSized, sym::meta_sized, sized_trait, Target::Trait, GenericRequirement::Exact(0); + PointeeSized, sym::pointee_sized, sized_trait, Target::Trait, GenericRequirement::Exact(0); Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1); /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ"). StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index a562f2d0af2..bdf8b453e2d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -87,9 +87,12 @@ use crate::{ attr::Attrs, builtin_type::BuiltinType, db::DefDatabase, + expr_store::ExpressionStoreSourceMap, hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId}, nameres::{ - LocalDefMap, assoc::ImplItems, block_def_map, crate_def_map, crate_local_def_map, + LocalDefMap, + assoc::{ImplItems, TraitItems}, + block_def_map, crate_def_map, crate_local_def_map, diagnostics::DefDiagnostics, }, signatures::{EnumVariants, InactiveEnumVariantCode, VariantFields}, @@ -252,9 +255,35 @@ impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); type StructLoc = ItemLoc<ast::Struct>; impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); +impl StructId { + pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { + VariantFields::firewall(db, self.into()) + } + + pub fn fields_with_source_map( + self, + db: &dyn DefDatabase, + ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>) { + VariantFields::query(db, self.into()) + } +} + pub type UnionLoc = ItemLoc<ast::Union>; impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); +impl UnionId { + pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { + VariantFields::firewall(db, self.into()) + } + + pub fn fields_with_source_map( + self, + db: &dyn DefDatabase, + ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>) { + VariantFields::query(db, self.into()) + } +} + pub type EnumLoc = ItemLoc<ast::Enum>; impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); @@ -282,6 +311,13 @@ impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); pub type TraitLoc = ItemLoc<ast::Trait>; impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); +impl TraitId { + #[inline] + pub fn trait_items(self, db: &dyn DefDatabase) -> &TraitItems { + TraitItems::query(db, self) + } +} + pub type TraitAliasLoc = ItemLoc<ast::TraitAlias>; impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias); @@ -328,6 +364,20 @@ pub struct EnumVariantLoc { } impl_intern!(EnumVariantId, EnumVariantLoc, intern_enum_variant, lookup_intern_enum_variant); impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId); + +impl EnumVariantId { + pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { + VariantFields::firewall(db, self.into()) + } + + pub fn fields_with_source_map( + self, + db: &dyn DefDatabase, + ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>) { + VariantFields::query(db, self.into()) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Macro2Loc { pub container: ModuleId, @@ -1015,8 +1065,15 @@ pub enum VariantId { impl_from!(EnumVariantId, StructId, UnionId for VariantId); impl VariantId { - pub fn variant_data(self, db: &dyn DefDatabase) -> Arc<VariantFields> { - db.variant_fields(self) + pub fn fields(self, db: &dyn DefDatabase) -> &VariantFields { + VariantFields::firewall(db, self) + } + + pub fn fields_with_source_map( + self, + db: &dyn DefDatabase, + ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>) { + VariantFields::query(db, self) } pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs index 7aaa918d1c9..07210df8873 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs @@ -38,16 +38,18 @@ pub struct TraitItems { pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>, } +#[salsa::tracked] impl TraitItems { #[inline] - pub(crate) fn trait_items_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitItems> { - db.trait_items_with_diagnostics(tr).0 + pub(crate) fn query(db: &dyn DefDatabase, tr: TraitId) -> &TraitItems { + &Self::query_with_diagnostics(db, tr).0 } - pub(crate) fn trait_items_with_diagnostics_query( + #[salsa::tracked(returns(ref))] + pub fn query_with_diagnostics( db: &dyn DefDatabase, tr: TraitId, - ) -> (Arc<TraitItems>, DefDiagnostics) { + ) -> (TraitItems, DefDiagnostics) { let ItemLoc { container: module_id, id: ast_id } = tr.lookup(db); let collector = @@ -55,7 +57,7 @@ impl TraitItems { let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db); let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list()); - (Arc::new(TraitItems { macro_calls, items }), DefDiagnostics::new(diagnostics)) + (TraitItems { macro_calls, items }, DefDiagnostics::new(diagnostics)) } pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 78fdc275606..0c3274d849a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -41,6 +41,7 @@ use crate::{ macro_call_as_call_id, nameres::{ BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode, + assoc::TraitItems, attr_resolution::{attr_macro_as_call_id, derive_macro_as_call_id}, crate_def_map, diagnostics::DefDiagnostic, @@ -1020,8 +1021,7 @@ impl<'db> DefCollector<'db> { let resolutions = if true { vec![] } else { - self.db - .trait_items(it) + TraitItems::query(self.db, it) .items .iter() .map(|&(ref name, variant)| { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index e8235b1c96f..4641b220daa 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -24,8 +24,8 @@ use crate::{ item_scope::{BUILTIN_SCOPE, ImportOrExternCrate}, item_tree::FieldsShape, nameres::{ - BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, crate_def_map, - sub_namespace_match, + BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, assoc::TraitItems, + crate_def_map, sub_namespace_match, }, per_ns::PerNs, visibility::{RawVisibility, Visibility}, @@ -584,8 +584,11 @@ impl DefMap { // now resulting in a cycle. // To properly implement this, trait item collection needs to be done in def map // collection... - let item = - if true { None } else { db.trait_items(t).assoc_item_by_name(segment) }; + let item = if true { + None + } else { + TraitItems::query(db, t).assoc_item_by_name(segment) + }; return match item { Some(item) => ResolvePathResult::new( match item { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index 377a545ebf4..1958eb6c6a1 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -1,6 +1,6 @@ //! Item signature IR definitions -use std::ops::Not as _; +use std::{cell::LazyCell, ops::Not as _}; use bitflags::bitflags; use cfg::{CfgExpr, CfgOptions}; @@ -731,29 +731,26 @@ pub struct VariantFields { pub store: Arc<ExpressionStore>, pub shape: FieldsShape, } + +#[salsa::tracked] impl VariantFields { - #[inline] + #[salsa::tracked(returns(clone))] pub(crate) fn query( db: &dyn DefDatabase, id: VariantId, ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { - let (shape, (fields, store, source_map)) = match id { + let (shape, result) = match id { VariantId::EnumVariantId(id) => { let loc = id.lookup(db); let parent = loc.parent.lookup(db); let source = loc.source(db); let shape = adt_shape(source.value.kind()); - let span_map = db.span_map(source.file_id); - let override_visibility = visibility_from_ast( - db, - source.value.parent_enum().visibility(), - &mut |range| span_map.span_for_range(range).ctx, - ); + let enum_vis = Some(source.value.parent_enum().visibility()); let fields = lower_field_list( db, parent.container, source.map(|src| src.field_list()), - Some(override_visibility), + enum_vis, ); (shape, fields) } @@ -777,10 +774,29 @@ impl VariantFields { (FieldsShape::Record, fields) } }; + match result { + Some((fields, store, source_map)) => ( + Arc::new(VariantFields { fields, store: Arc::new(store), shape }), + Arc::new(source_map), + ), + None => ( + Arc::new(VariantFields { + fields: Arena::default(), + store: ExpressionStore::empty_singleton(), + shape, + }), + ExpressionStoreSourceMap::empty_singleton(), + ), + } + } - (Arc::new(VariantFields { fields, store: Arc::new(store), shape }), Arc::new(source_map)) + #[salsa::tracked(returns(deref))] + pub(crate) fn firewall(db: &dyn DefDatabase, id: VariantId) -> Arc<Self> { + Self::query(db, id).0 } +} +impl VariantFields { pub fn len(&self) -> usize { self.fields.len() } @@ -798,31 +814,24 @@ fn lower_field_list( db: &dyn DefDatabase, module: ModuleId, fields: InFile<Option<ast::FieldList>>, - override_visibility: Option<RawVisibility>, -) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) { + override_visibility: Option<Option<ast::Visibility>>, +) -> Option<(Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap)> { let file_id = fields.file_id; - match fields.value { - Some(ast::FieldList::RecordFieldList(fields)) => lower_fields( + match fields.value? { + ast::FieldList::RecordFieldList(fields) => lower_fields( db, module, InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))), |_, field| as_name_opt(field.name()), override_visibility, ), - Some(ast::FieldList::TupleFieldList(fields)) => lower_fields( + ast::FieldList::TupleFieldList(fields) => lower_fields( db, module, InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))), |idx, _| Name::new_tuple_field(idx), override_visibility, ), - None => lower_fields( - db, - module, - InFile::new(file_id, std::iter::empty::<(Option<ast::Type>, ast::RecordField)>()), - |_, _| Name::missing(), - None, - ), } } @@ -831,22 +840,34 @@ fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>( module: ModuleId, fields: InFile<impl Iterator<Item = (Option<ast::Type>, Field)>>, mut field_name: impl FnMut(usize, &Field) -> Name, - override_visibility: Option<RawVisibility>, -) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) { - let mut arena = Arena::new(); + override_visibility: Option<Option<ast::Visibility>>, +) -> Option<(Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap)> { let cfg_options = module.krate.cfg_options(db); let mut col = ExprCollector::new(db, module, fields.file_id); + let override_visibility = override_visibility.map(|vis| { + LazyCell::new(|| { + let span_map = db.span_map(fields.file_id); + visibility_from_ast(db, vis, &mut |range| span_map.span_for_range(range).ctx) + }) + }); + + let mut arena = Arena::new(); let mut idx = 0; + let mut has_fields = false; for (ty, field) in fields.value { + has_fields = true; match Attrs::is_cfg_enabled_for(db, &field, col.span_map(), cfg_options) { Ok(()) => { let type_ref = col.lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator); - let visibility = override_visibility.clone().unwrap_or_else(|| { - visibility_from_ast(db, field.visibility(), &mut |range| { - col.span_map().span_for_range(range).ctx - }) - }); + let visibility = override_visibility.as_ref().map_or_else( + || { + visibility_from_ast(db, field.visibility(), &mut |range| { + col.span_map().span_for_range(range).ctx + }) + }, + |it| RawVisibility::clone(it), + ); let is_unsafe = field .syntax() .children_with_tokens() @@ -867,9 +888,12 @@ fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>( } } } + if !has_fields { + return None; + } let store = col.store.finish(); arena.shrink_to_fit(); - (arena, store, col.source_map) + Some((arena, store, col.source_map)) } #[derive(Debug, PartialEq, Eq)] @@ -948,7 +972,7 @@ impl EnumVariants { self.variants.iter().all(|&(v, _, _)| { // The condition check order is slightly modified from rustc // to improve performance by early returning with relatively fast checks - let variant = &db.variant_fields(v.into()); + let variant = v.fields(db); if !variant.fields().is_empty() { return false; } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index 2514e88864f..b5eb84c25f2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -273,7 +273,7 @@ pub(crate) fn field_visibilities_query( db: &dyn DefDatabase, variant_id: VariantId, ) -> Arc<ArenaMap<LocalFieldId, Visibility>> { - let variant_fields = db.variant_fields(variant_id); + let variant_fields = variant_id.fields(db); let fields = variant_fields.fields(); if fields.is_empty() { return Arc::default(); diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml index ed818c5be3f..80a3c084865 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] cov-mark = "2.0.0" diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 94c97713f06..986f8764f5c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -433,20 +433,19 @@ fn unescape(s: &str) -> Option<Cow<'_, str>> { let mut buf = String::new(); let mut prev_end = 0; let mut has_error = false; - unescape::unescape_unicode(s, unescape::Mode::Str, &mut |char_range, unescaped_char| match ( - unescaped_char, - buf.capacity() == 0, - ) { - (Ok(c), false) => buf.push(c), - (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { - prev_end = char_range.end - } - (Ok(c), true) => { - buf.reserve_exact(s.len()); - buf.push_str(&s[..prev_end]); - buf.push(c); + unescape::unescape_str(s, |char_range, unescaped_char| { + match (unescaped_char, buf.capacity() == 0) { + (Ok(c), false) => buf.push(c), + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { + prev_end = char_range.end + } + (Ok(c), true) => { + buf.reserve_exact(s.len()); + buf.push_str(&s[..prev_end]); + buf.push(c); + } + (Err(_), _) => has_error = true, } - (Err(_), _) => has_error = true, }); match (has_error, buf.capacity() == 0) { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index 3180b8dae10..f9abe4f5566 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -12,7 +12,7 @@ use span::{Edition, FileId, Span}; use stdx::format_to; use syntax::{ format_smolstr, - unescape::{Mode, unescape_byte, unescape_char, unescape_unicode}, + unescape::{unescape_byte, unescape_char, unescape_str}, }; use syntax_bridge::syntax_node_to_token_tree; @@ -430,7 +430,7 @@ fn compile_error_expand( kind: tt::LitKind::Str | tt::LitKind::StrRaw(_), suffix: _, })), - ] => ExpandError::other(span, Box::from(unescape_str(text).as_str())), + ] => ExpandError::other(span, Box::from(unescape_symbol(text).as_str())), _ => ExpandError::other(span, "`compile_error!` argument must be a string"), }; @@ -481,7 +481,7 @@ fn concat_expand( format_to!(text, "{}", it.symbol.as_str()) } tt::LitKind::Str => { - text.push_str(unescape_str(&it.symbol).as_str()); + text.push_str(unescape_symbol(&it.symbol).as_str()); record_span(it.span); } tt::LitKind::StrRaw(_) => { @@ -691,7 +691,7 @@ fn parse_string(tt: &tt::TopSubtree) -> Result<(Symbol, Span), ExpandError> { span, kind: tt::LitKind::Str, suffix: _, - })) => Ok((unescape_str(text), *span)), + })) => Ok((unescape_symbol(text), *span)), TtElement::Leaf(tt::Leaf::Literal(tt::Literal { symbol: text, span, @@ -712,7 +712,7 @@ fn parse_string(tt: &tt::TopSubtree) -> Result<(Symbol, Span), ExpandError> { span, kind: tt::LitKind::Str, suffix: _, - })) => Some((unescape_str(text), *span)), + })) => Some((unescape_symbol(text), *span)), TtElement::Leaf(tt::Leaf::Literal(tt::Literal { symbol: text, span, @@ -897,11 +897,11 @@ fn quote_expand( ) } -fn unescape_str(s: &Symbol) -> Symbol { +fn unescape_symbol(s: &Symbol) -> Symbol { if s.as_str().contains('\\') { let s = s.as_str(); let mut buf = String::with_capacity(s.len()); - unescape_unicode(s, Mode::Str, &mut |_, c| { + unescape_str(s, |_, c| { if let Ok(c) = c { buf.push(c) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 8b65126e7b7..7cc0a26d37c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] cov-mark = "2.0.0" diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index 7acc9456ec9..cc8f7bf04a5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -208,7 +208,7 @@ pub(crate) fn deref_by_trait( }; let trait_id = trait_id()?; let target = - db.trait_items(trait_id).associated_type_by_name(&Name::new_symbol_root(sym::Target))?; + trait_id.trait_items(db).associated_type_by_name(&Name::new_symbol_root(sym::Target))?; let projection = { let b = TyBuilder::subst_for_def(db, trait_id, None); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 79454428112..26b635298a6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -315,9 +315,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> { crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => { if let Some((future_trait, future_output)) = LangItem::Future.resolve_trait(self.db, self.krate).and_then(|trait_| { - let alias = self - .db - .trait_items(trait_) + let alias = trait_ + .trait_items(self.db) .associated_type_by_name(&Name::new_symbol_root(sym::Output))?; Some((trait_, alias)) }) @@ -711,7 +710,7 @@ pub(crate) fn trait_datum_query( }; let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); let associated_ty_ids = - db.trait_items(trait_).associated_types().map(to_assoc_type_id).collect(); + trait_.trait_items(db).associated_types().map(to_assoc_type_id).collect(); let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses }; let well_known = db.lang_attr(trait_.into()).and_then(well_known_trait_from_lang_item); let trait_datum = TraitDatum { @@ -802,7 +801,7 @@ pub(crate) fn adt_datum_query( // this slows down rust-analyzer by quite a bit unfortunately, so enabling this is currently not worth it let _variant_id_to_fields = |id: VariantId| { - let variant_data = &id.variant_data(db); + let variant_data = &id.fields(db); let fields = if variant_data.fields().is_empty() { vec![] } else { @@ -879,7 +878,7 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId) let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive }; let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses }; - let trait_data = db.trait_items(trait_); + let trait_data = trait_.trait_items(db); let associated_ty_value_ids = impl_id .impl_items(db) .items @@ -931,8 +930,9 @@ fn type_alias_associated_ty_value( .into_value_and_skipped_binders() .0; // we don't return any assoc ty values if the impl'd trait can't be resolved - let assoc_ty = db - .trait_items(trait_ref.hir_trait_id()) + let assoc_ty = trait_ref + .hir_trait_id() + .trait_items(db) .associated_type_by_name(&type_alias_data.name) .expect("assoc ty value should not exist"); // validated when building the impl data as well let (ty, binders) = db.ty(type_alias.into()).into_value_and_skipped_binders(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index 1873f12fb7c..9c0f8f40080 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -307,7 +307,7 @@ impl<'a> DeclValidator<'a> { /// Check incorrect names for struct fields. fn validate_struct_fields(&mut self, struct_id: StructId) { - let data = self.db.variant_fields(struct_id.into()); + let data = struct_id.fields(self.db); if data.shape != FieldsShape::Record { return; }; @@ -468,7 +468,7 @@ impl<'a> DeclValidator<'a> { /// Check incorrect names for fields of enum variant. fn validate_enum_variant_fields(&mut self, variant_id: EnumVariantId) { - let variant_data = self.db.variant_fields(variant_id.into()); + let variant_data = variant_id.fields(self.db); if variant_data.shape != FieldsShape::Record { return; }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index df2eb410b99..5d56957be6d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -494,7 +494,7 @@ impl FilterMapNextChecker { Some(next_function_id), match next_function_id.lookup(db).container { ItemContainerId::TraitId(iterator_trait_id) => { - let iterator_trait_items = &db.trait_items(iterator_trait_id).items; + let iterator_trait_items = &iterator_trait_id.trait_items(db).items; iterator_trait_items.iter().find_map(|(name, it)| match it { &AssocItemId::FunctionId(id) if *name == sym::filter_map => Some(id), _ => None, @@ -558,7 +558,7 @@ pub fn record_literal_missing_fields( return None; } - let variant_data = variant_def.variant_data(db); + let variant_data = variant_def.fields(db); let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); let missed_fields: Vec<LocalFieldId> = variant_data @@ -588,7 +588,7 @@ pub fn record_pattern_missing_fields( return None; } - let variant_data = variant_def.variant_data(db); + let variant_data = variant_def.fields(db); let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); let missed_fields: Vec<LocalFieldId> = variant_data diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs index 916876d4ac9..0bce32a6778 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs @@ -169,13 +169,13 @@ impl<'a> PatCtxt<'a> { } hir_def::hir::Pat::TupleStruct { ref args, ellipsis, .. } if variant.is_some() => { - let expected_len = variant.unwrap().variant_data(self.db).fields().len(); + let expected_len = variant.unwrap().fields(self.db).fields().len(); let subpatterns = self.lower_tuple_subpats(args, expected_len, ellipsis); self.lower_variant_or_leaf(pat, ty, subpatterns) } hir_def::hir::Pat::Record { ref args, .. } if variant.is_some() => { - let variant_data = variant.unwrap().variant_data(self.db); + let variant_data = variant.unwrap().fields(self.db); let subpatterns = args .iter() .map(|field| { @@ -345,7 +345,7 @@ impl HirDisplay for Pat { )?, }; - let variant_data = variant.variant_data(f.db); + let variant_data = variant.fields(f.db); if variant_data.shape == FieldsShape::Record { write!(f, " {{ ")?; @@ -377,7 +377,7 @@ impl HirDisplay for Pat { } let num_fields = - variant.map_or(subpatterns.len(), |v| v.variant_data(f.db).fields().len()); + variant.map_or(subpatterns.len(), |v| v.fields(f.db).fields().len()); if num_fields != 0 || variant.is_none() { write!(f, "(")?; let subpats = (0..num_fields).map(|i| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 2873a3e09e7..7cf22c64d0f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -6,7 +6,7 @@ use std::fmt; use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId}; use intern::sym; use rustc_pattern_analysis::{ - Captures, IndexVec, PatCx, PrivateUninhabitedField, + IndexVec, PatCx, PrivateUninhabitedField, constructor::{Constructor, ConstructorSet, VariantVisibility}, usefulness::{PlaceValidity, UsefulnessReport, compute_match_usefulness}, }; @@ -138,15 +138,15 @@ impl<'db> MatchCheckCtx<'db> { } // This lists the fields of a variant along with their types. - fn list_variant_fields<'a>( - &'a self, - ty: &'a Ty, + fn list_variant_fields( + &self, + ty: &Ty, variant: VariantId, - ) -> impl Iterator<Item = (LocalFieldId, Ty)> + Captures<'a> + Captures<'db> { + ) -> impl Iterator<Item = (LocalFieldId, Ty)> { let (_, substs) = ty.as_adt().unwrap(); let field_tys = self.db.field_types(variant); - let fields_len = variant.variant_data(self.db).fields().len() as u32; + let fields_len = variant.fields(self.db).fields().len() as u32; (0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).map(move |fid| { let ty = field_tys[fid].clone().substitute(Interner, substs); @@ -229,7 +229,7 @@ impl<'db> MatchCheckCtx<'db> { } }; let variant = Self::variant_id_for_adt(self.db, &ctor, adt).unwrap(); - arity = variant.variant_data(self.db).fields().len(); + arity = variant.fields(self.db).fields().len(); } _ => { never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty); @@ -349,7 +349,7 @@ impl PatCx for MatchCheckCtx<'_> { 1 } else { let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap(); - variant.variant_data(self.db).fields().len() + variant.fields(self.db).fields().len() } } _ => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 1aa7e0fcf88..507bab29208 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -888,7 +888,7 @@ fn render_const_scalar( write!(f, "{}", data.name.display(f.db, f.edition()))?; let field_types = f.db.field_types(s.into()); render_variant_after_name( - &f.db.variant_fields(s.into()), + s.fields(f.db), f, &field_types, f.db.trait_environment(adt.0.into()), @@ -920,7 +920,7 @@ fn render_const_scalar( )?; let field_types = f.db.field_types(var_id.into()); render_variant_after_name( - &f.db.variant_fields(var_id.into()), + var_id.fields(f.db), f, &field_types, f.db.trait_environment(adt.0.into()), @@ -1394,7 +1394,7 @@ impl HirDisplay for Ty { let future_trait = LangItem::Future.resolve_trait(db, body.module(db).krate()); let output = future_trait.and_then(|t| { - db.trait_items(t) + t.trait_items(db) .associated_type_by_name(&Name::new_symbol_root(sym::Output)) }); write!(f, "impl ")?; @@ -2178,6 +2178,7 @@ impl HirDisplayWithExpressionStore for TypeRefId { f.write_joined( generic_params .where_predicates() + .iter() .filter_map(|it| match it { WherePredicate::TypeBound { target, bound } | WherePredicate::ForLifetime { lifetimes: _, target, bound } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 48094945c11..30949c83bfa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -101,7 +101,7 @@ where // rustc checks for non-lifetime binders here, but we don't support HRTB yet - let trait_data = db.trait_items(trait_); + let trait_data = trait_.trait_items(db); for (_, assoc_item) in &trait_data.items { dyn_compatibility_violation_for_assoc_item(db, trait_, *assoc_item, cb)?; } @@ -164,7 +164,7 @@ fn predicates_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool { // Same as the above, `predicates_reference_self` fn bounds_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool { - let trait_data = db.trait_items(trait_); + let trait_data = trait_.trait_items(db); trait_data .items .iter() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index a3ed39934cd..f14872e68c3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -60,7 +60,16 @@ impl Generics { } pub(crate) fn where_predicates(&self) -> impl Iterator<Item = &WherePredicate> { - self.params.where_predicates() + self.params.where_predicates().iter() + } + + pub(crate) fn has_no_predicates(&self) -> bool { + self.params.has_no_predicates() + && self.parent_generics.as_ref().is_none_or(|g| g.params.has_no_predicates()) + } + + pub(crate) fn is_empty(&self) -> bool { + self.params.is_empty() && self.parent_generics.as_ref().is_none_or(|g| g.params.is_empty()) } pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 80478f19371..ce53198e966 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -1813,7 +1813,7 @@ impl<'db> InferenceContext<'db> { } fn resolve_output_on(&self, trait_: TraitId) -> Option<TypeAliasId> { - self.db.trait_items(trait_).associated_type_by_name(&Name::new_symbol_root(sym::Output)) + trait_.trait_items(self.db).associated_type_by_name(&Name::new_symbol_root(sym::Output)) } fn resolve_lang_trait(&self, lang: LangItem) -> Option<TraitId> { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs index 8d345defdc1..4e95eca3f94 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs @@ -382,7 +382,7 @@ fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<Pointe return Err(()); }; - let struct_data = table.db.variant_fields(id.into()); + let struct_data = id.fields(table.db); if let Some((last_field, _)) = struct_data.fields().iter().last() { let last_field_ty = table.db.field_types(id.into())[last_field].clone().substitute(Interner, subst); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index b756bb859d3..65a273cdf8d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -677,7 +677,7 @@ impl CapturedItem { match proj { ProjectionElem::Deref => {} ProjectionElem::Field(Either::Left(f)) => { - let variant_data = f.parent.variant_data(db); + let variant_data = f.parent.fields(db); match variant_data.shape { FieldsShape::Record => { result.push('_'); @@ -720,7 +720,7 @@ impl CapturedItem { // In source code autoderef kicks in. ProjectionElem::Deref => {} ProjectionElem::Field(Either::Left(f)) => { - let variant_data = f.parent.variant_data(db); + let variant_data = f.parent.fields(db); match variant_data.shape { FieldsShape::Record => format_to!( result, @@ -782,7 +782,7 @@ impl CapturedItem { if field_need_paren { result = format!("({result})"); } - let variant_data = f.parent.variant_data(db); + let variant_data = f.parent.fields(db); let field = match variant_data.shape { FieldsShape::Record => { variant_data.fields()[f.local_id].name.as_str().to_owned() @@ -1210,9 +1210,8 @@ impl InferenceContext<'_> { if let Some(deref_trait) = self.resolve_lang_item(LangItem::DerefMut).and_then(|it| it.as_trait()) { - if let Some(deref_fn) = self - .db - .trait_items(deref_trait) + if let Some(deref_fn) = deref_trait + .trait_items(self.db) .method_by_name(&Name::new_symbol_root(sym::deref_mut)) { break 'b deref_fn == f; @@ -1560,7 +1559,7 @@ impl InferenceContext<'_> { self.consume_place(place) } VariantId::StructId(s) => { - let vd = &*self.db.variant_fields(s.into()); + let vd = s.fields(self.db); for field_pat in args.iter() { let arg = field_pat.pat; let Some(local_id) = vd.field(&field_pat.name) else { @@ -1612,7 +1611,7 @@ impl InferenceContext<'_> { self.consume_place(place) } VariantId::StructId(s) => { - let vd = &*self.db.variant_fields(s.into()); + let vd = s.fields(self.db); let (al, ar) = args.split_at(ellipsis.map_or(args.len(), |it| it as usize)); let fields = vd.fields().iter(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 64031279296..d40d52c134d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -542,7 +542,7 @@ impl InferenceContext<'_> { _ if fields.is_empty() => {} Some(def) => { let field_types = self.db.field_types(def); - let variant_data = def.variant_data(self.db); + let variant_data = def.fields(self.db); let visibilities = self.db.field_visibilities(def); for field in fields.iter() { let field_def = { @@ -654,9 +654,8 @@ impl InferenceContext<'_> { match op { UnaryOp::Deref => { if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) { - if let Some(deref_fn) = self - .db - .trait_items(deref_trait) + if let Some(deref_fn) = deref_trait + .trait_items(self.db) .method_by_name(&Name::new_symbol_root(sym::deref)) { // FIXME: this is wrong in multiple ways, subst is empty, and we emit it even for builtin deref (note that @@ -813,9 +812,8 @@ impl InferenceContext<'_> { self.table.new_lifetime_var(), )); self.write_expr_adj(*base, adj.into_boxed_slice()); - if let Some(func) = self - .db - .trait_items(index_trait) + if let Some(func) = index_trait + .trait_items(self.db) .method_by_name(&Name::new_symbol_root(sym::index)) { let subst = TyBuilder::subst_for_def(self.db, index_trait, None); @@ -1148,7 +1146,7 @@ impl InferenceContext<'_> { let Some(trait_) = fn_x.get_id(self.db, self.table.trait_env.krate) else { return; }; - let trait_data = self.db.trait_items(trait_); + let trait_data = trait_.trait_items(self.db); if let Some(func) = trait_data.method_by_name(&fn_x.method_name()) { let subst = TyBuilder::subst_for_def(self.db, trait_, None) .push(callee_ty.clone()) @@ -1316,7 +1314,7 @@ impl InferenceContext<'_> { let trait_func = lang_items_for_bin_op(op).and_then(|(name, lang_item)| { let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?; - let func = self.db.trait_items(trait_id).method_by_name(&name)?; + let func = trait_id.trait_items(self.db).method_by_name(&name)?; Some((trait_id, func)) }); let (trait_, func) = match trait_func { @@ -1568,12 +1566,12 @@ impl InferenceContext<'_> { }); } &TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), ref parameters) => { - let local_id = self.db.variant_fields(s.into()).field(name)?; + let local_id = s.fields(self.db).field(name)?; let field = FieldId { parent: s.into(), local_id }; (field, parameters.clone()) } &TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), ref parameters) => { - let local_id = self.db.variant_fields(u.into()).field(name)?; + let local_id = u.fields(self.db).field(name)?; let field = FieldId { parent: u.into(), local_id }; (field, parameters.clone()) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index ac450c0b559..d2eaf212365 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -129,9 +129,8 @@ impl InferenceContext<'_> { if let Some(index_trait) = LangItem::IndexMut.resolve_trait(self.db, self.table.trait_env.krate) { - if let Some(index_fn) = self - .db - .trait_items(index_trait) + if let Some(index_fn) = index_trait + .trait_items(self.db) .method_by_name(&Name::new_symbol_root(sym::index_mut)) { *f = index_fn; @@ -194,9 +193,8 @@ impl InferenceContext<'_> { }); if is_mut_ptr { mutability = Mutability::Not; - } else if let Some(deref_fn) = self - .db - .trait_items(deref_trait) + } else if let Some(deref_fn) = deref_trait + .trait_items(self.db) .method_by_name(&Name::new_symbol_root(sym::deref_mut)) { *f = deref_fn; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 4bc3e167ebf..99d3b5c7a84 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -38,7 +38,7 @@ impl InferenceContext<'_> { decl: Option<DeclContext>, ) -> Ty { let (ty, def) = self.resolve_variant(id.into(), path, true); - let var_data = def.map(|it| it.variant_data(self.db)); + let var_data = def.map(|it| it.fields(self.db)); if let Some(variant) = def { self.write_variant_resolution(id.into(), variant); } @@ -60,7 +60,7 @@ impl InferenceContext<'_> { _ if subs.is_empty() => {} Some(def) => { let field_types = self.db.field_types(def); - let variant_data = def.variant_data(self.db); + let variant_data = def.fields(self.db); let visibilities = self.db.field_visibilities(def); let (pre, post) = match ellipsis { @@ -129,7 +129,7 @@ impl InferenceContext<'_> { _ if subs.len() == 0 => {} Some(def) => { let field_types = self.db.field_types(def); - let variant_data = def.variant_data(self.db); + let variant_data = def.fields(self.db); let visibilities = self.db.field_visibilities(def); let substs = ty.as_adt().map(TupleExt::tail); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index c327c13b664..bc8648ecdd9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -278,7 +278,7 @@ impl InferenceContext<'_> { ) -> Option<(ValueNs, Substitution)> { let trait_ = trait_ref.hir_trait_id(); let item = - self.db.trait_items(trait_).items.iter().map(|(_name, id)| *id).find_map(|item| { + trait_.trait_items(self.db).items.iter().map(|(_name, id)| *id).find_map(|item| { match item { AssocItemId::FunctionId(func) => { if segment.name == &self.db.function_signature(func).name { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 631b571465f..c07755535f2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -859,7 +859,7 @@ impl<'a> InferenceTable<'a> { ] { let krate = self.trait_env.krate; let fn_trait = fn_trait_name.get_id(self.db, krate)?; - let trait_data = self.db.trait_items(fn_trait); + let trait_data = fn_trait.trait_items(self.db); let output_assoc_type = trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?; @@ -1001,7 +1001,7 @@ impl<'a> InferenceTable<'a> { // Must use a loop here and not recursion because otherwise users will conduct completely // artificial examples of structs that have themselves as the tail field and complain r-a crashes. while let Some((AdtId::StructId(id), subst)) = ty.as_adt() { - let struct_data = self.db.variant_fields(id.into()); + let struct_data = id.fields(self.db); if let Some((last_field, _)) = struct_data.fields().iter().next_back() { let last_field_ty = self.db.field_types(id.into())[last_field] .clone() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs index 79a99321f10..b16b6a11784 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -132,7 +132,7 @@ impl UninhabitedFrom<'_> { variant: VariantId, subst: &Substitution, ) -> ControlFlow<VisiblyUninhabited> { - let variant_data = self.db.variant_fields(variant); + let variant_data = variant.fields(self.db); let fields = variant_data.fields(); if fields.is_empty() { return CONTINUE_OPAQUELY_INHABITED; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index c58bd1b773e..3fa2bfbd1b7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -375,7 +375,7 @@ pub(crate) fn layout_of_ty_cycle_result( fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty { match pointee.kind(Interner) { &TyKind::Adt(AdtId(hir_def::AdtId::StructId(i)), ref subst) => { - let data = db.variant_fields(i.into()); + let data = i.fields(db); let mut it = data.fields().iter().rev(); match it.next() { Some((f, _)) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs index dff986fec3c..236f316366d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs @@ -42,7 +42,7 @@ pub fn layout_of_adt_query( AdtId::StructId(s) => { let sig = db.struct_signature(s); let mut r = SmallVec::<[_; 1]>::new(); - r.push(handle_variant(s.into(), &db.variant_fields(s.into()))?); + r.push(handle_variant(s.into(), s.fields(db))?); ( r, sig.repr.unwrap_or_default(), @@ -52,7 +52,7 @@ pub fn layout_of_adt_query( AdtId::UnionId(id) => { let data = db.union_signature(id); let mut r = SmallVec::new(); - r.push(handle_variant(id.into(), &db.variant_fields(id.into()))?); + r.push(handle_variant(id.into(), id.fields(db))?); (r, data.repr.unwrap_or_default(), false) } AdtId::EnumId(e) => { @@ -60,7 +60,7 @@ pub fn layout_of_adt_query( let r = variants .variants .iter() - .map(|&(v, _, _)| handle_variant(v.into(), &db.variant_fields(v.into()))) + .map(|&(v, _, _)| handle_variant(v.into(), v.fields(db))) .collect::<Result<SmallVec<_>, _>>()?; (r, db.enum_signature(e).repr.unwrap_or_default(), false) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 148f2a41e7d..e787fd9b1e5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -891,8 +891,8 @@ pub fn callable_sig_from_fn_trait( ) -> Option<(FnTrait, CallableSig)> { let krate = trait_env.krate; let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; - let output_assoc_type = db - .trait_items(fn_once_trait) + let output_assoc_type = fn_once_trait + .trait_items(db) .associated_type_by_name(&Name::new_symbol_root(sym::Output))?; let mut table = InferenceTable::new(db, trait_env.clone()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 0a546768dab..f32b6af4d85 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -581,11 +581,28 @@ impl<'a> TyLoweringContext<'a> { match bound { &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => { // FIXME Don't silently drop the hrtb lifetimes here - if let Some((trait_ref, ctx)) = self.lower_trait_ref_from_path(path, self_ty) { - if !ignore_bindings { - assoc_bounds = ctx.assoc_type_bindings_from_type_bound(trait_ref.clone()); + if let Some((trait_ref, mut ctx)) = + self.lower_trait_ref_from_path(path, self_ty.clone()) + { + // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented + // sized-hierarchy correctly. + let meta_sized = LangItem::MetaSized + .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate()); + let pointee_sized = LangItem::PointeeSized + .resolve_trait(ctx.ty_ctx().db, ctx.ty_ctx().resolver.krate()); + if meta_sized.is_some_and(|it| it == trait_ref.hir_trait_id()) { + // Ignore this bound + } else if pointee_sized.is_some_and(|it| it == trait_ref.hir_trait_id()) { + // Regard this as `?Sized` bound + ctx.ty_ctx().unsized_types.insert(self_ty); + } else { + if !ignore_bindings { + assoc_bounds = + ctx.assoc_type_bindings_from_type_bound(trait_ref.clone()); + } + clause = + Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref))); } - clause = Some(crate::wrap_empty_binders(WhereClause::Implemented(trait_ref))); } } &TypeBound::Path(path, TraitBoundModifier::Maybe) => { @@ -711,7 +728,7 @@ impl<'a> TyLoweringContext<'a> { .unwrap_or(it), None => it, }, - None => static_lifetime(), + None => error_lifetime(), }, }) .intern(Interner) @@ -805,7 +822,7 @@ fn named_associated_type_shorthand_candidates<R>( ) -> Option<R> { let mut search = |t| { all_super_trait_refs(db, t, |t| { - let data = db.trait_items(t.hir_trait_id()); + let data = t.hir_trait_id().trait_items(db); for (name, assoc_id) in &data.items { if let AssocItemId::TypeAliasId(alias) = assoc_id { @@ -883,7 +900,12 @@ pub(crate) fn field_types_with_diagnostics_query( db: &dyn HirDatabase, variant_id: VariantId, ) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics) { - let var_data = db.variant_fields(variant_id); + let var_data = variant_id.fields(db); + let fields = var_data.fields(); + if fields.is_empty() { + return (Arc::new(ArenaMap::default()), None); + } + let (resolver, def): (_, GenericDefId) = match variant_id { VariantId::StructId(it) => (it.resolver(db), it.into()), VariantId::UnionId(it) => (it.resolver(db), it.into()), @@ -899,7 +921,7 @@ pub(crate) fn field_types_with_diagnostics_query( LifetimeElisionKind::AnonymousReportError, ) .with_type_param_mode(ParamLoweringMode::Variable); - for (field_id, field_data) in var_data.fields().iter() { + for (field_id, field_data) in fields.iter() { res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref))); } (Arc::new(res), create_diagnostics(ctx.diagnostics)) @@ -920,6 +942,10 @@ pub(crate) fn generic_predicates_for_param_query( assoc_name: Option<Name>, ) -> GenericPredicates { let generics = generics(db, def); + if generics.has_no_predicates() && generics.is_empty() { + return GenericPredicates(None); + } + let resolver = def.resolver(db); let mut ctx = TyLoweringContext::new( db, @@ -936,8 +962,32 @@ pub(crate) fn generic_predicates_for_param_query( | WherePredicate::TypeBound { target, bound, .. } => { let invalid_target = { ctx.lower_ty_only_param(*target) != Some(param_id) }; if invalid_target { - // If this is filtered out without lowering, `?Sized` is not gathered into `ctx.unsized_types` - if let TypeBound::Path(_, TraitBoundModifier::Maybe) = bound { + // FIXME(sized-hierarchy): Revisit and adjust this properly once we have implemented + // sized-hierarchy correctly. + // If this is filtered out without lowering, `?Sized` or `PointeeSized` is not gathered into + // `ctx.unsized_types` + let lower = || -> bool { + match bound { + TypeBound::Path(_, TraitBoundModifier::Maybe) => true, + TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { + let TypeRef::Path(path) = &ctx.store[path.type_ref()] else { + return false; + }; + let Some(pointee_sized) = + LangItem::PointeeSized.resolve_trait(ctx.db, ctx.resolver.krate()) + else { + return false; + }; + // Lower the path directly with `Resolver` instead of PathLoweringContext` + // to prevent diagnostics duplications. + ctx.resolver.resolve_path_in_type_ns_fully(ctx.db, path).is_some_and( + |it| matches!(it, TypeNs::TraitId(tr) if tr == pointee_sized), + ) + } + _ => false, + } + }(); + if lower { ctx.lower_where_predicate(pred, true).for_each(drop); } return false; @@ -957,7 +1007,7 @@ pub(crate) fn generic_predicates_for_param_query( }; all_super_traits(db, tr).iter().any(|tr| { - db.trait_items(*tr).items.iter().any(|(name, item)| { + tr.trait_items(db).items.iter().any(|(name, item)| { matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name }) }) @@ -1025,6 +1075,10 @@ pub(crate) fn trait_environment_query( def: GenericDefId, ) -> Arc<TraitEnvironment> { let generics = generics(db, def); + if generics.has_no_predicates() && generics.is_empty() { + return TraitEnvironment::empty(def.krate(db)); + } + let resolver = def.resolver(db); let mut ctx = TyLoweringContext::new( db, @@ -1128,6 +1182,10 @@ where F: Fn(&WherePredicate, GenericDefId) -> bool, { let generics = generics(db, def); + if generics.has_no_predicates() && generics.is_empty() { + return (GenericPredicates(None), None); + } + let resolver = def.resolver(db); let mut ctx = TyLoweringContext::new( db, @@ -1154,7 +1212,7 @@ where } } - if generics.len() > 0 { + if !generics.is_empty() { let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); let explicitly_unsized_tys = ctx.unsized_types; if let Some(implicitly_sized_predicates) = @@ -1229,7 +1287,7 @@ pub(crate) fn generic_defaults_with_diagnostics_query( def: GenericDefId, ) -> (GenericDefaults, Diagnostics) { let generic_params = generics(db, def); - if generic_params.len() == 0 { + if generic_params.is_empty() { return (GenericDefaults(None), None); } let resolver = def.resolver(db); @@ -1418,7 +1476,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS /// Build the type of a tuple struct constructor. fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Option<Binders<Ty>> { - let struct_data = db.variant_fields(def.into()); + let struct_data = def.fields(db); match struct_data.shape { FieldsShape::Record => None, FieldsShape::Unit => Some(type_for_adt(db, def.into())), @@ -1451,7 +1509,7 @@ fn type_for_enum_variant_constructor( def: EnumVariantId, ) -> Option<Binders<Ty>> { let e = def.lookup(db).parent; - match db.variant_fields(def.into()).shape { + match def.fields(db).shape { FieldsShape::Record => None, FieldsShape::Unit => Some(type_for_adt(db, e.into())), FieldsShape::Tuple => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index 726eaf8b0a1..06686b6a164 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -173,7 +173,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> { self.skip_resolved_segment(); let segment = self.current_or_prev_segment; let found = - self.ctx.db.trait_items(trait_).associated_type_by_name(segment.name); + trait_.trait_items(self.ctx.db).associated_type_by_name(segment.name); match found { Some(associated_ty) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 25f1782bdd8..a6150a9bc17 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -1302,7 +1302,7 @@ fn iterate_trait_method_candidates( // trait, but if we find out it doesn't, we'll skip the rest of the // iteration let mut known_implemented = false; - for &(_, item) in db.trait_items(t).items.iter() { + for &(_, item) in t.trait_items(db).items.iter() { // Don't pass a `visible_from_module` down to `is_valid_candidate`, // since only inherent methods should be included into visibility checking. let visible = @@ -1429,7 +1429,7 @@ fn iterate_inherent_methods( ) -> ControlFlow<()> { let db = table.db; for t in traits { - let data = db.trait_items(t); + let data = t.trait_items(db); for &(_, item) in data.items.iter() { // We don't pass `visible_from_module` as all trait items should be visible. let visible = match is_valid_trait_method_candidate( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index a8156ec375b..1ec55a82092 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -657,12 +657,12 @@ impl Evaluator<'_> { cached_ptr_size, cached_fn_trait_func: LangItem::Fn .resolve_trait(db, crate_id) - .and_then(|x| db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call))), + .and_then(|x| x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call))), cached_fn_mut_trait_func: LangItem::FnMut.resolve_trait(db, crate_id).and_then(|x| { - db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_mut)) + x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call_mut)) }), cached_fn_once_trait_func: LangItem::FnOnce.resolve_trait(db, crate_id).and_then(|x| { - db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_once)) + x.trait_items(db).method_by_name(&Name::new_symbol_root(sym::call_once)) }), }) } @@ -1749,8 +1749,7 @@ impl Evaluator<'_> { AdtId::UnionId(_) => not_supported!("unsizing unions"), AdtId::EnumId(_) => not_supported!("unsizing enums"), }; - let Some((last_field, _)) = - self.db.variant_fields(id.into()).fields().iter().next_back() + let Some((last_field, _)) = id.fields(self.db).fields().iter().next_back() else { not_supported!("unsizing struct without field"); }; @@ -2232,7 +2231,7 @@ impl Evaluator<'_> { } chalk_ir::TyKind::Adt(adt, subst) => match adt.0 { AdtId::StructId(s) => { - let data = this.db.variant_fields(s.into()); + let data = s.fields(this.db); let layout = this.layout(ty)?; let field_types = this.db.field_types(s.into()); for (f, _) in data.fields().iter() { @@ -2261,7 +2260,7 @@ impl Evaluator<'_> { bytes, e, ) { - let data = &this.db.variant_fields(v.into()); + let data = v.fields(this.db); let field_types = this.db.field_types(v.into()); for (f, _) in data.fields().iter() { let offset = @@ -2808,7 +2807,7 @@ impl Evaluator<'_> { ) -> Result<()> { let Some(drop_fn) = (|| { let drop_trait = LangItem::Drop.resolve_trait(self.db, self.crate_id)?; - self.db.trait_items(drop_trait).method_by_name(&Name::new_symbol_root(sym::drop)) + drop_trait.trait_items(self.db).method_by_name(&Name::new_symbol_root(sym::drop)) })() else { // in some tests we don't have drop trait in minicore, and // we can ignore drop in them. @@ -2838,7 +2837,7 @@ impl Evaluator<'_> { return Ok(()); } let layout = self.layout_adt(id.0, subst.clone())?; - let variant_fields = self.db.variant_fields(s.into()); + let variant_fields = s.fields(self.db); match variant_fields.shape { FieldsShape::Record | FieldsShape::Tuple => { let field_types = self.db.field_types(s.into()); @@ -2918,7 +2917,7 @@ pub fn render_const_using_debug_impl( not_supported!("core::fmt::Debug not found"); }; let Some(debug_fmt_fn) = - db.trait_items(debug_trait).method_by_name(&Name::new_symbol_root(sym::fmt)) + debug_trait.trait_items(db).method_by_name(&Name::new_symbol_root(sym::fmt)) else { not_supported!("core::fmt::Debug::fmt not found"); }; @@ -3045,7 +3044,10 @@ impl IntValue { (8, true) => Self::I64(i64::from_le_bytes(bytes.try_into().unwrap())), (16, false) => Self::U128(u128::from_le_bytes(bytes.try_into().unwrap())), (16, true) => Self::I128(i128::from_le_bytes(bytes.try_into().unwrap())), - _ => panic!("invalid integer size"), + (len, is_signed) => { + never!("invalid integer size: {len}, signed: {is_signed}"); + Self::I32(0) + } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 6ebde013344..e9665d5ae9c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -1257,9 +1257,8 @@ impl Evaluator<'_> { args.push(IntervalAndTy::new(addr, field, self, locals)?); } if let Some(target) = LangItem::FnOnce.resolve_trait(self.db, self.crate_id) { - if let Some(def) = self - .db - .trait_items(target) + if let Some(def) = target + .trait_items(self.db) .method_by_name(&Name::new_symbol_root(sym::call_once)) { self.exec_fn_trait( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs index 984648cfec3..bc331a23d98 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -31,7 +31,7 @@ impl Evaluator<'_> { Some(len) => len, _ => { if let AdtId::StructId(id) = id.0 { - let struct_data = self.db.variant_fields(id.into()); + let struct_data = id.fields(self.db); let fields = struct_data.fields(); let Some((first_field, _)) = fields.iter().next() else { not_supported!("simd type with no field"); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index 3abbbe45e6f..c1f86960e15 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -984,3 +984,17 @@ fn main<'a, T: Foo + Bar + Baz>( |e| matches!(e, MirEvalError::MirLowerError(_, MirLowerError::GenericArgNotProvided(..))), ); } + +#[test] +fn format_args_pass() { + check_pass( + r#" +//- minicore: fmt +fn main() { + let x1 = format_args!(""); + let x2 = format_args!("{}", x1); + let x3 = format_args!("{} {}", x1, x2); +} +"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 71e038b92f0..845d6b8eae1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -503,7 +503,7 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(Some(current)) } ValueNs::EnumVariantId(variant_id) => { - let variant_fields = &self.db.variant_fields(variant_id.into()); + let variant_fields = variant_id.fields(self.db); if variant_fields.shape == FieldsShape::Unit { let ty = self.infer.type_of_expr[expr_id].clone(); current = self.lower_enum_variant( @@ -856,7 +856,7 @@ impl<'ctx> MirLowerCtx<'ctx> { TyKind::Adt(_, s) => s.clone(), _ => not_supported!("Non ADT record literal"), }; - let variant_fields = self.db.variant_fields(variant_id); + let variant_fields = variant_id.fields(self.db); match variant_id { VariantId::EnumVariantId(_) | VariantId::StructId(_) => { let mut operands = vec![None; variant_fields.fields().len()]; @@ -1176,8 +1176,7 @@ impl<'ctx> MirLowerCtx<'ctx> { place, Rvalue::Aggregate( AggregateKind::Adt(st.into(), subst.clone()), - self.db - .variant_fields(st.into()) + st.fields(self.db) .fields() .iter() .map(|it| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs index ad664693e29..e7bffead931 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs @@ -193,9 +193,8 @@ impl MirLowerCtx<'_> { if let Some(deref_trait) = self.resolve_lang_item(LangItem::DerefMut)?.as_trait() { - if let Some(deref_fn) = self - .db - .trait_items(deref_trait) + if let Some(deref_fn) = deref_trait + .trait_items(self.db) .method_by_name(&Name::new_symbol_root(sym::deref_mut)) { break 'b deref_fn == f; @@ -347,9 +346,8 @@ impl MirLowerCtx<'_> { .resolve_lang_item(trait_lang_item)? .as_trait() .ok_or(MirLowerError::LangItemNotFound(trait_lang_item))?; - let deref_fn = self - .db - .trait_items(deref_trait) + let deref_fn = deref_trait + .trait_items(self.db) .method_by_name(&trait_method_name) .ok_or(MirLowerError::LangItemNotFound(trait_lang_item))?; let deref_fn_op = Operand::const_zst( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index b3c1f6f387f..61c0685c48a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -609,7 +609,7 @@ impl MirLowerCtx<'_> { } self.pattern_matching_variant_fields( shape, - &self.db.variant_fields(v.into()), + v.fields(self.db), variant, current, current_else, @@ -619,7 +619,7 @@ impl MirLowerCtx<'_> { } VariantId::StructId(s) => self.pattern_matching_variant_fields( shape, - &self.db.variant_fields(s.into()), + s.fields(self.db), variant, current, current_else, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index 8764e48b538..78a69cf4509 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -326,7 +326,7 @@ impl<'a> MirPrettyCtx<'a> { w!(this, ")"); } ProjectionElem::Field(Either::Left(field)) => { - let variant_fields = this.db.variant_fields(field.parent); + let variant_fields = field.parent.fields(this.db); let name = &variant_fields.fields()[field.local_id].name; match field.parent { hir_def::VariantId::EnumVariantId(e) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index 9ca6ee476c6..79754bc8a09 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -486,7 +486,7 @@ pub(crate) fn visit_module( }); } ModuleDefId::TraitId(it) => { - let trait_data = db.trait_items(it); + let trait_data = it.trait_items(db); for &(_, item) in trait_data.items.iter() { match item { AssocItemId::FunctionId(it) => cb(it.into()), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs index ddc5b715194..3894b4b6f7b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs @@ -561,7 +561,7 @@ trait Foo {} fn test(f: impl Foo, g: &(impl Foo + ?Sized)) { let _: &dyn Foo = &f; let _: &dyn Foo = g; - //^ expected &'? (dyn Foo + 'static), got &'? impl Foo + ?Sized + //^ expected &'? (dyn Foo + '?), got &'? impl Foo + ?Sized } "#, ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs index a986b54a7b0..6e3faa05a62 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs @@ -67,11 +67,11 @@ trait B: A {} fn test<'a>( _: &(dyn A<Assoc = ()> + Send), - //^ &(dyn A<Assoc = ()> + Send + 'static) + //^ &(dyn A<Assoc = ()> + Send) _: &'a (dyn Send + A<Assoc = ()>), - //^ &'a (dyn A<Assoc = ()> + Send + 'static) + //^ &'a (dyn A<Assoc = ()> + Send) _: &dyn B<Assoc = ()>, - //^ &(dyn B<Assoc = ()> + 'static) + //^ &(dyn B<Assoc = ()>) ) {} "#, ); @@ -85,7 +85,7 @@ fn render_dyn_for_ty() { trait Foo<'a> {} fn foo(foo: &dyn for<'a> Foo<'a>) {} - // ^^^ &(dyn Foo<'?> + 'static) + // ^^^ &dyn Foo<'?> "#, ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index 905fd8a3bca..0377ce95f19 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -567,7 +567,7 @@ fn main() { "ast_id_map_shim", "parse_shim", "real_span_map_shim", - "trait_items_with_diagnostics_shim", + "query_with_diagnostics_", "body_shim", "body_with_source_map_shim", "attrs_shim", @@ -596,8 +596,8 @@ fn main() { "struct_signature_with_source_map_shim", "generic_predicates_shim", "value_ty_shim", - "variant_fields_shim", - "variant_fields_with_source_map_shim", + "firewall_", + "query_", "lang_item", "inherent_impls_in_crate_shim", "impl_signature_shim", @@ -674,7 +674,7 @@ fn main() { "file_item_tree_query", "real_span_map_shim", "crate_local_def_map", - "trait_items_with_diagnostics_shim", + "query_with_diagnostics_", "body_with_source_map_shim", "attrs_shim", "body_shim", @@ -695,11 +695,9 @@ fn main() { "return_type_impl_traits_shim", "infer_shim", "function_signature_with_source_map_shim", - "trait_environment_shim", "expr_scopes_shim", "struct_signature_with_source_map_shim", - "generic_predicates_shim", - "variant_fields_with_source_map_shim", + "query_", "inherent_impls_in_crate_shim", "impl_signature_with_source_map_shim", "impl_signature_shim", @@ -709,7 +707,6 @@ fn main() { "impl_trait_with_diagnostics_shim", "impl_self_ty_with_diagnostics_shim", "generic_predicates_shim", - "generic_predicates_shim", ] "#]], ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index 94826acca30..c58ca6c67a8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -1153,9 +1153,9 @@ fn dyn_trait_super_trait_not_in_scope() { 51..55 'self': &'? Self 64..69 '{ 0 }': u32 66..67 '0': u32 - 176..177 'd': &'? (dyn Trait + 'static) + 176..177 'd': &'? (dyn Trait + '?) 191..207 '{ ...o(); }': () - 197..198 'd': &'? (dyn Trait + 'static) + 197..198 'd': &'? (dyn Trait + '?) 197..204 'd.foo()': u32 "#]], ); @@ -2019,10 +2019,10 @@ impl dyn Error + Send { /// Attempts to downcast the box to a concrete type. pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> { let err: Box<dyn Error> = self; - // ^^^^ expected Box<dyn Error + 'static>, got Box<dyn Error + Send + 'static> + // ^^^^ expected Box<dyn Error + '?>, got Box<dyn Error + Send + '?> // FIXME, type mismatch should not occur <dyn Error>::downcast(err).map_err(|_| loop {}) - //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error + 'static>) -> Result<Box<{unknown}>, Box<dyn Error + 'static>> + //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error + '?>) -> Result<Box<{unknown}>, Box<dyn Error + '?>> } } "#, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index ff8adeef1db..238753e12e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -629,7 +629,7 @@ fn issue_4053_diesel_where_clauses() { 488..522 '{ ... }': () 498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}> 498..508 'self.order': O - 498..515 'self.o...into()': dyn QueryFragment<DB> + 'static + 498..515 'self.o...into()': dyn QueryFragment<DB> + '? "#]], ); } @@ -773,7 +773,7 @@ fn issue_4800() { "#, expect![[r#" 379..383 'self': &'? mut PeerSet<D> - 401..424 '{ ... }': dyn Future<Output = ()> + 'static + 401..424 '{ ... }': dyn Future<Output = ()> + '? 411..418 'loop {}': ! 416..418 '{}': () 575..579 'self': &'? mut Self diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index cf51671afb2..43e8f3747ab 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -2741,11 +2741,11 @@ impl B for Astruct {} 715..744 '#[rust...1i32])': Box<[i32; 1], Global> 737..743 '[1i32]': [i32; 1] 738..742 '1i32': i32 - 755..756 'v': Vec<Box<dyn B + 'static, Global>, Global> - 776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B + 'static, Global>, Global>(Box<[Box<dyn B + 'static, Global>], Global>) -> Vec<Box<dyn B + 'static, Global>, Global> - 776..850 '<[_]> ...ct)]))': Vec<Box<dyn B + 'static, Global>, Global> - 794..849 '#[rust...uct)])': Box<[Box<dyn B + 'static, Global>; 1], Global> - 816..848 '[#[rus...ruct)]': [Box<dyn B + 'static, Global>; 1] + 755..756 'v': Vec<Box<dyn B + '?, Global>, Global> + 776..793 '<[_]> ...to_vec': fn into_vec<Box<dyn B + '?, Global>, Global>(Box<[Box<dyn B + '?, Global>], Global>) -> Vec<Box<dyn B + '?, Global>, Global> + 776..850 '<[_]> ...ct)]))': Vec<Box<dyn B + '?, Global>, Global> + 794..849 '#[rust...uct)])': Box<[Box<dyn B + '?, Global>; 1], Global> + 816..848 '[#[rus...ruct)]': [Box<dyn B + '?, Global>; 1] 817..847 '#[rust...truct)': Box<Astruct, Global> 839..846 'Astruct': Astruct "#]], diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index e5d1fbe9def..56e31a1af1b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -1475,26 +1475,26 @@ fn test(x: Box<dyn Trait<u64>>, y: &dyn Trait<u64>) { expect![[r#" 29..33 'self': &'? Self 54..58 'self': &'? Self - 198..200 '{}': Box<dyn Trait<u64> + 'static> - 210..211 'x': Box<dyn Trait<u64> + 'static> - 234..235 'y': &'? (dyn Trait<u64> + 'static) + 198..200 '{}': Box<dyn Trait<u64> + '?> + 210..211 'x': Box<dyn Trait<u64> + '?> + 234..235 'y': &'? (dyn Trait<u64> + '?) 254..371 '{ ...2(); }': () - 260..261 'x': Box<dyn Trait<u64> + 'static> - 267..268 'y': &'? (dyn Trait<u64> + 'static) - 278..279 'z': Box<dyn Trait<u64> + 'static> - 282..285 'bar': fn bar() -> Box<dyn Trait<u64> + 'static> - 282..287 'bar()': Box<dyn Trait<u64> + 'static> - 293..294 'x': Box<dyn Trait<u64> + 'static> + 260..261 'x': Box<dyn Trait<u64> + '?> + 267..268 'y': &'? (dyn Trait<u64> + '?) + 278..279 'z': Box<dyn Trait<u64> + '?> + 282..285 'bar': fn bar() -> Box<dyn Trait<u64> + '?> + 282..287 'bar()': Box<dyn Trait<u64> + '?> + 293..294 'x': Box<dyn Trait<u64> + '?> 293..300 'x.foo()': u64 - 306..307 'y': &'? (dyn Trait<u64> + 'static) + 306..307 'y': &'? (dyn Trait<u64> + '?) 306..313 'y.foo()': u64 - 319..320 'z': Box<dyn Trait<u64> + 'static> + 319..320 'z': Box<dyn Trait<u64> + '?> 319..326 'z.foo()': u64 - 332..333 'x': Box<dyn Trait<u64> + 'static> + 332..333 'x': Box<dyn Trait<u64> + '?> 332..340 'x.foo2()': i64 - 346..347 'y': &'? (dyn Trait<u64> + 'static) + 346..347 'y': &'? (dyn Trait<u64> + '?) 346..354 'y.foo2()': i64 - 360..361 'z': Box<dyn Trait<u64> + 'static> + 360..361 'z': Box<dyn Trait<u64> + '?> 360..368 'z.foo2()': i64 "#]], ); @@ -1523,14 +1523,14 @@ fn test(s: S<u32, i32>) { expect![[r#" 32..36 'self': &'? Self 102..106 'self': &'? S<T, U> - 128..139 '{ loop {} }': &'? (dyn Trait<T, U> + 'static) + 128..139 '{ loop {} }': &'? (dyn Trait<T, U> + '?) 130..137 'loop {}': ! 135..137 '{}': () 175..179 'self': &'? Self 251..252 's': S<u32, i32> 267..289 '{ ...z(); }': () 273..274 's': S<u32, i32> - 273..280 's.bar()': &'? (dyn Trait<u32, i32> + 'static) + 273..280 's.bar()': &'? (dyn Trait<u32, i32> + '?) 273..286 's.bar().baz()': (u32, i32) "#]], ); @@ -1556,20 +1556,20 @@ fn test(x: Trait, y: &Trait) -> u64 { }"#, expect![[r#" 26..30 'self': &'? Self - 60..62 '{}': dyn Trait + 'static - 72..73 'x': dyn Trait + 'static - 82..83 'y': &'? (dyn Trait + 'static) + 60..62 '{}': dyn Trait + '? + 72..73 'x': dyn Trait + '? + 82..83 'y': &'? (dyn Trait + '?) 100..175 '{ ...o(); }': u64 - 106..107 'x': dyn Trait + 'static - 113..114 'y': &'? (dyn Trait + 'static) - 124..125 'z': dyn Trait + 'static - 128..131 'bar': fn bar() -> dyn Trait + 'static - 128..133 'bar()': dyn Trait + 'static - 139..140 'x': dyn Trait + 'static + 106..107 'x': dyn Trait + '? + 113..114 'y': &'? (dyn Trait + '?) + 124..125 'z': dyn Trait + '? + 128..131 'bar': fn bar() -> dyn Trait + '? + 128..133 'bar()': dyn Trait + '? + 139..140 'x': dyn Trait + '? 139..146 'x.foo()': u64 - 152..153 'y': &'? (dyn Trait + 'static) + 152..153 'y': &'? (dyn Trait + '?) 152..159 'y.foo()': u64 - 165..166 'z': dyn Trait + 'static + 165..166 'z': dyn Trait + '? 165..172 'z.foo()': u64 "#]], ); @@ -1589,10 +1589,10 @@ fn main() { expect![[r#" 31..35 'self': &'? S 37..39 '{}': () - 47..48 '_': &'? (dyn Fn(S) + 'static) + 47..48 '_': &'? (dyn Fn(S) + '?) 58..60 '{}': () 71..105 '{ ...()); }': () - 77..78 'f': fn f(&'? (dyn Fn(S) + 'static)) + 77..78 'f': fn f(&'? (dyn Fn(S) + '?)) 77..102 'f(&|nu...foo())': () 79..101 '&|numb....foo()': &'? impl Fn(S) 80..101 '|numbe....foo()': impl Fn(S) @@ -2927,13 +2927,13 @@ fn test(x: &dyn Foo) { foo(x); }"#, expect![[r#" - 21..22 'x': &'? (dyn Foo + 'static) + 21..22 'x': &'? (dyn Foo + '?) 34..36 '{}': () - 46..47 'x': &'? (dyn Foo + 'static) + 46..47 'x': &'? (dyn Foo + '?) 59..74 '{ foo(x); }': () - 65..68 'foo': fn foo(&'? (dyn Foo + 'static)) + 65..68 'foo': fn foo(&'? (dyn Foo + '?)) 65..71 'foo(x)': () - 69..70 'x': &'? (dyn Foo + 'static) + 69..70 'x': &'? (dyn Foo + '?) "#]], ); } @@ -3210,13 +3210,13 @@ fn foo() { 218..324 '{ ...&s); }': () 228..229 's': Option<i32> 232..236 'None': Option<i32> - 246..247 'f': Box<dyn FnOnce(&'? Option<i32>) + 'static> - 281..310 'Box { ... {}) }': Box<dyn FnOnce(&'? Option<i32>) + 'static> + 246..247 'f': Box<dyn FnOnce(&'? Option<i32>) + '?> + 281..310 'Box { ... {}) }': Box<dyn FnOnce(&'? Option<i32>) + '?> 294..308 '&mut (|ps| {})': &'? mut impl FnOnce(&'? Option<i32>) 300..307 '|ps| {}': impl FnOnce(&'? Option<i32>) 301..303 'ps': &'? Option<i32> 305..307 '{}': () - 316..317 'f': Box<dyn FnOnce(&'? Option<i32>) + 'static> + 316..317 'f': Box<dyn FnOnce(&'? Option<i32>) + '?> 316..321 'f(&s)': () 318..320 '&s': &'? Option<i32> 319..320 's': Option<i32> @@ -4252,9 +4252,9 @@ fn f<'a>(v: &dyn Trait<Assoc<i32> = &'a i32>) { "#, expect![[r#" 90..94 'self': &'? Self - 127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + 'static) + 127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + '?) 164..195 '{ ...f(); }': () - 170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + 'static) + 170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + '?) 170..184 'v.get::<i32>()': &'? i32 170..192 'v.get:...eref()': &'? i32 "#]], diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 4c8e635eff9..d07c1aa33b4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -1,7 +1,7 @@ //! Helper functions for working with def, which don't need to be a separate //! query, but can't be computed directly from `*Data` (ie, which need a `db`). -use std::iter; +use std::{cell::LazyCell, iter}; use base_db::Crate; use chalk_ir::{ @@ -161,11 +161,12 @@ impl Iterator for ClauseElaborator<'_> { } fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { - let resolver = trait_.resolver(db); + let resolver = LazyCell::new(|| trait_.resolver(db)); let (generic_params, store) = db.generic_params_and_store(trait_.into()); let trait_self = generic_params.trait_self_param(); generic_params .where_predicates() + .iter() .filter_map(|pred| match pred { WherePredicate::ForLifetime { target, bound, .. } | WherePredicate::TypeBound { target, bound } => { @@ -218,7 +219,7 @@ pub(super) fn associated_type_by_name_including_super_traits( name: &Name, ) -> Option<(TraitRef, TypeAliasId)> { all_super_trait_refs(db, trait_ref, |t| { - let assoc_type = db.trait_items(t.hir_trait_id()).associated_type_by_name(name)?; + let assoc_type = t.hir_trait_id().trait_items(db).associated_type_by_name(name)?; Some((t, assoc_type)) }) } diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index 2af3c2e4c35..c68ff706e48 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] rustc-hash.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index 0bce69a179b..c8645b62823 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -207,7 +207,7 @@ fn resolve_assoc_or_field( // Doc paths in this context may only resolve to an item of this trait // (i.e. no items of its supertraits), so we need to handle them here // independently of others. - return db.trait_items(id).items.iter().find(|it| it.0 == name).map(|(_, assoc_id)| { + return id.trait_items(db).items.iter().find(|it| it.0 == name).map(|(_, assoc_id)| { let def = match *assoc_id { AssocItemId::FunctionId(it) => ModuleDef::Function(it.into()), AssocItemId::ConstId(it) => ModuleDef::Const(it.into()), diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 074bde91fb6..aba2e032b32 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -490,7 +490,7 @@ impl<'db> AnyDiagnostic<'db> { ) -> Option<AnyDiagnostic<'db>> { match diagnostic { BodyValidationDiagnostic::RecordMissingFields { record, variant, missed_fields } => { - let variant_data = variant.variant_data(db); + let variant_data = variant.fields(db); let missed_fields = missed_fields .into_iter() .map(|idx| variant_data.fields()[idx].name.clone()) diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 112558bdd04..2960ebedf38 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -404,7 +404,7 @@ impl HirDisplay for TupleField { impl HirDisplay for Variant { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write!(f, "{}", self.name(f.db).display(f.db, f.edition()))?; - let data = f.db.variant_fields(self.id.into()); + let data = self.id.fields(f.db); match data.shape { FieldsShape::Unit => {} FieldsShape::Tuple => { @@ -633,7 +633,7 @@ fn has_disaplayable_predicates( params: &GenericParams, store: &ExpressionStore, ) -> bool { - params.where_predicates().any(|pred| { + params.where_predicates().iter().any(|pred| { !matches!( pred, WherePredicate::TypeBound { target, .. } @@ -668,7 +668,7 @@ fn write_where_predicates( _ => false, }; - let mut iter = params.where_predicates().peekable(); + let mut iter = params.where_predicates().iter().peekable(); while let Some(pred) = iter.next() { if matches!(pred, TypeBound { target, .. } if is_unnamed_type_target(*target)) { continue; diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 3b39707cf60..e8a18169712 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -54,7 +54,7 @@ use hir_def::{ }, item_tree::ImportAlias, layout::{self, ReprOptions, TargetDataLayout}, - nameres::{self, diagnostics::DefDiagnostic}, + nameres::{self, assoc::TraitItems, diagnostics::DefDiagnostic}, per_ns::PerNs, resolver::{HasResolver, Resolver}, signatures::{ImplFlags, StaticFlags, TraitFlags, VariantFields}, @@ -649,7 +649,7 @@ impl Module { acc.extend(def.diagnostics(db, style_lints)) } ModuleDef::Trait(t) => { - for diag in db.trait_items_with_diagnostics(t.id).1.iter() { + for diag in TraitItems::query_with_diagnostics(db, t.id).1.iter() { emit_def_diagnostic(db, acc, diag, edition); } @@ -668,25 +668,25 @@ impl Module { Adt::Struct(s) => { let source_map = db.struct_signature_with_source_map(s.id).1; expr_store_diagnostics(db, acc, &source_map); - let source_map = db.variant_fields_with_source_map(s.id.into()).1; - expr_store_diagnostics(db, acc, &source_map); + let source_map = &s.id.fields_with_source_map(db).1; + expr_store_diagnostics(db, acc, source_map); push_ty_diagnostics( db, acc, db.field_types_with_diagnostics(s.id.into()).1, - &source_map, + source_map, ); } Adt::Union(u) => { let source_map = db.union_signature_with_source_map(u.id).1; expr_store_diagnostics(db, acc, &source_map); - let source_map = db.variant_fields_with_source_map(u.id.into()).1; - expr_store_diagnostics(db, acc, &source_map); + let source_map = &u.id.fields_with_source_map(db).1; + expr_store_diagnostics(db, acc, source_map); push_ty_diagnostics( db, acc, db.field_types_with_diagnostics(u.id.into()).1, - &source_map, + source_map, ); } Adt::Enum(e) => { @@ -711,14 +711,14 @@ impl Module { } } for &(v, _, _) in &variants.variants { - let source_map = db.variant_fields_with_source_map(v.into()).1; + let source_map = &v.fields_with_source_map(db).1; push_ty_diagnostics( db, acc, db.field_types_with_diagnostics(v.into()).1, - &source_map, + source_map, ); - expr_store_diagnostics(db, acc, &source_map); + expr_store_diagnostics(db, acc, source_map); } } } @@ -822,7 +822,7 @@ impl Module { // Negative impls can't have items, don't emit missing items diagnostic for them if let (false, Some(trait_)) = (impl_is_negative, trait_) { - let items = &db.trait_items(trait_.into()).items; + let items = &trait_.id.trait_items(db).items; let required_items = items.iter().filter(|&(_, assoc)| match *assoc { AssocItemId::FunctionId(it) => !db.function_signature(it).has_body(), AssocItemId::ConstId(id) => !db.const_signature(id).has_body(), @@ -1311,7 +1311,7 @@ impl AstNode for FieldSource { impl Field { pub fn name(&self, db: &dyn HirDatabase) -> Name { - db.variant_fields(self.parent.into()).fields()[self.id].name.clone() + VariantId::from(self.parent).fields(db).fields()[self.id].name.clone() } pub fn index(&self) -> usize { @@ -1380,7 +1380,7 @@ impl Field { impl HasVisibility for Field { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { - let variant_data = db.variant_fields(self.parent.into()); + let variant_data = VariantId::from(self.parent).fields(db); let visibility = &variant_data.fields()[self.id].visibility; let parent_id: hir_def::VariantId = self.parent.into(); // FIXME: RawVisibility::Public doesn't need to construct a resolver @@ -1403,7 +1403,8 @@ impl Struct { } pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { - db.variant_fields(self.id.into()) + self.id + .fields(db) .fields() .iter() .map(|(id, _)| Field { parent: self.into(), id }) @@ -1434,8 +1435,8 @@ impl Struct { } } - fn variant_fields(self, db: &dyn HirDatabase) -> Arc<VariantFields> { - db.variant_fields(self.id.into()) + fn variant_fields(self, db: &dyn HirDatabase) -> &VariantFields { + self.id.fields(db) } pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { @@ -1478,7 +1479,7 @@ impl Union { } pub fn kind(self, db: &dyn HirDatabase) -> StructKind { - match db.variant_fields(self.id.into()).shape { + match self.id.fields(db).shape { hir_def::item_tree::FieldsShape::Record => StructKind::Record, hir_def::item_tree::FieldsShape::Tuple => StructKind::Tuple, hir_def::item_tree::FieldsShape::Unit => StructKind::Unit, @@ -1486,7 +1487,8 @@ impl Union { } pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { - db.variant_fields(self.id.into()) + self.id + .fields(db) .fields() .iter() .map(|(id, _)| Field { parent: self.into(), id }) @@ -1626,7 +1628,8 @@ impl Variant { } pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { - db.variant_fields(self.id.into()) + self.id + .fields(db) .fields() .iter() .map(|(id, _)| Field { parent: self.into(), id }) @@ -1634,7 +1637,7 @@ impl Variant { } pub fn kind(self, db: &dyn HirDatabase) -> StructKind { - match db.variant_fields(self.id.into()).shape { + match self.id.fields(db).shape { hir_def::item_tree::FieldsShape::Record => StructKind::Record, hir_def::item_tree::FieldsShape::Tuple => StructKind::Tuple, hir_def::item_tree::FieldsShape::Unit => StructKind::Unit, @@ -1727,10 +1730,10 @@ impl Adt { pub fn ty_with_args<'db>( self, db: &'db dyn HirDatabase, - args: impl Iterator<Item = Type<'db>>, + args: impl IntoIterator<Item = Type<'db>>, ) -> Type<'db> { let id = AdtId::from(self); - let mut it = args.map(|t| t.ty); + let mut it = args.into_iter().map(|t| t.ty); let ty = TyBuilder::def_ty(db, id.into(), None) .fill(|x| { let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner)); @@ -2883,7 +2886,7 @@ impl Trait { } pub fn function(self, db: &dyn HirDatabase, name: impl PartialEq<Name>) -> Option<Function> { - db.trait_items(self.id).items.iter().find(|(n, _)| name == *n).and_then(|&(_, it)| match it + self.id.trait_items(db).items.iter().find(|(n, _)| name == *n).and_then(|&(_, it)| match it { AssocItemId::FunctionId(id) => Some(Function { id }), _ => None, @@ -2891,7 +2894,7 @@ impl Trait { } pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { - db.trait_items(self.id).items.iter().map(|(_name, it)| (*it).into()).collect() + self.id.trait_items(db).items.iter().map(|(_name, it)| (*it).into()).collect() } pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec<AssocItem> { @@ -2939,7 +2942,7 @@ impl Trait { } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> { - db.trait_items(self.id).macro_calls.to_vec().into_boxed_slice() + self.id.trait_items(db).macro_calls.to_vec().into_boxed_slice() } /// `#[rust_analyzer::completions(...)]` mode. @@ -3043,10 +3046,17 @@ pub struct BuiltinType { } impl BuiltinType { + // Constructors are added on demand, feel free to add more. pub fn str() -> BuiltinType { BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str } } + pub fn i32() -> BuiltinType { + BuiltinType { + inner: hir_def::builtin_type::BuiltinType::Int(hir_ty::primitive::BuiltinInt::I32), + } + } + pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { let core = Crate::core(db).map(|core| core.id).unwrap_or_else(|| db.all_crates()[0]); Type::new_for_crate(core, TyBuilder::builtin(self.inner)) @@ -3667,7 +3677,7 @@ impl GenericDef { let generics = db.generic_params(def); - if generics.is_empty() && generics.no_predicates() { + if generics.is_empty() && generics.has_no_predicates() { return; } @@ -5000,7 +5010,7 @@ impl<'db> Type<'db> { } let output_assoc_type = - db.trait_items(trait_).associated_type_by_name(&Name::new_symbol_root(sym::Output))?; + trait_.trait_items(db).associated_type_by_name(&Name::new_symbol_root(sym::Output))?; self.normalize_trait_assoc_type(db, &[], output_assoc_type.into()) } @@ -5013,8 +5023,8 @@ impl<'db> Type<'db> { /// This does **not** resolve `IntoIterator`, only `Iterator`. pub fn iterator_item(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> { let iterator_trait = LangItem::Iterator.resolve_trait(db, self.env.krate)?; - let iterator_item = db - .trait_items(iterator_trait) + let iterator_item = iterator_trait + .trait_items(db) .associated_type_by_name(&Name::new_symbol_root(sym::Item))?; self.normalize_trait_assoc_type(db, &[], iterator_item.into()) } @@ -5044,8 +5054,8 @@ impl<'db> Type<'db> { return None; } - let into_iter_assoc_type = db - .trait_items(trait_) + let into_iter_assoc_type = trait_ + .trait_items(db) .associated_type_by_name(&Name::new_symbol_root(sym::IntoIter))?; self.normalize_trait_assoc_type(db, &[], into_iter_assoc_type.into()) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index d96975831e0..247bb693983 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -2199,6 +2199,10 @@ pub struct SemanticsScope<'db> { } impl<'db> SemanticsScope<'db> { + pub fn file_id(&self) -> HirFileId { + self.file_id + } + pub fn module(&self) -> Module { Module { id: self.resolver.module() } } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs index fedd8239d03..e7db93d375d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs @@ -35,7 +35,7 @@ pub(crate) trait ChildBySource { impl ChildBySource for TraitId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { - let data = db.trait_items(*self); + let data = self.trait_items(db); data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( |(ast_id, call_id)| { @@ -191,7 +191,7 @@ impl ChildBySource for VariantId { Either::Right(source) => res[keys::RECORD_FIELD].insert(AstPtr::new(&source), id), } } - let (_, sm) = db.variant_fields_with_source_map(*self); + let (_, sm) = self.fields_with_source_map(db); sm.expansions().for_each(|(ast, &exp_id)| res[keys::MACRO_CALL].insert(ast.value, exp_id)); } } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 48543ca581f..f18ca7cb201 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -156,14 +156,14 @@ impl<'db> SourceAnalyzer<'db> { InFile { file_id, .. }: InFile<&SyntaxNode>, _offset: Option<TextSize>, ) -> SourceAnalyzer<'db> { - let (fields, source_map) = db.variant_fields_with_source_map(def); + let (fields, source_map) = def.fields_with_source_map(db); let resolver = def.resolver(db); SourceAnalyzer { resolver, body_or_sig: Some(BodyOrSig::VariantFields { def, store: fields.store.clone(), - source_map, + source_map: source_map.clone(), }), file_id, } @@ -713,7 +713,7 @@ impl<'db> SourceAnalyzer<'db> { }; let (adt, subst) = self.infer()?.type_of_expr_or_pat(expr_id)?.as_adt()?; let variant = self.infer()?.variant_resolution_for_expr_or_pat(expr_id)?; - let variant_data = variant.variant_data(db); + let variant_data = variant.fields(db); let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; let field_ty = db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst); @@ -734,7 +734,7 @@ impl<'db> SourceAnalyzer<'db> { let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?; let pat_id = self.pat_id(&record_pat.into())?; let variant = self.infer()?.variant_resolution_for_pat(pat_id.as_pat()?)?; - let variant_data = variant.variant_data(db); + let variant_data = variant.fields(db); let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? }; let (adt, subst) = self.infer()?.type_of_pat.get(pat_id.as_pat()?)?.as_adt()?; let field_ty = @@ -803,8 +803,8 @@ impl<'db> SourceAnalyzer<'db> { }; container = Either::Right(db.normalize_projection(projection, trait_env.clone())); } - let handle_variants = |variant, subst: &Substitution, container: &mut _| { - let fields = db.variant_fields(variant); + let handle_variants = |variant: VariantId, subst: &Substitution, container: &mut _| { + let fields = variant.fields(db); let field = fields.field(&field_name.as_name())?; let field_types = db.field_types(variant); *container = Either::Right(field_types[field].clone().substitute(Interner, subst)); @@ -1423,7 +1423,7 @@ impl<'db> SourceAnalyzer<'db> { method_name: &Name, ) -> Option<(TraitId, FunctionId)> { let trait_id = lang_trait.resolve_trait(db, self.resolver.krate())?; - let fn_id = db.trait_items(trait_id).method_by_name(method_name)?; + let fn_id = trait_id.trait_items(db).method_by_name(method_name)?; Some((trait_id, fn_id)) } @@ -1580,7 +1580,7 @@ fn resolve_hir_path_( // within the trait's associated types. if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) { if let Some(type_alias_id) = - db.trait_items(trait_id).associated_type_by_name(unresolved.name) + trait_id.trait_items(db).associated_type_by_name(unresolved.name) { return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into())); } @@ -1731,7 +1731,7 @@ fn resolve_hir_path_qualifier( // within the trait's associated types. if let (Some(unresolved), &TypeNs::TraitId(trait_id)) = (&unresolved, &ty) { if let Some(type_alias_id) = - db.trait_items(trait_id).associated_type_by_name(unresolved.name) + trait_id.trait_items(db).associated_type_by_name(unresolved.name) { return Some(PathResolution::Def(ModuleDefId::from(type_alias_id).into())); } diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index 64f2a910bd1..756650891d4 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -334,7 +334,7 @@ impl<'a> SymbolCollector<'a> { fn collect_from_trait(&mut self, trait_id: TraitId, trait_do_not_complete: Complete) { let trait_data = self.db.trait_signature(trait_id); self.with_container_name(Some(trait_data.name.as_str().into()), |s| { - for &(ref name, assoc_item_id) in &self.db.trait_items(trait_id).items { + for &(ref name, assoc_item_id) in &trait_id.trait_items(self.db).items { s.push_assoc_item(assoc_item_id, name, Some(trait_do_not_complete)); } }); diff --git a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml index 53af980c194..385b0e1eb7c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] cov-mark = "2.0.0" diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs index 3e6d0bec68a..517906b429a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_is_method.rs @@ -1,3 +1,5 @@ +use std::slice; + use ide_db::assists::GroupLabel; use stdx::to_lower_snake_case; use syntax::ast::HasVisibility; @@ -52,7 +54,7 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext<'_> let fn_name = format!("is_{}", &to_lower_snake_case(&variant_name.text())); // Return early if we've found an existing new fn - let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?; + let impl_def = find_struct_impl(ctx, &parent_enum, slice::from_ref(&fn_name))?; let target = variant.syntax().text_range(); acc.add_group( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs index 3974bcf6187..e4b0f830497 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_projection_method.rs @@ -1,3 +1,5 @@ +use std::slice; + use ide_db::assists::GroupLabel; use itertools::Itertools; use stdx::to_lower_snake_case; @@ -148,7 +150,7 @@ fn generate_enum_projection_method( let fn_name = format!("{fn_name_prefix}_{}", &to_lower_snake_case(&variant_name.text())); // Return early if we've found an existing new fn - let impl_def = find_struct_impl(ctx, &parent_enum, &[fn_name.clone()])?; + let impl_def = find_struct_impl(ctx, &parent_enum, slice::from_ref(&fn_name))?; let target = variant.syntax().text_range(); acc.add_group( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs index 019ddaf1441..6527d3706e2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs @@ -100,9 +100,7 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!() }"#, fn test_complete_todo_with_msg() { check_assist( term_search, - // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure. - // Should implement super let and remove `fmt_before_1_89_0` - r#"//- minicore: todo, unimplemented, fmt_before_1_89_0 + r#"//- minicore: todo, unimplemented fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, r#"fn f() { let a: u128 = 1; let b: u128 = a }"#, ) @@ -112,10 +110,8 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, fn test_complete_unimplemented_with_msg() { check_assist( term_search, - // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure. - // Should implement super let and remove `fmt_before_1_89_0` - r#"//- minicore: todo, unimplemented, fmt_before_1_89_0 -fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, + r#"//- minicore: todo, unimplemented +fn f() { let a: u128 = 1; let b: u128 = unimplemented$0!("asd") }"#, r#"fn f() { let a: u128 = 1; let b: u128 = a }"#, ) } @@ -124,10 +120,8 @@ fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, fn test_complete_unimplemented() { check_assist( term_search, - // FIXME: Since we are lacking of `super let`, term search fails due to borrowck failure. - // Should implement super let and remove `fmt_before_1_89_0` - r#"//- minicore: todo, unimplemented, fmt_before_1_89_0 -fn f() { let a: u128 = 1; let b: u128 = todo$0!("asd") }"#, + r#"//- minicore: todo, unimplemented +fn f() { let a: u128 = 1; let b: u128 = unimplemented$0!() }"#, r#"fn f() { let a: u128 = 1; let b: u128 = a }"#, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs index 9ea78719b20..d7189aa5dbb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs @@ -56,7 +56,8 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op }; let type_ref = &ret_type.ty()?; - let ty = ctx.sema.resolve_type(type_ref)?.as_adt(); + let ty = ctx.sema.resolve_type(type_ref)?; + let ty_adt = ty.as_adt(); let famous_defs = FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()); for kind in WrapperKind::ALL { @@ -64,7 +65,7 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op continue; }; - if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == core_wrapper) { + if matches!(ty_adt, Some(hir::Adt::Enum(ret_type)) if ret_type == core_wrapper) { // The return type is already wrapped cov_mark::hit!(wrap_return_type_simple_return_type_already_wrapped); continue; @@ -78,10 +79,23 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op |builder| { let mut editor = builder.make_editor(&parent); let make = SyntaxFactory::with_mappings(); - let alias = wrapper_alias(ctx, &make, &core_wrapper, type_ref, kind.symbol()); - let new_return_ty = alias.unwrap_or_else(|| match kind { - WrapperKind::Option => make.ty_option(type_ref.clone()), - WrapperKind::Result => make.ty_result(type_ref.clone(), make.ty_infer().into()), + let alias = wrapper_alias(ctx, &make, core_wrapper, type_ref, &ty, kind.symbol()); + let (ast_new_return_ty, semantic_new_return_ty) = alias.unwrap_or_else(|| { + let (ast_ty, ty_constructor) = match kind { + WrapperKind::Option => { + (make.ty_option(type_ref.clone()), famous_defs.core_option_Option()) + } + WrapperKind::Result => ( + make.ty_result(type_ref.clone(), make.ty_infer().into()), + famous_defs.core_result_Result(), + ), + }; + let semantic_ty = ty_constructor + .map(|ty_constructor| { + hir::Adt::from(ty_constructor).ty_with_args(ctx.db(), [ty.clone()]) + }) + .unwrap_or_else(|| ty.clone()); + (ast_ty, semantic_ty) }); let mut exprs_to_wrap = Vec::new(); @@ -96,6 +110,17 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op for_each_tail_expr(&body_expr, tail_cb); for ret_expr_arg in exprs_to_wrap { + if let Some(ty) = ctx.sema.type_of_expr(&ret_expr_arg) { + if ty.adjusted().could_unify_with(ctx.db(), &semantic_new_return_ty) { + // The type is already correct, don't wrap it. + // We deliberately don't use `could_unify_with_deeply()`, because as long as the outer + // enum matches it's okay for us, as we don't trigger the assist if the return type + // is already `Option`/`Result`, so mismatched exact type is more likely a mistake + // than something intended. + continue; + } + } + let happy_wrapped = make.expr_call( make.expr_path(make.ident_path(kind.happy_ident())), make.arg_list(iter::once(ret_expr_arg.clone())), @@ -103,12 +128,12 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op editor.replace(ret_expr_arg.syntax(), happy_wrapped.syntax()); } - editor.replace(type_ref.syntax(), new_return_ty.syntax()); + editor.replace(type_ref.syntax(), ast_new_return_ty.syntax()); if let WrapperKind::Result = kind { // Add a placeholder snippet at the first generic argument that doesn't equal the return type. // This is normally the error type, but that may not be the case when we inserted a type alias. - let args = new_return_ty + let args = ast_new_return_ty .path() .unwrap() .segment() @@ -188,27 +213,28 @@ impl WrapperKind { } // Try to find an wrapper type alias in the current scope (shadowing the default). -fn wrapper_alias( - ctx: &AssistContext<'_>, +fn wrapper_alias<'db>( + ctx: &AssistContext<'db>, make: &SyntaxFactory, - core_wrapper: &hir::Enum, - ret_type: &ast::Type, + core_wrapper: hir::Enum, + ast_ret_type: &ast::Type, + semantic_ret_type: &hir::Type<'db>, wrapper: hir::Symbol, -) -> Option<ast::PathType> { +) -> Option<(ast::PathType, hir::Type<'db>)> { let wrapper_path = hir::ModPath::from_segments( hir::PathKind::Plain, iter::once(hir::Name::new_symbol_root(wrapper)), ); - ctx.sema.resolve_mod_path(ret_type.syntax(), &wrapper_path).and_then(|def| { + ctx.sema.resolve_mod_path(ast_ret_type.syntax(), &wrapper_path).and_then(|def| { def.filter_map(|def| match def.into_module_def() { hir::ModuleDef::TypeAlias(alias) => { let enum_ty = alias.ty(ctx.db()).as_adt()?.as_enum()?; - (&enum_ty == core_wrapper).then_some(alias) + (enum_ty == core_wrapper).then_some((alias, enum_ty)) } _ => None, }) - .find_map(|alias| { + .find_map(|(alias, enum_ty)| { let mut inserted_ret_type = false; let generic_args = alias.source(ctx.db())?.value.generic_param_list()?.generic_params().map(|param| { @@ -216,7 +242,7 @@ fn wrapper_alias( // Replace the very first type parameter with the function's return type. ast::GenericParam::TypeParam(_) if !inserted_ret_type => { inserted_ret_type = true; - make.type_arg(ret_type.clone()).into() + make.type_arg(ast_ret_type.clone()).into() } ast::GenericParam::LifetimeParam(_) => { make.lifetime_arg(make.lifetime("'_")).into() @@ -231,7 +257,10 @@ fn wrapper_alias( make.path_segment_generics(make.name_ref(name.as_str()), generic_arg_list), ); - Some(make.ty_path(path)) + let new_ty = + hir::Adt::from(enum_ty).ty_with_args(ctx.db(), [semantic_ret_type.clone()]); + + Some((make.ty_path(path), new_ty)) }) }) } @@ -605,29 +634,39 @@ fn foo() -> Option<i32> { check_assist_by_label( wrap_return_type, r#" -//- minicore: option +//- minicore: option, future +struct F(i32); +impl core::future::Future for F { + type Output = i32; + fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> { 0 } +} async fn foo() -> i$032 { if true { if false { - 1.await + F(1).await } else { - 2.await + F(2).await } } else { - 24i32.await + F(24i32).await } } "#, r#" +struct F(i32); +impl core::future::Future for F { + type Output = i32; + fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> { 0 } +} async fn foo() -> Option<i32> { if true { if false { - Some(1.await) + Some(F(1).await) } else { - Some(2.await) + Some(F(2).await) } } else { - Some(24i32.await) + Some(F(24i32).await) } } "#, @@ -1666,29 +1705,39 @@ fn foo() -> Result<i32, ${0:_}> { check_assist_by_label( wrap_return_type, r#" -//- minicore: result +//- minicore: result, future +struct F(i32); +impl core::future::Future for F { + type Output = i32; + fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> { 0 } +} async fn foo() -> i$032 { if true { if false { - 1.await + F(1).await } else { - 2.await + F(2).await } } else { - 24i32.await + F(24i32).await } } "#, r#" +struct F(i32); +impl core::future::Future for F { + type Output = i32; + fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<Self::Output> { 0 } +} async fn foo() -> Result<i32, ${0:_}> { if true { if false { - Ok(1.await) + Ok(F(1).await) } else { - Ok(2.await) + Ok(F(2).await) } } else { - Ok(24i32.await) + Ok(F(24i32).await) } } "#, @@ -2460,4 +2509,54 @@ fn foo() -> Result<i32, ${0:_}> { WrapperKind::Result.label(), ); } + + #[test] + fn already_wrapped() { + check_assist_by_label( + wrap_return_type, + r#" +//- minicore: option +fn foo() -> i32$0 { + if false { + 0 + } else { + Some(1) + } +} + "#, + r#" +fn foo() -> Option<i32> { + if false { + Some(0) + } else { + Some(1) + } +} + "#, + WrapperKind::Option.label(), + ); + check_assist_by_label( + wrap_return_type, + r#" +//- minicore: result +fn foo() -> i32$0 { + if false { + 0 + } else { + Ok(1) + } +} + "#, + r#" +fn foo() -> Result<i32, ${0:_}> { + if false { + Ok(0) + } else { + Ok(1) + } +} + "#, + WrapperKind::Result.label(), + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml index 94c01e333ed..9bad21fc8e9 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] cov-mark = "2.0.0" diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs index 6d1e973dc4c..809e71cc119 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs @@ -195,5 +195,5 @@ fn comma_wrapper(ctx: &CompletionContext<'_>) -> Option<(impl Fn(&str) -> String matches!(prev_token_kind, SyntaxKind::COMMA | SyntaxKind::L_PAREN | SyntaxKind::PIPE); let leading = if has_leading_comma { "" } else { ", " }; - Some((move |label: &_| (format!("{leading}{label}{trailing}")), param.text_range())) + Some((move |label: &_| format!("{leading}{label}{trailing}"), param.text_range())) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 6e3a76f346a..ea5fb39338b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -4,6 +4,7 @@ use std::iter; use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant}; use ide_db::{RootDatabase, active_parameter::ActiveParameter}; use itertools::Either; +use stdx::always; use syntax::{ AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, T, TextRange, TextSize, @@ -869,8 +870,15 @@ fn classify_name_ref<'db>( return None; } + let mut receiver_ty = receiver.as_ref().and_then(|it| sema.type_of_expr(it)); + if receiver_is_ambiguous_float_literal { + // `123.|` is parsed as a float but should actually be an integer. + always!(receiver_ty.as_ref().is_none_or(|receiver_ty| receiver_ty.original.is_float())); + receiver_ty = Some(TypeInfo { original: hir::BuiltinType::i32().ty(sema.db), adjusted: None }); + } + let kind = NameRefKind::DotAccess(DotAccess { - receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)), + receiver_ty, kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal }, receiver, ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index b2d18b796f1..33f729f0166 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -2241,3 +2241,37 @@ fn main() { "#, ); } + +#[test] +fn ambiguous_float_literal() { + check( + r#" +#![rustc_coherence_is_core] + +impl i32 { + pub fn int_method(self) {} +} +impl f64 { + pub fn float_method(self) {} +} + +fn foo() { + 1.$0 +} + "#, + expect![[r#" + me int_method() fn(self) + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs index fcdf10c8561..179d6693602 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs @@ -550,3 +550,30 @@ fn inside_extern_blocks() { "#]], ) } + +#[test] +fn tokens_from_macro() { + check_edit( + "fn as_ref", + r#" +//- proc_macros: identity +//- minicore: as_ref +struct Foo; + +#[proc_macros::identity] +impl<'a> AsRef<&'a i32> for Foo { + $0 +} + "#, + r#" +struct Foo; + +#[proc_macros::identity] +impl<'a> AsRef<&'a i32> for Foo { + fn as_ref(&self) -> &&'a i32 { + $0 +} +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs index 125e11e9e35..c7e2d058257 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs @@ -429,18 +429,18 @@ trait Tr<T> { impl Tr<$0 "#, expect![[r#" - en Enum Enum - ma makro!(…) macro_rules! makro + en Enum Enum + ma makro!(…) macro_rules! makro md module - sp Self dyn Tr<{unknown}> + 'static - st Record Record - st S S - st Tuple Tuple - st Unit Unit + sp Self dyn Tr<{unknown}> + st Record Record + st S S + st Tuple Tuple + st Unit Unit tt Tr tt Trait - un Union Union - bt u32 u32 + un Union Union + bt u32 u32 kw crate:: kw self:: "#]], diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml index acde1d665da..e065adb0f0b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] cov-mark = "2.0.0" diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 232648af661..0ab880bcfe7 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -2,7 +2,10 @@ use crate::helpers::mod_path_to_ast; use either::Either; -use hir::{AsAssocItem, HirDisplay, ImportPathConfig, ModuleDef, SemanticsScope}; +use hir::{ + AsAssocItem, HirDisplay, HirFileId, ImportPathConfig, ModuleDef, SemanticsScope, + prettify_macro_expansion, +}; use itertools::Itertools; use rustc_hash::FxHashMap; use span::Edition; @@ -136,6 +139,25 @@ impl<'a> PathTransform<'a> { } } + fn prettify_target_node(&self, node: SyntaxNode) -> SyntaxNode { + match self.target_scope.file_id() { + HirFileId::FileId(_) => node, + HirFileId::MacroFile(file_id) => { + let db = self.target_scope.db; + prettify_macro_expansion( + db, + node, + &db.expansion_span_map(file_id), + self.target_scope.module().krate().into(), + ) + } + } + } + + fn prettify_target_ast<N: AstNode>(&self, node: N) -> N { + N::cast(self.prettify_target_node(node.syntax().clone())).unwrap() + } + fn build_ctx(&self) -> Ctx<'a> { let db = self.source_scope.db; let target_module = self.target_scope.module(); @@ -163,7 +185,7 @@ impl<'a> PathTransform<'a> { .for_each(|(k, v)| match (k.split(db), v) { (Either::Right(k), Some(TypeOrConst::Either(v))) => { if let Some(ty) = v.ty() { - type_substs.insert(k, ty); + type_substs.insert(k, self.prettify_target_ast(ty)); } } (Either::Right(k), None) => { @@ -178,7 +200,7 @@ impl<'a> PathTransform<'a> { } (Either::Left(k), Some(TypeOrConst::Either(v))) => { if let Some(ty) = v.ty() { - const_substs.insert(k, ty.syntax().clone()); + const_substs.insert(k, self.prettify_target_node(ty.syntax().clone())); } } (Either::Left(k), Some(TypeOrConst::Const(v))) => { @@ -189,7 +211,7 @@ impl<'a> PathTransform<'a> { // and sometimes require slight modifications; see // https://doc.rust-lang.org/reference/statements.html#expression-statements // (default values in curly brackets can cause the same problem) - const_substs.insert(k, expr.syntax().clone()); + const_substs.insert(k, self.prettify_target_node(expr.syntax().clone())); } } (Either::Left(k), None) => { @@ -204,6 +226,7 @@ impl<'a> PathTransform<'a> { } _ => (), // ignore mismatching params }); + // No need to prettify lifetimes, there's nothing to prettify. let lifetime_substs: FxHashMap<_, _> = self .generic_def .into_iter() diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml index 96be51e1b26..6f1e66948f4 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] cov-mark = "2.0.0" diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index e2957fcaefb..ac54ac0950f 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -1171,7 +1171,7 @@ trait B {} fn test(a: &dyn A) -> &dyn B { a - //^ error: expected &(dyn B + 'static), found &(dyn A + 'static) + //^ error: expected &dyn B, found &dyn A } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml index 1212fa9f9c6..0620bd26fef 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] cov-mark = "2.0.0" diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml index 2f8ed88fbb5..06d2776ebe8 100644 --- a/src/tools/rust-analyzer/crates/ide/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] cov-mark = "2.0.0" diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs index 194e8c968f7..9bd8504733a 100755 --- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs +++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs @@ -2,7 +2,7 @@ use ide_db::{FxHashSet, syntax_helpers::node_ext::vis_eq}; use syntax::{ Direction, NodeOrToken, SourceFile, SyntaxKind::{self, *}, - TextRange, TextSize, + SyntaxNode, TextRange, TextSize, ast::{self, AstNode, AstToken}, match_ast, }; @@ -16,16 +16,21 @@ const REGION_END: &str = "// endregion"; pub enum FoldKind { Comment, Imports, - Mods, + Region, Block, ArgList, - Region, - Consts, - Statics, Array, WhereClause, ReturnType, MatchArm, + // region: item runs + Modules, + Consts, + Statics, + TypeAliases, + TraitAliases, + ExternCrates, + // endregion: item runs } #[derive(Debug)] @@ -41,10 +46,7 @@ pub struct Fold { pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> { let mut res = vec![]; let mut visited_comments = FxHashSet::default(); - let mut visited_imports = FxHashSet::default(); - let mut visited_mods = FxHashSet::default(); - let mut visited_consts = FxHashSet::default(); - let mut visited_statics = FxHashSet::default(); + let mut visited_nodes = FxHashSet::default(); // regions can be nested, here is a LIFO buffer let mut region_starts: Vec<TextSize> = vec![]; @@ -93,30 +95,40 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> { if module.item_list().is_none() { if let Some(range) = contiguous_range_for_item_group( module, - &mut visited_mods, + &mut visited_nodes, ) { - res.push(Fold { range, kind: FoldKind::Mods }) + res.push(Fold { range, kind: FoldKind::Modules }) } } }, ast::Use(use_) => { - if let Some(range) = contiguous_range_for_item_group(use_, &mut visited_imports) { + if let Some(range) = contiguous_range_for_item_group(use_, &mut visited_nodes) { res.push(Fold { range, kind: FoldKind::Imports }) } }, ast::Const(konst) => { - if let Some(range) = contiguous_range_for_item_group(konst, &mut visited_consts) { + if let Some(range) = contiguous_range_for_item_group(konst, &mut visited_nodes) { res.push(Fold { range, kind: FoldKind::Consts }) } }, ast::Static(statik) => { - if let Some(range) = contiguous_range_for_item_group(statik, &mut visited_statics) { + if let Some(range) = contiguous_range_for_item_group(statik, &mut visited_nodes) { res.push(Fold { range, kind: FoldKind::Statics }) } }, - ast::WhereClause(where_clause) => { - if let Some(range) = fold_range_for_where_clause(where_clause) { - res.push(Fold { range, kind: FoldKind::WhereClause }) + ast::TypeAlias(alias) => { + if let Some(range) = contiguous_range_for_item_group(alias, &mut visited_nodes) { + res.push(Fold { range, kind: FoldKind::TypeAliases }) + } + }, + ast::TraitAlias(alias) => { + if let Some(range) = contiguous_range_for_item_group(alias, &mut visited_nodes) { + res.push(Fold { range, kind: FoldKind::TraitAliases }) + } + }, + ast::ExternCrate(extern_crate) => { + if let Some(range) = contiguous_range_for_item_group(extern_crate, &mut visited_nodes) { + res.push(Fold { range, kind: FoldKind::ExternCrates }) } }, ast::MatchArm(match_arm) => { @@ -137,9 +149,10 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> { fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> { match kind { COMMENT => Some(FoldKind::Comment), - ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList), + ARG_LIST | PARAM_LIST | GENERIC_ARG_LIST | GENERIC_PARAM_LIST => Some(FoldKind::ArgList), ARRAY_EXPR => Some(FoldKind::Array), RET_TYPE => Some(FoldKind::ReturnType), + WHERE_CLAUSE => Some(FoldKind::WhereClause), ASSOC_ITEM_LIST | RECORD_FIELD_LIST | RECORD_PAT_FIELD_LIST @@ -155,11 +168,14 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> { } } -fn contiguous_range_for_item_group<N>(first: N, visited: &mut FxHashSet<N>) -> Option<TextRange> +fn contiguous_range_for_item_group<N>( + first: N, + visited: &mut FxHashSet<SyntaxNode>, +) -> Option<TextRange> where N: ast::HasVisibility + Clone + Hash + Eq, { - if !visited.insert(first.clone()) { + if !visited.insert(first.syntax().clone()) { return None; } @@ -183,7 +199,7 @@ where if let Some(next) = N::cast(node) { let next_vis = next.visibility(); if eq_visibility(next_vis.clone(), last_vis) { - visited.insert(next.clone()); + visited.insert(next.syntax().clone()); last_vis = next_vis; last = next; continue; @@ -259,18 +275,6 @@ fn contiguous_range_for_comment( } } -fn fold_range_for_where_clause(where_clause: ast::WhereClause) -> Option<TextRange> { - let first_where_pred = where_clause.predicates().next(); - let last_where_pred = where_clause.predicates().last(); - - if first_where_pred != last_where_pred { - let start = where_clause.where_token()?.text_range().end(); - let end = where_clause.syntax().text_range().end(); - return Some(TextRange::new(start, end)); - } - None -} - fn fold_range_for_multiline_match_arm(match_arm: ast::MatchArm) -> Option<TextRange> { if fold_kind(match_arm.expr()?.syntax().kind()).is_some() { None @@ -307,16 +311,19 @@ mod tests { let kind = match fold.kind { FoldKind::Comment => "comment", FoldKind::Imports => "imports", - FoldKind::Mods => "mods", + FoldKind::Modules => "mods", FoldKind::Block => "block", FoldKind::ArgList => "arglist", FoldKind::Region => "region", FoldKind::Consts => "consts", FoldKind::Statics => "statics", + FoldKind::TypeAliases => "typealiases", FoldKind::Array => "array", FoldKind::WhereClause => "whereclause", FoldKind::ReturnType => "returntype", FoldKind::MatchArm => "matcharm", + FoldKind::TraitAliases => "traitaliases", + FoldKind::ExternCrates => "externcrates", }; assert_eq!(kind, &attr.unwrap()); } @@ -594,19 +601,18 @@ static SECOND_STATIC: &str = "second";</fold> #[test] fn fold_where_clause() { - // fold multi-line and don't fold single line. check( r#" fn foo() -where<fold whereclause> +<fold whereclause>where A: Foo, B: Foo, C: Foo, D: Foo,</fold> {} fn bar() -where - A: Bar, {} +<fold whereclause>where + A: Bar,</fold> {} "#, ) } @@ -624,4 +630,16 @@ fn bar() -> (bool, bool) { (true, true) } "#, ) } + + #[test] + fn fold_generics() { + check( + r#" +type Foo<T, U> = foo<fold arglist>< + T, + U, +></fold>; +"#, + ) + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 574803fb9e8..fd465f31d43 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -291,13 +291,14 @@ fn handle_control_flow_keywords( token: &SyntaxToken, ) -> Option<Vec<NavigationTarget>> { match token.kind() { - // For `fn` / `loop` / `while` / `for` / `async`, return the keyword it self, + // For `fn` / `loop` / `while` / `for` / `async` / `match`, return the keyword it self, // so that VSCode will find the references when using `ctrl + click` T![fn] | T![async] | T![try] | T![return] => nav_for_exit_points(sema, token), T![loop] | T![while] | T![break] | T![continue] => nav_for_break_points(sema, token), T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => { nav_for_break_points(sema, token) } + T![match] | T![=>] | T![if] => nav_for_branch_exit_points(sema, token), _ => None, } } @@ -407,6 +408,91 @@ fn nav_for_exit_points( Some(navs) } +pub(crate) fn find_branch_root( + sema: &Semantics<'_, RootDatabase>, + token: &SyntaxToken, +) -> Vec<SyntaxNode> { + let find_nodes = |node_filter: fn(SyntaxNode) -> Option<SyntaxNode>| { + sema.descend_into_macros(token.clone()) + .into_iter() + .filter_map(|token| node_filter(token.parent()?)) + .collect_vec() + }; + + match token.kind() { + T![match] => find_nodes(|node| Some(ast::MatchExpr::cast(node)?.syntax().clone())), + T![=>] => find_nodes(|node| Some(ast::MatchArm::cast(node)?.syntax().clone())), + T![if] => find_nodes(|node| { + let if_expr = ast::IfExpr::cast(node)?; + + let root_if = iter::successors(Some(if_expr.clone()), |if_expr| { + let parent_if = if_expr.syntax().parent().and_then(ast::IfExpr::cast)?; + let ast::ElseBranch::IfExpr(else_branch) = parent_if.else_branch()? else { + return None; + }; + + (else_branch.syntax() == if_expr.syntax()).then_some(parent_if) + }) + .last()?; + + Some(root_if.syntax().clone()) + }), + _ => vec![], + } +} + +fn nav_for_branch_exit_points( + sema: &Semantics<'_, RootDatabase>, + token: &SyntaxToken, +) -> Option<Vec<NavigationTarget>> { + let db = sema.db; + + let navs = match token.kind() { + T![match] => find_branch_root(sema, token) + .into_iter() + .filter_map(|node| { + let file_id = sema.hir_file_for(&node); + let match_expr = ast::MatchExpr::cast(node)?; + let focus_range = match_expr.match_token()?.text_range(); + let match_expr_in_file = InFile::new(file_id, match_expr.into()); + Some(expr_to_nav(db, match_expr_in_file, Some(focus_range))) + }) + .flatten() + .collect_vec(), + + T![=>] => find_branch_root(sema, token) + .into_iter() + .filter_map(|node| { + let match_arm = ast::MatchArm::cast(node)?; + let match_expr = sema + .ancestors_with_macros(match_arm.syntax().clone()) + .find_map(ast::MatchExpr::cast)?; + let file_id = sema.hir_file_for(match_expr.syntax()); + let focus_range = match_arm.fat_arrow_token()?.text_range(); + let match_expr_in_file = InFile::new(file_id, match_expr.into()); + Some(expr_to_nav(db, match_expr_in_file, Some(focus_range))) + }) + .flatten() + .collect_vec(), + + T![if] => find_branch_root(sema, token) + .into_iter() + .filter_map(|node| { + let file_id = sema.hir_file_for(&node); + let if_expr = ast::IfExpr::cast(node)?; + let focus_range = if_expr.if_token()?.text_range(); + let if_expr_in_file = InFile::new(file_id, if_expr.into()); + Some(expr_to_nav(db, if_expr_in_file, Some(focus_range))) + }) + .flatten() + .collect_vec(), + + _ => return Some(Vec::new()), + }; + + Some(navs) +} + pub(crate) fn find_loops( sema: &Semantics<'_, RootDatabase>, token: &SyntaxToken, @@ -3614,4 +3700,155 @@ fn foo() { "#, ); } + + #[test] + fn goto_def_for_match_keyword() { + check( + r#" +fn main() { + match$0 0 { + // ^^^^^ + 0 => {}, + _ => {}, + } +} +"#, + ); + } + + #[test] + fn goto_def_for_match_arm_fat_arrow() { + check( + r#" +fn main() { + match 0 { + 0 =>$0 {}, + // ^^ + _ => {}, + } +} +"#, + ); + } + + #[test] + fn goto_def_for_if_keyword() { + check( + r#" +fn main() { + if$0 true { + // ^^ + () + } +} +"#, + ); + } + + #[test] + fn goto_def_for_match_nested_in_if() { + check( + r#" +fn main() { + if true { + match$0 0 { + // ^^^^^ + 0 => {}, + _ => {}, + } + } +} +"#, + ); + } + + #[test] + fn goto_def_for_multiple_match_expressions() { + check( + r#" +fn main() { + match 0 { + 0 => {}, + _ => {}, + }; + + match$0 1 { + // ^^^^^ + 1 => {}, + _ => {}, + } +} +"#, + ); + } + + #[test] + fn goto_def_for_nested_match_expressions() { + check( + r#" +fn main() { + match 0 { + 0 => match$0 1 { + // ^^^^^ + 1 => {}, + _ => {}, + }, + _ => {}, + } +} +"#, + ); + } + + #[test] + fn goto_def_for_if_else_chains() { + check( + r#" +fn main() { + if true { + // ^^ + () + } else if$0 false { + () + } else { + () + } +} +"#, + ); + } + + #[test] + fn goto_def_for_match_with_guards() { + check( + r#" +fn main() { + match 42 { + x if x > 0 =>$0 {}, + // ^^ + _ => {}, + } +} +"#, + ); + } + + #[test] + fn goto_def_for_match_with_macro_arm() { + check( + r#" +macro_rules! arm { + () => { 0 => {} }; +} + +fn main() { + match$0 0 { + // ^^^^^ + arm!(), + _ => {}, + } +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs index 86d72fefe05..b80e81d39c6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs @@ -70,11 +70,10 @@ pub(crate) fn goto_type_definition( } let range = token.text_range(); - sema.descend_into_macros_no_opaque(token,false) + sema.descend_into_macros_no_opaque(token, false) .into_iter() .filter_map(|token| { - sema - .token_ancestors_with_macros(token.value) + sema.token_ancestors_with_macros(token.value) // When `token` is within a macro call, we can't determine its type. Don't continue // this traversal because otherwise we'll end up returning the type of *that* macro // call, which is not what we want in general. @@ -103,7 +102,6 @@ pub(crate) fn goto_type_definition( _ => return None, } }; - Some(ty) }) }) diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index aa947921a9b..356bd69aa44 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -37,8 +37,11 @@ pub struct HighlightRelatedConfig { pub break_points: bool, pub closure_captures: bool, pub yield_points: bool, + pub branch_exit_points: bool, } +type HighlightMap = FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>; + // Feature: Highlight Related // // Highlights constructs related to the thing under the cursor: @@ -64,7 +67,7 @@ pub(crate) fn highlight_related( let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind { T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?` - T![->] => 4, + T![->] | T![=>] => 4, kind if kind.is_keyword(file_id.edition(sema.db)) => 3, IDENT | INT_NUMBER => 2, T![|] => 1, @@ -78,6 +81,9 @@ pub(crate) fn highlight_related( T![fn] | T![return] | T![->] if config.exit_points => { highlight_exit_points(sema, token).remove(&file_id) } + T![match] | T![=>] | T![if] if config.branch_exit_points => { + highlight_branch_exit_points(sema, token).remove(&file_id) + } T![await] | T![async] if config.yield_points => { highlight_yield_points(sema, token).remove(&file_id) } @@ -300,11 +306,93 @@ fn highlight_references( if res.is_empty() { None } else { Some(res.into_iter().collect()) } } +pub(crate) fn highlight_branch_exit_points( + sema: &Semantics<'_, RootDatabase>, + token: SyntaxToken, +) -> FxHashMap<EditionedFileId, Vec<HighlightedRange>> { + let mut highlights: HighlightMap = FxHashMap::default(); + + let push_to_highlights = |file_id, range, highlights: &mut HighlightMap| { + if let Some(FileRange { file_id, range }) = original_frange(sema.db, file_id, range) { + let hrange = HighlightedRange { category: ReferenceCategory::empty(), range }; + highlights.entry(file_id).or_default().insert(hrange); + } + }; + + let push_tail_expr = |tail: Option<ast::Expr>, highlights: &mut HighlightMap| { + let Some(tail) = tail else { + return; + }; + + for_each_tail_expr(&tail, &mut |tail| { + let file_id = sema.hir_file_for(tail.syntax()); + let range = tail.syntax().text_range(); + push_to_highlights(file_id, Some(range), highlights); + }); + }; + + let nodes = goto_definition::find_branch_root(sema, &token).into_iter(); + match token.kind() { + T![match] => { + for match_expr in nodes.filter_map(ast::MatchExpr::cast) { + let file_id = sema.hir_file_for(match_expr.syntax()); + let range = match_expr.match_token().map(|token| token.text_range()); + push_to_highlights(file_id, range, &mut highlights); + + let Some(arm_list) = match_expr.match_arm_list() else { + continue; + }; + for arm in arm_list.arms() { + push_tail_expr(arm.expr(), &mut highlights); + } + } + } + T![=>] => { + for arm in nodes.filter_map(ast::MatchArm::cast) { + let file_id = sema.hir_file_for(arm.syntax()); + let range = arm.fat_arrow_token().map(|token| token.text_range()); + push_to_highlights(file_id, range, &mut highlights); + + push_tail_expr(arm.expr(), &mut highlights); + } + } + T![if] => { + for mut if_to_process in nodes.map(ast::IfExpr::cast) { + while let Some(cur_if) = if_to_process.take() { + let file_id = sema.hir_file_for(cur_if.syntax()); + + let if_kw_range = cur_if.if_token().map(|token| token.text_range()); + push_to_highlights(file_id, if_kw_range, &mut highlights); + + if let Some(then_block) = cur_if.then_branch() { + push_tail_expr(Some(then_block.into()), &mut highlights); + } + + match cur_if.else_branch() { + Some(ast::ElseBranch::Block(else_block)) => { + push_tail_expr(Some(else_block.into()), &mut highlights); + if_to_process = None; + } + Some(ast::ElseBranch::IfExpr(nested_if)) => if_to_process = Some(nested_if), + None => if_to_process = None, + } + } + } + } + _ => {} + } + + highlights + .into_iter() + .map(|(file_id, ranges)| (file_id, ranges.into_iter().collect())) + .collect() +} + fn hl_exit_points( sema: &Semantics<'_, RootDatabase>, def_token: Option<SyntaxToken>, body: ast::Expr, -) -> Option<FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>> { +) -> Option<HighlightMap> { let mut highlights: FxHashMap<EditionedFileId, FxHashSet<_>> = FxHashMap::default(); let mut push_to_highlights = |file_id, range| { @@ -411,7 +499,7 @@ pub(crate) fn highlight_break_points( loop_token: Option<SyntaxToken>, label: Option<ast::Label>, expr: ast::Expr, - ) -> Option<FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>> { + ) -> Option<HighlightMap> { let mut highlights: FxHashMap<EditionedFileId, FxHashSet<_>> = FxHashMap::default(); let mut push_to_highlights = |file_id, range| { @@ -504,7 +592,7 @@ pub(crate) fn highlight_yield_points( sema: &Semantics<'_, RootDatabase>, async_token: Option<SyntaxToken>, body: Option<ast::Expr>, - ) -> Option<FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>> { + ) -> Option<HighlightMap> { let mut highlights: FxHashMap<EditionedFileId, FxHashSet<_>> = FxHashMap::default(); let mut push_to_highlights = |file_id, range| { @@ -597,10 +685,7 @@ fn original_frange( InFile::new(file_id, text_range?).original_node_file_range_opt(db).map(|(frange, _)| frange) } -fn merge_map( - res: &mut FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>, - new: Option<FxHashMap<EditionedFileId, FxHashSet<HighlightedRange>>>, -) { +fn merge_map(res: &mut HighlightMap, new: Option<HighlightMap>) { let Some(new) = new else { return; }; @@ -750,6 +835,7 @@ mod tests { references: true, closure_captures: true, yield_points: true, + branch_exit_points: true, }; #[track_caller] @@ -2135,6 +2221,62 @@ fn main() { } #[test] + fn nested_match() { + check( + r#" +fn main() { + match$0 0 { + // ^^^^^ + 0 => match 1 { + 1 => 2, + // ^ + _ => 3, + // ^ + }, + _ => 4, + // ^ + } +} +"#, + ) + } + + #[test] + fn single_arm_highlight() { + check( + r#" +fn main() { + match 0 { + 0 =>$0 { + // ^^ + let x = 1; + x + // ^ + } + _ => 2, + } +} +"#, + ) + } + + #[test] + fn no_branches_when_disabled() { + let config = HighlightRelatedConfig { branch_exit_points: false, ..ENABLED_CONFIG }; + check_with_config( + r#" +fn main() { + match$0 0 { + 0 => 1, + _ => 2, + } +} +"#, + config, + ); + } + + #[test] fn asm() { check( r#" @@ -2165,6 +2307,200 @@ pub unsafe fn bootstrap() -> ! { } #[test] + fn complex_arms_highlight() { + check( + r#" +fn calculate(n: i32) -> i32 { n * 2 } + +fn main() { + match$0 Some(1) { + // ^^^^^ + Some(x) => match x { + 0 => { let y = x; y }, + // ^ + 1 => calculate(x), + //^^^^^^^^^^^^ + _ => (|| 6)(), + // ^^^^^^^^ + }, + None => loop { + break 5; + // ^^^^^^^ + }, + } +} +"#, + ) + } + + #[test] + fn match_in_macro_highlight() { + check( + r#" +macro_rules! M { + ($e:expr) => { $e }; +} + +fn main() { + M!{ + match$0 Some(1) { + // ^^^^^ + Some(x) => x, + // ^ + None => 0, + // ^ + } + } +} +"#, + ) + } + + #[test] + fn match_in_macro_highlight_2() { + check( + r#" +macro_rules! match_ast { + (match $node:ident { $($tt:tt)* }) => { $crate::match_ast!(match ($node) { $($tt)* }) }; + + (match ($node:expr) { + $( $( $path:ident )::+ ($it:pat) => $res:expr, )* + _ => $catch_all:expr $(,)? + }) => {{ + $( if let Some($it) = $($path::)+cast($node.clone()) { $res } else )* + { $catch_all } + }}; +} + +fn main() { + match_ast! { + match$0 Some(1) { + Some(x) => x, + } + } +} + "#, + ); + } + + #[test] + fn nested_if_else() { + check( + r#" +fn main() { + if$0 true { + // ^^ + if false { + 1 + // ^ + } else { + 2 + // ^ + } + } else { + 3 + // ^ + } +} +"#, + ) + } + + #[test] + fn if_else_if_highlight() { + check( + r#" +fn main() { + if$0 true { + // ^^ + 1 + // ^ + } else if false { + // ^^ + 2 + // ^ + } else { + 3 + // ^ + } +} +"#, + ) + } + + #[test] + fn complex_if_branches() { + check( + r#" +fn calculate(n: i32) -> i32 { n * 2 } + +fn main() { + if$0 true { + // ^^ + let x = 5; + calculate(x) + // ^^^^^^^^^^^^ + } else if false { + // ^^ + (|| 10)() + // ^^^^^^^^^ + } else { + loop { + break 15; + // ^^^^^^^^ + } + } +} +"#, + ) + } + + #[test] + fn if_in_macro_highlight() { + check( + r#" +macro_rules! M { + ($e:expr) => { $e }; +} + +fn main() { + M!{ + if$0 true { + // ^^ + 5 + // ^ + } else { + 10 + // ^^ + } + } +} +"#, + ) + } + + #[test] + fn match_in_macro() { + // We should not highlight the outer `match` expression. + check( + r#" +macro_rules! M { + (match) => { 1 }; +} + +fn main() { + match Some(1) { + Some(x) => x, + None => { + M!(match$0) + } + } +} + "#, + ) + } + + #[test] fn labeled_block_tail_expr() { check( r#" diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 36fdd90e8ae..729349365e6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -380,9 +380,9 @@ fn main() { let foo = foo3(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo4(); - // ^^^ &'static (dyn Fn(f64, f64) -> u32 + 'static) + // ^^^ &'static dyn Fn(f64, f64) -> u32 let foo = foo5(); - // ^^^ &'static (dyn Fn(&(dyn Fn(f64, f64) -> u32 + 'static), f64) -> u32 + 'static) + // ^^^ &'static dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32 let foo = foo6(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo7(); @@ -413,7 +413,7 @@ fn main() { let foo = foo3(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo4(); - // ^^^ &'static (dyn Fn(f64, f64) -> u32 + 'static) + // ^^^ &'static dyn Fn(f64, f64) -> u32 let foo = foo5(); let foo = foo6(); let foo = foo7(); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs index b9a98f88be7..f0003dae3f3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs @@ -143,7 +143,7 @@ fn foo<T>() {} file_id: FileId( 1, ), - range: 135..140, + range: 446..451, }, ), ), diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs index ca3a982760f..d2216e66ccb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs @@ -193,7 +193,7 @@ impl Tr for () { //^ impl Tr for () impl dyn Tr { } -//^ impl dyn Tr + 'static +//^ impl dyn Tr static S0: () = 0; static S1: () = {}; diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index c6a323d4081..fe874bc99b4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -21,6 +21,7 @@ use hir::{PathResolution, Semantics}; use ide_db::{ FileId, RootDatabase, defs::{Definition, NameClass, NameRefClass}, + helpers::pick_best_token, search::{ReferenceCategory, SearchScope, UsageSearchResult}, }; use itertools::Itertools; @@ -397,7 +398,11 @@ fn handle_control_flow_keywords( .attach_first_edition(file_id) .map(|it| it.edition(sema.db)) .unwrap_or(Edition::CURRENT); - let token = file.syntax().token_at_offset(offset).find(|t| t.kind().is_keyword(edition))?; + let token = pick_best_token(file.syntax().token_at_offset(offset), |kind| match kind { + _ if kind.is_keyword(edition) => 4, + T![=>] => 3, + _ => 1, + })?; let references = match token.kind() { T![fn] | T![return] | T![try] => highlight_related::highlight_exit_points(sema, token), @@ -408,6 +413,7 @@ fn handle_control_flow_keywords( T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => { highlight_related::highlight_break_points(sema, token) } + T![if] | T![=>] | T![match] => highlight_related::highlight_branch_exit_points(sema, token), _ => return None, } .into_iter() @@ -1344,6 +1350,159 @@ impl Foo { ); } + #[test] + fn test_highlight_if_branches() { + check( + r#" +fn main() { + let x = if$0 true { + 1 + } else if false { + 2 + } else { + 3 + }; + + println!("x: {}", x); +} +"#, + expect![[r#" + FileId(0) 24..26 + FileId(0) 42..43 + FileId(0) 55..57 + FileId(0) 74..75 + FileId(0) 97..98 + "#]], + ); + } + + #[test] + fn test_highlight_match_branches() { + check( + r#" +fn main() { + $0match Some(42) { + Some(x) if x > 0 => println!("positive"), + Some(0) => println!("zero"), + Some(_) => println!("negative"), + None => println!("none"), + }; +} +"#, + expect![[r#" + FileId(0) 16..21 + FileId(0) 61..81 + FileId(0) 102..118 + FileId(0) 139..159 + FileId(0) 177..193 + "#]], + ); + } + + #[test] + fn test_highlight_match_arm_arrow() { + check( + r#" +fn main() { + match Some(42) { + Some(x) if x > 0 $0=> println!("positive"), + Some(0) => println!("zero"), + Some(_) => println!("negative"), + None => println!("none"), + } +} +"#, + expect![[r#" + FileId(0) 58..60 + FileId(0) 61..81 + "#]], + ); + } + + #[test] + fn test_highlight_nested_branches() { + check( + r#" +fn main() { + let x = $0if true { + if false { + 1 + } else { + match Some(42) { + Some(_) => 2, + None => 3, + } + } + } else { + 4 + }; + + println!("x: {}", x); +} +"#, + expect![[r#" + FileId(0) 24..26 + FileId(0) 65..66 + FileId(0) 140..141 + FileId(0) 167..168 + FileId(0) 215..216 + "#]], + ); + } + + #[test] + fn test_highlight_match_with_complex_guards() { + check( + r#" +fn main() { + let x = $0match (x, y) { + (a, b) if a > b && a % 2 == 0 => 1, + (a, b) if a < b || b % 2 == 1 => 2, + (a, _) if a > 40 => 3, + _ => 4, + }; + + println!("x: {}", x); +} +"#, + expect![[r#" + FileId(0) 24..29 + FileId(0) 80..81 + FileId(0) 124..125 + FileId(0) 155..156 + FileId(0) 171..172 + "#]], + ); + } + + #[test] + fn test_highlight_mixed_if_match_expressions() { + check( + r#" +fn main() { + let x = $0if let Some(x) = Some(42) { + 1 + } else if let None = None { + 2 + } else { + match 42 { + 0 => 3, + _ => 4, + } + }; +} +"#, + expect![[r#" + FileId(0) 24..26 + FileId(0) 60..61 + FileId(0) 73..75 + FileId(0) 102..103 + FileId(0) 153..154 + FileId(0) 173..174 + "#]], + ); + } + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { check_with_scope(ra_fixture, None, expect) } @@ -2867,4 +3026,66 @@ const FOO$0: i32 = 0; "#]], ); } + + #[test] + fn test_highlight_if_let_match_combined() { + check( + r#" +enum MyEnum { A(i32), B(String), C } + +fn main() { + let val = MyEnum::A(42); + + let x = $0if let MyEnum::A(x) = val { + 1 + } else if let MyEnum::B(s) = val { + 2 + } else { + match val { + MyEnum::C => 3, + _ => 4, + } + }; +} +"#, + expect![[r#" + FileId(0) 92..94 + FileId(0) 128..129 + FileId(0) 141..143 + FileId(0) 177..178 + FileId(0) 237..238 + FileId(0) 257..258 + "#]], + ); + } + + #[test] + fn test_highlight_nested_match_expressions() { + check( + r#" +enum Outer { A(Inner), B } +enum Inner { X, Y(i32) } + +fn main() { + let val = Outer::A(Inner::Y(42)); + + $0match val { + Outer::A(inner) => match inner { + Inner::X => println!("Inner::X"), + Inner::Y(n) if n > 0 => println!("Inner::Y positive: {}", n), + Inner::Y(_) => println!("Inner::Y non-positive"), + }, + Outer::B => println!("Outer::B"), + } +} +"#, + expect![[r#" + FileId(0) 108..113 + FileId(0) 185..205 + FileId(0) 243..279 + FileId(0) 308..341 + FileId(0) 374..394 + "#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/intern/Cargo.toml b/src/tools/rust-analyzer/crates/intern/Cargo.toml index 9ff656cb744..81b6703deef 100644 --- a/src/tools/rust-analyzer/crates/intern/Cargo.toml +++ b/src/tools/rust-analyzer/crates/intern/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index adc581309d1..1ccd20c25e9 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -438,6 +438,8 @@ define_symbols! { shr, simd, sized, + meta_sized, + pointee_sized, skip, slice_len_fn, Some, diff --git a/src/tools/rust-analyzer/crates/mbe/Cargo.toml b/src/tools/rust-analyzer/crates/mbe/Cargo.toml index f3ab093bae0..eef718b7062 100644 --- a/src/tools/rust-analyzer/crates/mbe/Cargo.toml +++ b/src/tools/rust-analyzer/crates/mbe/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] cov-mark = "2.0.0" diff --git a/src/tools/rust-analyzer/crates/parser/Cargo.toml b/src/tools/rust-analyzer/crates/parser/Cargo.toml index c80510eedfb..c7da654de6d 100644 --- a/src/tools/rust-analyzer/crates/parser/Cargo.toml +++ b/src/tools/rust-analyzer/crates/parser/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] drop_bomb = "0.1.5" diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs index ea5a3bc8593..55c5dc400b9 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs @@ -122,7 +122,7 @@ fn lifetime_bounds(p: &mut Parser<'_>) { } // test type_param_bounds -// struct S<T: 'a + ?Sized + (Copy) + ~const Drop>; +// struct S<T: 'a + ?Sized + (Copy) + [const] Drop>; pub(super) fn bounds(p: &mut Parser<'_>) { p.expect(T![:]); bounds_without_colon(p); @@ -187,6 +187,11 @@ fn type_bound(p: &mut Parser<'_>) -> bool { p.bump_any(); p.expect(T![const]); } + T!['['] => { + p.bump_any(); + p.expect(T![const]); + p.expect(T![']']); + } // test const_trait_bound // const fn foo(_: impl const Trait) {} T![const] => { diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index 0fa9a264545..e6c92dec681 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -11,7 +11,8 @@ use std::ops; use rustc_literal_escaper::{ - EscapeError, Mode, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, + EscapeError, Mode, unescape_byte, unescape_byte_str, unescape_c_str, unescape_char, + unescape_str, }; use crate::{ @@ -151,14 +152,14 @@ impl<'a> Converter<'a> { self.res } - fn push(&mut self, kind: SyntaxKind, len: usize, err: Option<&str>) { + fn push(&mut self, kind: SyntaxKind, len: usize, errors: Vec<String>) { self.res.push(kind, self.offset); self.offset += len; - if let Some(err) = err { - let token = self.res.len() as u32; - let msg = err.to_owned(); - self.res.error.push(LexError { msg, token }); + for msg in errors { + if !msg.is_empty() { + self.res.error.push(LexError { msg, token: self.res.len() as u32 }); + } } } @@ -167,14 +168,16 @@ impl<'a> Converter<'a> { // We drop some useful information here (see patterns with double dots `..`) // Storing that info in `SyntaxKind` is not possible due to its layout requirements of // being `u16` that come from `rowan::SyntaxKind`. - let mut err = ""; + let mut errors: Vec<String> = vec![]; let syntax_kind = { match kind { rustc_lexer::TokenKind::LineComment { doc_style: _ } => COMMENT, rustc_lexer::TokenKind::BlockComment { doc_style: _, terminated } => { if !terminated { - err = "Missing trailing `*/` symbols to terminate the block comment"; + errors.push( + "Missing trailing `*/` symbols to terminate the block comment".into(), + ); } COMMENT } @@ -184,9 +187,9 @@ impl<'a> Converter<'a> { invalid_infostring, } => { if *has_invalid_preceding_whitespace { - err = "invalid preceding whitespace for frontmatter opening" + errors.push("invalid preceding whitespace for frontmatter opening".into()); } else if *invalid_infostring { - err = "invalid infostring for frontmatter" + errors.push("invalid infostring for frontmatter".into()); } FRONTMATTER } @@ -198,7 +201,7 @@ impl<'a> Converter<'a> { SyntaxKind::from_keyword(token_text, self.edition).unwrap_or(IDENT) } rustc_lexer::TokenKind::InvalidIdent => { - err = "Ident contains invalid characters"; + errors.push("Ident contains invalid characters".into()); IDENT } @@ -206,7 +209,7 @@ impl<'a> Converter<'a> { rustc_lexer::TokenKind::GuardedStrPrefix if self.edition.at_least_2024() => { // FIXME: rustc does something better for recovery. - err = "Invalid string literal (reserved syntax)"; + errors.push("Invalid string literal (reserved syntax)".into()); ERROR } rustc_lexer::TokenKind::GuardedStrPrefix => { @@ -222,12 +225,12 @@ impl<'a> Converter<'a> { rustc_lexer::TokenKind::Lifetime { starts_with_number } => { if *starts_with_number { - err = "Lifetime name cannot start with a number"; + errors.push("Lifetime name cannot start with a number".into()); } LIFETIME_IDENT } rustc_lexer::TokenKind::UnknownPrefixLifetime => { - err = "Unknown lifetime prefix"; + errors.push("Unknown lifetime prefix".into()); LIFETIME_IDENT } rustc_lexer::TokenKind::RawLifetime => LIFETIME_IDENT, @@ -262,119 +265,128 @@ impl<'a> Converter<'a> { rustc_lexer::TokenKind::Unknown => ERROR, rustc_lexer::TokenKind::UnknownPrefix if token_text == "builtin" => IDENT, rustc_lexer::TokenKind::UnknownPrefix => { - err = "unknown literal prefix"; + errors.push("unknown literal prefix".into()); IDENT } rustc_lexer::TokenKind::Eof => EOF, } }; - let err = if err.is_empty() { None } else { Some(err) }; - self.push(syntax_kind, token_text.len(), err); + self.push(syntax_kind, token_text.len(), errors); } fn extend_literal(&mut self, len: usize, kind: &rustc_lexer::LiteralKind) { - let mut err = ""; + let invalid_raw_msg = String::from("Invalid raw string literal"); + + let mut errors = vec![]; + let mut no_end_quote = |c: char, kind: &str| { + errors.push(format!("Missing trailing `{c}` symbol to terminate the {kind} literal")); + }; let syntax_kind = match *kind { rustc_lexer::LiteralKind::Int { empty_int, base: _ } => { if empty_int { - err = "Missing digits after the integer base prefix"; + errors.push("Missing digits after the integer base prefix".into()); } INT_NUMBER } rustc_lexer::LiteralKind::Float { empty_exponent, base: _ } => { if empty_exponent { - err = "Missing digits after the exponent symbol"; + errors.push("Missing digits after the exponent symbol".into()); } FLOAT_NUMBER } rustc_lexer::LiteralKind::Char { terminated } => { if !terminated { - err = "Missing trailing `'` symbol to terminate the character literal"; + no_end_quote('\'', "character"); } else { let text = &self.res.text[self.offset + 1..][..len - 1]; - let i = text.rfind('\'').unwrap(); - let text = &text[..i]; + let text = &text[..text.rfind('\'').unwrap()]; if let Err(e) = unescape_char(text) { - err = error_to_diagnostic_message(e, Mode::Char); + errors.push(err_to_msg(e, Mode::Char)); } } CHAR } rustc_lexer::LiteralKind::Byte { terminated } => { if !terminated { - err = "Missing trailing `'` symbol to terminate the byte literal"; + no_end_quote('\'', "byte"); } else { let text = &self.res.text[self.offset + 2..][..len - 2]; - let i = text.rfind('\'').unwrap(); - let text = &text[..i]; + let text = &text[..text.rfind('\'').unwrap()]; if let Err(e) = unescape_byte(text) { - err = error_to_diagnostic_message(e, Mode::Byte); + errors.push(err_to_msg(e, Mode::Byte)); } } - BYTE } rustc_lexer::LiteralKind::Str { terminated } => { if !terminated { - err = "Missing trailing `\"` symbol to terminate the string literal"; + no_end_quote('"', "string"); } else { let text = &self.res.text[self.offset + 1..][..len - 1]; - let i = text.rfind('"').unwrap(); - let text = &text[..i]; - err = unescape_string_error_message(text, Mode::Str); + let text = &text[..text.rfind('"').unwrap()]; + unescape_str(text, |_, res| { + if let Err(e) = res { + errors.push(err_to_msg(e, Mode::Str)); + } + }); } STRING } rustc_lexer::LiteralKind::ByteStr { terminated } => { if !terminated { - err = "Missing trailing `\"` symbol to terminate the byte string literal"; + no_end_quote('"', "byte string"); } else { let text = &self.res.text[self.offset + 2..][..len - 2]; - let i = text.rfind('"').unwrap(); - let text = &text[..i]; - err = unescape_string_error_message(text, Mode::ByteStr); + let text = &text[..text.rfind('"').unwrap()]; + unescape_byte_str(text, |_, res| { + if let Err(e) = res { + errors.push(err_to_msg(e, Mode::ByteStr)); + } + }); } BYTE_STRING } rustc_lexer::LiteralKind::CStr { terminated } => { if !terminated { - err = "Missing trailing `\"` symbol to terminate the string literal"; + no_end_quote('"', "C string") } else { let text = &self.res.text[self.offset + 2..][..len - 2]; - let i = text.rfind('"').unwrap(); - let text = &text[..i]; - err = unescape_string_error_message(text, Mode::CStr); + let text = &text[..text.rfind('"').unwrap()]; + unescape_c_str(text, |_, res| { + if let Err(e) = res { + errors.push(err_to_msg(e, Mode::CStr)); + } + }); } C_STRING } rustc_lexer::LiteralKind::RawStr { n_hashes } => { if n_hashes.is_none() { - err = "Invalid raw string literal"; + errors.push(invalid_raw_msg); } STRING } rustc_lexer::LiteralKind::RawByteStr { n_hashes } => { if n_hashes.is_none() { - err = "Invalid raw string literal"; + errors.push(invalid_raw_msg); } BYTE_STRING } rustc_lexer::LiteralKind::RawCStr { n_hashes } => { if n_hashes.is_none() { - err = "Invalid raw string literal"; + errors.push(invalid_raw_msg); } C_STRING } }; - let err = if err.is_empty() { None } else { Some(err) }; - self.push(syntax_kind, len, err); + self.push(syntax_kind, len, errors); } } -fn error_to_diagnostic_message(error: EscapeError, mode: Mode) -> &'static str { +fn err_to_msg(error: EscapeError, mode: Mode) -> String { match error { EscapeError::ZeroChars => "empty character literal", EscapeError::MoreThanOneChar => "character literal may only contain one codepoint", @@ -410,28 +422,5 @@ fn error_to_diagnostic_message(error: EscapeError, mode: Mode) -> &'static str { EscapeError::UnskippedWhitespaceWarning => "", EscapeError::MultipleSkippedLinesWarning => "", } -} - -fn unescape_string_error_message(text: &str, mode: Mode) -> &'static str { - let mut error_message = ""; - match mode { - Mode::CStr => { - unescape_mixed(text, mode, &mut |_, res| { - if let Err(e) = res { - error_message = error_to_diagnostic_message(e, mode); - } - }); - } - Mode::ByteStr | Mode::Str => { - unescape_unicode(text, mode, &mut |_, res| { - if let Err(e) = res { - error_message = error_to_diagnostic_message(e, mode); - } - }); - } - _ => { - // Other Modes are not supported yet or do not apply - } - } - error_message + .into() } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rast index dee860c2418..259637c898a 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rast @@ -40,8 +40,9 @@ SOURCE_FILE PLUS "+" WHITESPACE " " TYPE_BOUND - TILDE "~" + L_BRACK "[" CONST_KW "const" + R_BRACK "]" WHITESPACE " " PATH_TYPE PATH diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rs index 5da3083b9c5..8f37af78e9f 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_param_bounds.rs @@ -1 +1 @@ -struct S<T: 'a + ?Sized + (Copy) + ~const Drop>; +struct S<T: 'a + ?Sized + (Copy) + [const] Drop>; diff --git a/src/tools/rust-analyzer/crates/paths/Cargo.toml b/src/tools/rust-analyzer/crates/paths/Cargo.toml index 4cc70726da0..f0dafab70c1 100644 --- a/src/tools/rust-analyzer/crates/paths/Cargo.toml +++ b/src/tools/rust-analyzer/crates/paths/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] camino.workspace = true diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml index f5ba40a994b..dac8e094357 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] serde.workspace = true diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml index 8fd675d0d31..4034f244393 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] object.workspace = true diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml index c416d997a89..bc04482273e 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" license = "MIT OR Apache-2.0" [lib] +doctest = false [build-dependencies] cargo_metadata = "0.20.0" diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs index b97569d4dbd..b9e84a474dd 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs @@ -109,13 +109,11 @@ fn main() { let mut artifact_path = None; for message in Message::parse_stream(output.stdout.as_slice()) { - if let Message::CompilerArtifact(artifact) = message.unwrap() { - if artifact.target.kind.contains(&cargo_metadata::TargetKind::ProcMacro) - && (artifact.package_id.repr.starts_with(&repr) - || artifact.package_id.repr == pkgid) - { - artifact_path = Some(PathBuf::from(&artifact.filenames[0])); - } + if let Message::CompilerArtifact(artifact) = message.unwrap() + && artifact.target.kind.contains(&cargo_metadata::TargetKind::ProcMacro) + && (artifact.package_id.repr.starts_with(&repr) || artifact.package_id.repr == pkgid) + { + artifact_path = Some(PathBuf::from(&artifact.filenames[0])); } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml index 33b7c2bb0ad..e1678bddff8 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" publish = false [lib] +doctest = false proc-macro = true [dependencies] diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml index bae891c1984..4828419003a 100644 --- a/src/tools/rust-analyzer/crates/profile/Cargo.toml +++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] cfg-if = "1.0.1" diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml index 64ea75922fb..27fe9f79bbc 100644 --- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml +++ b/src/tools/rust-analyzer/crates/project-model/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] anyhow.workspace = true diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs index 4435376eab6..bbaa8f4f292 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs @@ -20,9 +20,7 @@ use toolchain::Tool; use crate::{ CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot, - TargetKind, - toolchain_info::{QueryConfig, version}, - utf8_stdout, + TargetKind, utf8_stdout, }; /// Output of the build script and proc-macro building steps for a workspace. @@ -64,6 +62,7 @@ impl WorkspaceBuildScripts { workspace: &CargoWorkspace, progress: &dyn Fn(String), sysroot: &Sysroot, + toolchain: Option<&semver::Version>, ) -> io::Result<WorkspaceBuildScripts> { let current_dir = workspace.workspace_root(); @@ -74,6 +73,7 @@ impl WorkspaceBuildScripts { workspace.manifest_path(), current_dir, sysroot, + toolchain, )?; Self::run_per_ws(cmd, workspace, progress) } @@ -95,6 +95,7 @@ impl WorkspaceBuildScripts { &ManifestPath::try_from(working_directory.clone()).unwrap(), working_directory, &Sysroot::empty(), + None, )?; // NB: Cargo.toml could have been modified between `cargo metadata` and // `cargo check`. We shouldn't assume that package ids we see here are @@ -356,7 +357,7 @@ impl WorkspaceBuildScripts { }); } Message::CompilerMessage(message) => { - progress(message.target.name); + progress(format!("received compiler message for: {}", message.target.name)); if let Some(diag) = message.message.rendered.as_deref() { push_err(diag); @@ -387,12 +388,13 @@ impl WorkspaceBuildScripts { manifest_path: &ManifestPath, current_dir: &AbsPath, sysroot: &Sysroot, + toolchain: Option<&semver::Version>, ) -> io::Result<Command> { - let mut cmd = match config.run_build_script_command.as_deref() { + match config.run_build_script_command.as_deref() { Some([program, args @ ..]) => { let mut cmd = toolchain::command(program, current_dir, &config.extra_env); cmd.args(args); - cmd + Ok(cmd) } _ => { let mut cmd = sysroot.tool(Tool::Cargo, current_dir, &config.extra_env); @@ -444,40 +446,35 @@ impl WorkspaceBuildScripts { cmd.arg("--keep-going"); - cmd + // If [`--compile-time-deps` flag](https://github.com/rust-lang/cargo/issues/14434) is + // available in current toolchain's cargo, use it to build compile time deps only. + const COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION: semver::Version = semver::Version { + major: 1, + minor: 89, + patch: 0, + pre: semver::Prerelease::EMPTY, + build: semver::BuildMetadata::EMPTY, + }; + + let cargo_comp_time_deps_available = + toolchain.is_some_and(|v| *v >= COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION); + + if cargo_comp_time_deps_available { + cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly"); + cmd.arg("-Zunstable-options"); + cmd.arg("--compile-time-deps"); + } else if config.wrap_rustc_in_build_scripts { + // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use + // that to compile only proc macros and build scripts during the initial + // `cargo check`. + // We don't need this if we are using `--compile-time-deps` flag. + let myself = std::env::current_exe()?; + cmd.env("RUSTC_WRAPPER", myself); + cmd.env("RA_RUSTC_WRAPPER", "1"); + } + Ok(cmd) } - }; - - // If [`--compile-time-deps` flag](https://github.com/rust-lang/cargo/issues/14434) is - // available in current toolchain's cargo, use it to build compile time deps only. - const COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION: semver::Version = semver::Version { - major: 1, - minor: 90, - patch: 0, - pre: semver::Prerelease::EMPTY, - build: semver::BuildMetadata::EMPTY, - }; - - let query_config = QueryConfig::Cargo(sysroot, manifest_path); - let toolchain = version::get(query_config, &config.extra_env).ok().flatten(); - let cargo_comp_time_deps_available = - toolchain.is_some_and(|v| v >= COMP_TIME_DEPS_MIN_TOOLCHAIN_VERSION); - - if cargo_comp_time_deps_available { - cmd.env("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS", "nightly"); - cmd.arg("-Zunstable-options"); - cmd.arg("--compile-time-deps"); - } else if config.wrap_rustc_in_build_scripts { - // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use - // that to compile only proc macros and build scripts during the initial - // `cargo check`. - // We don't need this if we are using `--compile-time-deps` flag. - let myself = std::env::current_exe()?; - cmd.env("RUSTC_WRAPPER", myself); - cmd.env("RA_RUSTC_WRAPPER", "1"); } - - Ok(cmd) } } diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 58507418e4d..4bacc904174 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -48,6 +48,7 @@ pub struct CargoWorkspace { is_sysroot: bool, /// Environment variables set in the `.cargo/config` file. config_env: Env, + requires_rustc_private: bool, } impl ops::Index<Package> for CargoWorkspace { @@ -513,6 +514,7 @@ impl CargoWorkspace { let workspace_root = AbsPathBuf::assert(meta.workspace_root); let target_directory = AbsPathBuf::assert(meta.target_directory); let mut is_virtual_workspace = true; + let mut requires_rustc_private = false; meta.packages.sort_by(|a, b| a.id.cmp(&b.id)); for meta_pkg in meta.packages { @@ -577,6 +579,7 @@ impl CargoWorkspace { metadata: meta.rust_analyzer.unwrap_or_default(), }); let pkg_data = &mut packages[pkg]; + requires_rustc_private |= pkg_data.metadata.rustc_private; pkg_by_id.insert(id, pkg); for meta_tgt in meta_targets { let cargo_metadata::Target { name, kind, required_features, src_path, .. } = @@ -626,6 +629,7 @@ impl CargoWorkspace { target_directory, manifest_path: ws_manifest_path, is_virtual_workspace, + requires_rustc_private, is_sysroot, config_env: cargo_config_env, } @@ -724,4 +728,8 @@ impl CargoWorkspace { pub fn is_sysroot(&self) -> bool { self.is_sysroot } + + pub fn requires_rustc_private(&self) -> bool { + self.requires_rustc_private + } } diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs index 450def5461d..9e0415c3b39 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/env.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs @@ -1,6 +1,6 @@ //! Cargo-like environment variables injection. use base_db::Env; -use paths::Utf8Path; +use paths::{Utf8Path, Utf8PathBuf}; use rustc_hash::FxHashMap; use toolchain::Tool; @@ -123,6 +123,26 @@ fn parse_output_cargo_config_env(manifest: &ManifestPath, stdout: &str) -> Env { env } +pub(crate) fn cargo_config_build_target_dir( + manifest: &ManifestPath, + extra_env: &FxHashMap<String, Option<String>>, + sysroot: &Sysroot, +) -> Option<Utf8PathBuf> { + let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env); + cargo_config + .args(["-Z", "unstable-options", "config", "get", "build.target-dir"]) + .env("RUSTC_BOOTSTRAP", "1"); + if manifest.is_rust_manifest() { + cargo_config.arg("-Zscript"); + } + utf8_stdout(&mut cargo_config) + .map(|stdout| { + Utf8Path::new(stdout.trim_start_matches("build.target-dir = ").trim_matches('"')) + .to_owned() + }) + .ok() +} + #[test] fn parse_output_cargo_config_env_works() { let stdout = r#" diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index a6743a32b14..5bc64df535c 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -16,6 +16,7 @@ use paths::{AbsPath, AbsPathBuf, Utf8PathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; use span::{Edition, FileId}; +use toolchain::Tool; use tracing::instrument; use triomphe::Arc; @@ -25,10 +26,14 @@ use crate::{ WorkspaceBuildScripts, build_dependencies::BuildScriptOutput, cargo_workspace::{CargoMetadataConfig, DepKind, PackageData, RustLibSource}, - env::{cargo_config_env, inject_cargo_env, inject_cargo_package_env, inject_rustc_tool_env}, + env::{ + cargo_config_build_target_dir, cargo_config_env, inject_cargo_env, + inject_cargo_package_env, inject_rustc_tool_env, + }, project_json::{Crate, CrateArrayIdx}, sysroot::RustLibSrcWorkspace, toolchain_info::{QueryConfig, rustc_cfg, target_data_layout, target_tuple, version}, + utf8_stdout, }; use tracing::{debug, error, info}; @@ -208,8 +213,7 @@ impl ProjectWorkspace { config: &CargoConfig, progress: &(dyn Fn(String) + Sync), ) -> Result<ProjectWorkspace, anyhow::Error> { - progress("Discovering sysroot".to_owned()); - let workspace_dir = cargo_toml.parent(); + progress("discovering sysroot".to_owned()); let CargoConfig { features, rustc_source, @@ -224,6 +228,7 @@ impl ProjectWorkspace { no_deps, .. } = config; + let workspace_dir = cargo_toml.parent(); let mut sysroot = match (sysroot, sysroot_src) { (Some(RustLibSource::Discover), None) => Sysroot::discover(workspace_dir, extra_env), (Some(RustLibSource::Discover), Some(sysroot_src)) => { @@ -238,8 +243,33 @@ impl ProjectWorkspace { (None, _) => Sysroot::empty(), }; + // Resolve the Cargo.toml to the workspace root as we base the `target` dir off of it. + let mut cmd = sysroot.tool(Tool::Cargo, workspace_dir, extra_env); + cmd.args(["locate-project", "--workspace", "--manifest-path", cargo_toml.as_str()]); + let cargo_toml = &match utf8_stdout(&mut cmd) { + Ok(output) => { + #[derive(serde_derive::Deserialize)] + struct Root { + root: Utf8PathBuf, + } + match serde_json::from_str::<Root>(&output) { + Ok(object) => ManifestPath::try_from(AbsPathBuf::assert(object.root)) + .expect("manifest path should be absolute"), + Err(e) => { + tracing::error!(%e, %cargo_toml, "failed fetching cargo workspace root"); + cargo_toml.clone() + } + } + } + Err(e) => { + tracing::error!(%e, %cargo_toml, "failed fetching cargo workspace root"); + cargo_toml.clone() + } + }; + let workspace_dir = cargo_toml.parent(); + tracing::info!(workspace = %cargo_toml, src_root = ?sysroot.rust_lib_src_root(), root = ?sysroot.root(), "Using sysroot"); - progress("Querying project metadata".to_owned()); + progress("querying project metadata".to_owned()); let toolchain_config = QueryConfig::Cargo(&sysroot, cargo_toml); let targets = target_tuple::get(toolchain_config, target.as_deref(), extra_env).unwrap_or_default(); @@ -252,8 +282,11 @@ impl ProjectWorkspace { .ok() .flatten(); - let target_dir = - config.target_dir.clone().unwrap_or_else(|| workspace_dir.join("target").into()); + let target_dir = config + .target_dir + .clone() + .or_else(|| cargo_config_build_target_dir(cargo_toml, extra_env, &sysroot)) + .unwrap_or_else(|| workspace_dir.join("target").into()); // We spawn a bunch of processes to query various information about the workspace's // toolchain and sysroot @@ -374,11 +407,17 @@ impl ProjectWorkspace { )) }); - let (rustc_cfg, data_layout, rustc, loaded_sysroot, cargo_metadata, cargo_config_extra_env) = - match join { - Ok(it) => it, - Err(e) => std::panic::resume_unwind(e), - }; + let ( + rustc_cfg, + data_layout, + mut rustc, + loaded_sysroot, + cargo_metadata, + cargo_config_extra_env, + ) = match join { + Ok(it) => it, + Err(e) => std::panic::resume_unwind(e), + }; let (meta, error) = cargo_metadata.with_context(|| { format!( @@ -391,6 +430,14 @@ impl ProjectWorkspace { sysroot.set_workspace(loaded_sysroot); } + if !cargo.requires_rustc_private() { + if let Err(e) = &mut rustc { + // We don't need the rustc sources here, + // so just discard the error. + _ = e.take(); + } + } + Ok(ProjectWorkspace { kind: ProjectWorkspaceKind::Cargo { cargo, @@ -413,17 +460,25 @@ impl ProjectWorkspace { config: &CargoConfig, progress: &(dyn Fn(String) + Sync), ) -> ProjectWorkspace { - progress("Discovering sysroot".to_owned()); + progress("discovering sysroot".to_owned()); let mut sysroot = Sysroot::new(project_json.sysroot.clone(), project_json.sysroot_src.clone()); tracing::info!(workspace = %project_json.manifest_or_root(), src_root = ?sysroot.rust_lib_src_root(), root = ?sysroot.root(), "Using sysroot"); - progress("Querying project metadata".to_owned()); + progress("querying project metadata".to_owned()); let sysroot_project = project_json.sysroot_project.take(); let query_config = QueryConfig::Rustc(&sysroot, project_json.path().as_ref()); let targets = target_tuple::get(query_config, config.target.as_deref(), &config.extra_env) .unwrap_or_default(); let toolchain = version::get(query_config, &config.extra_env).ok().flatten(); + let project_root = project_json.project_root(); + let target_dir = config + .target_dir + .clone() + .or_else(|| { + cargo_config_build_target_dir(project_json.manifest()?, &config.extra_env, &sysroot) + }) + .unwrap_or_else(|| project_root.join("target").into()); // We spawn a bunch of processes to query various information about the workspace's // toolchain and sysroot @@ -441,7 +496,6 @@ impl ProjectWorkspace { ) }); let loaded_sysroot = s.spawn(|| { - let project_root = project_json.project_root(); if let Some(sysroot_project) = sysroot_project { sysroot.load_workspace( &RustSourceWorkspaceConfig::Json(*sysroot_project), @@ -449,10 +503,6 @@ impl ProjectWorkspace { progress, ) } else { - let target_dir = config - .target_dir - .clone() - .unwrap_or_else(|| project_root.join("target").into()); sysroot.load_workspace( &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config( config, @@ -507,7 +557,12 @@ impl ProjectWorkspace { .unwrap_or_default(); let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env); let data_layout = target_data_layout::get(query_config, None, &config.extra_env); - let target_dir = config.target_dir.clone().unwrap_or_else(|| dir.join("target").into()); + let target_dir = config + .target_dir + .clone() + .or_else(|| cargo_config_build_target_dir(detached_file, &config.extra_env, &sysroot)) + .unwrap_or_else(|| dir.join("target").into()); + let loaded_sysroot = sysroot.load_workspace( &RustSourceWorkspaceConfig::CargoMetadata(sysroot_metadata_config( config, @@ -581,10 +636,16 @@ impl ProjectWorkspace { match &self.kind { ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _, None)), .. } | ProjectWorkspaceKind::Cargo { cargo, error: None, .. } => { - WorkspaceBuildScripts::run_for_workspace(config, cargo, progress, &self.sysroot) - .with_context(|| { - format!("Failed to run build scripts for {}", cargo.workspace_root()) - }) + WorkspaceBuildScripts::run_for_workspace( + config, + cargo, + progress, + &self.sysroot, + self.toolchain.as_ref(), + ) + .with_context(|| { + format!("Failed to run build scripts for {}", cargo.workspace_root()) + }) } _ => Ok(WorkspaceBuildScripts::default()), } @@ -1166,14 +1227,10 @@ fn cargo_to_crate_graph( // Mapping of a package to its library target let mut pkg_to_lib_crate = FxHashMap::default(); let mut pkg_crates = FxHashMap::default(); - // Does any crate signal to rust-analyzer that they need the rustc_private crates? - let mut has_private = false; let workspace_proc_macro_cwd = Arc::new(cargo.workspace_root().to_path_buf()); // Next, create crates for each package, target pair for pkg in cargo.packages() { - has_private |= cargo[pkg].metadata.rustc_private; - let cfg_options = { let mut cfg_options = cfg_options.clone(); @@ -1318,7 +1375,7 @@ fn cargo_to_crate_graph( add_dep(crate_graph, from, name, to); } - if has_private { + if cargo.requires_rustc_private() { // If the user provided a path to rustc sources, we add all the rustc_private crates // and create dependencies on them for the crates which opt-in to that if let Some((rustc_workspace, rustc_build_scripts)) = rustc { @@ -1588,7 +1645,7 @@ fn add_target_crate_root( None => Err("proc-macro crate build data is missing dylib path".to_owned()), } } - None => Err("proc-macro crate is missing its build data".to_owned()), + None => Err("build scripts have not been built".to_owned()), }; proc_macros.insert(crate_id, proc_macro); } diff --git a/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml b/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml index 8b03d8f8cc7..5991120a30d 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml +++ b/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false proc-macro = true [dependencies] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index 5e63521d747..b301a7189b3 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -13,6 +13,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [[bin]] name = "rust-analyzer" diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 05e1b832cd1..e716d140752 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -94,6 +94,8 @@ config_data! { + /// Enables highlighting of related return values while the cursor is on any `match`, `if`, or match arm arrow (`=>`). + highlightRelated_branchExitPoints_enable: bool = true, /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. highlightRelated_breakPoints_enable: bool = true, /// Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure. @@ -1629,6 +1631,7 @@ impl Config { exit_points: self.highlightRelated_exitPoints_enable().to_owned(), yield_points: self.highlightRelated_yieldPoints_enable().to_owned(), closure_captures: self.highlightRelated_closureCaptures_enable().to_owned(), + branch_exit_points: self.highlightRelated_branchExitPoints_enable().to_owned(), } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index afd9eff5264..a76a65220d3 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -2433,17 +2433,14 @@ fn run_rustfmt( } _ => { // Something else happened - e.g. `rustfmt` is missing or caught a signal - Err(LspError::new( - -32900, - format!( - r#"rustfmt exited with: - Status: {} - stdout: {captured_stdout} - stderr: {captured_stderr}"#, - output.status, - ), - ) - .into()) + tracing::error!( + ?command, + %output.status, + %captured_stdout, + %captured_stderr, + "rustfmt failed" + ); + Ok(None) } }; } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index 4efe330f16a..8a848fb848c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -900,14 +900,17 @@ pub(crate) fn folding_range( FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment), FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports), FoldKind::Region => Some(lsp_types::FoldingRangeKind::Region), - FoldKind::Mods + FoldKind::Modules | FoldKind::Block | FoldKind::ArgList | FoldKind::Consts | FoldKind::Statics + | FoldKind::TypeAliases | FoldKind::WhereClause | FoldKind::ReturnType | FoldKind::Array + | FoldKind::TraitAliases + | FoldKind::ExternCrates | FoldKind::MatchArm => None, }; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index 189d95ec7ed..133d5a6cf7a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -428,7 +428,7 @@ impl GlobalState { let expansion_res = match client { Ok(client) => match res { Ok((crate_name, path)) => { - progress(path.to_string()); + progress(format!("loading proc-macros: {path}")); let ignored_proc_macros = ignored_proc_macros .iter() .find_map(|(name, macros)| { diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml index a6d57816608..2c19f00f082 100644 --- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml +++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] backtrace = { version = "0.3.75", optional = true } diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/Cargo.toml b/src/tools/rust-analyzer/crates/syntax-bridge/Cargo.toml index cccd41d5429..b0fd40ff59f 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/Cargo.toml +++ b/src/tools/rust-analyzer/crates/syntax-bridge/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] rustc-hash.workspace = true diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml index 9d3aaa8d4e3..1ee93013e3e 100644 --- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml +++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] either.workspace = true diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index c81da06682e..3f439472337 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -669,7 +669,7 @@ TypeBoundList = TypeBound = Lifetime -| ('~' 'const' | 'const')? 'async'? '?'? Type +| ('~' 'const' | '[' 'const' ']' | 'const')? 'async'? '?'? Type | 'use' UseBoundGenericArgs UseBoundGenericArgs = diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index 04c7e8a578c..79a9f4da338 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1766,6 +1766,10 @@ impl TypeBound { support::child(&self.syntax) } #[inline] + pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } + #[inline] + pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } + #[inline] pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) } #[inline] pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs index ced3b713d8d..4afdda78a0e 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs @@ -1,9 +1,11 @@ //! There are many AstNodes, but only a few tokens, so we hand-write them here. +use std::ops::Range; use std::{borrow::Cow, num::ParseIntError}; use rustc_literal_escaper::{ - EscapeError, MixedUnit, Mode, unescape_byte, unescape_char, unescape_mixed, unescape_unicode, + EscapeError, MixedUnit, unescape_byte, unescape_byte_str, unescape_c_str, unescape_char, + unescape_str, }; use stdx::always; @@ -150,7 +152,7 @@ impl QuoteOffsets { pub trait IsString: AstToken { const RAW_PREFIX: &'static str; - const MODE: Mode; + fn unescape(s: &str, callback: impl FnMut(Range<usize>, Result<char, EscapeError>)); fn is_raw(&self) -> bool { self.text().starts_with(Self::RAW_PREFIX) } @@ -185,7 +187,7 @@ pub trait IsString: AstToken { let text = &self.text()[text_range_no_quotes - start]; let offset = text_range_no_quotes.start() - start; - unescape_unicode(text, Self::MODE, &mut |range, unescaped_char| { + Self::unescape(text, &mut |range: Range<usize>, unescaped_char| { if let Some((s, e)) = range.start.try_into().ok().zip(range.end.try_into().ok()) { cb(TextRange::new(s, e) + offset, unescaped_char); } @@ -203,7 +205,9 @@ pub trait IsString: AstToken { impl IsString for ast::String { const RAW_PREFIX: &'static str = "r"; - const MODE: Mode = Mode::Str; + fn unescape(s: &str, cb: impl FnMut(Range<usize>, Result<char, EscapeError>)) { + unescape_str(s, cb) + } } impl ast::String { @@ -218,20 +222,19 @@ impl ast::String { let mut buf = String::new(); let mut prev_end = 0; let mut has_error = None; - unescape_unicode(text, Self::MODE, &mut |char_range, unescaped_char| match ( - unescaped_char, - buf.capacity() == 0, - ) { - (Ok(c), false) => buf.push(c), - (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { - prev_end = char_range.end - } - (Ok(c), true) => { - buf.reserve_exact(text.len()); - buf.push_str(&text[..prev_end]); - buf.push(c); + unescape_str(text, |char_range, unescaped_char| { + match (unescaped_char, buf.capacity() == 0) { + (Ok(c), false) => buf.push(c), + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { + prev_end = char_range.end + } + (Ok(c), true) => { + buf.reserve_exact(text.len()); + buf.push_str(&text[..prev_end]); + buf.push(c); + } + (Err(e), _) => has_error = Some(e), } - (Err(e), _) => has_error = Some(e), }); match (has_error, buf.capacity() == 0) { @@ -244,7 +247,9 @@ impl ast::String { impl IsString for ast::ByteString { const RAW_PREFIX: &'static str = "br"; - const MODE: Mode = Mode::ByteStr; + fn unescape(s: &str, mut callback: impl FnMut(Range<usize>, Result<char, EscapeError>)) { + unescape_byte_str(s, |range, res| callback(range, res.map(char::from))) + } } impl ast::ByteString { @@ -259,20 +264,19 @@ impl ast::ByteString { let mut buf: Vec<u8> = Vec::new(); let mut prev_end = 0; let mut has_error = None; - unescape_unicode(text, Self::MODE, &mut |char_range, unescaped_char| match ( - unescaped_char, - buf.capacity() == 0, - ) { - (Ok(c), false) => buf.push(c as u8), - (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { - prev_end = char_range.end - } - (Ok(c), true) => { - buf.reserve_exact(text.len()); - buf.extend_from_slice(&text.as_bytes()[..prev_end]); - buf.push(c as u8); + unescape_byte_str(text, |char_range, unescaped_byte| { + match (unescaped_byte, buf.capacity() == 0) { + (Ok(b), false) => buf.push(b), + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { + prev_end = char_range.end + } + (Ok(b), true) => { + buf.reserve_exact(text.len()); + buf.extend_from_slice(&text.as_bytes()[..prev_end]); + buf.push(b); + } + (Err(e), _) => has_error = Some(e), } - (Err(e), _) => has_error = Some(e), }); match (has_error, buf.capacity() == 0) { @@ -285,25 +289,10 @@ impl ast::ByteString { impl IsString for ast::CString { const RAW_PREFIX: &'static str = "cr"; - const MODE: Mode = Mode::CStr; - - fn escaped_char_ranges(&self, cb: &mut dyn FnMut(TextRange, Result<char, EscapeError>)) { - let text_range_no_quotes = match self.text_range_between_quotes() { - Some(it) => it, - None => return, - }; - - let start = self.syntax().text_range().start(); - let text = &self.text()[text_range_no_quotes - start]; - let offset = text_range_no_quotes.start() - start; - - unescape_mixed(text, Self::MODE, &mut |range, unescaped_char| { - let text_range = - TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap()); - // XXX: This method should only be used for highlighting ranges. The unescaped - // char/byte is not used. For simplicity, we return an arbitrary placeholder char. - cb(text_range + offset, unescaped_char.map(|_| ' ')); - }); + // NOTE: This method should only be used for highlighting ranges. The unescaped + // char/byte is not used. For simplicity, we return an arbitrary placeholder char. + fn unescape(s: &str, mut callback: impl FnMut(Range<usize>, Result<char, EscapeError>)) { + unescape_c_str(s, |range, _res| callback(range, Ok('_'))) } } @@ -323,10 +312,7 @@ impl ast::CString { MixedUnit::Char(c) => buf.extend(c.encode_utf8(&mut [0; 4]).as_bytes()), MixedUnit::HighByte(b) => buf.push(b), }; - unescape_mixed(text, Self::MODE, &mut |char_range, unescaped| match ( - unescaped, - buf.capacity() == 0, - ) { + unescape_c_str(text, |char_range, unescaped| match (unescaped, buf.capacity() == 0) { (Ok(u), false) => extend_unit(&mut buf, u), (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { prev_end = char_range.end diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation.rs b/src/tools/rust-analyzer/crates/syntax/src/validation.rs index 5bfeb3bff87..4180f9cd185 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/validation.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/validation.rs @@ -6,7 +6,9 @@ mod block; use itertools::Itertools; use rowan::Direction; -use rustc_literal_escaper::{self, EscapeError, Mode, unescape_mixed, unescape_unicode}; +use rustc_literal_escaper::{ + EscapeError, unescape_byte, unescape_byte_str, unescape_c_str, unescape_char, unescape_str, +}; use crate::{ AstNode, SyntaxError, @@ -47,7 +49,7 @@ pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec<SyntaxError>) { } fn rustc_unescape_error_to_string(err: EscapeError) -> (&'static str, bool) { - use rustc_literal_escaper::EscapeError as EE; + use EscapeError as EE; #[rustfmt::skip] let err_message = match err { @@ -142,7 +144,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { ast::LiteralKind::String(s) => { if !s.is_raw() { if let Some(without_quotes) = unquote(text, 1, '"') { - unescape_unicode(without_quotes, Mode::Str, &mut |range, char| { + unescape_str(without_quotes, |range, char| { if let Err(err) = char { push_err(1, range.start, err); } @@ -153,7 +155,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { ast::LiteralKind::ByteString(s) => { if !s.is_raw() { if let Some(without_quotes) = unquote(text, 2, '"') { - unescape_unicode(without_quotes, Mode::ByteStr, &mut |range, char| { + unescape_byte_str(without_quotes, |range, char| { if let Err(err) = char { push_err(1, range.start, err); } @@ -164,7 +166,7 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { ast::LiteralKind::CString(s) => { if !s.is_raw() { if let Some(without_quotes) = unquote(text, 2, '"') { - unescape_mixed(without_quotes, Mode::CStr, &mut |range, char| { + unescape_c_str(without_quotes, |range, char| { if let Err(err) = char { push_err(1, range.start, err); } @@ -174,20 +176,16 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { } ast::LiteralKind::Char(_) => { if let Some(without_quotes) = unquote(text, 1, '\'') { - unescape_unicode(without_quotes, Mode::Char, &mut |range, char| { - if let Err(err) = char { - push_err(1, range.start, err); - } - }); + if let Err(err) = unescape_char(without_quotes) { + push_err(1, 0, err); + } } } ast::LiteralKind::Byte(_) => { if let Some(without_quotes) = unquote(text, 2, '\'') { - unescape_unicode(without_quotes, Mode::Byte, &mut |range, char| { - if let Err(err) = char { - push_err(2, range.start, err); - } - }); + if let Err(err) = unescape_byte(without_quotes) { + push_err(2, 0, err); + } } } ast::LiteralKind::IntNumber(_) diff --git a/src/tools/rust-analyzer/crates/test-utils/Cargo.toml b/src/tools/rust-analyzer/crates/test-utils/Cargo.toml index c27e850ce7f..6d1930aa268 100644 --- a/src/tools/rust-analyzer/crates/test-utils/Cargo.toml +++ b/src/tools/rust-analyzer/crates/test-utils/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] # Avoid adding deps here, this crate is widely used in tests it should compile fast! diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index d13a81d287f..d48063fb86f 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -26,7 +26,7 @@ //! deref: sized //! derive: //! discriminant: -//! drop: +//! drop: sized //! env: option //! eq: sized //! error: fmt @@ -37,7 +37,7 @@ //! future: pin //! coroutine: pin //! dispatch_from_dyn: unsize, pin -//! hash: +//! hash: sized //! include: //! index: sized //! infallible: @@ -77,33 +77,46 @@ pub mod marker { // region:sized + #[lang = "pointee_sized"] + #[fundamental] + #[rustc_specialization_trait] + #[rustc_coinductive] + pub trait PointeeSized {} + + #[lang = "meta_sized"] + #[fundamental] + #[rustc_specialization_trait] + #[rustc_coinductive] + pub trait MetaSized: PointeeSized {} + #[lang = "sized"] #[fundamental] #[rustc_specialization_trait] - pub trait Sized {} + #[rustc_coinductive] + pub trait Sized: MetaSized {} // endregion:sized // region:send pub unsafe auto trait Send {} - impl<T: ?Sized> !Send for *const T {} - impl<T: ?Sized> !Send for *mut T {} + impl<T: PointeeSized> !Send for *const T {} + impl<T: PointeeSized> !Send for *mut T {} // region:sync - unsafe impl<T: Sync + ?Sized> Send for &T {} - unsafe impl<T: Send + ?Sized> Send for &mut T {} + unsafe impl<T: Sync + PointeeSized> Send for &T {} + unsafe impl<T: Send + PointeeSized> Send for &mut T {} // endregion:sync // endregion:send // region:sync pub unsafe auto trait Sync {} - impl<T: ?Sized> !Sync for *const T {} - impl<T: ?Sized> !Sync for *mut T {} + impl<T: PointeeSized> !Sync for *const T {} + impl<T: PointeeSized> !Sync for *mut T {} // endregion:sync // region:unsize #[lang = "unsize"] - pub trait Unsize<T: ?Sized> {} + pub trait Unsize<T: PointeeSized>: PointeeSized {} // endregion:unsize // region:unpin @@ -120,7 +133,7 @@ pub mod marker { // endregion:derive mod copy_impls { - use super::Copy; + use super::{Copy, PointeeSized}; macro_rules! impl_copy { ($($t:ty)*) => { @@ -137,9 +150,9 @@ pub mod marker { bool char } - impl<T: ?Sized> Copy for *const T {} - impl<T: ?Sized> Copy for *mut T {} - impl<T: ?Sized> Copy for &T {} + impl<T: PointeeSized> Copy for *const T {} + impl<T: PointeeSized> Copy for *mut T {} + impl<T: PointeeSized> Copy for &T {} impl Copy for ! {} } // endregion:copy @@ -151,7 +164,7 @@ pub mod marker { // region:phantom_data #[lang = "phantom_data"] - pub struct PhantomData<T: ?Sized>; + pub struct PhantomData<T: PointeeSized>; // endregion:phantom_data // region:discriminant @@ -206,9 +219,11 @@ pub mod default { // region:hash pub mod hash { + use crate::marker::PointeeSized; + pub trait Hasher {} - pub trait Hash { + pub trait Hash: PointeeSized { fn hash<H: Hasher>(&self, state: &mut H); } @@ -221,10 +236,11 @@ pub mod hash { // region:cell pub mod cell { + use crate::marker::PointeeSized; use crate::mem; #[lang = "unsafe_cell"] - pub struct UnsafeCell<T: ?Sized> { + pub struct UnsafeCell<T: PointeeSized> { value: T, } @@ -238,7 +254,7 @@ pub mod cell { } } - pub struct Cell<T: ?Sized> { + pub struct Cell<T: PointeeSized> { value: UnsafeCell<T>, } @@ -357,7 +373,7 @@ pub mod convert { // endregion:from // region:as_ref - pub trait AsRef<T: ?Sized> { + pub trait AsRef<T: crate::marker::PointeeSized>: crate::marker::PointeeSized { fn as_ref(&self) -> &T; } // endregion:as_ref @@ -368,9 +384,11 @@ pub mod convert { pub mod mem { // region:manually_drop + use crate::marker::PointeeSized; + #[lang = "manually_drop"] #[repr(transparent)] - pub struct ManuallyDrop<T: ?Sized> { + pub struct ManuallyDrop<T: PointeeSized> { value: T, } @@ -381,7 +399,7 @@ pub mod mem { } // region:deref - impl<T: ?Sized> crate::ops::Deref for ManuallyDrop<T> { + impl<T: PointeeSized> crate::ops::Deref for ManuallyDrop<T> { type Target = T; fn deref(&self) -> &T { &self.value @@ -428,7 +446,7 @@ pub mod mem { pub mod ptr { // region:drop #[lang = "drop_in_place"] - pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { + pub unsafe fn drop_in_place<T: crate::marker::PointeeSized>(to_drop: *mut T) { unsafe { drop_in_place(to_drop) } } pub const unsafe fn read<T>(src: *const T) -> T { @@ -444,7 +462,7 @@ pub mod ptr { // region:pointee #[lang = "pointee_trait"] #[rustc_deny_explicit_impl(implement_via_object = false)] - pub trait Pointee { + pub trait Pointee: crate::marker::PointeeSized { #[lang = "metadata_type"] type Metadata: Copy + Send + Sync + Ord + Hash + Unpin; } @@ -452,12 +470,14 @@ pub mod ptr { // region:non_null #[rustc_layout_scalar_valid_range_start(1)] #[rustc_nonnull_optimization_guaranteed] - pub struct NonNull<T: ?Sized> { + pub struct NonNull<T: crate::marker::PointeeSized> { pointer: *const T, } // region:coerce_unsized - impl<T: ?Sized, U: ?Sized> crate::ops::CoerceUnsized<NonNull<U>> for NonNull<T> where - T: crate::marker::Unsize<U> + impl<T: crate::marker::PointeeSized, U: crate::marker::PointeeSized> + crate::ops::CoerceUnsized<NonNull<U>> for NonNull<T> + where + T: crate::marker::Unsize<U>, { } // endregion:coerce_unsized @@ -478,42 +498,44 @@ pub mod ptr { pub mod ops { // region:coerce_unsized mod unsize { - use crate::marker::Unsize; + use crate::marker::{PointeeSized, Unsize}; #[lang = "coerce_unsized"] - pub trait CoerceUnsized<T: ?Sized> {} + pub trait CoerceUnsized<T> {} - impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} - impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} - impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} - impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} + impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a mut U> for &'a mut T {} + impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b mut T {} + impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*mut U> for &'a mut T {} + impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for &'a mut T {} - impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} - impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {} + impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b T {} + impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for &'a T {} - impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} - impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {} - impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {} + impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*mut U> for *mut T {} + impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for *mut T {} + impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for *const T {} } pub use self::unsize::CoerceUnsized; // endregion:coerce_unsized // region:deref mod deref { + use crate::marker::PointeeSized; + #[lang = "deref"] - pub trait Deref { + pub trait Deref: PointeeSized { #[lang = "deref_target"] type Target: ?Sized; fn deref(&self) -> &Self::Target; } - impl<T: ?Sized> Deref for &T { + impl<T: PointeeSized> Deref for &T { type Target = T; fn deref(&self) -> &T { loop {} } } - impl<T: ?Sized> Deref for &mut T { + impl<T: PointeeSized> Deref for &mut T { type Target = T; fn deref(&self) -> &T { loop {} @@ -521,19 +543,19 @@ pub mod ops { } // region:deref_mut #[lang = "deref_mut"] - pub trait DerefMut: Deref { + pub trait DerefMut: Deref + PointeeSized { fn deref_mut(&mut self) -> &mut Self::Target; } // endregion:deref_mut // region:receiver #[lang = "receiver"] - pub trait Receiver { + pub trait Receiver: PointeeSized { #[lang = "receiver_target"] type Target: ?Sized; } - impl<P: ?Sized, T: ?Sized> Receiver for P + impl<P: PointeeSized, T: PointeeSized> Receiver for P where P: Deref<Target = T>, { @@ -686,7 +708,7 @@ pub mod ops { #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] impl<A: Tuple, F: ?Sized> const Fn<A> for &F where - F: ~const Fn<A>, + F: [const] Fn<A>, { extern "rust-call" fn call(&self, args: A) -> F::Output { (**self).call(args) @@ -697,7 +719,7 @@ pub mod ops { #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] impl<A: Tuple, F: ?Sized> const FnMut<A> for &F where - F: ~const Fn<A>, + F: [const] Fn<A>, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (**self).call(args) @@ -708,7 +730,7 @@ pub mod ops { #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] impl<A: Tuple, F: ?Sized> const FnOnce<A> for &F where - F: ~const Fn<A>, + F: [const] Fn<A>, { type Output = F::Output; @@ -721,7 +743,7 @@ pub mod ops { #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] impl<A: Tuple, F: ?Sized> const FnMut<A> for &mut F where - F: ~const FnMut<A>, + F: [const] FnMut<A>, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (*self).call_mut(args) @@ -732,7 +754,7 @@ pub mod ops { #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")] impl<A: Tuple, F: ?Sized> const FnOnce<A> for &mut F where - F: ~const FnMut<A>, + F: [const] FnMut<A>, { type Output = F::Output; extern "rust-call" fn call_once(self, args: A) -> F::Output { @@ -1006,18 +1028,18 @@ pub mod ops { // region:dispatch_from_dyn mod dispatch_from_dyn { - use crate::marker::Unsize; + use crate::marker::{PointeeSized, Unsize}; #[lang = "dispatch_from_dyn"] pub trait DispatchFromDyn<T> {} - impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} + impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a U> for &'a T {} - impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} + impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a mut U> for &'a mut T {} - impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {} + impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*const U> for *const T {} - impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} + impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*mut U> for *mut T {} } pub use self::dispatch_from_dyn::DispatchFromDyn; // endregion:dispatch_from_dyn @@ -1025,15 +1047,17 @@ pub mod ops { // region:eq pub mod cmp { + use crate::marker::PointeeSized; + #[lang = "eq"] - pub trait PartialEq<Rhs: ?Sized = Self> { + pub trait PartialEq<Rhs: PointeeSized = Self>: PointeeSized { fn eq(&self, other: &Rhs) -> bool; fn ne(&self, other: &Rhs) -> bool { !self.eq(other) } } - pub trait Eq: PartialEq<Self> {} + pub trait Eq: PartialEq<Self> + PointeeSized {} // region:derive #[rustc_builtin_macro] @@ -1044,11 +1068,11 @@ pub mod cmp { // region:ord #[lang = "partial_ord"] - pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized { fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; } - pub trait Ord: Eq + PartialOrd<Self> { + pub trait Ord: Eq + PartialOrd<Self> + PointeeSized { fn cmp(&self, other: &Self) -> Ordering; } @@ -1071,6 +1095,8 @@ pub mod cmp { // region:fmt pub mod fmt { + use crate::marker::PointeeSized; + pub struct Error; pub type Result = crate::result::Result<(), Error>; pub struct Formatter<'a>; @@ -1106,10 +1132,10 @@ pub mod fmt { } } - pub trait Debug { + pub trait Debug: PointeeSized { fn fmt(&self, f: &mut Formatter<'_>) -> Result; } - pub trait Display { + pub trait Display: PointeeSized { fn fmt(&self, f: &mut Formatter<'_>) -> Result; } @@ -1268,7 +1294,7 @@ pub mod fmt { } } - impl<T: Debug + ?Sized> Debug for &T { + impl<T: Debug + PointeeSized> Debug for &T { fn fmt(&self, f: &mut Formatter<'_>) -> Result { (&**self).fmt(f) } @@ -1512,6 +1538,8 @@ pub mod iter { mod traits { mod iterator { + use crate::marker::PointeeSized; + #[doc(notable_trait)] #[lang = "iterator"] pub trait Iterator { @@ -1543,7 +1571,7 @@ pub mod iter { } // endregion:iterators } - impl<I: Iterator + ?Sized> Iterator for &mut I { + impl<I: Iterator + PointeeSized> Iterator for &mut I { type Item = I::Item; fn next(&mut self) -> Option<I::Item> { (**self).next() diff --git a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml index 315a3a2890f..f561c1c0e2b 100644 --- a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml +++ b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] home = "0.5.11" diff --git a/src/tools/rust-analyzer/crates/tt/Cargo.toml b/src/tools/rust-analyzer/crates/tt/Cargo.toml index 529fad3244a..82e7c24668f 100644 --- a/src/tools/rust-analyzer/crates/tt/Cargo.toml +++ b/src/tools/rust-analyzer/crates/tt/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] arrayvec.workspace = true diff --git a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml index 9b32ee17abc..bd6c8331e66 100644 --- a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml +++ b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] tracing.workspace = true diff --git a/src/tools/rust-analyzer/crates/vfs/Cargo.toml b/src/tools/rust-analyzer/crates/vfs/Cargo.toml index 546195481c6..e8a6195036e 100644 --- a/src/tools/rust-analyzer/crates/vfs/Cargo.toml +++ b/src/tools/rust-analyzer/crates/vfs/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true rust-version.workspace = true [lib] +doctest = false [dependencies] rustc-hash.workspace = true diff --git a/src/tools/rust-analyzer/docs/book/src/SUMMARY.md b/src/tools/rust-analyzer/docs/book/src/SUMMARY.md index 1f211a97d78..dffdae94a6e 100644 --- a/src/tools/rust-analyzer/docs/book/src/SUMMARY.md +++ b/src/tools/rust-analyzer/docs/book/src/SUMMARY.md @@ -6,6 +6,7 @@ - [rust-analyzer Binary](rust_analyzer_binary.md) - [Other Editors](other_editors.md) - [Troubleshooting](troubleshooting.md) + - [FAQ](faq.md) - [Configuration](configuration.md) - [Non-Cargo Based Projects](non_cargo_based_projects.md) - [Security](security.md) diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 9404b1454a0..ebac26e1d60 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -612,6 +612,13 @@ Default: `"client"` Controls file watching implementation. +## rust-analyzer.highlightRelated.branchExitPoints.enable {#highlightRelated.branchExitPoints.enable} + +Default: `true` + +Enables highlighting of related return values while the cursor is on any `match`, `if`, or match arm arrow (`=>`). + + ## rust-analyzer.highlightRelated.breakPoints.enable {#highlightRelated.breakPoints.enable} Default: `true` diff --git a/src/tools/rust-analyzer/docs/book/src/faq.md b/src/tools/rust-analyzer/docs/book/src/faq.md new file mode 100644 index 00000000000..c8720330901 --- /dev/null +++ b/src/tools/rust-analyzer/docs/book/src/faq.md @@ -0,0 +1,7 @@ +# Troubleshooting FAQ + +### I see a warning "Variable `None` should have snake_case name, e.g. `none`" + +rust-analyzer fails to resolve `None`, and thinks you are binding to a variable +named `None`. That's usually a sign of a corrupted sysroot. Try removing and re-installing +it: `rustup component remove rust-src` then `rustup component install rust-src`. diff --git a/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md b/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md index bbdb48bbbc9..befb631ec03 100644 --- a/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md +++ b/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md @@ -40,6 +40,9 @@ interface ProjectJson { /// several different "sysroots" in one graph of /// crates. sysroot_src?: string; + /// A ProjectJson describing the crates of the sysroot. + sysroot_project?: ProjectJson; + /// List of groups of common cfg values, to allow /// sharing them between crates. /// diff --git a/src/tools/rust-analyzer/docs/book/src/troubleshooting.md b/src/tools/rust-analyzer/docs/book/src/troubleshooting.md index 1b2841421a4..a357cbef415 100644 --- a/src/tools/rust-analyzer/docs/book/src/troubleshooting.md +++ b/src/tools/rust-analyzer/docs/book/src/troubleshooting.md @@ -1,5 +1,8 @@ # Troubleshooting +First, search the [troubleshooting FAQ](faq.html). If your problem appears +there (and the proposed solution works for you), great! Otherwise, read on. + Start with looking at the rust-analyzer version. Try **rust-analyzer: Show RA Version** in VS Code (using **Command Palette** feature typically activated by Ctrl+Shift+P) or `rust-analyzer --version` in the diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 26a21c1468d..3cb4c21ee1f 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -1532,6 +1532,16 @@ { "title": "highlightRelated", "properties": { + "rust-analyzer.highlightRelated.branchExitPoints.enable": { + "markdownDescription": "Enables highlighting of related return values while the cursor is on any `match`, `if`, or match arm arrow (`=>`).", + "default": true, + "type": "boolean" + } + } + }, + { + "title": "highlightRelated", + "properties": { "rust-analyzer.highlightRelated.breakPoints.enable": { "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.", "default": true, diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index cdeea7333a6..073ff2f4703 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -3,7 +3,7 @@ import * as lc from "vscode-languageclient/node"; import * as vscode from "vscode"; import * as ra from "../src/lsp_ext"; import * as Is from "vscode-languageclient/lib/common/utils/is"; -import { assert, unwrapUndefinable } from "./util"; +import { assert } from "./util"; import * as diagnostics from "./diagnostics"; import { WorkspaceEdit } from "vscode"; import { type Config, prepareVSCodeConfig } from "./config"; @@ -188,11 +188,17 @@ export async function createClient( context: await client.code2ProtocolConverter.asCodeActionContext(context, token), }; const callback = async ( - values: (lc.Command | lc.CodeAction)[] | null, + values: (lc.Command | lc.CodeAction | object)[] | null, ): Promise<(vscode.Command | vscode.CodeAction)[] | undefined> => { if (values === null) return undefined; const result: (vscode.CodeAction | vscode.Command)[] = []; - const groups = new Map<string, { index: number; items: vscode.CodeAction[] }>(); + const groups = new Map< + string, + { + primary: vscode.CodeAction; + items: { label: string; arguments: lc.CodeAction }[]; + } + >(); for (const item of values) { // In our case we expect to get code edits only from diagnostics if (lc.CodeAction.is(item)) { @@ -204,62 +210,55 @@ export async function createClient( result.push(action); continue; } - assert( - isCodeActionWithoutEditsAndCommands(item), - "We don't expect edits or commands here", - ); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const kind = client.protocol2CodeConverter.asCodeActionKind((item as any).kind); - const action = new vscode.CodeAction(item.title, kind); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const group = (item as any).group; - action.command = { - command: "rust-analyzer.resolveCodeAction", - title: item.title, - arguments: [item], - }; + assertIsCodeActionWithoutEditsAndCommands(item); + const kind = client.protocol2CodeConverter.asCodeActionKind(item.kind); + const group = item.group; - // Set a dummy edit, so that VS Code doesn't try to resolve this. - action.edit = new WorkspaceEdit(); + const mkAction = () => { + const action = new vscode.CodeAction(item.title, kind); + action.command = { + command: "rust-analyzer.resolveCodeAction", + title: item.title, + arguments: [item], + }; + // Set a dummy edit, so that VS Code doesn't try to resolve this. + action.edit = new WorkspaceEdit(); + return action; + }; if (group) { let entry = groups.get(group); if (!entry) { - entry = { index: result.length, items: [] }; + entry = { primary: mkAction(), items: [] }; groups.set(group, entry); - result.push(action); + } else { + entry.items.push({ + label: item.title, + arguments: item, + }); } - entry.items.push(action); } else { - result.push(action); + result.push(mkAction()); } } - for (const [group, { index, items }] of groups) { - if (items.length === 1) { - const item = unwrapUndefinable(items[0]); - result[index] = item; - } else { - const action = new vscode.CodeAction(group); - const item = unwrapUndefinable(items[0]); - action.kind = item.kind; - action.command = { + for (const [group, { items, primary }] of groups) { + // This group contains more than one item, so rewrite it to be a group action + if (items.length !== 0) { + const args = [ + { + label: primary.title, + arguments: primary.command!.arguments![0], + }, + ...items, + ]; + primary.title = group; + primary.command = { command: "rust-analyzer.applyActionGroup", title: "", - arguments: [ - items.map((item) => { - return { - label: item.title, - arguments: item.command!.arguments![0], - }; - }), - ], + arguments: [args], }; - - // Set a dummy edit, so that VS Code doesn't try to resolve this. - action.edit = new WorkspaceEdit(); - - result[index] = action; } + result.push(primary); } return result; }; @@ -363,17 +362,22 @@ class OverrideFeatures implements lc.StaticFeature { clear(): void {} } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function isCodeActionWithoutEditsAndCommands(value: any): boolean { - const candidate: lc.CodeAction = value; - return ( +function assertIsCodeActionWithoutEditsAndCommands( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + candidate: any, +): asserts candidate is lc.CodeAction & { + group?: string; +} { + assert( candidate && - Is.string(candidate.title) && - (candidate.diagnostics === void 0 || - Is.typedArray(candidate.diagnostics, lc.Diagnostic.is)) && - (candidate.kind === void 0 || Is.string(candidate.kind)) && - candidate.edit === void 0 && - candidate.command === void 0 + Is.string(candidate.title) && + (candidate.diagnostics === undefined || + Is.typedArray(candidate.diagnostics, lc.Diagnostic.is)) && + (candidate.group === undefined || Is.string(candidate.group)) && + (candidate.kind === undefined || Is.string(candidate.kind)) && + candidate.edit === undefined && + candidate.command === undefined, + `Expected a CodeAction without edits or commands, got: ${JSON.stringify(candidate)}`, ); } diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts index 3ac1a933d9e..25b30013fa1 100644 --- a/src/tools/rust-analyzer/editors/code/src/commands.ts +++ b/src/tools/rust-analyzer/editors/code/src/commands.ts @@ -1114,11 +1114,11 @@ export function applySnippetWorkspaceEditCommand(_ctx: CtxInit): Cmd { }; } -export function run(ctx: CtxInit): Cmd { +export function run(ctx: CtxInit, mode?: "cursor"): Cmd { let prevRunnable: RunnableQuickPick | undefined; return async () => { - const item = await selectRunnable(ctx, prevRunnable); + const item = await selectRunnable(ctx, prevRunnable, false, true, mode); if (!item) return; item.detail = "rerun"; diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts index 5e500730693..996298524f1 100644 --- a/src/tools/rust-analyzer/editors/code/src/main.ts +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -167,7 +167,7 @@ function createCommands(): Record<string, CommandFactory> { viewCrateGraph: { enabled: commands.viewCrateGraph }, viewFullCrateGraph: { enabled: commands.viewFullCrateGraph }, expandMacro: { enabled: commands.expandMacro }, - run: { enabled: commands.run }, + run: { enabled: (ctx) => (mode?: "cursor") => commands.run(ctx, mode)() }, copyRunCommandLine: { enabled: commands.copyRunCommandLine }, debug: { enabled: commands.debug }, newDebugConfig: { enabled: commands.newDebugConfig }, diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts index 40027cc7c85..95166c427b2 100644 --- a/src/tools/rust-analyzer/editors/code/src/run.ts +++ b/src/tools/rust-analyzer/editors/code/src/run.ts @@ -18,10 +18,15 @@ export async function selectRunnable( prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true, + mode?: "cursor", ): Promise<RunnableQuickPick | undefined> { const editor = ctx.activeRustEditor ?? ctx.activeCargoTomlEditor; if (!editor) return; + if (mode === "cursor") { + return selectRunnableAtCursor(ctx, editor, prevRunnable); + } + // show a placeholder while we get the runnables from the server const quickPick = vscode.window.createQuickPick(); quickPick.title = "Select Runnable"; @@ -54,6 +59,58 @@ export async function selectRunnable( ); } +async function selectRunnableAtCursor( + ctx: CtxInit, + editor: RustEditor, + prevRunnable?: RunnableQuickPick, +): Promise<RunnableQuickPick | undefined> { + const runnableQuickPicks = await getRunnables(ctx.client, editor, prevRunnable, false); + let runnableQuickPickAtCursor = null; + const cursorPosition = ctx.client.code2ProtocolConverter.asPosition(editor.selection.active); + for (const runnableQuickPick of runnableQuickPicks) { + if (!runnableQuickPick.runnable.location?.targetRange) { + continue; + } + const runnableQuickPickRange = runnableQuickPick.runnable.location.targetRange; + if ( + runnableQuickPickAtCursor?.runnable?.location?.targetRange != null && + rangeContainsOtherRange( + runnableQuickPickRange, + runnableQuickPickAtCursor.runnable.location.targetRange, + ) + ) { + continue; + } + if (rangeContainsPosition(runnableQuickPickRange, cursorPosition)) { + runnableQuickPickAtCursor = runnableQuickPick; + } + } + if (runnableQuickPickAtCursor == null) { + return; + } + return Promise.resolve(runnableQuickPickAtCursor); +} + +function rangeContainsPosition(range: lc.Range, position: lc.Position): boolean { + return ( + (position.line > range.start.line || + (position.line === range.start.line && position.character >= range.start.character)) && + (position.line < range.end.line || + (position.line === range.end.line && position.character <= range.end.character)) + ); +} + +function rangeContainsOtherRange(range: lc.Range, otherRange: lc.Range) { + return ( + (range.start.line < otherRange.start.line || + (range.start.line === otherRange.start.line && + range.start.character <= otherRange.start.character)) && + (range.end.line > otherRange.end.line || + (range.end.line === otherRange.end.line && + range.end.character >= otherRange.end.character)) + ); +} + export class RunnableQuickPick implements vscode.QuickPickItem { public label: string; public description?: string | undefined; diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index a454087b0cd..902793225ea 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -27733d46d79f4eb92e240fbba502c43022665735 +ad3b7257615c28aaf8212a189ec032b8af75de51 diff --git a/src/tools/rust-installer/README.md b/src/tools/rust-installer/README.md index 99d8e5ca4cf..505ffe4093f 100644 --- a/src/tools/rust-installer/README.md +++ b/src/tools/rust-installer/README.md @@ -51,7 +51,7 @@ To combine installers. * Make install.sh not have to be customized, pull it's data from a config file. -* Be more resiliant to installation failures, particularly if the disk +* Be more resilient to installation failures, particularly if the disk is full. * Pre-install and post-uninstall scripts. * Allow components to depend on or contradict other components. diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 7e27e0258c2..4f9af6d53dd 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1368,7 +1368,6 @@ ui/infinite/issue-41731-infinite-macro-println.rs ui/intrinsics/issue-28575.rs ui/intrinsics/issue-84297-reifying-copy.rs ui/invalid/issue-114435-layout-type-err.rs -ui/issue-11881.rs ui/issue-15924.rs ui/issue-16822.rs ui/issues-71798.rs diff --git a/tests/crashes/132882.rs b/tests/crashes/132882.rs deleted file mode 100644 index 6b5e4dba803..00000000000 --- a/tests/crashes/132882.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #132882 - -use std::ops::Add; - -pub trait Numoid -where - for<N: Numoid> &'a Self: Add<Self>, -{ -} - -pub fn compute<N: Numoid>(a: N) -> N { - &a + a -} diff --git a/tests/run-make/short-ice/rmake.rs b/tests/run-make/short-ice/rmake.rs index 483def62fc7..dbe0f692aef 100644 --- a/tests/run-make/short-ice/rmake.rs +++ b/tests/run-make/short-ice/rmake.rs @@ -5,9 +5,12 @@ // See https://github.com/rust-lang/rust/issues/107910 //@ needs-target-std -//@ ignore-i686-pc-windows-msvc -// Reason: the assert_eq! on line 37 fails, almost seems like it missing debug info? -// Haven't been able to reproduce locally, but it happens on CI. +//@ ignore-windows-msvc +// +// - FIXME(#143198): On `i686-pc-windows-msvc`: the assert_eq! on line 37 fails, almost seems like +// it missing debug info? Haven't been able to reproduce locally, but it happens on CI. +// - FIXME(#143198): On `x86_64-pc-windows-msvc`: full backtrace sometimes do not contain matching +// count of short backtrace markers (e.g. 5x end marker, but 3x start marker). use run_make_support::rustc; diff --git a/tests/rustdoc-json/attrs/link_section_2021.rs b/tests/rustdoc-json/attrs/link_section_2021.rs new file mode 100644 index 00000000000..a1312f4210b --- /dev/null +++ b/tests/rustdoc-json/attrs/link_section_2021.rs @@ -0,0 +1,6 @@ +//@ edition: 2021 +#![no_std] + +//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]' +#[link_section = ".text"] +pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/link_section_2024.rs b/tests/rustdoc-json/attrs/link_section_2024.rs new file mode 100644 index 00000000000..edb028451a8 --- /dev/null +++ b/tests/rustdoc-json/attrs/link_section_2024.rs @@ -0,0 +1,9 @@ +//@ edition: 2024 +#![no_std] + +// Since the 2024 edition the link_section attribute must use the unsafe qualification. +// However, the unsafe qualification is not shown by rustdoc. + +//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]' +#[unsafe(link_section = ".text")] +pub extern "C" fn example() {} diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index 692c24f0544..64194e72888 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -19,12 +19,6 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use stable_mir::crate_def::CrateDef; -use stable_mir::mir::alloc::GlobalAlloc; -use stable_mir::mir::mono::{Instance, InstanceKind, StaticDef}; -use stable_mir::mir::{Body, TerminatorKind}; -use stable_mir::ty::{Allocation, ConstantKind, RigidTy, TyKind}; -use stable_mir::{CrateItem, CrateItems, ItemKind}; use std::ascii::Char; use std::assert_matches::assert_matches; use std::cmp::{max, min}; @@ -33,6 +27,13 @@ use std::ffi::CStr; use std::io::Write; use std::ops::ControlFlow; +use stable_mir::crate_def::CrateDef; +use stable_mir::mir::Body; +use stable_mir::mir::alloc::GlobalAlloc; +use stable_mir::mir::mono::{Instance, StaticDef}; +use stable_mir::ty::{Allocation, ConstantKind}; +use stable_mir::{CrateItem, CrateItems, ItemKind}; + const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. @@ -44,7 +45,6 @@ fn test_stable_mir() -> ControlFlow<()> { check_len(*get_item(&items, (ItemKind::Static, "LEN")).unwrap()); check_cstr(*get_item(&items, (ItemKind::Static, "C_STR")).unwrap()); check_other_consts(*get_item(&items, (ItemKind::Fn, "other_consts")).unwrap()); - check_type_id(*get_item(&items, (ItemKind::Fn, "check_type_id")).unwrap()); ControlFlow::Continue(()) } @@ -107,7 +107,9 @@ fn check_other_consts(item: CrateItem) { // Instance body will force constant evaluation. let body = Instance::try_from(item).unwrap().body().unwrap(); let assigns = collect_consts(&body); - assert_eq!(assigns.len(), 8); + assert_eq!(assigns.len(), 10); + let mut char_id = None; + let mut bool_id = None; for (name, alloc) in assigns { match name.as_str() { "_max_u128" => { @@ -149,35 +151,21 @@ fn check_other_consts(item: CrateItem) { assert_eq!(max(first, second) as u32, u32::MAX); assert_eq!(min(first, second), 10); } + "_bool_id" => { + bool_id = Some(alloc); + } + "_char_id" => { + char_id = Some(alloc); + } _ => { unreachable!("{name} -- {alloc:?}") } } } -} - -/// Check that we can retrieve the type id of char and bool, and that they have different values. -fn check_type_id(item: CrateItem) { - let body = Instance::try_from(item).unwrap().body().unwrap(); - let mut ids: Vec<u128> = vec![]; - for term in body.blocks.iter().map(|bb| &bb.terminator) { - match &term.kind { - TerminatorKind::Call { func, destination, .. } => { - let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else { - unreachable!() - }; - let RigidTy::FnDef(def, args) = ty else { unreachable!() }; - let instance = Instance::resolve(def, &args).unwrap(); - assert_eq!(instance.kind, InstanceKind::Intrinsic); - let dest_ty = destination.ty(body.locals()).unwrap(); - let alloc = instance.try_const_eval(dest_ty).unwrap(); - ids.push(alloc.read_uint().unwrap()); - } - _ => { /* Do nothing */ } - } - } - assert_eq!(ids.len(), 2); - assert_ne!(ids[0], ids[1]); + let bool_id = bool_id.unwrap(); + let char_id = char_id.unwrap(); + // FIXME(stable_mir): add `read_ptr` to `Allocation` + assert_ne!(bool_id, char_id); } /// Collects all the constant assignments. @@ -235,6 +223,7 @@ fn generate_input(path: &str) -> std::io::Result<()> { file, r#" #![feature(core_intrinsics)] + #![expect(internal_features)] use std::intrinsics::type_id; static LEN: usize = 2; @@ -254,11 +243,8 @@ fn generate_input(path: &str) -> std::io::Result<()> { let _ptr = &BAR; let _null_ptr: *const u8 = NULL; let _tuple = TUPLE; - }} - - fn check_type_id() {{ - let _char_id = type_id::<char>(); - let _bool_id = type_id::<bool>(); + let _char_id = const {{ type_id::<char>() }}; + let _bool_id = const {{ type_id::<bool>() }}; }} pub fn main() {{ diff --git a/tests/ui/attributes/inner-attrs-impl-cfg.rs b/tests/ui/attributes/inner-attrs-impl-cfg.rs new file mode 100644 index 00000000000..e7a5cfa9e2f --- /dev/null +++ b/tests/ui/attributes/inner-attrs-impl-cfg.rs @@ -0,0 +1,36 @@ +//! Test inner attributes (#![...]) behavior in impl blocks with cfg conditions. +//! +//! This test verifies that: +//! - Inner attributes can conditionally exclude entire impl blocks +//! - Regular attributes within impl blocks work independently +//! - Attribute parsing doesn't consume too eagerly + +//@ run-pass + +struct Foo; + +impl Foo { + #![cfg(false)] + + fn method(&self) -> bool { + false + } +} + +impl Foo { + #![cfg(not(FALSE))] + + // Check that we don't eat attributes too eagerly. + #[cfg(false)] + fn method(&self) -> bool { + false + } + + fn method(&self) -> bool { + true + } +} + +pub fn main() { + assert!(Foo.method()); +} diff --git a/tests/ui/codegen/maximal-hir-to-mir-coverage-flag.rs b/tests/ui/codegen/maximal-hir-to-mir-coverage-flag.rs new file mode 100644 index 00000000000..64c31beba28 --- /dev/null +++ b/tests/ui/codegen/maximal-hir-to-mir-coverage-flag.rs @@ -0,0 +1,12 @@ +//! Test that -Z maximal-hir-to-mir-coverage flag is accepted. +//! +//! Original PR: https://github.com/rust-lang/rust/pull/105286 + +//@ compile-flags: -Zmaximal-hir-to-mir-coverage +//@ run-pass + +fn main() { + let x = 1; + let y = x + 1; + println!("{y}"); +} diff --git a/tests/ui/codegen/mono-respects-abi-alignment.rs b/tests/ui/codegen/mono-respects-abi-alignment.rs new file mode 100644 index 00000000000..045d82b761f --- /dev/null +++ b/tests/ui/codegen/mono-respects-abi-alignment.rs @@ -0,0 +1,37 @@ +//! Test that monomorphization correctly distinguishes types with different ABI alignment. +//! +//! On x86_64-linux-gnu and similar platforms, structs get 8-byte "preferred" +//! alignment, but their "ABI" alignment (what actually matters for data layout) +//! is the largest alignment of any field. If monomorphization incorrectly uses +//! "preferred" alignment instead of "ABI" alignment, it might unify types `A` +//! and `B` even though `S<A>` and `S<B>` have field `t` at different offsets, +//! leading to incorrect method dispatch for `unwrap()`. + +//@ run-pass + +#[derive(Copy, Clone)] +struct S<T> { + #[allow(dead_code)] + i: u8, + t: T, +} + +impl<T> S<T> { + fn unwrap(self) -> T { + self.t + } +} + +#[derive(Copy, Clone, PartialEq, Debug)] +struct A((u32, u32)); // Different ABI alignment than B + +#[derive(Copy, Clone, PartialEq, Debug)] +struct B(u64); // Different ABI alignment than A + +pub fn main() { + static CA: S<A> = S { i: 0, t: A((13, 104)) }; + static CB: S<B> = S { i: 0, t: B(31337) }; + + assert_eq!(CA.unwrap(), A((13, 104))); + assert_eq!(CB.unwrap(), B(31337)); +} diff --git a/tests/ui/codegen/msvc-opt-level-z-no-corruption.rs b/tests/ui/codegen/msvc-opt-level-z-no-corruption.rs new file mode 100644 index 00000000000..ba97acec822 --- /dev/null +++ b/tests/ui/codegen/msvc-opt-level-z-no-corruption.rs @@ -0,0 +1,37 @@ +//! Test that opt-level=z produces correct code on Windows MSVC targets. +//! +//! A previously outdated version of LLVM caused compilation failures and +//! generated invalid code on Windows specifically with optimization level `z`. +//! The bug manifested as corrupted base pointers due to incorrect register +//! usage in the generated assembly (e.g., `popl %esi` corrupting local variables). +//! After updating to a more recent LLVM version, this test ensures that +//! compilation and execution both succeed with opt-level=z. +//! +//! Regression test for <https://github.com/rust-lang/rust/issues/45034>. + +//@ ignore-cross-compile +// Reason: the compiled binary is executed +//@ only-windows +// Reason: the observed bug only occurred on Windows MSVC targets +//@ run-pass +//@ compile-flags: -C opt-level=z + +#![feature(test)] +extern crate test; + +fn foo(x: i32, y: i32) -> i64 { + (x + y) as i64 +} + +#[inline(never)] +fn bar() { + let _f = Box::new(0); + // This call used to trigger an LLVM bug in opt-level=z where the base + // pointer gets corrupted due to incorrect register allocation + let y: fn(i32, i32) -> i64 = test::black_box(foo); + test::black_box(y(1, 2)); +} + +fn main() { + bar(); +} diff --git a/tests/ui/compiletest-self-test/ui-test-missing-annotations-detection.rs b/tests/ui/compiletest-self-test/ui-test-missing-annotations-detection.rs new file mode 100644 index 00000000000..3a110bdad35 --- /dev/null +++ b/tests/ui/compiletest-self-test/ui-test-missing-annotations-detection.rs @@ -0,0 +1,9 @@ +//! Regression test checks UI tests without error annotations are detected as failing. +//! +//! This tests that when we forget to use any `//~ ERROR` comments whatsoever, +//! the test doesn't succeed +//! Originally created in https://github.com/rust-lang/rust/pull/56244 + +//@ should-fail + +fn main() {} diff --git a/tests/ui/consts/const-fn-type-name.rs b/tests/ui/consts/const-fn-type-name.rs index 5403c26b979..733ab79b7cd 100644 --- a/tests/ui/consts/const-fn-type-name.rs +++ b/tests/ui/consts/const-fn-type-name.rs @@ -5,7 +5,7 @@ #![allow(dead_code)] const fn type_name_wrapper<T>(_: &T) -> &'static str { - core::intrinsics::type_name::<T>() + const { core::intrinsics::type_name::<T>() } } struct Struct<TA, TB, TC> { diff --git a/tests/ui/derives/derive-Debug-enum-variants.rs b/tests/ui/derives/derive-Debug-enum-variants.rs new file mode 100644 index 00000000000..26f527f7664 --- /dev/null +++ b/tests/ui/derives/derive-Debug-enum-variants.rs @@ -0,0 +1,30 @@ +//! Test that `#[derive(Debug)]` for enums correctly formats variant names. + +//@ run-pass + +#[derive(Debug)] +enum Foo { + A(usize), + C, +} + +#[derive(Debug)] +enum Bar { + D, +} + +pub fn main() { + // Test variant with data + let foo_a = Foo::A(22); + assert_eq!("A(22)".to_string(), format!("{:?}", foo_a)); + + if let Foo::A(value) = foo_a { + println!("Value: {}", value); // This needs to remove #[allow(dead_code)] + } + + // Test unit variant + assert_eq!("C".to_string(), format!("{:?}", Foo::C)); + + // Test unit variant from different enum + assert_eq!("D".to_string(), format!("{:?}", Bar::D)); +} diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 1243ed5d8f4..02b9e2f06ee 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -387,14 +387,6 @@ LL | #![link()] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1 - | -LL | #![link_section = "1800"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a function or static - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - warning: attribute should be applied to a function definition --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 | @@ -411,6 +403,14 @@ LL | #![link_name = "1900"] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1 + | +LL | #![link_section = "1800"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: `#[must_use]` has no effect when applied to a module --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 | diff --git a/tests/ui/logging-only-prints-once.rs b/tests/ui/fmt/debug-single-call.rs index bb8c29694b5..b59a766c71a 100644 --- a/tests/ui/logging-only-prints-once.rs +++ b/tests/ui/fmt/debug-single-call.rs @@ -1,9 +1,12 @@ +//! Test that Debug::fmt is called exactly once during formatting. +//! +//! This is a regression test for PR https://github.com/rust-lang/rust/pull/10715 + //@ run-pass //@ needs-threads use std::cell::Cell; -use std::fmt; -use std::thread; +use std::{fmt, thread}; struct Foo(Cell<isize>); diff --git a/tests/ui/integral-indexing.rs b/tests/ui/indexing/indexing-integral-types.rs index e20553af8a2..a91696a6fd5 100644 --- a/tests/ui/integral-indexing.rs +++ b/tests/ui/indexing/indexing-integral-types.rs @@ -1,16 +1,20 @@ +//! Test that only usize can be used for indexing arrays and slices. + pub fn main() { let v: Vec<isize> = vec![0, 1, 2, 3, 4, 5]; let s: String = "abcdef".to_string(); + + // Valid indexing with usize v[3_usize]; v[3]; - v[3u8]; //~ ERROR the type `[isize]` cannot be indexed by `u8` - v[3i8]; //~ ERROR the type `[isize]` cannot be indexed by `i8` + v[3u8]; //~ ERROR the type `[isize]` cannot be indexed by `u8` + v[3i8]; //~ ERROR the type `[isize]` cannot be indexed by `i8` v[3u32]; //~ ERROR the type `[isize]` cannot be indexed by `u32` v[3i32]; //~ ERROR the type `[isize]` cannot be indexed by `i32` s.as_bytes()[3_usize]; s.as_bytes()[3]; - s.as_bytes()[3u8]; //~ ERROR the type `[u8]` cannot be indexed by `u8` - s.as_bytes()[3i8]; //~ ERROR the type `[u8]` cannot be indexed by `i8` + s.as_bytes()[3u8]; //~ ERROR the type `[u8]` cannot be indexed by `u8` + s.as_bytes()[3i8]; //~ ERROR the type `[u8]` cannot be indexed by `i8` s.as_bytes()[3u32]; //~ ERROR the type `[u8]` cannot be indexed by `u32` s.as_bytes()[3i32]; //~ ERROR the type `[u8]` cannot be indexed by `i32` } diff --git a/tests/ui/integral-indexing.stderr b/tests/ui/indexing/indexing-integral-types.stderr index 26253e078cb..b63991ec2c4 100644 --- a/tests/ui/integral-indexing.stderr +++ b/tests/ui/indexing/indexing-integral-types.stderr @@ -1,5 +1,5 @@ error[E0277]: the type `[isize]` cannot be indexed by `u8` - --> $DIR/integral-indexing.rs:6:7 + --> $DIR/indexing-integral-types.rs:10:7 | LL | v[3u8]; | ^^^ slice indices are of type `usize` or ranges of `usize` @@ -11,7 +11,7 @@ LL | v[3u8]; = note: required for `Vec<isize>` to implement `Index<u8>` error[E0277]: the type `[isize]` cannot be indexed by `i8` - --> $DIR/integral-indexing.rs:7:7 + --> $DIR/indexing-integral-types.rs:11:7 | LL | v[3i8]; | ^^^ slice indices are of type `usize` or ranges of `usize` @@ -23,7 +23,7 @@ LL | v[3i8]; = note: required for `Vec<isize>` to implement `Index<i8>` error[E0277]: the type `[isize]` cannot be indexed by `u32` - --> $DIR/integral-indexing.rs:8:7 + --> $DIR/indexing-integral-types.rs:12:7 | LL | v[3u32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` @@ -35,7 +35,7 @@ LL | v[3u32]; = note: required for `Vec<isize>` to implement `Index<u32>` error[E0277]: the type `[isize]` cannot be indexed by `i32` - --> $DIR/integral-indexing.rs:9:7 + --> $DIR/indexing-integral-types.rs:13:7 | LL | v[3i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` @@ -47,7 +47,7 @@ LL | v[3i32]; = note: required for `Vec<isize>` to implement `Index<i32>` error[E0277]: the type `[u8]` cannot be indexed by `u8` - --> $DIR/integral-indexing.rs:12:18 + --> $DIR/indexing-integral-types.rs:16:18 | LL | s.as_bytes()[3u8]; | ^^^ slice indices are of type `usize` or ranges of `usize` @@ -59,7 +59,7 @@ LL | s.as_bytes()[3u8]; = note: required for `[u8]` to implement `Index<u8>` error[E0277]: the type `[u8]` cannot be indexed by `i8` - --> $DIR/integral-indexing.rs:13:18 + --> $DIR/indexing-integral-types.rs:17:18 | LL | s.as_bytes()[3i8]; | ^^^ slice indices are of type `usize` or ranges of `usize` @@ -71,7 +71,7 @@ LL | s.as_bytes()[3i8]; = note: required for `[u8]` to implement `Index<i8>` error[E0277]: the type `[u8]` cannot be indexed by `u32` - --> $DIR/integral-indexing.rs:14:18 + --> $DIR/indexing-integral-types.rs:18:18 | LL | s.as_bytes()[3u32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` @@ -83,7 +83,7 @@ LL | s.as_bytes()[3u32]; = note: required for `[u8]` to implement `Index<u32>` error[E0277]: the type `[u8]` cannot be indexed by `i32` - --> $DIR/integral-indexing.rs:15:18 + --> $DIR/indexing-integral-types.rs:19:18 | LL | s.as_bytes()[3i32]; | ^^^^ slice indices are of type `usize` or ranges of `usize` diff --git a/tests/ui/inner-attrs-on-impl.rs b/tests/ui/inner-attrs-on-impl.rs deleted file mode 100644 index 1dce1cdd261..00000000000 --- a/tests/ui/inner-attrs-on-impl.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ run-pass - -struct Foo; - -impl Foo { - #![cfg(false)] - - fn method(&self) -> bool { false } -} - -impl Foo { - #![cfg(not(FALSE))] - - // check that we don't eat attributes too eagerly. - #[cfg(false)] - fn method(&self) -> bool { false } - - fn method(&self) -> bool { true } -} - - -pub fn main() { - assert!(Foo.method()); -} diff --git a/tests/ui/inner-module.rs b/tests/ui/inner-module.rs deleted file mode 100644 index 111f2cab857..00000000000 --- a/tests/ui/inner-module.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass - -mod inner { - pub mod inner2 { - pub fn hello() { println!("hello, modular world"); } - } - pub fn hello() { inner2::hello(); } -} - -pub fn main() { inner::hello(); inner::inner2::hello(); } diff --git a/tests/ui/inner-static-type-parameter.rs b/tests/ui/inner-static-type-parameter.rs deleted file mode 100644 index a1994e7529c..00000000000 --- a/tests/ui/inner-static-type-parameter.rs +++ /dev/null @@ -1,11 +0,0 @@ -// see #9186 - -enum Bar<T> { What } //~ ERROR parameter `T` is never used - -fn foo<T>() { - static a: Bar<T> = Bar::What; -//~^ ERROR can't use generic parameters from outer item -} - -fn main() { -} diff --git a/tests/ui/auxiliary/msvc-data-only-lib.rs b/tests/ui/linkage-attr/auxiliary/msvc-static-data-import-lib.rs index b8a8f905e8b..b8a8f905e8b 100644 --- a/tests/ui/auxiliary/msvc-data-only-lib.rs +++ b/tests/ui/linkage-attr/auxiliary/msvc-static-data-import-lib.rs diff --git a/tests/ui/link-section.rs b/tests/ui/linkage-attr/link-section-placement.rs index a8de8c2e1e7..6a143bfedb4 100644 --- a/tests/ui/link-section.rs +++ b/tests/ui/linkage-attr/link-section-placement.rs @@ -1,8 +1,9 @@ +//! Test placement of functions and statics in custom link sections + //@ run-pass // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] - #![allow(non_upper_case_globals)] #[cfg(not(target_vendor = "apple"))] #[link_section = ".moretext"] diff --git a/tests/ui/linkage-attr/msvc-static-data-import.rs b/tests/ui/linkage-attr/msvc-static-data-import.rs new file mode 100644 index 00000000000..e53eb404ef6 --- /dev/null +++ b/tests/ui/linkage-attr/msvc-static-data-import.rs @@ -0,0 +1,18 @@ +//! Test that static data from external crates can be imported on MSVC targets. +//! +//! On Windows MSVC targets, static data from external rlibs must be imported +//! through `__imp_<symbol>` stubs to ensure proper linking. Without this, +//! the linker would fail with "unresolved external symbol" errors when trying +//! to reference static data from another crate. +//! +//! Regression test for <https://github.com/rust-lang/rust/issues/26591>. +//! Fixed in <https://github.com/rust-lang/rust/pull/28646>. + +//@ run-pass +//@ aux-build:msvc-static-data-import-lib.rs + +extern crate msvc_static_data_import_lib; + +fn main() { + println!("The answer is {}!", msvc_static_data_import_lib::FOO); +} diff --git a/tests/ui/missing_debug_impls.rs b/tests/ui/lint/missing-debug-implementations-lint.rs index 3abc0706887..8a93f052f9c 100644 --- a/tests/ui/missing_debug_impls.rs +++ b/tests/ui/lint/missing-debug-implementations-lint.rs @@ -1,3 +1,7 @@ +//! Test the `missing_debug_implementations` lint that warns about public types without Debug. +//! +//! See https://github.com/rust-lang/rust/issues/20855 + //@ compile-flags: --crate-type lib #![deny(missing_debug_implementations)] #![allow(unused)] @@ -10,7 +14,6 @@ pub enum A {} //~ ERROR type does not implement `Debug` pub enum B {} pub enum C {} - impl fmt::Debug for C { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { Ok(()) @@ -23,15 +26,14 @@ pub struct Foo; //~ ERROR type does not implement `Debug` pub struct Bar; pub struct Baz; - impl fmt::Debug for Baz { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { Ok(()) } } +// Private types should not trigger the lint struct PrivateStruct; - enum PrivateEnum {} #[derive(Debug)] diff --git a/tests/ui/missing_debug_impls.stderr b/tests/ui/lint/missing-debug-implementations-lint.stderr index 0538f207b44..288ab981034 100644 --- a/tests/ui/missing_debug_impls.stderr +++ b/tests/ui/lint/missing-debug-implementations-lint.stderr @@ -1,17 +1,17 @@ error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation - --> $DIR/missing_debug_impls.rs:7:1 + --> $DIR/missing-debug-implementations-lint.rs:11:1 | LL | pub enum A {} | ^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/missing_debug_impls.rs:2:9 + --> $DIR/missing-debug-implementations-lint.rs:6:9 | LL | #![deny(missing_debug_implementations)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation - --> $DIR/missing_debug_impls.rs:20:1 + --> $DIR/missing-debug-implementations-lint.rs:23:1 | LL | pub struct Foo; | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/unused/unused-attr-duplicate.rs b/tests/ui/lint/unused/unused-attr-duplicate.rs index 407af40654e..bf94a42f6e0 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.rs +++ b/tests/ui/lint/unused/unused-attr-duplicate.rs @@ -102,4 +102,10 @@ pub fn no_mangle_test() {} #[used] //~ ERROR unused attribute static FOO: u32 = 0; +#[link_section = ".text"] +//~^ ERROR unused attribute +//~| WARN this was previously accepted +#[link_section = ".bss"] +pub extern "C" fn example() {} + fn main() {} diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index e8452465efc..feae8528cf7 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -289,5 +289,18 @@ note: attribute also specified here LL | #[used] | ^^^^^^^ -error: aborting due to 23 previous errors +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:105:1 + | +LL | #[link_section = ".text"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:108:1 + | +LL | #[link_section = ".bss"] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error: aborting due to 24 previous errors diff --git a/tests/ui/log-err-phi.rs b/tests/ui/log-err-phi.rs deleted file mode 100644 index 1bb97758782..00000000000 --- a/tests/ui/log-err-phi.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass - -pub fn main() { - if false { - println!("{}", "foobar"); - } -} diff --git a/tests/ui/log-knows-the-names-of-variants.rs b/tests/ui/log-knows-the-names-of-variants.rs deleted file mode 100644 index cb82cb4878a..00000000000 --- a/tests/ui/log-knows-the-names-of-variants.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ run-pass - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#[derive(Debug)] -enum foo { - a(usize), - b(String), - c, -} - -#[derive(Debug)] -enum bar { - d, e, f -} - -pub fn main() { - assert_eq!("a(22)".to_string(), format!("{:?}", foo::a(22))); - assert_eq!("c".to_string(), format!("{:?}", foo::c)); - assert_eq!("d".to_string(), format!("{:?}", bar::d)); -} diff --git a/tests/ui/loud_ui.rs b/tests/ui/loud_ui.rs deleted file mode 100644 index 2a73e49e172..00000000000 --- a/tests/ui/loud_ui.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ should-fail - -// this test ensures that when we forget to use -// any `//~ ERROR` comments whatsoever, that the test doesn't succeed - -fn main() {} diff --git a/tests/ui/maximal_mir_to_hir_coverage.rs b/tests/ui/maximal_mir_to_hir_coverage.rs deleted file mode 100644 index e57c83d007e..00000000000 --- a/tests/ui/maximal_mir_to_hir_coverage.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ compile-flags: -Zmaximal-hir-to-mir-coverage -//@ run-pass - -// Just making sure this flag is accepted and doesn't crash the compiler - -fn main() { - let x = 1; - let y = x + 1; - println!("{y}"); -} diff --git a/tests/ui/maybe-bounds.rs b/tests/ui/maybe-bounds.rs deleted file mode 100644 index 02ed45c656f..00000000000 --- a/tests/ui/maybe-bounds.rs +++ /dev/null @@ -1,9 +0,0 @@ -trait Tr: ?Sized {} -//~^ ERROR `?Trait` is not permitted in supertraits - -type A1 = dyn Tr + (?Sized); -//~^ ERROR `?Trait` is not permitted in trait object types -type A2 = dyn for<'a> Tr + (?Sized); -//~^ ERROR `?Trait` is not permitted in trait object types - -fn main() {} diff --git a/tests/ui/method-output-diff-issue-127263.rs b/tests/ui/method-output-diff-issue-127263.rs deleted file mode 100644 index 85a903e2453..00000000000 --- a/tests/ui/method-output-diff-issue-127263.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn bar() {} -fn foo(x: i32) -> u32 { - 0 -} -fn main() { - let b: fn() -> u32 = bar; //~ ERROR mismatched types [E0308] - let f: fn(i32) = foo; //~ ERROR mismatched types [E0308] -} diff --git a/tests/ui/mismatched_types/fn-pointer-mismatch-diagnostics.rs b/tests/ui/mismatched_types/fn-pointer-mismatch-diagnostics.rs new file mode 100644 index 00000000000..e28ca3e55b5 --- /dev/null +++ b/tests/ui/mismatched_types/fn-pointer-mismatch-diagnostics.rs @@ -0,0 +1,16 @@ +//! This test checks that when there's a type mismatch between a function item and +//! a function pointer, the error message focuses on the actual type difference +//! (return types, argument types) rather than the confusing "pointer vs item" distinction. +//! +//! See https://github.com/rust-lang/rust/issues/127263 + +fn bar() {} + +fn foo(x: i32) -> u32 { + 0 +} + +fn main() { + let b: fn() -> u32 = bar; //~ ERROR mismatched types [E0308] + let f: fn(i32) = foo; //~ ERROR mismatched types [E0308] +} diff --git a/tests/ui/method-output-diff-issue-127263.stderr b/tests/ui/mismatched_types/fn-pointer-mismatch-diagnostics.stderr index 35b86114f16..8d63f2ea2d3 100644 --- a/tests/ui/method-output-diff-issue-127263.stderr +++ b/tests/ui/mismatched_types/fn-pointer-mismatch-diagnostics.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/method-output-diff-issue-127263.rs:6:26 + --> $DIR/fn-pointer-mismatch-diagnostics.rs:14:26 | LL | let b: fn() -> u32 = bar; | ----------- ^^^ expected fn pointer, found fn item @@ -10,7 +10,7 @@ LL | let b: fn() -> u32 = bar; found fn item `fn() -> () {bar}` error[E0308]: mismatched types - --> $DIR/method-output-diff-issue-127263.rs:7:22 + --> $DIR/fn-pointer-mismatch-diagnostics.rs:15:22 | LL | let f: fn(i32) = foo; | ------- ^^^ expected fn pointer, found fn item diff --git a/tests/ui/integral-variable-unification-error.rs b/tests/ui/mismatched_types/int-float-type-mismatch.rs index 8d1621321e8..b45d02730d9 100644 --- a/tests/ui/integral-variable-unification-error.rs +++ b/tests/ui/mismatched_types/int-float-type-mismatch.rs @@ -1,3 +1,6 @@ +//! Check that a type mismatch error is reported when trying +//! to unify a {float} value assignment to an {integer} variable. + fn main() { let mut x //~ NOTE expected due to the type of this binding = diff --git a/tests/ui/integral-variable-unification-error.stderr b/tests/ui/mismatched_types/int-float-type-mismatch.stderr index 1caa6042fd2..43b8609a49d 100644 --- a/tests/ui/integral-variable-unification-error.stderr +++ b/tests/ui/mismatched_types/int-float-type-mismatch.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/integral-variable-unification-error.rs:5:9 + --> $DIR/int-float-type-mismatch.rs:8:9 | LL | let mut x | ----- expected due to the type of this binding diff --git a/tests/ui/mod-subitem-as-enum-variant.rs b/tests/ui/mod-subitem-as-enum-variant.rs deleted file mode 100644 index 959024c46f4..00000000000 --- a/tests/ui/mod-subitem-as-enum-variant.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod Mod { - pub struct FakeVariant<T>(pub T); -} - -fn main() { - Mod::FakeVariant::<i32>(0); - Mod::<i32>::FakeVariant(0); - //~^ ERROR type arguments are not allowed on module `Mod` [E0109] -} diff --git a/tests/ui/modules/nested-modules-basic.rs b/tests/ui/modules/nested-modules-basic.rs new file mode 100644 index 00000000000..12eccec2808 --- /dev/null +++ b/tests/ui/modules/nested-modules-basic.rs @@ -0,0 +1,19 @@ +//! Basic test for nested module functionality and path resolution + +//@ run-pass + +mod inner { + pub mod inner2 { + pub fn hello() { + println!("hello, modular world"); + } + } + pub fn hello() { + inner2::hello(); + } +} + +pub fn main() { + inner::hello(); + inner::inner2::hello(); +} diff --git a/tests/ui/monomorphize-abi-alignment.rs b/tests/ui/monomorphize-abi-alignment.rs deleted file mode 100644 index 62df1aca357..00000000000 --- a/tests/ui/monomorphize-abi-alignment.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ run-pass - -#![allow(non_upper_case_globals)] -#![allow(dead_code)] -/*! - * On x86_64-linux-gnu and possibly other platforms, structs get 8-byte "preferred" alignment, - * but their "ABI" alignment (i.e., what actually matters for data layout) is the largest alignment - * of any field. (Also, `u64` has 8-byte ABI alignment; this is not always true). - * - * On such platforms, if monomorphize uses the "preferred" alignment, then it will unify - * `A` and `B`, even though `S<A>` and `S<B>` have the field `t` at different offsets, - * and apply the wrong instance of the method `unwrap`. - */ - -#[derive(Copy, Clone)] -struct S<T> { i:u8, t:T } - -impl<T> S<T> { - fn unwrap(self) -> T { - self.t - } -} - -#[derive(Copy, Clone, PartialEq, Debug)] -struct A((u32, u32)); - -#[derive(Copy, Clone, PartialEq, Debug)] -struct B(u64); - -pub fn main() { - static Ca: S<A> = S { i: 0, t: A((13, 104)) }; - static Cb: S<B> = S { i: 0, t: B(31337) }; - assert_eq!(Ca.unwrap(), A((13, 104))); - assert_eq!(Cb.unwrap(), B(31337)); -} diff --git a/tests/ui/msvc-data-only.rs b/tests/ui/msvc-data-only.rs deleted file mode 100644 index 15d799085fe..00000000000 --- a/tests/ui/msvc-data-only.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass -//@ aux-build:msvc-data-only-lib.rs - -extern crate msvc_data_only_lib; - -fn main() { - println!("The answer is {} !", msvc_data_only_lib::FOO); -} diff --git a/tests/ui/msvc-opt-minsize.rs b/tests/ui/msvc-opt-minsize.rs deleted file mode 100644 index c1be168a05d..00000000000 --- a/tests/ui/msvc-opt-minsize.rs +++ /dev/null @@ -1,31 +0,0 @@ -// A previously outdated version of LLVM caused compilation failures on Windows -// specifically with optimization level `z`. After the update to a more recent LLVM -// version, this test checks that compilation and execution both succeed. -// See https://github.com/rust-lang/rust/issues/45034 - -//@ ignore-cross-compile -// Reason: the compiled binary is executed -//@ only-windows -// Reason: the observed bug only occurs on Windows -//@ run-pass -//@ compile-flags: -C opt-level=z - -#![feature(test)] -extern crate test; - -fn foo(x: i32, y: i32) -> i64 { - (x + y) as i64 -} - -#[inline(never)] -fn bar() { - let _f = Box::new(0); - // This call used to trigger an LLVM bug in opt-level z where the base - // pointer gets corrupted, see issue #45034 - let y: fn(i32, i32) -> i64 = test::black_box(foo); - test::black_box(y(1, 2)); -} - -fn main() { - bar(); -} diff --git a/tests/ui/multibyte.rs b/tests/ui/multibyte.rs deleted file mode 100644 index d585a791fb9..00000000000 --- a/tests/ui/multibyte.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass -// - -// Test that multibyte characters don't crash the compiler -pub fn main() { - println!("마이너스 사인이 없으면"); -} diff --git a/tests/ui/multiline-comment.rs b/tests/ui/multiline-comment.rs deleted file mode 100644 index 98174882032..00000000000 --- a/tests/ui/multiline-comment.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ run-pass - -/* - * This is a multi-line oldcomment. - */ -pub fn main() { } diff --git a/tests/ui/parser/multiline-comments-basic.rs b/tests/ui/parser/multiline-comments-basic.rs new file mode 100644 index 00000000000..1aa2a531f5c --- /dev/null +++ b/tests/ui/parser/multiline-comments-basic.rs @@ -0,0 +1,10 @@ +//! Test that basic multiline comments are parsed correctly. +//! +//! Feature implementation test for <https://github.com/rust-lang/rust/issues/66>. + +//@ run-pass + +/* + * This is a multi-line comment. + */ +pub fn main() {} diff --git a/tests/ui/parser/unicode-multibyte-chars-no-ice.rs b/tests/ui/parser/unicode-multibyte-chars-no-ice.rs new file mode 100644 index 00000000000..b1bb0c66ae2 --- /dev/null +++ b/tests/ui/parser/unicode-multibyte-chars-no-ice.rs @@ -0,0 +1,9 @@ +//! Test that multibyte Unicode characters don't crash the compiler. +//! +//! Regression test for <https://github.com/rust-lang/rust/issues/4780>. + +//@ run-pass + +pub fn main() { + println!("마이너스 사인이 없으면"); +} diff --git a/tests/ui/max-min-classes.rs b/tests/ui/resolve/struct-function-same-name.rs index 338a3156a9a..bb2837d7ca6 100644 --- a/tests/ui/max-min-classes.rs +++ b/tests/ui/resolve/struct-function-same-name.rs @@ -1,3 +1,5 @@ +//! Test that a struct and function can have the same name +//! //@ run-pass #![allow(non_snake_case)] @@ -23,7 +25,7 @@ impl Product for Foo { } fn Foo(x: isize, y: isize) -> Foo { - Foo { x: x, y: y } + Foo { x, y } } pub fn main() { diff --git a/tests/ui/lexical-scoping.rs b/tests/ui/resolve/type-param-local-var-shadowing.rs index f858369f7ce..e08379e2acf 100644 --- a/tests/ui/lexical-scoping.rs +++ b/tests/ui/resolve/type-param-local-var-shadowing.rs @@ -1,8 +1,13 @@ +//! Test that items in subscopes correctly shadow type parameters and local variables +//! +//! Regression test for https://github.com/rust-lang/rust/issues/23880 + //@ run-pass -// Tests that items in subscopes can shadow type parameters and local variables (see issue #23880). #![allow(unused)] -struct Foo<X> { x: Box<X> } +struct Foo<X> { + x: Box<X>, +} impl<Bar> Foo<Bar> { fn foo(&self) { type Bar = i32; diff --git a/tests/ui/statics/static-generic-param-soundness.rs b/tests/ui/statics/static-generic-param-soundness.rs new file mode 100644 index 00000000000..aabcca514d3 --- /dev/null +++ b/tests/ui/statics/static-generic-param-soundness.rs @@ -0,0 +1,20 @@ +//! Originally, inner statics in generic functions were generated only once, causing the same +//! static to be shared across all generic instantiations. This created a soundness hole where +//! different types could be coerced through thread-local storage in safe code. +//! +//! This test checks that generic parameters from outer scopes cannot be used in inner statics, +//! preventing this soundness issue. +//! +//! See https://github.com/rust-lang/rust/issues/9186 + +enum Bar<T> { + //~^ ERROR parameter `T` is never used + What, +} + +fn foo<T>() { + static a: Bar<T> = Bar::What; + //~^ ERROR can't use generic parameters from outer item +} + +fn main() {} diff --git a/tests/ui/inner-static-type-parameter.stderr b/tests/ui/statics/static-generic-param-soundness.stderr index 88d33b44c59..47554c7fcb0 100644 --- a/tests/ui/inner-static-type-parameter.stderr +++ b/tests/ui/statics/static-generic-param-soundness.stderr @@ -1,5 +1,5 @@ error[E0401]: can't use generic parameters from outer item - --> $DIR/inner-static-type-parameter.rs:6:19 + --> $DIR/static-generic-param-soundness.rs:16:19 | LL | fn foo<T>() { | - type parameter from outer item @@ -9,9 +9,9 @@ LL | static a: Bar<T> = Bar::What; = note: a `static` is a separate item from the item that contains it error[E0392]: type parameter `T` is never used - --> $DIR/inner-static-type-parameter.rs:3:10 + --> $DIR/static-generic-param-soundness.rs:10:10 | -LL | enum Bar<T> { What } +LL | enum Bar<T> { | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` diff --git a/tests/ui/stats/macro-stats.rs b/tests/ui/stats/macro-stats.rs index ee265d682fd..d986904ddd6 100644 --- a/tests/ui/stats/macro-stats.rs +++ b/tests/ui/stats/macro-stats.rs @@ -49,12 +49,17 @@ fn opt(x: Option<u32>) { } } -macro_rules! this_is_a_really_really_long_macro_name { +macro_rules! long_name_that_fits_on_a_single_line { + () => {} +} +long_name_that_fits_on_a_single_line!(); + +macro_rules! long_name_that_doesnt_fit_on_one_line { ($t:ty) => { fn f(_: $t) {} } } -this_is_a_really_really_long_macro_name!(u32!()); // AstFragmentKind::{Items,Ty} +long_name_that_doesnt_fit_on_one_line!(u32!()); // AstFragmentKind::{Items,Ty} macro_rules! trait_tys { () => { diff --git a/tests/ui/stats/macro-stats.stderr b/tests/ui/stats/macro-stats.stderr index 00c6b55c6a2..8d0fdb8958a 100644 --- a/tests/ui/stats/macro-stats.stderr +++ b/tests/ui/stats/macro-stats.stderr @@ -15,12 +15,13 @@ macro-stats #[derive(Copy)] 1 2 2.0 macro-stats p! 1 3 3.0 32 32.0 macro-stats trait_impl_tys! 1 2 2.0 28 28.0 macro-stats foreign_item! 1 1 1.0 21 21.0 -macro-stats this_is_a_really_really_long_macro_name! +macro-stats long_name_that_doesnt_fit_on_one_line! macro-stats 1 1 1.0 18 18.0 macro-stats impl_const! 1 1 1.0 17 17.0 macro-stats trait_tys! 1 2 2.0 15 15.0 macro-stats n99! 2 2 1.0 4 2.0 macro-stats none! 1 1 1.0 4 4.0 macro-stats u32! 1 1 1.0 3 3.0 +macro-stats long_name_that_fits_on_a_single_line! 1 1 1.0 0 0.0 macro-stats #[test] 1 1 1.0 0 0.0 macro-stats =================================================================================== diff --git a/tests/ui/invalid_dispatch_from_dyn_impls.rs b/tests/ui/traits/dispatch-from-dyn-invalid-impls.rs index b1d4b261bab..f5f66ca69cf 100644 --- a/tests/ui/invalid_dispatch_from_dyn_impls.rs +++ b/tests/ui/traits/dispatch-from-dyn-invalid-impls.rs @@ -1,20 +1,30 @@ +//! Test various invalid implementations of DispatchFromDyn trait. +//! +//! DispatchFromDyn is a special trait used by the compiler for dyn-compatible dynamic dispatch. +//! This checks that the compiler correctly rejects invalid implementations: +//! - Structs with extra non-coercible fields +//! - Structs with multiple pointer fields +//! - Structs with no coercible fields +//! - Structs with repr(C) or other incompatible representations +//! - Structs with over-aligned fields + #![feature(unsize, dispatch_from_dyn)] -use std::{ - ops::DispatchFromDyn, - marker::{Unsize, PhantomData}, -}; +use std::marker::{PhantomData, Unsize}; +use std::ops::DispatchFromDyn; +// Extra field prevents DispatchFromDyn struct WrapperWithExtraField<T>(T, i32); impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T> //~^ ERROR [E0378] where - T: DispatchFromDyn<U>, -{} - + T: DispatchFromDyn<U> +{ +} -struct MultiplePointers<T: ?Sized>{ +// Multiple pointer fields create ambiguous coercion +struct MultiplePointers<T: ?Sized> { ptr1: *const T, ptr2: *const T, } @@ -22,10 +32,11 @@ struct MultiplePointers<T: ?Sized>{ impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T> //~^ ERROR implementing `DispatchFromDyn` does not allow multiple fields to be coerced where - T: Unsize<U>, -{} - + T: Unsize<U> +{ +} +// No coercible fields (only PhantomData) struct NothingToCoerce<T: ?Sized> { data: PhantomData<T>, } @@ -33,23 +44,28 @@ struct NothingToCoerce<T: ?Sized> { impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {} //~^ ERROR implementing `DispatchFromDyn` requires a field to be coerced +// repr(C) is incompatible with DispatchFromDyn #[repr(C)] struct HasReprC<T: ?Sized>(Box<T>); impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T> //~^ ERROR [E0378] where - T: Unsize<U>, -{} + T: Unsize<U> +{ +} +// Over-aligned fields are incompatible #[repr(align(64))] struct OverAlignedZst; + struct OverAligned<T: ?Sized>(Box<T>, OverAlignedZst); impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T> //~^ ERROR [E0378] - where - T: Unsize<U>, -{} +where + T: Unsize<U> +{ +} fn main() {} diff --git a/tests/ui/invalid_dispatch_from_dyn_impls.stderr b/tests/ui/traits/dispatch-from-dyn-invalid-impls.stderr index 93ec6bbe089..676da0ce81f 100644 --- a/tests/ui/invalid_dispatch_from_dyn_impls.stderr +++ b/tests/ui/traits/dispatch-from-dyn-invalid-impls.stderr @@ -1,25 +1,25 @@ error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else - --> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1 + --> $DIR/dispatch-from-dyn-invalid-impls.rs:19:1 | LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T> LL | | LL | | where -LL | | T: DispatchFromDyn<U>, - | |__________________________^ +LL | | T: DispatchFromDyn<U> + | |_________________________^ | = note: extra field `1` of type `i32` is not allowed error[E0375]: implementing `DispatchFromDyn` does not allow multiple fields to be coerced - --> $DIR/invalid_dispatch_from_dyn_impls.rs:22:1 + --> $DIR/dispatch-from-dyn-invalid-impls.rs:32:1 | LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T> LL | | LL | | where -LL | | T: Unsize<U>, - | |_________________^ +LL | | T: Unsize<U> + | |________________^ | note: the trait `DispatchFromDyn` may only be implemented when a single field is being coerced - --> $DIR/invalid_dispatch_from_dyn_impls.rs:18:5 + --> $DIR/dispatch-from-dyn-invalid-impls.rs:28:5 | LL | ptr1: *const T, | ^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | ptr2: *const T, | ^^^^^^^^^^^^^^ error[E0374]: implementing `DispatchFromDyn` requires a field to be coerced - --> $DIR/invalid_dispatch_from_dyn_impls.rs:33:1 + --> $DIR/dispatch-from-dyn-invalid-impls.rs:44:1 | LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,22 +35,22 @@ LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingT = note: expected a single field to be coerced, none found error[E0378]: structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]` - --> $DIR/invalid_dispatch_from_dyn_impls.rs:39:1 + --> $DIR/dispatch-from-dyn-invalid-impls.rs:51:1 | LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T> LL | | LL | | where -LL | | T: Unsize<U>, - | |_________________^ +LL | | T: Unsize<U> + | |________________^ error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else - --> $DIR/invalid_dispatch_from_dyn_impls.rs:49:1 + --> $DIR/dispatch-from-dyn-invalid-impls.rs:64:1 | LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T> LL | | -LL | | where -LL | | T: Unsize<U>, - | |_____________________^ +LL | | where +LL | | T: Unsize<U> + | |________________^ | = note: extra field `1` of type `OverAlignedZst` is not allowed diff --git a/tests/ui/issue-11881.rs b/tests/ui/traits/encoder-trait-bounds-regression.rs index 1abe0797203..292b921cdf7 100644 --- a/tests/ui/issue-11881.rs +++ b/tests/ui/traits/encoder-trait-bounds-regression.rs @@ -1,14 +1,23 @@ +//! Regression test for issue #11881 +//! +//! Originally, the compiler would ICE when trying to parameterize on certain encoder types +//! due to issues with higher-ranked trait bounds and lifetime inference. This test checks +//! that various encoder patterns work correctly: +//! - Generic encoders with associated error types +//! - Higher-ranked trait bounds (for<'r> Encodable<JsonEncoder<'r>>) +//! - Multiple encoder implementations for the same type +//! - Polymorphic encoding functions + //@ run-pass #![allow(unused_must_use)] #![allow(dead_code)] #![allow(unused_imports)] -use std::fmt; -use std::io::prelude::*; use std::io::Cursor; -use std::slice; +use std::io::prelude::*; use std::marker::PhantomData; +use std::{fmt, slice}; trait Encoder { type Error; @@ -45,7 +54,6 @@ impl Encoder for OpaqueEncoder { type Error = (); } - struct Foo { baz: bool, } @@ -69,7 +77,6 @@ impl<S: Encoder> Encodable<S> for Bar { enum WireProtocol { JSON, Opaque, - // ... } fn encode_json<T: for<'a> Encodable<JsonEncoder<'a>>>(val: &T, wr: &mut Cursor<Vec<u8>>) { diff --git a/tests/ui/traits/eval-caching-error-region.rs b/tests/ui/traits/eval-caching-error-region.rs new file mode 100644 index 00000000000..831b5ab80c1 --- /dev/null +++ b/tests/ui/traits/eval-caching-error-region.rs @@ -0,0 +1,23 @@ +// Regression test for #132882. + +use std::ops::Add; + +pub trait Numoid: Sized +where + &'missing Self: Add<Self>, + //~^ ERROR use of undeclared lifetime name `'missing` +{ +} + +// Proving `N: Numoid`'s well-formedness causes us to have to prove `&'missing N: Add<N>`. +// Since `'missing` is a region error, that will lead to us consider the predicate to hold, +// since it references errors. Since the freshener turns error regions into fresh regions, +// this means that subsequent lookups of `&'?0 N: Add<N>` will also hit this cache entry +// even if candidate assembly can't assemble anything for `&'?0 N: Add<?1>` anyways. This +// led to an ICE. +pub fn compute<N: Numoid>(a: N) { + let _ = &a + a; + //~^ ERROR cannot add `N` to `&N` +} + +fn main() {} diff --git a/tests/ui/traits/eval-caching-error-region.stderr b/tests/ui/traits/eval-caching-error-region.stderr new file mode 100644 index 00000000000..6365d242d2e --- /dev/null +++ b/tests/ui/traits/eval-caching-error-region.stderr @@ -0,0 +1,33 @@ +error[E0261]: use of undeclared lifetime name `'missing` + --> $DIR/eval-caching-error-region.rs:7:6 + | +LL | &'missing Self: Add<Self>, + | ^^^^^^^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'missing` lifetime + | +LL | for<'missing> &'missing Self: Add<Self>, + | +++++++++++++ +help: consider introducing lifetime `'missing` here + | +LL | pub trait Numoid<'missing>: Sized + | ++++++++++ + +error[E0369]: cannot add `N` to `&N` + --> $DIR/eval-caching-error-region.rs:19:16 + | +LL | let _ = &a + a; + | -- ^ - N + | | + | &N + | +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | pub fn compute<N: Numoid>(a: N) where &N: Add<N> { + | ++++++++++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0261, E0369. +For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs b/tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs new file mode 100644 index 00000000000..04963c98765 --- /dev/null +++ b/tests/ui/traits/maybe-trait-bounds-forbidden-locations.rs @@ -0,0 +1,18 @@ +//! Test that ?Trait bounds are forbidden in supertraits and trait object types. +//! +//! While `?Sized` and other maybe bounds are allowed in type parameter bounds and where clauses, +//! they are explicitly forbidden in certain syntactic positions: +//! - As supertraits in trait definitions +//! - In trait object type expressions +//! +//! See https://github.com/rust-lang/rust/issues/20503 + +trait Tr: ?Sized {} +//~^ ERROR `?Trait` is not permitted in supertraits + +type A1 = dyn Tr + (?Sized); +//~^ ERROR `?Trait` is not permitted in trait object types +type A2 = dyn for<'a> Tr + (?Sized); +//~^ ERROR `?Trait` is not permitted in trait object types + +fn main() {} diff --git a/tests/ui/maybe-bounds.stderr b/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr index 230d11fd0ae..bd0baa580bd 100644 --- a/tests/ui/maybe-bounds.stderr +++ b/tests/ui/traits/maybe-trait-bounds-forbidden-locations.stderr @@ -1,5 +1,5 @@ error[E0658]: `?Trait` is not permitted in supertraits - --> $DIR/maybe-bounds.rs:1:11 + --> $DIR/maybe-trait-bounds-forbidden-locations.rs:10:11 | LL | trait Tr: ?Sized {} | ^^^^^^ @@ -9,7 +9,7 @@ LL | trait Tr: ?Sized {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `?Trait` is not permitted in trait object types - --> $DIR/maybe-bounds.rs:4:20 + --> $DIR/maybe-trait-bounds-forbidden-locations.rs:13:20 | LL | type A1 = dyn Tr + (?Sized); | ^^^^^^^^ @@ -18,7 +18,7 @@ LL | type A1 = dyn Tr + (?Sized); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `?Trait` is not permitted in trait object types - --> $DIR/maybe-bounds.rs:6:28 + --> $DIR/maybe-trait-bounds-forbidden-locations.rs:15:28 | LL | type A2 = dyn for<'a> Tr + (?Sized); | ^^^^^^^^ diff --git a/tests/ui/type-alias-enum-variants/module-type-args-error.rs b/tests/ui/type-alias-enum-variants/module-type-args-error.rs new file mode 100644 index 00000000000..9f7dae4f4f5 --- /dev/null +++ b/tests/ui/type-alias-enum-variants/module-type-args-error.rs @@ -0,0 +1,16 @@ +//! Test that type arguments are properly rejected on modules. +//! +//! Related PR: https://github.com/rust-lang/rust/pull/56225 (RFC 2338 implementation) + +mod Mod { + pub struct FakeVariant<T>(pub T); +} + +fn main() { + // This should work fine - normal generic struct constructor + Mod::FakeVariant::<i32>(0); + + // This should error - type arguments not allowed on modules + Mod::<i32>::FakeVariant(0); + //~^ ERROR type arguments are not allowed on module `Mod` [E0109] +} diff --git a/tests/ui/mod-subitem-as-enum-variant.stderr b/tests/ui/type-alias-enum-variants/module-type-args-error.stderr index 92d972eba42..4c59d19eaa7 100644 --- a/tests/ui/mod-subitem-as-enum-variant.stderr +++ b/tests/ui/type-alias-enum-variants/module-type-args-error.stderr @@ -1,5 +1,5 @@ error[E0109]: type arguments are not allowed on module `Mod` - --> $DIR/mod-subitem-as-enum-variant.rs:7:11 + --> $DIR/module-type-args-error.rs:14:11 | LL | Mod::<i32>::FakeVariant(0); | --- ^^^ type argument not allowed |
