diff options
436 files changed, 6888 insertions, 3378 deletions
diff --git a/.gitmodules b/.gitmodules index b48fddf963f..a13a2f5e01b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -33,7 +33,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/16.0-2023-06-05 + branch = rustc/17.0-2023-07-29 shallow = true [submodule "src/doc/embedded-book"] path = src/doc/embedded-book diff --git a/Cargo.lock b/Cargo.lock index 7cde7989bc0..3b270c14bb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -154,7 +154,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -164,7 +164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -797,7 +797,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e" dependencies = [ "nix", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1108,7 +1108,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1191,7 +1191,7 @@ dependencies = [ "cfg-if", "libc", "redox_syscall 0.2.16", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1910,7 +1910,7 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.2", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1927,7 +1927,7 @@ checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" dependencies = [ "hermit-abi 0.3.2", "rustix 0.38.2", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -2320,16 +2320,16 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "miow" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123" +checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044" dependencies = [ - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -4046,6 +4046,7 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_middle", + "rustc_mir_build", "rustc_mir_dataflow", "rustc_serialize", "rustc_session", @@ -4561,7 +4562,7 @@ dependencies = [ "io-lifetimes", "libc", "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -4574,7 +4575,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.3", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -4611,11 +4612,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -5044,7 +5045,7 @@ dependencies = [ "fastrand", "redox_syscall 0.3.5", "rustix 0.37.22", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -5085,7 +5086,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ "rustix 0.37.22", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -5264,7 +5265,7 @@ dependencies = [ "num_cpus", "pin-project-lite", "socket2", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -5874,21 +5875,6 @@ checksum = "2f5bca94a32bf1e6a376522b6601275a3b611ee885ec0f1b6a05f17e8cfd3385" [[package]] name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" @@ -5902,13 +5888,13 @@ version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -5919,84 +5905,42 @@ checksum = "b34c9a3b28cb41db7385546f7f9a8179348dffc89923dde66857b1ba5312f6b4" [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs index e87f6e820a1..f825b10f489 100644 --- a/compiler/rustc_ast/src/expand/allocator.rs +++ b/compiler/rustc_ast/src/expand/allocator.rs @@ -33,29 +33,41 @@ pub enum AllocatorTy { pub struct AllocatorMethod { pub name: Symbol, - pub inputs: &'static [AllocatorTy], + pub inputs: &'static [AllocatorMethodInput], pub output: AllocatorTy, } +pub struct AllocatorMethodInput { + pub name: &'static str, + pub ty: AllocatorTy, +} + pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ AllocatorMethod { name: sym::alloc, - inputs: &[AllocatorTy::Layout], + inputs: &[AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }], output: AllocatorTy::ResultPtr, }, AllocatorMethod { name: sym::dealloc, - inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout], + inputs: &[ + AllocatorMethodInput { name: "ptr", ty: AllocatorTy::Ptr }, + AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }, + ], output: AllocatorTy::Unit, }, AllocatorMethod { name: sym::realloc, - inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize], + inputs: &[ + AllocatorMethodInput { name: "ptr", ty: AllocatorTy::Ptr }, + AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }, + AllocatorMethodInput { name: "new_size", ty: AllocatorTy::Usize }, + ], output: AllocatorTy::ResultPtr, }, AllocatorMethod { name: sym::alloc_zeroed, - inputs: &[AllocatorTy::Layout], + inputs: &[AllocatorMethodInput { name: "layout", ty: AllocatorTy::Layout }], output: AllocatorTy::ResultPtr, }, ]; diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ac750690046..d29e9f9b3f6 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -512,11 +512,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.node_id_to_def_id.get(&node).map(|local_def_id| *local_def_id) } - fn orig_local_def_id(&self, node: NodeId) -> LocalDefId { - self.orig_opt_local_def_id(node) - .unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) - } - /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name /// resolver (if any), after applying any remapping from `get_remapped_def_id`. /// @@ -1521,209 +1516,86 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - let opaque_ty_def_id = self.create_def( - self.current_hir_id_owner.def_id, - opaque_ty_node_id, - DefPathData::ImplTrait, - opaque_ty_span, - ); - debug!(?opaque_ty_def_id); - - // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want - // to capture the lifetimes that appear in the bounds. So visit the bounds to find out - // exactly which ones those are. - let lifetimes_to_remap = match origin { + let captured_lifetimes_to_duplicate = match origin { hir::OpaqueTyOrigin::TyAlias { .. } => { - // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters + // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't duplicate any + // lifetimes, since we don't have the issue that any are late-bound. Vec::new() } - hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => { - // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example, - // we only keep the lifetimes that appear in the `impl Debug` itself: + hir::OpaqueTyOrigin::FnReturn(..) => { + // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` + // example, we only need to duplicate lifetimes that appear in the + // bounds, since those are the only ones that are captured by the opaque. lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds) } + hir::OpaqueTyOrigin::AsyncFn(..) => { + unreachable!("should be using `lower_async_fn_ret_ty`") + } }; - debug!(?lifetimes_to_remap); - - let mut new_remapping = FxHashMap::default(); - - // Contains the new lifetime definitions created for the TAIT (if any). - // If this opaque type is only capturing a subset of the lifetimes (those that appear in - // bounds), then create the new lifetime parameters required and create a mapping from the - // old `'a` (on the function) to the new `'a` (on the opaque type). - let collected_lifetimes = - self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping); - debug!(?collected_lifetimes); - debug!(?new_remapping); - - // This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type - // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`. - let collected_lifetime_mapping: Vec<_> = collected_lifetimes - .iter() - .map(|(node_id, lifetime)| { - let id = self.next_node_id(); - let lifetime = self.new_named_lifetime(lifetime.id, id, lifetime.ident); - let def_id = self.local_def_id(*node_id); - (lifetime, def_id) - }) - .collect(); - debug!(?collected_lifetime_mapping); - - self.with_hir_id_owner(opaque_ty_node_id, |lctx| { - // Install the remapping from old to new (if any): - lctx.with_remapping(new_remapping, |lctx| { - // This creates HIR lifetime definitions as `hir::GenericParam`, in the given - // example `type TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection - // containing `&['x]`. - let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map( - |&(new_node_id, lifetime)| { - let hir_id = lctx.lower_node_id(new_node_id); - debug_assert_ne!(lctx.opt_local_def_id(new_node_id), None); - - let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime { - (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided) - } else { - ( - hir::ParamName::Plain(lifetime.ident), - hir::LifetimeParamKind::Explicit, - ) - }; + debug!(?captured_lifetimes_to_duplicate); - hir::GenericParam { - hir_id, - def_id: lctx.local_def_id(new_node_id), - name, - span: lifetime.ident.span, - pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { kind }, - colon_span: None, - source: hir::GenericParamSource::Generics, - } - }, - )); - debug!(?lifetime_defs); - - // Then when we lower the param bounds, references to 'a are remapped to 'a1, so we - // get back Debug + 'a1, which is suitable for use on the TAIT. - let hir_bounds = lctx.lower_param_bounds(bounds, itctx); - debug!(?hir_bounds); - - let lifetime_mapping = if in_trait { - Some( - &*self.arena.alloc_from_iter( - collected_lifetime_mapping - .iter() - .map(|(lifetime, def_id)| (**lifetime, *def_id)), - ), - ) - } else { - None - }; - - let opaque_ty_item = hir::OpaqueTy { - generics: self.arena.alloc(hir::Generics { - params: lifetime_defs, - predicates: &[], - has_where_clause_predicates: false, - where_clause_span: lctx.lower_span(span), - span: lctx.lower_span(span), - }), - bounds: hir_bounds, - origin, - lifetime_mapping, - in_trait, - }; - debug!(?opaque_ty_item); - - lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span) - }) - }); - - // `impl Trait` now just becomes `Foo<'a, 'b, ..>`. - hir::TyKind::OpaqueDef( - hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, - self.arena.alloc_from_iter( - collected_lifetime_mapping - .iter() - .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), - ), + self.lower_opaque_inner( + opaque_ty_node_id, + origin, in_trait, + captured_lifetimes_to_duplicate, + span, + opaque_ty_span, + |this| this.lower_param_bounds(bounds, itctx), ) } - /// Registers a new opaque type with the proper `NodeId`s and - /// returns the lowered node-ID for the opaque type. - fn generate_opaque_type( + fn lower_opaque_inner( &mut self, - opaque_ty_id: LocalDefId, - opaque_ty_item: hir::OpaqueTy<'hir>, + opaque_ty_node_id: NodeId, + origin: hir::OpaqueTyOrigin, + in_trait: bool, + captured_lifetimes_to_duplicate: Vec<Lifetime>, span: Span, opaque_ty_span: Span, - ) -> hir::OwnerNode<'hir> { - let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(self.arena.alloc(opaque_ty_item)); - // Generate an `type Foo = impl Trait;` declaration. - trace!("registering opaque type with id {:#?}", opaque_ty_id); - let opaque_ty_item = hir::Item { - owner_id: hir::OwnerId { def_id: opaque_ty_id }, - ident: Ident::empty(), - kind: opaque_ty_item_kind, - vis_span: self.lower_span(span.shrink_to_lo()), - span: self.lower_span(opaque_ty_span), - }; - hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item)) - } - - /// Given a `parent_def_id`, a list of `lifetimes_in_bounds` and a `remapping` hash to be - /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the - /// new definition, adds it to the remapping with the definition of the given lifetime and - /// returns a list of lifetimes to be lowered afterwards. - fn create_lifetime_defs( - &mut self, - parent_def_id: LocalDefId, - lifetimes_in_bounds: &[Lifetime], - remapping: &mut FxHashMap<LocalDefId, LocalDefId>, - ) -> Vec<(NodeId, Lifetime)> { - let mut result = Vec::new(); + lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], + ) -> hir::TyKind<'hir> { + let opaque_ty_def_id = self.create_def( + self.current_hir_id_owner.def_id, + opaque_ty_node_id, + DefPathData::ImplTrait, + opaque_ty_span, + ); + debug!(?opaque_ty_def_id); - for lifetime in lifetimes_in_bounds { + // Map from captured (old) lifetime to synthetic (new) lifetime. + // Used to resolve lifetimes in the bounds of the opaque. + let mut captured_to_synthesized_mapping = FxHashMap::default(); + // List of (early-bound) synthetic lifetimes that are owned by the opaque. + // This is used to create the `hir::Generics` owned by the opaque. + let mut synthesized_lifetime_definitions = vec![]; + // Pairs of lifetime arg (that resolves to the captured lifetime) + // and the def-id of the (early-bound) synthetic lifetime definition. + // This is used both to create generics for the `TyKind::OpaqueDef` that + // we return, and also as a captured lifetime mapping for RPITITs. + let mut synthesized_lifetime_args = vec![]; + + for lifetime in captured_lifetimes_to_duplicate { let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error); - debug!(?res); - - match res { - LifetimeRes::Param { param: old_def_id, binder: _ } => { - if remapping.get(&old_def_id).is_none() { - let node_id = self.next_node_id(); - - let new_def_id = self.create_def( - parent_def_id, - node_id, - DefPathData::LifetimeNs(lifetime.ident.name), - lifetime.ident.span, - ); - remapping.insert(old_def_id, new_def_id); - - result.push((node_id, *lifetime)); - } - } + let old_def_id = match res { + LifetimeRes::Param { param: old_def_id, binder: _ } => old_def_id, LifetimeRes::Fresh { param, binder: _ } => { debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); - if let Some(old_def_id) = self.orig_opt_local_def_id(param) && remapping.get(&old_def_id).is_none() { - let node_id = self.next_node_id(); - - let new_def_id = self.create_def( - parent_def_id, - node_id, - DefPathData::LifetimeNs(kw::UnderscoreLifetime), - lifetime.ident.span, - ); - remapping.insert(old_def_id, new_def_id); - - result.push((node_id, *lifetime)); + if let Some(old_def_id) = self.orig_opt_local_def_id(param) { + old_def_id + } else { + self.tcx + .sess + .delay_span_bug(lifetime.ident.span, "no def-id for fresh lifetime"); + continue; } } - LifetimeRes::Static | LifetimeRes::Error => {} + // Opaques do not capture `'static` + LifetimeRes::Static | LifetimeRes::Error => { + continue; + } res => { let bug_msg = format!( @@ -1732,10 +1604,113 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); span_bug!(lifetime.ident.span, "{}", bug_msg); } + }; + + if captured_to_synthesized_mapping.get(&old_def_id).is_none() { + // Create a new lifetime parameter local to the opaque. + let duplicated_lifetime_node_id = self.next_node_id(); + let duplicated_lifetime_def_id = self.create_def( + opaque_ty_def_id, + duplicated_lifetime_node_id, + DefPathData::LifetimeNs(lifetime.ident.name), + lifetime.ident.span, + ); + captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id); + // FIXME: Instead of doing this, we could move this whole loop + // into the `with_hir_id_owner`, then just directly construct + // the `hir::GenericParam` here. + synthesized_lifetime_definitions.push(( + duplicated_lifetime_node_id, + duplicated_lifetime_def_id, + lifetime.ident, + )); + + // Now make an arg that we can use for the substs of the opaque tykind. + let id = self.next_node_id(); + let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res); + let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id); + synthesized_lifetime_args.push((lifetime_arg, duplicated_lifetime_def_id)) } } - result + self.with_hir_id_owner(opaque_ty_node_id, |this| { + // Install the remapping from old to new (if any). This makes sure that + // any lifetimes that would have resolved to the def-id of captured + // lifetimes are remapped to the new *synthetic* lifetimes of the opaque. + let bounds = this + .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this)); + + let generic_params = this.arena.alloc_from_iter( + synthesized_lifetime_definitions.iter().map(|&(new_node_id, new_def_id, ident)| { + let hir_id = this.lower_node_id(new_node_id); + let (name, kind) = if ident.name == kw::UnderscoreLifetime { + (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided) + } else { + (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) + }; + + hir::GenericParam { + hir_id, + def_id: new_def_id, + name, + span: ident.span, + pure_wrt_drop: false, + kind: hir::GenericParamKind::Lifetime { kind }, + colon_span: None, + source: hir::GenericParamSource::Generics, + } + }), + ); + debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params); + + let lifetime_mapping = if in_trait { + Some(&*self.arena.alloc_slice(&synthesized_lifetime_args)) + } else { + None + }; + + let opaque_ty_item = hir::OpaqueTy { + generics: this.arena.alloc(hir::Generics { + params: generic_params, + predicates: &[], + has_where_clause_predicates: false, + where_clause_span: this.lower_span(span), + span: this.lower_span(span), + }), + bounds, + origin, + lifetime_mapping, + in_trait, + }; + + // Generate an `type Foo = impl Trait;` declaration. + trace!("registering opaque type with id {:#?}", opaque_ty_def_id); + let opaque_ty_item = hir::Item { + owner_id: hir::OwnerId { def_id: opaque_ty_def_id }, + ident: Ident::empty(), + kind: hir::ItemKind::OpaqueTy(this.arena.alloc(opaque_ty_item)), + vis_span: this.lower_span(span.shrink_to_lo()), + span: this.lower_span(opaque_ty_span), + }; + + hir::OwnerNode::Item(this.arena.alloc(opaque_ty_item)) + }); + + let generic_args = self.arena.alloc_from_iter( + synthesized_lifetime_args + .iter() + .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), + ); + + // Create the `Foo<...>` reference itself. Note that the `type + // Foo = impl Trait` is, internally, created as a child of the + // async fn, so the *type parameters* are inherited. It's + // only the lifetime parameters that we must supply. + hir::TyKind::OpaqueDef( + hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, + generic_args, + in_trait, + ) } fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] { @@ -1813,9 +1788,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + let fn_def_id = self.local_def_id(fn_node_id); self.lower_async_fn_ret_ty( &decl.output, - fn_node_id, + fn_def_id, ret_id, matches!(kind, FnDeclKind::Trait), ) @@ -1892,151 +1868,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_async_fn_ret_ty( &mut self, output: &FnRetTy, - fn_node_id: NodeId, + fn_def_id: LocalDefId, opaque_ty_node_id: NodeId, in_trait: bool, ) -> hir::FnRetTy<'hir> { - let span = output.span(); - + let span = self.lower_span(output.span()); let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None); - let fn_def_id = self.local_def_id(fn_node_id); - - let opaque_ty_def_id = - self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait, opaque_ty_span); - - // When we create the opaque type for this async fn, it is going to have - // to capture all the lifetimes involved in the signature (including in the - // return type). This is done by introducing lifetime parameters for: - // - // - all the explicitly declared lifetimes from the impl and function itself; - // - all the elided lifetimes in the fn arguments; - // - all the elided lifetimes in the return type. - // - // So for example in this snippet: - // - // ```rust - // impl<'a> Foo<'a> { - // async fn bar<'b>(&self, x: &'b Vec<f64>, y: &str) -> &u32 { - // // ^ '0 ^ '1 ^ '2 - // // elided lifetimes used below - // } - // } - // ``` - // - // we would create an opaque type like: - // - // ``` - // type Bar<'a, 'b, '0, '1, '2> = impl Future<Output = &'2 u32>; - // ``` - // - // and we would then desugar `bar` to the equivalent of: - // - // ```rust - // impl<'a> Foo<'a> { - // fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'a, 'b, '0, '1, '_> - // } - // ``` - // - // Note that the final parameter to `Bar` is `'_`, not `'2` -- - // this is because the elided lifetimes from the return type - // should be figured out using the ordinary elision rules, and - // this desugaring achieves that. - - // Calculate all the lifetimes that should be captured - // by the opaque type. This should include all in-scope - // lifetime parameters, including those defined in-band. - - // Contains the new lifetime definitions created for the TAIT (if any) generated for the - // return type. - let mut collected_lifetimes = Vec::new(); - let mut new_remapping = FxHashMap::default(); - - let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id); - debug!(?extra_lifetime_params); - for (ident, outer_node_id, outer_res) in extra_lifetime_params { - let outer_def_id = self.orig_local_def_id(outer_node_id); - let inner_node_id = self.next_node_id(); - - // Add a definition for the in scope lifetime def. - let inner_def_id = self.create_def( - opaque_ty_def_id, - inner_node_id, - DefPathData::LifetimeNs(ident.name), - ident.span, - ); - new_remapping.insert(outer_def_id, inner_def_id); - - let inner_res = match outer_res { - // Input lifetime like `'a`: - LifetimeRes::Param { param, .. } => { - LifetimeRes::Param { param, binder: fn_node_id } - } - // Input lifetime like `'1`: - LifetimeRes::Fresh { param, .. } => { - LifetimeRes::Fresh { param, binder: fn_node_id } - } - LifetimeRes::Static | LifetimeRes::Error => continue, - res => { - panic!( - "Unexpected lifetime resolution {:?} for {:?} at {:?}", - res, ident, ident.span - ) - } - }; - - let lifetime = Lifetime { id: outer_node_id, ident }; - collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res))); - } - debug!(?collected_lifetimes); - - // We only want to capture the lifetimes that appear in the bounds. So visit the bounds to - // find out exactly which ones those are. - // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example, - // we only keep the lifetimes that appear in the `impl Debug` itself: - let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output); - debug!(?lifetimes_to_remap); - - // If this opaque type is only capturing a subset of the lifetimes (those that appear in - // bounds), then create the new lifetime parameters required and create a mapping from the - // old `'a` (on the function) to the new `'a` (on the opaque type). - collected_lifetimes.extend( - self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping) - .into_iter() - .map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)), - ); - debug!(?collected_lifetimes); - debug!(?new_remapping); - - // This creates pairs of HIR lifetimes and def_ids. In the given example `type - // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing the - // new lifetime of the RPIT 'x and the def_id of the lifetime 'x corresponding to - // `TestReturn`. - let collected_lifetime_mapping: Vec<_> = collected_lifetimes - .iter() - .map(|(node_id, lifetime, res)| { - let id = self.next_node_id(); - let res = res.unwrap_or( - self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error), - ); - let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res); - let def_id = self.local_def_id(*node_id); - (lifetime, def_id) - }) + let captured_lifetimes: Vec<_> = self + .resolver + .take_extra_lifetime_params(opaque_ty_node_id) + .into_iter() + .map(|(ident, id, _)| Lifetime { id, ident }) .collect(); - debug!(?collected_lifetime_mapping); - self.with_hir_id_owner(opaque_ty_node_id, |this| { - // Install the remapping from old to new (if any): - this.with_remapping(new_remapping, |this| { - // We have to be careful to get elision right here. The - // idea is that we create a lifetime parameter for each - // lifetime in the return type. So, given a return type - // like `async fn foo(..) -> &[&u32]`, we lower to `impl - // Future<Output = &'1 [ &'2 u32 ]>`. - // - // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and - // hence the elision takes place at the fn site. + let opaque_ty_ref = self.lower_opaque_inner( + opaque_ty_node_id, + hir::OpaqueTyOrigin::AsyncFn(fn_def_id), + in_trait, + captured_lifetimes, + span, + opaque_ty_span, + |this| { let future_bound = this.lower_async_fn_output_type_to_future_bound( output, span, @@ -2052,96 +1905,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }, ); - - let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map( - |&(new_node_id, lifetime, _)| { - let hir_id = this.lower_node_id(new_node_id); - debug_assert_ne!(this.opt_local_def_id(new_node_id), None); - - let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime { - (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided) - } else { - ( - hir::ParamName::Plain(lifetime.ident), - hir::LifetimeParamKind::Explicit, - ) - }; - - hir::GenericParam { - hir_id, - def_id: this.local_def_id(new_node_id), - name, - span: lifetime.ident.span, - pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { kind }, - colon_span: None, - source: hir::GenericParamSource::Generics, - } - }, - )); - debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params); - - let lifetime_mapping = if in_trait { - Some( - &*self.arena.alloc_from_iter( - collected_lifetime_mapping - .iter() - .map(|(lifetime, def_id)| (**lifetime, *def_id)), - ), - ) - } else { - None - }; - - let opaque_ty_item = hir::OpaqueTy { - generics: this.arena.alloc(hir::Generics { - params: generic_params, - predicates: &[], - has_where_clause_predicates: false, - where_clause_span: this.lower_span(span), - span: this.lower_span(span), - }), - bounds: arena_vec![this; future_bound], - origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id), - lifetime_mapping, - in_trait, - }; - - trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id); - this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span) - }) - }); - - // As documented above, we need to create the lifetime - // arguments to our opaque type. Continuing with our example, - // we're creating the type arguments for the return type: - // - // ``` - // Bar<'a, 'b, '0, '1, '_> - // ``` - // - // For the "input" lifetime parameters, we wish to create - // references to the parameters themselves, including the - // "implicit" ones created from parameter types (`'a`, `'b`, - // '`0`, `'1`). - // - // For the "output" lifetime parameters, we just want to - // generate `'_`. - let generic_args = self.arena.alloc_from_iter( - collected_lifetime_mapping - .iter() - .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), + arena_vec![this; future_bound] + }, ); - // Create the `Foo<...>` reference itself. Note that the `type - // Foo = impl Trait` is, internally, created as a child of the - // async fn, so the *type parameters* are inherited. It's - // only the lifetime parameters that we must supply. - let opaque_ty_ref = hir::TyKind::OpaqueDef( - hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, - generic_args, - in_trait, - ); let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref); hir::FnRetTy::Return(self.arena.alloc(opaque_ty)) } diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs index 3989fc48619..0e0bdf17389 100644 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs @@ -1,6 +1,6 @@ use super::ResolverAstLoweringExt; use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor}; -use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind}; +use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind}; use rustc_hir::def::LifetimeRes; use rustc_middle::span_bug; use rustc_middle::ty::ResolverAstLowering; @@ -94,12 +94,6 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> { } } -pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec<Lifetime> { - let mut visitor = LifetimeCollectVisitor::new(resolver); - visitor.visit_fn_ret_ty(ret_ty); - visitor.collected_lifetimes -} - pub fn lifetimes_in_bounds( resolver: &ResolverAstLowering, bounds: &GenericBounds, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index be6eb2d1d12..337af89b21f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -516,7 +516,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { // be the same as those of the ADT. // FIXME: We should be able to do something similar to // match_adt_and_segment in this case. - Res::Def(DefKind::TyAlias, _) => (), + Res::Def(DefKind::TyAlias { .. }, _) => (), _ => { if let Some(last_segment) = path.segments.last() { if let Some(highlight) = self.match_adt_and_segment( diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 053f5730f6e..1bec00add55 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -2,7 +2,7 @@ use crate::util::check_builtin_macro_attribute; use crate::errors; use rustc_ast::expand::allocator::{ - global_fn_name, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS, + global_fn_name, AllocatorMethod, AllocatorMethodInput, AllocatorTy, ALLOCATOR_METHODS, }; use rustc_ast::ptr::P; use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind}; @@ -70,19 +70,13 @@ struct AllocFnFactory<'a, 'b> { impl AllocFnFactory<'_, '_> { fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt { let mut abi_args = ThinVec::new(); - let mut i = 0; - let mut mk = || { - let name = Ident::from_str_and_span(&format!("arg{i}"), self.span); - i += 1; - name - }; - let args = method.inputs.iter().map(|ty| self.arg_ty(ty, &mut abi_args, &mut mk)).collect(); + let args = method.inputs.iter().map(|input| self.arg_ty(input, &mut abi_args)).collect(); let result = self.call_allocator(method.name, args); - let (output_ty, output_expr) = self.ret_ty(&method.output, result); + let output_ty = self.ret_ty(&method.output); let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty)); let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() }; let sig = FnSig { decl, header, span: self.span }; - let body = Some(self.cx.block_expr(output_expr)); + let body = Some(self.cx.block_expr(result)); let kind = ItemKind::Fn(Box::new(Fn { defaultness: ast::Defaultness::Final, sig, @@ -113,18 +107,19 @@ impl AllocFnFactory<'_, '_> { thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)] } - fn arg_ty( - &self, - ty: &AllocatorTy, - args: &mut ThinVec<Param>, - ident: &mut dyn FnMut() -> Ident, - ) -> P<Expr> { - match *ty { + fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec<Param>) -> P<Expr> { + match input.ty { AllocatorTy::Layout => { + // If an allocator method is ever introduced having multiple + // Layout arguments, these argument names need to be + // disambiguated somehow. Currently the generated code would + // fail to compile with "identifier is bound more than once in + // this parameter list". + let size = Ident::from_str_and_span("size", self.span); + let align = Ident::from_str_and_span("align", self.span); + let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span)); let ty_usize = self.cx.ty_path(usize); - let size = ident(); - let align = ident(); args.push(self.cx.param(self.span, size, ty_usize.clone())); args.push(self.cx.param(self.span, align, ty_usize)); @@ -138,14 +133,13 @@ impl AllocFnFactory<'_, '_> { } AllocatorTy::Ptr => { - let ident = ident(); + let ident = Ident::from_str_and_span(input.name, self.span); args.push(self.cx.param(self.span, ident, self.ptr_u8())); - let arg = self.cx.expr_ident(self.span, ident); - self.cx.expr_cast(self.span, arg, self.ptr_u8()) + self.cx.expr_ident(self.span, ident) } AllocatorTy::Usize => { - let ident = ident(); + let ident = Ident::from_str_and_span(input.name, self.span); args.push(self.cx.param(self.span, ident, self.usize())); self.cx.expr_ident(self.span, ident) } @@ -156,18 +150,11 @@ impl AllocFnFactory<'_, '_> { } } - fn ret_ty(&self, ty: &AllocatorTy, expr: P<Expr>) -> (P<Ty>, P<Expr>) { + fn ret_ty(&self, ty: &AllocatorTy) -> P<Ty> { match *ty { - AllocatorTy::ResultPtr => { - // We're creating: - // - // #expr as *mut u8 - - let expr = self.cx.expr_cast(self.span, expr, self.ptr_u8()); - (self.ptr_u8(), expr) - } + AllocatorTy::ResultPtr => self.ptr_u8(), - AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(ThinVec::new())), expr), + AllocatorTy::Unit => self.cx.ty(self.span, TyKind::Tup(ThinVec::new())), AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { panic!("can't convert `AllocatorTy` to an output") diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index e92280b26b0..4e4c595de82 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -39,8 +39,8 @@ fn codegen_inner( if kind == AllocatorKind::Default { for method in ALLOCATOR_METHODS { let mut arg_tys = Vec::with_capacity(method.inputs.len()); - for ty in method.inputs.iter() { - match *ty { + for input in method.inputs.iter() { + match input.ty { AllocatorTy::Layout => { arg_tys.push(usize_ty); // size arg_tys.push(usize_ty); // align diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index e3006b253b7..36e9ba9c7f8 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1155,6 +1155,20 @@ fn codegen_regular_intrinsic_call<'tcx>( ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout())); } + sym::compare_bytes => { + intrinsic_args!(fx, args => (lhs_ptr, rhs_ptr, bytes_val); intrinsic); + let lhs_ptr = lhs_ptr.load_scalar(fx); + let rhs_ptr = rhs_ptr.load_scalar(fx); + let bytes_val = bytes_val.load_scalar(fx); + + let params = vec![AbiParam::new(fx.pointer_type); 3]; + let returns = vec![AbiParam::new(types::I32)]; + let args = &[lhs_ptr, rhs_ptr, bytes_val]; + // Here we assume that the `memcmp` provided by the target is a NOP for size 0. + let cmp = fx.lib_call("memcmp", params, returns, args)[0]; + ret.write_cvalue(fx, CValue::by_val(cmp, ret.layout())); + } + sym::const_allocate => { intrinsic_args!(fx, args => (_size, _align); intrinsic); diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index 13f88192bbc..edd7ab722f6 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -27,8 +27,8 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam if kind == AllocatorKind::Default { for method in ALLOCATOR_METHODS { let mut types = Vec::with_capacity(method.inputs.len()); - for ty in method.inputs.iter() { - match *ty { + for input in method.inputs.iter() { + match input.ty { AllocatorTy::Layout => { types.push(usize); types.push(usize); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 68edde13829..f8c32c6dbbb 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -302,6 +302,21 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } } + sym::compare_bytes => { + let a = args[0].immediate(); + let b = args[1].immediate(); + let n = args[2].immediate(); + + let void_ptr_type = self.context.new_type::<*const ()>(); + let a_ptr = self.bitcast(a, void_ptr_type); + let b_ptr = self.bitcast(b, void_ptr_type); + + // Here we assume that the `memcmp` provided by the target is a NOP for size 0. + let builtin = self.context.get_builtin_function("memcmp"); + let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]); + self.sext(cmp, self.type_ix(32)) + } + sym::black_box => { args[0].val.store(self, result); diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index ca123334fca..8bb93025c45 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -34,8 +34,8 @@ pub(crate) unsafe fn codegen( if kind == AllocatorKind::Default { for method in ALLOCATOR_METHODS { let mut args = Vec::with_capacity(method.inputs.len()); - for ty in method.inputs.iter() { - match *ty { + for input in method.inputs.iter() { + match input.ty { AllocatorTy::Layout => { args.push(usize); // size args.push(usize); // align diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 3577fb2d951..b4f7e20e05d 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -145,6 +145,17 @@ pub unsafe fn create_module<'ll>( target_data_layout = target_data_layout.replace("-n32:64-", "-n64-"); } } + if llvm_version < (17, 0, 0) { + if sess.target.arch.starts_with("powerpc") { + // LLVM 17 specifies function pointer alignment for ppc: + // https://reviews.llvm.org/D147016 + target_data_layout = target_data_layout + .replace("-Fn32", "") + .replace("-Fi32", "") + .replace("-Fn64", "") + .replace("-Fi64", ""); + } + } // Ensure the data-layout values hardcoded remain the defaults. if sess.target.is_builtin { @@ -891,7 +902,8 @@ impl<'ll> CodegenCx<'ll, '_> { ifn!("llvm.prefetch", fn(ptr, t_i32, t_i32, t_i32) -> void); // This isn't an "LLVM intrinsic", but LLVM's optimization passes - // recognize it like one and we assume it exists in `core::slice::cmp` + // recognize it like one (including turning it into `bcmp` sometimes) + // and we use it to implement intrinsics like `raw_eq` and `compare_bytes` match self.sess().target.arch.as_ref() { "avr" | "msp430" => ifn!("memcmp", fn(ptr, ptr, t_isize) -> t_i16), _ => ifn!("memcmp", fn(ptr, ptr, t_isize) -> t_i32), diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 6f1e4c5178a..a9b06030e70 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -329,6 +329,16 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } + sym::compare_bytes => { + // Here we assume that the `memcmp` provided by the target is a NOP for size 0. + let cmp = self.call_intrinsic( + "memcmp", + &[args[0].immediate(), args[1].immediate(), args[2].immediate()], + ); + // Some targets have `memcmp` returning `i16`, but the intrinsic is always `i32`. + self.sext(cmp, self.type_ix(32)) + } + sym::black_box => { args[0].val.store(self, result); let result_val_span = [result.llval]; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index cbe7e519079..326b28ad104 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -233,15 +233,6 @@ fn exported_symbols_provider_local( )); } - symbols.push(( - ExportedSymbol::NoDefId(SymbolName::new(tcx, OomStrategy::SYMBOL)), - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Text, - used: false, - }, - )); - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, NO_ALLOC_SHIM_IS_UNSTABLE)); symbols.push(( diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 64c6d17469b..e7c3906d977 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -441,7 +441,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Place(place) => place, LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx), LocalRef::Operand(..) => { - if place_ref.has_deref() { + if place_ref.is_indirect_first_projection() { base = 1; let cg_base = self.codegen_consume( bx, diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 98e561b0aef..c370ba9be56 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -29,7 +29,6 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("aclass", Some(sym::arm_target_feature)), ("aes", Some(sym::arm_target_feature)), ("crc", Some(sym::arm_target_feature)), - ("crypto", Some(sym::arm_target_feature)), ("d32", Some(sym::arm_target_feature)), ("dotprod", Some(sym::arm_target_feature)), ("dsp", Some(sym::arm_target_feature)), diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 123eb3125f0..f22cd919c36 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -261,6 +261,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::write_bytes => { self.write_bytes_intrinsic(&args[0], &args[1], &args[2])?; } + sym::compare_bytes => { + let result = self.compare_bytes_intrinsic(&args[0], &args[1], &args[2])?; + self.write_scalar(result, dest)?; + } sym::arith_offset => { let ptr = self.read_pointer(&args[0])?; let offset_count = self.read_target_isize(&args[1])?; @@ -643,6 +647,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_bytes_ptr(dst, bytes) } + pub(crate) fn compare_bytes_intrinsic( + &mut self, + left: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, + right: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, + byte_count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, + ) -> InterpResult<'tcx, Scalar<M::Provenance>> { + let left = self.read_pointer(left)?; + let right = self.read_pointer(right)?; + let n = Size::from_bytes(self.read_target_usize(byte_count)?); + + let left_bytes = self.read_bytes_ptr_strip_provenance(left, n)?; + let right_bytes = self.read_bytes_ptr_strip_provenance(right, n)?; + + // `Ordering`'s discriminants are -1/0/+1, so casting does the right thing. + let result = Ord::cmp(left_bytes, right_bytes) as i32; + Ok(Scalar::from_i32(result)) + } + pub(crate) fn raw_eq_intrinsic( &mut self, lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>, diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 2dc856528f5..ec226808f1b 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -826,10 +826,10 @@ where // predicate like `where Self: Sized` with `Self = dyn Trait`. // See #102553 for an example of such a predicate. if src.layout().is_unsized() { - throw_inval!(SizeOfUnsizedType(src.layout().ty)); + throw_inval!(ConstPropNonsense); } if dest.layout().is_unsized() { - throw_inval!(SizeOfUnsizedType(dest.layout().ty)); + throw_inval!(ConstPropNonsense); } assert_eq!(src.layout().size, dest.layout().size); // Yay, we got a value that we can write directly. diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 539b58b7e9b..882097ad2c3 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -101,7 +101,7 @@ where let (meta, offset) = if field_layout.is_unsized() { if base.layout().is_sized() { // An unsized field of a sized type? Sure... - // But const-prop actually feeds us such nonsense MIR! + // But const-prop actually feeds us such nonsense MIR! (see test `const_prop/issue-86351.rs`) throw_inval!(ConstPropNonsense); } let base_meta = base.meta(self)?; diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 0ef5522729a..f04c73105d2 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -247,7 +247,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { AddressOf(_, place) => { // Figure out whether this is an addr_of of an already raw place. - let place_base_raw = if place.has_deref() { + let place_base_raw = if place.is_indirect_first_projection() { let ty = self.frame().body.local_decls[place.local].ty; ty.is_unsafe_ptr() } else { @@ -269,7 +269,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?; let layout = self.layout_of(ty)?; if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op && layout.is_unsized() { - // FIXME: This should be a span_bug (#80742) + // FIXME: This should be a span_bug, but const generics can run MIR + // that is not properly type-checked yet (#97477). self.tcx.sess.delay_span_bug( self.frame().current_span(), format!("{null_op:?} MIR operator called for unsized type {ty}"), diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index d4532873854..60dc9b20077 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -391,6 +391,10 @@ fn run_compiler( pretty::print_after_hir_lowering(tcx, *ppm); Ok(()) })?; + + // Make sure the `output_filenames` query is run for its side + // effects of writing the dep-info and reporting errors. + queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(())); } else { let krate = queries.parse()?.steal(); pretty::print_after_parsing(sess, &krate, *ppm); diff --git a/compiler/rustc_error_codes/src/error_codes/E0577.md b/compiler/rustc_error_codes/src/error_codes/E0577.md index eba2d3b1417..383ca61f6c4 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0577.md +++ b/compiler/rustc_error_codes/src/error_codes/E0577.md @@ -3,7 +3,7 @@ Something other than a module was found in visibility scope. Erroneous code example: ```compile_fail,E0577,edition2018 -pub struct Sea; +pub enum Sea {} pub (in crate::Sea) struct Shark; // error! diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 0170d52e82a..b1f74643b69 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -53,6 +53,8 @@ declare_features! ( /// Allows the sysV64 ABI to be specified on all platforms /// instead of just the platforms on which it is the C ABI. (accepted, abi_sysv64, "1.24.0", Some(36167), None), + /// Allows using the `thiscall` ABI. + (accepted, abi_thiscall, "1.19.0", None, None), /// Allows using ADX intrinsics from `core::arch::{x86, x86_64}`. (accepted, adx_target_feature, "1.61.0", Some(44839), None), /// Allows explicit discriminants on non-unit enum variants. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 2a0dab64af5..ede3570510a 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -156,8 +156,6 @@ declare_features! ( // ------------------------------------------------------------------------- // no-tracking-issue-start - /// Allows using the `thiscall` ABI. - (active, abi_thiscall, "1.19.0", None, None), /// Allows using the `unadjusted` ABI; perma-unstable. (active, abi_unadjusted, "1.16.0", None, None), /// Allows using the `vectorcall` ABI. diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index beb6307846d..69e33115922 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -108,8 +108,6 @@ impl UnstableFeatures { fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> { if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) { - // FIXME (#28244): enforce that active features have issue numbers - // assert!(info.issue.is_some()) info.issue } else { // search in Accepted, Removed, or Stable Removed features diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 3a4eb90f7f9..64271309664 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -61,7 +61,9 @@ pub enum DefKind { Variant, Trait, /// Type alias: `type Foo = Bar;` - TyAlias, + TyAlias { + lazy: bool, + }, /// Type from an `extern` block. ForeignTy, /// Trait alias: `trait IntIterator = Iterator<Item = i32>;` @@ -141,7 +143,7 @@ impl DefKind { DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) => "tuple struct", DefKind::Ctor(CtorOf::Struct, CtorKind::Const) => "unit struct", DefKind::OpaqueTy => "opaque type", - DefKind::TyAlias => "type alias", + DefKind::TyAlias { .. } => "type alias", DefKind::TraitAlias => "trait alias", DefKind::AssocTy => "associated type", DefKind::Union => "union", @@ -197,7 +199,7 @@ impl DefKind { | DefKind::Variant | DefKind::Trait | DefKind::OpaqueTy - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy @@ -248,7 +250,7 @@ impl DefKind { | DefKind::Enum | DefKind::Variant | DefKind::Trait - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index bc05565fed4..c6f8d1e211d 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2675,7 +2675,7 @@ pub struct OpaqueTy<'hir> { /// /// This mapping associated a captured lifetime (first parameter) with the new /// early-bound lifetime that was generated for the opaque. - pub lifetime_mapping: Option<&'hir [(Lifetime, LocalDefId)]>, + pub lifetime_mapping: Option<&'hir [(&'hir Lifetime, LocalDefId)]>, /// Whether the opaque is a return-position impl trait (or async future) /// originating from a trait method. This makes it so that the opaque is /// lowered as an associated type. diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index 0d65ddb5642..644c4d8265d 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -101,7 +101,7 @@ impl Target { DefKind::Mod => Target::Mod, DefKind::ForeignMod => Target::ForeignMod, DefKind::GlobalAsm => Target::GlobalAsm, - DefKind::TyAlias => Target::TyAlias, + DefKind::TyAlias { .. } => Target::TyAlias, DefKind::OpaqueTy => Target::OpaqueTy, DefKind::Enum => Target::Enum, DefKind::Struct => Target::Struct, diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index b40e3123522..319573c85b4 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -907,19 +907,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { did: DefId, item_segment: &hir::PathSegment<'_>, ) -> Ty<'tcx> { + let tcx = self.tcx(); let args = self.ast_path_args_for_ty(span, did, item_segment); - let ty = self.tcx().at(span).type_of(did); + let ty = tcx.at(span).type_of(did); - if matches!(self.tcx().def_kind(did), DefKind::TyAlias) - && (ty.skip_binder().has_opaque_types() || self.tcx().features().lazy_type_alias) + if let DefKind::TyAlias { lazy } = tcx.def_kind(did) + && (lazy || ty.skip_binder().has_opaque_types()) { // Type aliases referring to types that contain opaque types (but aren't just directly - // referencing a single opaque type) get encoded as a type alias that normalization will + // referencing a single opaque type) as well as those defined in crates that have the + // feature `lazy_type_alias` enabled get encoded as a type alias that normalization will // then actually instantiate the where bounds of. - let alias_ty = self.tcx().mk_alias_ty(did, args); - Ty::new_alias(self.tcx(), ty::Weak, alias_ty) + let alias_ty = tcx.mk_alias_ty(did, args); + Ty::new_alias(tcx, ty::Weak, alias_ty) } else { - ty.instantiate(self.tcx(), args) + ty.instantiate(tcx, args) } } @@ -2158,7 +2160,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } Res::Def( DefKind::Enum - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::Struct | DefKind::Union | DefKind::ForeignTy, diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index c07ac35cba3..39db295044e 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { // we have some type like `&<Ty as Trait>::Assoc`, since users of // autoderef expect this type to have been structurally normalized. if self.infcx.next_trait_solver() - && let ty::Alias(ty::Projection, _) = ty.kind() + && let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = ty.kind() { let (normalized_ty, obligations) = self.structurally_normalize(ty)?; self.state.obligations.extend(obligations); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 73627a818e5..49307d96cc2 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -728,7 +728,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { check_opaque(tcx, id); } } - DefKind::TyAlias => { + DefKind::TyAlias { .. } => { let pty_ty = tcx.type_of(id.owner_id).instantiate_identity(); let generics = tcx.generics_of(id.owner_id); check_type_params_are_used(tcx, &generics, pty_ty); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 970efaf312c..f89e2e5c25b 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -273,6 +273,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ], Ty::new_unit(tcx), ), + sym::compare_bytes => { + let byte_ptr = Ty::new_imm_ptr(tcx, tcx.types.u8); + (0, vec![byte_ptr, byte_ptr, tcx.types.usize], tcx.types.i32) + } sym::write_bytes | sym::volatile_set_memory => ( 1, vec![ diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 2950ce683a3..83220be6883 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -82,7 +82,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen tcx, def_id, lifetime_mapping.iter().map(|(lifetime, def_id)| { - (*lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span)) + (**lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span)) }), tcx.generics_of(def_id.to_def_id()), &mut predicates, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 3cc6f574aec..6dd0c840de6 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1480,7 +1480,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { DefKind::Struct | DefKind::Union | DefKind::Enum - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::Trait, def_id, ) if depth == 0 => Some(def_id), @@ -1990,7 +1990,7 @@ fn is_late_bound_map( hir::TyKind::Path(hir::QPath::Resolved( None, - hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span }, + hir::Path { res: Res::Def(DefKind::TyAlias { .. }, alias_def), segments, span }, )) => { // See comments on `ConstrainedCollectorPostAstConv` for why this arm does not just consider // args to be unconstrained. diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 4a3d522e488..8a40509d7cc 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -78,9 +78,8 @@ pub fn add_constraints_from_crate<'a, 'tcx>( } } DefKind::Fn | DefKind::AssocFn => constraint_cx.build_constraints_for_item(def_id), - DefKind::TyAlias - if tcx.features().lazy_type_alias - || tcx.type_of(def_id).instantiate_identity().has_opaque_types() => + DefKind::TyAlias { lazy } + if lazy || tcx.type_of(def_id).instantiate_identity().has_opaque_types() => { constraint_cx.build_constraints_for_item(def_id) } @@ -111,8 +110,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // The type as returned by `type_of` is the underlying type and generally not a weak projection. // Therefore we need to check the `DefKind` first. - if let DefKind::TyAlias = tcx.def_kind(def_id) - && (tcx.features().lazy_type_alias || ty.has_opaque_types()) + if let DefKind::TyAlias { lazy } = tcx.def_kind(def_id) + && (lazy || ty.has_opaque_types()) { self.add_constraints_from_ty(current_item, ty, self.covariant); return; diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 2ef294c6793..d91d9fcbc8e 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -56,9 +56,8 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { let crate_map = tcx.crate_variances(()); return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]); } - DefKind::TyAlias - if tcx.features().lazy_type_alias - || tcx.type_of(item_def_id).instantiate_identity().has_opaque_types() => + DefKind::TyAlias { lazy } + if lazy || tcx.type_of(item_def_id).instantiate_identity().has_opaque_types() => { // These are inferred. let crate_map = tcx.crate_variances(()); diff --git a/compiler/rustc_hir_analysis/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs index 1ef3d383bd8..1a8ec5f0853 100644 --- a/compiler/rustc_hir_analysis/src/variance/terms.rs +++ b/compiler/rustc_hir_analysis/src/variance/terms.rs @@ -97,9 +97,8 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>( } } DefKind::Fn | DefKind::AssocFn => terms_cx.add_inferreds_for_item(def_id), - DefKind::TyAlias - if tcx.features().lazy_type_alias - || tcx.type_of(def_id).instantiate_identity().has_opaque_types() => + DefKind::TyAlias { lazy } + if lazy || tcx.type_of(def_id).instantiate_identity().has_opaque_types() => { terms_cx.add_inferreds_for_item(def_id) } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index fa6bad84376..b2b3f435505 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1012,6 +1012,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause: Option<ObligationCause<'tcx>>, ) -> RelateResult<'tcx, Ty<'tcx>> { let source = self.try_structurally_resolve_type(expr.span, expr_ty); + let target = self.try_structurally_resolve_type( + cause.as_ref().map_or(expr.span, |cause| cause.span), + target, + ); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); let cause = @@ -1097,8 +1101,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { where E: AsCoercionSite, { - let prev_ty = self.resolve_vars_with_obligations(prev_ty); - let new_ty = self.resolve_vars_with_obligations(new_ty); + let prev_ty = self.try_structurally_resolve_type(cause.span, prev_ty); + let new_ty = self.try_structurally_resolve_type(new.span, new_ty); debug!( "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)", prev_ty, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 1433c67d55d..322d726a89d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1474,7 +1474,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.resolve_vars_with_obligations(ty); if self.next_trait_solver() - && let ty::Alias(ty::Projection, _) = ty.kind() + && let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = ty.kind() { match self .at(&self.misc(sp), self.param_env) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c63dab63145..40f9a954034 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1359,7 +1359,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => bug!("unexpected type: {:?}", ty.normalized), }, - Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) + Res::Def( + DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy, + _, + ) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() { Some(adt) if !adt.is_enum() => { diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 4ea53c7eaae..7fb1dc2347e 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -557,7 +557,10 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id)) } Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _) - | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) + | Res::Def( + DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy, + _, + ) | Res::SelfCtor(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 9dfa45858a7..f2a3c47bdfe 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -951,7 +951,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { // // See the `need_type_info/issue-103053.rs` test for // a example. - if !matches!(path.res, Res::Def(DefKind::TyAlias, _)) => { + if !matches!(path.res, Res::Def(DefKind::TyAlias { .. }, _)) => { if let Some(ty) = self.opt_node_type(expr.hir_id) && let ty::Adt(_, args) = ty.kind() { @@ -1080,7 +1080,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { ) => { if tcx.res_generics_def_id(path.res) != Some(def.did()) { match path.res { - Res::Def(DefKind::TyAlias, _) => { + Res::Def(DefKind::TyAlias { .. }, _) => { // FIXME: Ideally we should support this. For that // we have to map back from the self type to the // type alias though. That's difficult. diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index a6052f52917..1c3a5c36076 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -64,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> { ct_op: |ct| ct, ty_op: |ty| match *ty.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) - if replace_opaque_type(def_id) => + if replace_opaque_type(def_id) && !ty.has_escaping_bound_vars() => { let def_span = self.tcx.def_span(def_id); let span = if span.contains(def_span) { def_span } else { span }; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 6b3facd041c..a34fdf4ecc9 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -846,10 +846,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { }, { sess.time("lint_checking", || { - rustc_lint::check_crate(tcx, || { - rustc_lint::BuiltinCombinedLateLintPass::new() - }); + rustc_lint::check_crate(tcx); }); + }, + { + tcx.ensure().clashing_extern_declarations(()); } ); }, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5e61073694f..2c9d212a6a6 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -24,10 +24,9 @@ use crate::fluent_generated as fluent; use crate::{ errors::BuiltinEllipsisInclusiveRangePatterns, lints::{ - BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinClashingExtern, - BuiltinClashingExternSub, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink, - BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr, - BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, + BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinConstNoMangle, + BuiltinDeprecatedAttrLink, BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, + BuiltinDerefNullptr, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, @@ -40,8 +39,7 @@ use crate::{ BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, BuiltinWhileTrue, SuggestChangingAssocTypes, }, - types::{transparent_newtype_field, CItemKind}, - EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, + EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, }; use hir::IsAsync; use rustc_ast::attr; @@ -49,29 +47,29 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::{self, expr_to_string}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, DecorateLint, MultiSpan}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::FnKind as HirFnKind; -use rustc_hir::{Body, FnDecl, ForeignItemKind, GenericParamKind, Node, PatKind, PredicateOrigin}; +use rustc_hir::{Body, FnDecl, GenericParamKind, Node, PatKind, PredicateOrigin}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::layout::{LayoutError, LayoutOf}; +use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::GenericArgKind; +use rustc_middle::ty::ToPredicate; use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef}; +use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef}; use rustc_session::config::ExpectedValues; use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason}; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, InnerSpan, Span}; -use rustc_target::abi::{Abi, FIRST_VARIANT}; +use rustc_target::abi::Abi; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy}; use crate::nonstandard_style::{method_context, MethodLateContext}; @@ -461,10 +459,7 @@ declare_lint! { report_in_external_macro } -pub struct MissingDoc { - /// Stack of whether `#[doc(hidden)]` is set at each level which has lint attributes. - doc_hidden_stack: Vec<bool>, -} +pub struct MissingDoc; impl_lint_pass!(MissingDoc => [MISSING_DOCS]); @@ -493,14 +488,6 @@ fn has_doc(attr: &ast::Attribute) -> bool { } impl MissingDoc { - pub fn new() -> MissingDoc { - MissingDoc { doc_hidden_stack: vec![false] } - } - - fn doc_hidden(&self) -> bool { - *self.doc_hidden_stack.last().expect("empty doc_hidden_stack") - } - fn check_missing_docs_attrs( &self, cx: &LateContext<'_>, @@ -514,11 +501,6 @@ impl MissingDoc { return; } - // `#[doc(hidden)]` disables missing_docs check. - if self.doc_hidden() { - return; - } - // Only check publicly-visible items, using the result from the privacy pass. // It's an option so the crate root can also use this function (it doesn't // have a `NodeId`). @@ -541,23 +523,6 @@ impl MissingDoc { } impl<'tcx> LateLintPass<'tcx> for MissingDoc { - #[inline] - fn enter_lint_attrs(&mut self, _cx: &LateContext<'_>, attrs: &[ast::Attribute]) { - let doc_hidden = self.doc_hidden() - || attrs.iter().any(|attr| { - attr.has_name(sym::doc) - && match attr.meta_item_list() { - None => false, - Some(l) => attr::list_contains_name(&l, sym::hidden), - } - }); - self.doc_hidden_stack.push(doc_hidden); - } - - fn exit_lint_attrs(&mut self, _: &LateContext<'_>, _attrs: &[ast::Attribute]) { - self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); - } - fn check_crate(&mut self, cx: &LateContext<'_>) { self.check_missing_docs_attrs(cx, CRATE_DEF_ID, "the", "crate"); } @@ -710,6 +675,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { if ty.is_copy_modulo_regions(cx.tcx, param_env) { return; } + if type_implements_negative_copy_modulo_regions(cx.tcx, ty, param_env) { + return; + } // We shouldn't recommend implementing `Copy` on stateful things, // such as iterators. @@ -745,6 +713,24 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { } } +/// Check whether a `ty` has a negative `Copy` implementation, ignoring outlives constraints. +fn type_implements_negative_copy_modulo_regions<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> bool { + let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]); + let pred = ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Negative }; + let obligation = traits::Obligation { + cause: traits::ObligationCause::dummy(), + param_env, + recursion_depth: 0, + predicate: ty::Binder::dummy(pred).to_predicate(tcx), + }; + + tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) +} + declare_lint! { /// The `missing_debug_implementations` lint detects missing /// implementations of [`fmt::Debug`] for public types. @@ -778,9 +764,7 @@ declare_lint! { } #[derive(Default)] -pub struct MissingDebugImplementations { - impling_types: Option<LocalDefIdSet>, -} +pub(crate) struct MissingDebugImplementations; impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]); @@ -795,23 +779,20 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { _ => return, } - let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else { return }; - - if self.impling_types.is_none() { - let mut impls = LocalDefIdSet::default(); - cx.tcx.for_each_impl(debug, |d| { - if let Some(ty_def) = cx.tcx.type_of(d).instantiate_identity().ty_adt_def() { - if let Some(def_id) = ty_def.did().as_local() { - impls.insert(def_id); - } - } - }); - - self.impling_types = Some(impls); - debug!("{:?}", self.impling_types); + // Avoid listing trait impls if the trait is allowed. + let (level, _) = cx.tcx.lint_level_at_node(MISSING_DEBUG_IMPLEMENTATIONS, item.hir_id()); + if level == Level::Allow { + return; } - if !self.impling_types.as_ref().unwrap().contains(&item.owner_id.def_id) { + let Some(debug) = cx.tcx.get_diagnostic_item(sym::Debug) else { return }; + + let has_impl = cx + .tcx + .non_blanket_impls_for_ty(debug, cx.tcx.type_of(item.owner_id).instantiate_identity()) + .next() + .is_some(); + if !has_impl { cx.emit_spanned_lint( MISSING_DEBUG_IMPLEMENTATIONS, item.span, @@ -2613,381 +2594,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { } declare_lint! { - /// The `clashing_extern_declarations` lint detects when an `extern fn` - /// has been declared with the same name but different types. - /// - /// ### Example - /// - /// ```rust - /// mod m { - /// extern "C" { - /// fn foo(); - /// } - /// } - /// - /// extern "C" { - /// fn foo(_: u32); - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Because two symbols of the same name cannot be resolved to two - /// different functions at link time, and one function cannot possibly - /// have two types, a clashing extern declaration is almost certainly a - /// mistake. Check to make sure that the `extern` definitions are correct - /// and equivalent, and possibly consider unifying them in one location. - /// - /// This lint does not run between crates because a project may have - /// dependencies which both rely on the same extern function, but declare - /// it in a different (but valid) way. For example, they may both declare - /// an opaque type for one or more of the arguments (which would end up - /// distinct types), or use types that are valid conversions in the - /// language the `extern fn` is defined in. In these cases, the compiler - /// can't say that the clashing declaration is incorrect. - pub CLASHING_EXTERN_DECLARATIONS, - Warn, - "detects when an extern fn has been declared with the same name but different types" -} - -pub struct ClashingExternDeclarations { - /// Map of function symbol name to the first-seen hir id for that symbol name.. If seen_decls - /// contains an entry for key K, it means a symbol with name K has been seen by this lint and - /// the symbol should be reported as a clashing declaration. - // FIXME: Technically, we could just store a &'tcx str here without issue; however, the - // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime. - seen_decls: FxHashMap<Symbol, hir::OwnerId>, -} - -/// Differentiate between whether the name for an extern decl came from the link_name attribute or -/// just from declaration itself. This is important because we don't want to report clashes on -/// symbol name if they don't actually clash because one or the other links against a symbol with a -/// different name. -enum SymbolName { - /// The name of the symbol + the span of the annotation which introduced the link name. - Link(Symbol, Span), - /// No link name, so just the name of the symbol. - Normal(Symbol), -} - -impl SymbolName { - fn get_name(&self) -> Symbol { - match self { - SymbolName::Link(s, _) | SymbolName::Normal(s) => *s, - } - } -} - -impl ClashingExternDeclarations { - pub(crate) fn new() -> Self { - ClashingExternDeclarations { seen_decls: FxHashMap::default() } - } - - /// Insert a new foreign item into the seen set. If a symbol with the same name already exists - /// for the item, return its HirId without updating the set. - fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<hir::OwnerId> { - let did = fi.owner_id.to_def_id(); - let instance = Instance::new(did, ty::List::identity_for_item(tcx, did)); - let name = Symbol::intern(tcx.symbol_name(instance).name); - if let Some(&existing_id) = self.seen_decls.get(&name) { - // Avoid updating the map with the new entry when we do find a collision. We want to - // make sure we're always pointing to the first definition as the previous declaration. - // This lets us avoid emitting "knock-on" diagnostics. - Some(existing_id) - } else { - self.seen_decls.insert(name, fi.owner_id) - } - } - - /// Get the name of the symbol that's linked against for a given extern declaration. That is, - /// the name specified in a #[link_name = ...] attribute if one was specified, else, just the - /// symbol's name. - fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName { - if let Some((overridden_link_name, overridden_link_name_span)) = - tcx.codegen_fn_attrs(fi.owner_id).link_name.map(|overridden_link_name| { - // FIXME: Instead of searching through the attributes again to get span - // information, we could have codegen_fn_attrs also give span information back for - // where the attribute was defined. However, until this is found to be a - // bottleneck, this does just fine. - (overridden_link_name, tcx.get_attr(fi.owner_id, sym::link_name).unwrap().span) - }) - { - SymbolName::Link(overridden_link_name, overridden_link_name_span) - } else { - SymbolName::Normal(fi.ident.name) - } - } - - /// Checks whether two types are structurally the same enough that the declarations shouldn't - /// clash. We need this so we don't emit a lint when two modules both declare an extern struct, - /// with the same members (as the declarations shouldn't clash). - fn structurally_same_type<'tcx>( - cx: &LateContext<'tcx>, - a: Ty<'tcx>, - b: Ty<'tcx>, - ckind: CItemKind, - ) -> bool { - fn structurally_same_type_impl<'tcx>( - seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>, - cx: &LateContext<'tcx>, - a: Ty<'tcx>, - b: Ty<'tcx>, - ckind: CItemKind, - ) -> bool { - debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b); - let tcx = cx.tcx; - - // Given a transparent newtype, reach through and grab the inner - // type unless the newtype makes the type non-null. - let non_transparent_ty = |mut ty: Ty<'tcx>| -> Ty<'tcx> { - loop { - if let ty::Adt(def, args) = *ty.kind() { - let is_transparent = def.repr().transparent(); - let is_non_null = crate::types::nonnull_optimization_guaranteed(tcx, def); - debug!( - "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}", - ty, is_transparent, is_non_null - ); - if is_transparent && !is_non_null { - debug_assert_eq!(def.variants().len(), 1); - let v = &def.variant(FIRST_VARIANT); - // continue with `ty`'s non-ZST field, - // otherwise `ty` is a ZST and we can return - if let Some(field) = transparent_newtype_field(tcx, v) { - ty = field.ty(tcx, args); - continue; - } - } - } - debug!("non_transparent_ty -> {:?}", ty); - return ty; - } - }; - - let a = non_transparent_ty(a); - let b = non_transparent_ty(b); - - if !seen_types.insert((a, b)) { - // We've encountered a cycle. There's no point going any further -- the types are - // structurally the same. - true - } else if a == b { - // All nominally-same types are structurally same, too. - true - } else { - // Do a full, depth-first comparison between the two. - use rustc_type_ir::sty::TyKind::*; - let a_kind = a.kind(); - let b_kind = b.kind(); - - let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> { - debug!("compare_layouts({:?}, {:?})", a, b); - let a_layout = &cx.layout_of(a)?.layout.abi(); - let b_layout = &cx.layout_of(b)?.layout.abi(); - debug!( - "comparing layouts: {:?} == {:?} = {}", - a_layout, - b_layout, - a_layout == b_layout - ); - Ok(a_layout == b_layout) - }; - - #[allow(rustc::usage_of_ty_tykind)] - let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| { - kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..)) - }; - - ensure_sufficient_stack(|| { - match (a_kind, b_kind) { - (Adt(a_def, _), Adt(b_def, _)) => { - // We can immediately rule out these types as structurally same if - // their layouts differ. - match compare_layouts(a, b) { - Ok(false) => return false, - _ => (), // otherwise, continue onto the full, fields comparison - } - - // Grab a flattened representation of all fields. - let a_fields = a_def.variants().iter().flat_map(|v| v.fields.iter()); - let b_fields = b_def.variants().iter().flat_map(|v| v.fields.iter()); - - // Perform a structural comparison for each field. - a_fields.eq_by( - b_fields, - |&ty::FieldDef { did: a_did, .. }, - &ty::FieldDef { did: b_did, .. }| { - structurally_same_type_impl( - seen_types, - cx, - tcx.type_of(a_did).instantiate_identity(), - tcx.type_of(b_did).instantiate_identity(), - ckind, - ) - }, - ) - } - (Array(a_ty, a_const), Array(b_ty, b_const)) => { - // For arrays, we also check the constness of the type. - a_const.kind() == b_const.kind() - && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind) - } - (Slice(a_ty), Slice(b_ty)) => { - structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind) - } - (RawPtr(a_tymut), RawPtr(b_tymut)) => { - a_tymut.mutbl == b_tymut.mutbl - && structurally_same_type_impl( - seen_types, cx, a_tymut.ty, b_tymut.ty, ckind, - ) - } - (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => { - // For structural sameness, we don't need the region to be same. - a_mut == b_mut - && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind) - } - (FnDef(..), FnDef(..)) => { - let a_poly_sig = a.fn_sig(tcx); - let b_poly_sig = b.fn_sig(tcx); - - // We don't compare regions, but leaving bound regions around ICEs, so - // we erase them. - let a_sig = tcx.erase_late_bound_regions(a_poly_sig); - let b_sig = tcx.erase_late_bound_regions(b_poly_sig); - - (a_sig.abi, a_sig.unsafety, a_sig.c_variadic) - == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic) - && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { - structurally_same_type_impl(seen_types, cx, *a, *b, ckind) - }) - && structurally_same_type_impl( - seen_types, - cx, - a_sig.output(), - b_sig.output(), - ckind, - ) - } - (Tuple(a_args), Tuple(b_args)) => { - a_args.iter().eq_by(b_args.iter(), |a_ty, b_ty| { - structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind) - }) - } - // For these, it's not quite as easy to define structural-sameness quite so easily. - // For the purposes of this lint, take the conservative approach and mark them as - // not structurally same. - (Dynamic(..), Dynamic(..)) - | (Error(..), Error(..)) - | (Closure(..), Closure(..)) - | (Generator(..), Generator(..)) - | (GeneratorWitness(..), GeneratorWitness(..)) - | (Alias(ty::Projection, ..), Alias(ty::Projection, ..)) - | (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..)) - | (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false, - - // These definitely should have been caught above. - (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(), - - // An Adt and a primitive or pointer type. This can be FFI-safe if non-null - // enum layout optimisation is being applied. - (Adt(..), other_kind) | (other_kind, Adt(..)) - if is_primitive_or_pointer(other_kind) => - { - let (primitive, adt) = - if is_primitive_or_pointer(a.kind()) { (a, b) } else { (b, a) }; - if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) { - ty == primitive - } else { - compare_layouts(a, b).unwrap_or(false) - } - } - // Otherwise, just compare the layouts. This may fail to lint for some - // incompatible types, but at the very least, will stop reads into - // uninitialised memory. - _ => compare_layouts(a, b).unwrap_or(false), - } - }) - } - } - let mut seen_types = FxHashSet::default(); - structurally_same_type_impl(&mut seen_types, cx, a, b, ckind) - } -} - -impl_lint_pass!(ClashingExternDeclarations => [CLASHING_EXTERN_DECLARATIONS]); - -impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { - #[instrument(level = "trace", skip(self, cx))] - fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignItem<'_>) { - if let ForeignItemKind::Fn(..) = this_fi.kind { - let tcx = cx.tcx; - if let Some(existing_did) = self.insert(tcx, this_fi) { - let existing_decl_ty = tcx.type_of(existing_did).skip_binder(); - let this_decl_ty = tcx.type_of(this_fi.owner_id).instantiate_identity(); - debug!( - "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}", - existing_did, existing_decl_ty, this_fi.owner_id, this_decl_ty - ); - // Check that the declarations match. - if !Self::structurally_same_type( - cx, - existing_decl_ty, - this_decl_ty, - CItemKind::Declaration, - ) { - let orig_fi = tcx.hir().expect_foreign_item(existing_did); - let orig = Self::name_of_extern_decl(tcx, orig_fi); - - // We want to ensure that we use spans for both decls that include where the - // name was defined, whether that was from the link_name attribute or not. - let get_relevant_span = - |fi: &hir::ForeignItem<'_>| match Self::name_of_extern_decl(tcx, fi) { - SymbolName::Normal(_) => fi.span, - SymbolName::Link(_, annot_span) => fi.span.to(annot_span), - }; - - // Finally, emit the diagnostic. - let this = this_fi.ident.name; - let orig = orig.get_name(); - let previous_decl_label = get_relevant_span(orig_fi); - let mismatch_label = get_relevant_span(this_fi); - let sub = BuiltinClashingExternSub { - tcx, - expected: existing_decl_ty, - found: this_decl_ty, - }; - let decorator = if orig == this { - BuiltinClashingExtern::SameName { - this, - orig, - previous_decl_label, - mismatch_label, - sub, - } - } else { - BuiltinClashingExtern::DiffName { - this, - orig, - previous_decl_label, - mismatch_label, - sub, - } - }; - tcx.emit_spanned_lint( - CLASHING_EXTERN_DECLARATIONS, - this_fi.hir_id(), - get_relevant_span(this_fi), - decorator, - ); - } - } - } - } -} - -declare_lint! { /// The `deref_nullptr` lint detects when an null pointer is dereferenced, /// which causes [undefined behavior]. /// diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs new file mode 100644 index 00000000000..7b291d558e0 --- /dev/null +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -0,0 +1,402 @@ +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_hir as hir; +use rustc_hir::def::DefKind; +use rustc_middle::query::Providers; +use rustc_middle::ty::layout::LayoutError; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_session::lint::{lint_array, LintArray}; +use rustc_span::{sym, Span, Symbol}; +use rustc_target::abi::FIRST_VARIANT; + +use crate::lints::{BuiltinClashingExtern, BuiltinClashingExternSub}; +use crate::types; + +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { clashing_extern_declarations, ..*providers }; +} + +pub(crate) fn get_lints() -> LintArray { + lint_array!(CLASHING_EXTERN_DECLARATIONS) +} + +fn clashing_extern_declarations(tcx: TyCtxt<'_>, (): ()) { + let mut lint = ClashingExternDeclarations::new(); + for id in tcx.hir_crate_items(()).foreign_items() { + lint.check_foreign_item(tcx, id); + } +} + +declare_lint! { + /// The `clashing_extern_declarations` lint detects when an `extern fn` + /// has been declared with the same name but different types. + /// + /// ### Example + /// + /// ```rust + /// mod m { + /// extern "C" { + /// fn foo(); + /// } + /// } + /// + /// extern "C" { + /// fn foo(_: u32); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Because two symbols of the same name cannot be resolved to two + /// different functions at link time, and one function cannot possibly + /// have two types, a clashing extern declaration is almost certainly a + /// mistake. Check to make sure that the `extern` definitions are correct + /// and equivalent, and possibly consider unifying them in one location. + /// + /// This lint does not run between crates because a project may have + /// dependencies which both rely on the same extern function, but declare + /// it in a different (but valid) way. For example, they may both declare + /// an opaque type for one or more of the arguments (which would end up + /// distinct types), or use types that are valid conversions in the + /// language the `extern fn` is defined in. In these cases, the compiler + /// can't say that the clashing declaration is incorrect. + pub CLASHING_EXTERN_DECLARATIONS, + Warn, + "detects when an extern fn has been declared with the same name but different types" +} + +struct ClashingExternDeclarations { + /// Map of function symbol name to the first-seen hir id for that symbol name.. If seen_decls + /// contains an entry for key K, it means a symbol with name K has been seen by this lint and + /// the symbol should be reported as a clashing declaration. + // FIXME: Technically, we could just store a &'tcx str here without issue; however, the + // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime. + seen_decls: FxHashMap<Symbol, hir::OwnerId>, +} + +/// Differentiate between whether the name for an extern decl came from the link_name attribute or +/// just from declaration itself. This is important because we don't want to report clashes on +/// symbol name if they don't actually clash because one or the other links against a symbol with a +/// different name. +enum SymbolName { + /// The name of the symbol + the span of the annotation which introduced the link name. + Link(Symbol, Span), + /// No link name, so just the name of the symbol. + Normal(Symbol), +} + +impl SymbolName { + fn get_name(&self) -> Symbol { + match self { + SymbolName::Link(s, _) | SymbolName::Normal(s) => *s, + } + } +} + +impl ClashingExternDeclarations { + pub(crate) fn new() -> Self { + ClashingExternDeclarations { seen_decls: FxHashMap::default() } + } + + /// Insert a new foreign item into the seen set. If a symbol with the same name already exists + /// for the item, return its HirId without updating the set. + fn insert(&mut self, tcx: TyCtxt<'_>, fi: hir::ForeignItemId) -> Option<hir::OwnerId> { + let did = fi.owner_id.to_def_id(); + let instance = Instance::new(did, ty::List::identity_for_item(tcx, did)); + let name = Symbol::intern(tcx.symbol_name(instance).name); + if let Some(&existing_id) = self.seen_decls.get(&name) { + // Avoid updating the map with the new entry when we do find a collision. We want to + // make sure we're always pointing to the first definition as the previous declaration. + // This lets us avoid emitting "knock-on" diagnostics. + Some(existing_id) + } else { + self.seen_decls.insert(name, fi.owner_id) + } + } + + #[instrument(level = "trace", skip(self, tcx))] + fn check_foreign_item<'tcx>(&mut self, tcx: TyCtxt<'tcx>, this_fi: hir::ForeignItemId) { + let DefKind::Fn = tcx.def_kind(this_fi.owner_id) else { return }; + let Some(existing_did) = self.insert(tcx, this_fi) else { return }; + + let existing_decl_ty = tcx.type_of(existing_did).skip_binder(); + let this_decl_ty = tcx.type_of(this_fi.owner_id).instantiate_identity(); + debug!( + "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}", + existing_did, existing_decl_ty, this_fi.owner_id, this_decl_ty + ); + + // Check that the declarations match. + if !structurally_same_type( + tcx, + tcx.param_env(this_fi.owner_id), + existing_decl_ty, + this_decl_ty, + types::CItemKind::Declaration, + ) { + let orig = name_of_extern_decl(tcx, existing_did); + + // Finally, emit the diagnostic. + let this = tcx.item_name(this_fi.owner_id.to_def_id()); + let orig = orig.get_name(); + let previous_decl_label = get_relevant_span(tcx, existing_did); + let mismatch_label = get_relevant_span(tcx, this_fi.owner_id); + let sub = + BuiltinClashingExternSub { tcx, expected: existing_decl_ty, found: this_decl_ty }; + let decorator = if orig == this { + BuiltinClashingExtern::SameName { + this, + orig, + previous_decl_label, + mismatch_label, + sub, + } + } else { + BuiltinClashingExtern::DiffName { + this, + orig, + previous_decl_label, + mismatch_label, + sub, + } + }; + tcx.emit_spanned_lint( + CLASHING_EXTERN_DECLARATIONS, + this_fi.hir_id(), + mismatch_label, + decorator, + ); + } + } +} + +/// Get the name of the symbol that's linked against for a given extern declaration. That is, +/// the name specified in a #[link_name = ...] attribute if one was specified, else, just the +/// symbol's name. +fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName { + if let Some((overridden_link_name, overridden_link_name_span)) = + tcx.codegen_fn_attrs(fi).link_name.map(|overridden_link_name| { + // FIXME: Instead of searching through the attributes again to get span + // information, we could have codegen_fn_attrs also give span information back for + // where the attribute was defined. However, until this is found to be a + // bottleneck, this does just fine. + (overridden_link_name, tcx.get_attr(fi, sym::link_name).unwrap().span) + }) + { + SymbolName::Link(overridden_link_name, overridden_link_name_span) + } else { + SymbolName::Normal(tcx.item_name(fi.to_def_id())) + } +} + +/// We want to ensure that we use spans for both decls that include where the +/// name was defined, whether that was from the link_name attribute or not. +fn get_relevant_span(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> Span { + match name_of_extern_decl(tcx, fi) { + SymbolName::Normal(_) => tcx.def_span(fi), + SymbolName::Link(_, annot_span) => annot_span, + } +} + +/// Checks whether two types are structurally the same enough that the declarations shouldn't +/// clash. We need this so we don't emit a lint when two modules both declare an extern struct, +/// with the same members (as the declarations shouldn't clash). +fn structurally_same_type<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + a: Ty<'tcx>, + b: Ty<'tcx>, + ckind: types::CItemKind, +) -> bool { + let mut seen_types = FxHashSet::default(); + structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind) +} + +fn structurally_same_type_impl<'tcx>( + seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + a: Ty<'tcx>, + b: Ty<'tcx>, + ckind: types::CItemKind, +) -> bool { + debug!("structurally_same_type_impl(tcx, a = {:?}, b = {:?})", a, b); + + // Given a transparent newtype, reach through and grab the inner + // type unless the newtype makes the type non-null. + let non_transparent_ty = |mut ty: Ty<'tcx>| -> Ty<'tcx> { + loop { + if let ty::Adt(def, args) = *ty.kind() { + let is_transparent = def.repr().transparent(); + let is_non_null = types::nonnull_optimization_guaranteed(tcx, def); + debug!( + "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}", + ty, is_transparent, is_non_null + ); + if is_transparent && !is_non_null { + debug_assert_eq!(def.variants().len(), 1); + let v = &def.variant(FIRST_VARIANT); + // continue with `ty`'s non-ZST field, + // otherwise `ty` is a ZST and we can return + if let Some(field) = types::transparent_newtype_field(tcx, v) { + ty = field.ty(tcx, args); + continue; + } + } + } + debug!("non_transparent_ty -> {:?}", ty); + return ty; + } + }; + + let a = non_transparent_ty(a); + let b = non_transparent_ty(b); + + if !seen_types.insert((a, b)) { + // We've encountered a cycle. There's no point going any further -- the types are + // structurally the same. + true + } else if a == b { + // All nominally-same types are structurally same, too. + true + } else { + // Do a full, depth-first comparison between the two. + use rustc_type_ir::sty::TyKind::*; + let a_kind = a.kind(); + let b_kind = b.kind(); + + let compare_layouts = |a, b| -> Result<bool, &'tcx LayoutError<'tcx>> { + debug!("compare_layouts({:?}, {:?})", a, b); + let a_layout = &tcx.layout_of(param_env.and(a))?.layout.abi(); + let b_layout = &tcx.layout_of(param_env.and(b))?.layout.abi(); + debug!( + "comparing layouts: {:?} == {:?} = {}", + a_layout, + b_layout, + a_layout == b_layout + ); + Ok(a_layout == b_layout) + }; + + #[allow(rustc::usage_of_ty_tykind)] + let is_primitive_or_pointer = + |kind: &ty::TyKind<'_>| kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..)); + + ensure_sufficient_stack(|| { + match (a_kind, b_kind) { + (Adt(a_def, _), Adt(b_def, _)) => { + // We can immediately rule out these types as structurally same if + // their layouts differ. + match compare_layouts(a, b) { + Ok(false) => return false, + _ => (), // otherwise, continue onto the full, fields comparison + } + + // Grab a flattened representation of all fields. + let a_fields = a_def.variants().iter().flat_map(|v| v.fields.iter()); + let b_fields = b_def.variants().iter().flat_map(|v| v.fields.iter()); + + // Perform a structural comparison for each field. + a_fields.eq_by( + b_fields, + |&ty::FieldDef { did: a_did, .. }, &ty::FieldDef { did: b_did, .. }| { + structurally_same_type_impl( + seen_types, + tcx, + param_env, + tcx.type_of(a_did).instantiate_identity(), + tcx.type_of(b_did).instantiate_identity(), + ckind, + ) + }, + ) + } + (Array(a_ty, a_const), Array(b_ty, b_const)) => { + // For arrays, we also check the constness of the type. + a_const.kind() == b_const.kind() + && structurally_same_type_impl( + seen_types, tcx, param_env, *a_ty, *b_ty, ckind, + ) + } + (Slice(a_ty), Slice(b_ty)) => { + structurally_same_type_impl(seen_types, tcx, param_env, *a_ty, *b_ty, ckind) + } + (RawPtr(a_tymut), RawPtr(b_tymut)) => { + a_tymut.mutbl == b_tymut.mutbl + && structurally_same_type_impl( + seen_types, tcx, param_env, a_tymut.ty, b_tymut.ty, ckind, + ) + } + (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => { + // For structural sameness, we don't need the region to be same. + a_mut == b_mut + && structurally_same_type_impl( + seen_types, tcx, param_env, *a_ty, *b_ty, ckind, + ) + } + (FnDef(..), FnDef(..)) => { + let a_poly_sig = a.fn_sig(tcx); + let b_poly_sig = b.fn_sig(tcx); + + // We don't compare regions, but leaving bound regions around ICEs, so + // we erase them. + let a_sig = tcx.erase_late_bound_regions(a_poly_sig); + let b_sig = tcx.erase_late_bound_regions(b_poly_sig); + + (a_sig.abi, a_sig.unsafety, a_sig.c_variadic) + == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic) + && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| { + structurally_same_type_impl(seen_types, tcx, param_env, *a, *b, ckind) + }) + && structurally_same_type_impl( + seen_types, + tcx, + param_env, + a_sig.output(), + b_sig.output(), + ckind, + ) + } + (Tuple(a_args), Tuple(b_args)) => { + a_args.iter().eq_by(b_args.iter(), |a_ty, b_ty| { + structurally_same_type_impl(seen_types, tcx, param_env, a_ty, b_ty, ckind) + }) + } + // For these, it's not quite as easy to define structural-sameness quite so easily. + // For the purposes of this lint, take the conservative approach and mark them as + // not structurally same. + (Dynamic(..), Dynamic(..)) + | (Error(..), Error(..)) + | (Closure(..), Closure(..)) + | (Generator(..), Generator(..)) + | (GeneratorWitness(..), GeneratorWitness(..)) + | (Alias(ty::Projection, ..), Alias(ty::Projection, ..)) + | (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..)) + | (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false, + + // These definitely should have been caught above. + (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(), + + // An Adt and a primitive or pointer type. This can be FFI-safe if non-null + // enum layout optimisation is being applied. + (Adt(..), other_kind) | (other_kind, Adt(..)) + if is_primitive_or_pointer(other_kind) => + { + let (primitive, adt) = + if is_primitive_or_pointer(a.kind()) { (a, b) } else { (b, a) }; + if let Some(ty) = types::repr_nullable_ptr(tcx, param_env, adt, ckind) { + ty == primitive + } else { + compare_layouts(a, b).unwrap_or(false) + } + } + // Otherwise, just compare the layouts. This may fail to lint for some + // incompatible types, but at the very least, will stop reads into + // uninitialised memory. + _ => compare_layouts(a, b).unwrap_or(false), + } + }) + } +} diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index fb12ded71d6..3331dbad4a9 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -17,7 +17,7 @@ use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore}; use rustc_ast as ast; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_data_structures::sync::{join, DynSend}; +use rustc_data_structures::sync::join; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit as hir_visit; @@ -336,7 +336,7 @@ macro_rules! impl_late_lint_pass { crate::late_lint_methods!(impl_late_lint_pass, []); -pub(super) fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( +pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( tcx: TyCtxt<'tcx>, module_def_id: LocalDefId, builtin_lints: T, @@ -376,6 +376,12 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>( let mut cx = LateContextAndPass { context, pass }; let (module, _span, hir_id) = tcx.hir().get_module(module_def_id); + + // There is no module lint that will have the crate itself as an item, so check it here. + if hir_id == hir::CRATE_HIR_ID { + lint_callback!(cx, check_crate,); + } + cx.process_mod(module, hir_id); // Visit the crate attributes @@ -383,10 +389,19 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>( for attr in tcx.hir().attrs(hir::CRATE_HIR_ID).iter() { cx.visit_attribute(attr) } + lint_callback!(cx, check_crate_post,); } } -fn late_lint_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(tcx: TyCtxt<'tcx>, builtin_lints: T) { +fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { + // Note: `passes` is often empty. + let mut passes: Vec<_> = + unerased_lint_store(tcx).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); + + if passes.is_empty() { + return; + } + let context = LateContext { tcx, enclosing_body: None, @@ -399,18 +414,8 @@ fn late_lint_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(tcx: TyCtxt<'tcx>, builti only_module: false, }; - // Note: `passes` is often empty. In that case, it's faster to run - // `builtin_lints` directly rather than bundling it up into the - // `RuntimeCombinedLateLintPass`. - let mut passes: Vec<_> = - unerased_lint_store(tcx).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); - if passes.is_empty() { - late_lint_crate_inner(tcx, context, builtin_lints); - } else { - passes.push(Box::new(builtin_lints)); - let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] }; - late_lint_crate_inner(tcx, context, pass); - } + let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] }; + late_lint_crate_inner(tcx, context, pass); } fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>( @@ -432,15 +437,12 @@ fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>( } /// Performs lint checking on a crate. -pub fn check_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>( - tcx: TyCtxt<'tcx>, - builtin_lints: impl FnOnce() -> T + Send + DynSend, -) { +pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) { join( || { tcx.sess.time("crate_lints", || { // Run whole crate non-incremental lints - late_lint_crate(tcx, builtin_lints()); + late_lint_crate(tcx); }); }, || { diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index fb407be1f02..18b178d8882 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,4 +1,5 @@ use crate::{ + builtin::MISSING_DOCS, context::{CheckLintNameResult, LintStore}, fluent_generated as fluent, late::unerased_lint_store, @@ -667,6 +668,16 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { continue; } + // `#[doc(hidden)]` disables missing_docs check. + if attr.has_name(sym::doc) + && attr + .meta_item_list() + .map_or(false, |l| ast::attr::list_contains_name(&l, sym::hidden)) + { + self.insert(LintId::of(MISSING_DOCS), (Level::Allow, LintLevelSource::Default)); + continue; + } + let level = match Level::from_attr(attr) { None => continue, // This is the only lint level with a `LintExpectationId` that can be created from an attribute diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 80bf53ea866..42378951af3 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -59,6 +59,7 @@ mod enum_intrinsics_non_enums; mod errors; mod expect; mod for_loops_over_fallibles; +mod foreign_modules; pub mod hidden_unicode_codepoints; mod internal; mod invalid_from_utf8; @@ -125,11 +126,11 @@ use types::*; use unused::*; /// Useful for other parts of the compiler / Clippy. -pub use builtin::SoftLints; +pub use builtin::{MissingDoc, SoftLints}; pub use context::{CheckLintNameResult, FindLintError, LintStore}; pub use context::{EarlyContext, LateContext, LintContext}; pub use early::{check_ast_node, EarlyCheckNode}; -pub use late::{check_crate, unerased_lint_store}; +pub use late::{check_crate, late_lint_mod, unerased_lint_store}; pub use passes::{EarlyLintPass, LateLintPass}; pub use rustc_session::lint::Level::{self, *}; pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId}; @@ -140,11 +141,12 @@ fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { levels::provide(providers); expect::provide(providers); + foreign_modules::provide(providers); *providers = Providers { lint_mod, ..*providers }; } fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - late::late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new()); + late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new()); } early_lint_methods!( @@ -182,25 +184,6 @@ early_lint_methods!( ] ); -// FIXME: Make a separate lint type which does not require typeck tables. - -late_lint_methods!( - declare_combined_late_lint_pass, - [ - pub BuiltinCombinedLateLintPass, - [ - // Tracks attributes of parents - MissingDoc: MissingDoc::new(), - // Builds a global list of all impls of `Debug`. - // FIXME: Turn the computation of types which implement Debug into a query - // and change this to a module lint pass - MissingDebugImplementations: MissingDebugImplementations::default(), - // Keeps a global list of foreign declarations. - ClashingExternDeclarations: ClashingExternDeclarations::new(), - ] - ] -); - late_lint_methods!( declare_combined_late_lint_pass, [ @@ -253,6 +236,8 @@ late_lint_methods!( OpaqueHiddenInferredBound: OpaqueHiddenInferredBound, MultipleSupertraitUpcastable: MultipleSupertraitUpcastable, MapUnitFn: MapUnitFn, + MissingDebugImplementations: MissingDebugImplementations, + MissingDoc: MissingDoc, ] ] ); @@ -281,7 +266,7 @@ fn register_builtins(store: &mut LintStore) { store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints()); store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints()); store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints()); - store.register_lints(&BuiltinCombinedLateLintPass::get_lints()); + store.register_lints(&foreign_modules::get_lints()); add_lint_group!( "nonstandard_style", @@ -521,20 +506,20 @@ fn register_internals(store: &mut LintStore) { store.register_lints(&LintPassImpl::get_lints()); store.register_early_pass(|| Box::new(LintPassImpl)); store.register_lints(&DefaultHashTypes::get_lints()); - store.register_late_pass(|_| Box::new(DefaultHashTypes)); + store.register_late_mod_pass(|_| Box::new(DefaultHashTypes)); store.register_lints(&QueryStability::get_lints()); - store.register_late_pass(|_| Box::new(QueryStability)); + store.register_late_mod_pass(|_| Box::new(QueryStability)); store.register_lints(&ExistingDocKeyword::get_lints()); - store.register_late_pass(|_| Box::new(ExistingDocKeyword)); + store.register_late_mod_pass(|_| Box::new(ExistingDocKeyword)); store.register_lints(&TyTyKind::get_lints()); - store.register_late_pass(|_| Box::new(TyTyKind)); + store.register_late_mod_pass(|_| Box::new(TyTyKind)); store.register_lints(&Diagnostics::get_lints()); store.register_early_pass(|| Box::new(Diagnostics)); - store.register_late_pass(|_| Box::new(Diagnostics)); + store.register_late_mod_pass(|_| Box::new(Diagnostics)); store.register_lints(&BadOptAccess::get_lints()); - store.register_late_pass(|_| Box::new(BadOptAccess)); + store.register_late_mod_pass(|_| Box::new(BadOptAccess)); store.register_lints(&PassByValue::get_lints()); - store.register_late_pass(|_| Box::new(PassByValue)); + store.register_late_mod_pass(|_| Box::new(PassByValue)); // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and // these lints will trigger all of the time - change this once migration to diagnostic structs diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 70311a5c576..25982a45853 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1496,7 +1496,7 @@ pub enum InvalidNanComparisons { #[diag(lint_invalid_nan_comparisons_eq_ne)] EqNe { #[subdiagnostic] - suggestion: InvalidNanComparisonsSuggestion, + suggestion: Option<InvalidNanComparisonsSuggestion>, }, #[diag(lint_invalid_nan_comparisons_lt_le_gt_ge)] LtLeGtGe, diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 226d01b79a8..1ba746eddeb 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -572,32 +572,36 @@ fn lint_nan<'tcx>( } fn eq_ne( + cx: &LateContext<'_>, e: &hir::Expr<'_>, l: &hir::Expr<'_>, r: &hir::Expr<'_>, f: impl FnOnce(Span, Span) -> InvalidNanComparisonsSuggestion, ) -> InvalidNanComparisons { - let suggestion = + // FIXME(#72505): This suggestion can be restored if `f{32,64}::is_nan` is made const. + let suggestion = (!cx.tcx.hir().is_inside_const_context(e.hir_id)).then(|| { if let Some(l_span) = l.span.find_ancestor_inside(e.span) && - let Some(r_span) = r.span.find_ancestor_inside(e.span) { + let Some(r_span) = r.span.find_ancestor_inside(e.span) + { f(l_span, r_span) } else { InvalidNanComparisonsSuggestion::Spanless - }; + } + }); InvalidNanComparisons::EqNe { suggestion } } let lint = match binop.node { hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, l) => { - eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { + eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { nan_plus_binop: l_span.until(r_span), float: r_span.shrink_to_hi(), neg: (binop.node == hir::BinOpKind::Ne).then(|| r_span.shrink_to_lo()), }) } hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, r) => { - eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { + eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { nan_plus_binop: l_span.shrink_to_hi().to(r_span), float: l_span.shrink_to_hi(), neg: (binop.node == hir::BinOpKind::Ne).then(|| l_span.shrink_to_lo()), @@ -815,8 +819,7 @@ pub fn transparent_newtype_field<'a, 'tcx>( } /// Is type known to be non-null? -fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool { - let tcx = cx.tcx; +fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool { match ty.kind() { ty::FnPtr(_) => true, ty::Ref(..) => true, @@ -835,8 +838,8 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi def.variants() .iter() - .filter_map(|variant| transparent_newtype_field(cx.tcx, variant)) - .any(|field| ty_is_known_nonnull(cx, field.ty(tcx, args), mode)) + .filter_map(|variant| transparent_newtype_field(tcx, variant)) + .any(|field| ty_is_known_nonnull(tcx, field.ty(tcx, args), mode)) } _ => false, } @@ -844,15 +847,12 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi /// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type. /// If the type passed in was not scalar, returns None. -fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { - let tcx = cx.tcx; +fn get_nullable_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { Some(match *ty.kind() { ty::Adt(field_def, field_args) => { let inner_field_ty = { - let mut first_non_zst_ty = field_def - .variants() - .iter() - .filter_map(|v| transparent_newtype_field(cx.tcx, v)); + let mut first_non_zst_ty = + field_def.variants().iter().filter_map(|v| transparent_newtype_field(tcx, v)); debug_assert_eq!( first_non_zst_ty.clone().count(), 1, @@ -863,7 +863,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t .expect("No non-zst fields in transparent type.") .ty(tcx, field_args) }; - return get_nullable_type(cx, inner_field_ty); + return get_nullable_type(tcx, inner_field_ty); } ty::Int(ty) => Ty::new_int(tcx, ty), ty::Uint(ty) => Ty::new_uint(tcx, ty), @@ -895,43 +895,44 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t /// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes. /// FIXME: This duplicates code in codegen. pub(crate) fn repr_nullable_ptr<'tcx>( - cx: &LateContext<'tcx>, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, ckind: CItemKind, ) -> Option<Ty<'tcx>> { - debug!("is_repr_nullable_ptr(cx, ty = {:?})", ty); + debug!("is_repr_nullable_ptr(tcx, ty = {:?})", ty); if let ty::Adt(ty_def, args) = ty.kind() { let field_ty = match &ty_def.variants().raw[..] { [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) { - ([], [field]) | ([field], []) => field.ty(cx.tcx, args), + ([], [field]) | ([field], []) => field.ty(tcx, args), _ => return None, }, _ => return None, }; - if !ty_is_known_nonnull(cx, field_ty, ckind) { + if !ty_is_known_nonnull(tcx, field_ty, ckind) { return None; } // At this point, the field's type is known to be nonnull and the parent enum is Option-like. // If the computed size for the field and the enum are different, the nonnull optimization isn't // being applied (and we've got a problem somewhere). - let compute_size_skeleton = |t| SizeSkeleton::compute(t, cx.tcx, cx.param_env).unwrap(); + let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, param_env).unwrap(); if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) { bug!("improper_ctypes: Option nonnull optimization not applied?"); } // Return the nullable type this Option-like enum can be safely represented with. - let field_ty_abi = &cx.layout_of(field_ty).unwrap().abi; + let field_ty_abi = &tcx.layout_of(param_env.and(field_ty)).unwrap().abi; if let Abi::Scalar(field_ty_scalar) = field_ty_abi { - match field_ty_scalar.valid_range(cx) { + match field_ty_scalar.valid_range(&tcx) { WrappingRange { start: 0, end } - if end == field_ty_scalar.size(&cx.tcx).unsigned_int_max() - 1 => + if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => { - return Some(get_nullable_type(cx, field_ty).unwrap()); + return Some(get_nullable_type(tcx, field_ty).unwrap()); } WrappingRange { start: 1, .. } => { - return Some(get_nullable_type(cx, field_ty).unwrap()); + return Some(get_nullable_type(tcx, field_ty).unwrap()); } WrappingRange { start, end } => { unreachable!("Unhandled start and end range: ({}, {})", start, end) @@ -1116,7 +1117,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none() { // Special-case types like `Option<extern fn()>`. - if repr_nullable_ptr(self.cx, ty, self.mode).is_none() { + if repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode) + .is_none() + { return FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_enum_repr_reason, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index ebf8a50ae8b..48b5fd6e283 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -322,8 +322,6 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, #if LLVM_VERSION_GE(17, 0) const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getAllProcessorDescriptions(); -#elif defined(LLVM_RUSTLLVM) - const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getCPUTable(); #else Buf << "Full target CPU help is not supported by this LLVM version.\n\n"; SubtargetSubTypeKV TargetCPUKV = { TargetCPU, {{}}, {{}} }; @@ -1120,9 +1118,15 @@ struct LLVMRustThinLTOData { // Not 100% sure what these are, but they impact what's internalized and // what's inlined across modules, I believe. +#if LLVM_VERSION_GE(18, 0) + DenseMap<StringRef, FunctionImporter::ImportMapTy> ImportLists; + DenseMap<StringRef, FunctionImporter::ExportSetTy> ExportLists; + DenseMap<StringRef, GVSummaryMapTy> ModuleToDefinedGVSummaries; +#else StringMap<FunctionImporter::ImportMapTy> ImportLists; StringMap<FunctionImporter::ExportSetTy> ExportLists; StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries; +#endif StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; LLVMRustThinLTOData() : Index(/* HaveGVs = */ false) {} diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f12094a271f..b34fead821f 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -819,7 +819,7 @@ fn should_encode_span(def_kind: DefKind) -> bool { | DefKind::Enum | DefKind::Variant | DefKind::Trait - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy @@ -854,7 +854,7 @@ fn should_encode_attrs(def_kind: DefKind) -> bool { | DefKind::Enum | DefKind::Variant | DefKind::Trait - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy @@ -895,7 +895,7 @@ fn should_encode_expn_that_defined(def_kind: DefKind) -> bool { | DefKind::Variant | DefKind::Trait | DefKind::Impl { .. } => true, - DefKind::TyAlias + DefKind::TyAlias { .. } | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy @@ -930,7 +930,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::Enum | DefKind::Variant | DefKind::Trait - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy @@ -974,7 +974,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool { | DefKind::Const | DefKind::Fn | DefKind::ForeignMod - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::OpaqueTy | DefKind::Enum | DefKind::Union @@ -1067,9 +1067,8 @@ fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: Def | DefKind::Closure | DefKind::Generator | DefKind::ExternCrate => false, - DefKind::TyAlias => { - tcx.features().lazy_type_alias - || tcx.type_of(def_id).instantiate_identity().has_opaque_types() + DefKind::TyAlias { lazy } => { + lazy || tcx.type_of(def_id).instantiate_identity().has_opaque_types() } } } @@ -1081,7 +1080,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool { | DefKind::Enum | DefKind::Variant | DefKind::Trait - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy @@ -1121,7 +1120,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::Fn | DefKind::Const | DefKind::Static(..) - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::ForeignTy | DefKind::Impl { .. } | DefKind::AssocFn @@ -1181,7 +1180,7 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool { | DefKind::Const | DefKind::Static(..) | DefKind::Ctor(..) - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::OpaqueTy | DefKind::ForeignTy | DefKind::Impl { .. } @@ -1222,7 +1221,7 @@ fn should_encode_constness(def_kind: DefKind) -> bool { | DefKind::AssocConst | DefKind::AnonConst | DefKind::Static(..) - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::OpaqueTy | DefKind::Impl { of_trait: false } | DefKind::ForeignTy @@ -1255,7 +1254,7 @@ fn should_encode_const(def_kind: DefKind) -> bool { | DefKind::Field | DefKind::Fn | DefKind::Static(..) - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::OpaqueTy | DefKind::ForeignTy | DefKind::Impl { .. } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 4287799a8e6..ea66c770b77 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -126,7 +126,8 @@ fixed_size_enum! { ( Enum ) ( Variant ) ( Trait ) - ( TyAlias ) + ( TyAlias { lazy: false } ) + ( TyAlias { lazy: true } ) ( ForeignTy ) ( TraitAlias ) ( AssocTy ) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 0256e09e4b5..fbc32263874 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -196,7 +196,9 @@ impl<'hir> Map<'hir> { ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind), ItemKind::Mod(..) => DefKind::Mod, ItemKind::OpaqueTy(..) => DefKind::OpaqueTy, - ItemKind::TyAlias(..) => DefKind::TyAlias, + ItemKind::TyAlias(..) => { + DefKind::TyAlias { lazy: self.tcx.features().lazy_type_alias } + } ItemKind::Enum(..) => DefKind::Enum, ItemKind::Struct(..) => DefKind::Struct, ItemKind::Union(..) => DefKind::Union, @@ -735,17 +737,6 @@ impl<'hir> Map<'hir> { } } - /// Returns the `OwnerId` of `id`'s nearest module parent, or `id` itself if no - /// module parent is in this map. - pub(super) fn get_module_parent_node(self, hir_id: HirId) -> OwnerId { - for (def_id, node) in self.parent_owner_iter(hir_id) { - if let OwnerNode::Item(&Item { kind: ItemKind::Mod(_), .. }) = node { - return def_id; - } - } - CRATE_OWNER_ID - } - /// When on an if expression, a match arm tail expression or a match arm, give back /// the enclosing `if` or `match` expression. /// diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 45a07fdd293..06b25556c82 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -102,7 +102,21 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn parent_module(self, id: HirId) -> LocalDefId { - self.parent_module_from_def_id(id.owner.def_id) + if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod { + id.owner.def_id + } else { + self.parent_module_from_def_id(id.owner.def_id) + } + } + + pub fn parent_module_from_def_id(self, mut id: LocalDefId) -> LocalDefId { + while let Some(parent) = self.opt_local_parent(id) { + id = parent; + if self.def_kind(id) == DefKind::Mod { + break; + } + } + id } pub fn impl_subject(self, def_id: DefId) -> EarlyBinder<ImplSubject<'tcx>> { @@ -120,10 +134,6 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn provide(providers: &mut Providers) { - providers.parent_module_from_def_id = |tcx, id| { - let hir = tcx.hir(); - hir.get_module_parent_node(hir.local_def_id_to_hir_id(id)).def_id - }; providers.hir_crate_items = map::hir_crate_items; providers.crate_hash = map::crate_hash; providers.hir_module_items = map::hir_module_items; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index c1f87d79b83..ddb5e248cdc 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1592,14 +1592,13 @@ impl<'tcx> Place<'tcx> { self.projection.iter().any(|elem| elem.is_indirect()) } - /// If MirPhase >= Derefered and if projection contains Deref, - /// It's guaranteed to be in the first place - pub fn has_deref(&self) -> bool { - // To make sure this is not accidentally used in wrong mir phase - debug_assert!( - self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref) - ); - self.projection.first() == Some(&PlaceElem::Deref) + /// Returns `true` if this `Place`'s first projection is `Deref`. + /// + /// This is useful because for MIR phases `AnalysisPhase::PostCleanup` and later, + /// `Deref` projections can only occur as the first projection. In that case this method + /// is equivalent to `is_indirect`, but faster. + pub fn is_indirect_first_projection(&self) -> bool { + self.as_ref().is_indirect_first_projection() } /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or @@ -1672,9 +1671,16 @@ impl<'tcx> PlaceRef<'tcx> { self.projection.iter().any(|elem| elem.is_indirect()) } - /// If MirPhase >= Derefered and if projection contains Deref, - /// It's guaranteed to be in the first place - pub fn has_deref(&self) -> bool { + /// Returns `true` if this `Place`'s first projection is `Deref`. + /// + /// This is useful because for MIR phases `AnalysisPhase::PostCleanup` and later, + /// `Deref` projections can only occur as the first projection. In that case this method + /// is equivalent to `is_indirect`, but faster. + pub fn is_indirect_first_projection(&self) -> bool { + // To make sure this is not accidentally used in wrong mir phase + debug_assert!( + self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref) + ); self.projection.first() == Some(&PlaceElem::Deref) } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a02f9a9f796..52a18c99edb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -231,7 +231,7 @@ rustc_queries! { action = { use rustc_hir::def::DefKind; match tcx.def_kind(key) { - DefKind::TyAlias => "expanding type alias", + DefKind::TyAlias { .. } => "expanding type alias", DefKind::TraitAlias => "expanding trait alias", _ => "computing type of", } @@ -398,11 +398,6 @@ rustc_queries! { desc { "computing `#[expect]`ed lints in this crate" } } - query parent_module_from_def_id(key: LocalDefId) -> LocalDefId { - eval_always - desc { |tcx| "getting the parent module of `{}`", tcx.def_path_str(key) } - } - query expn_that_defined(key: DefId) -> rustc_span::ExpnId { desc { |tcx| "getting the expansion that defined `{}`", tcx.def_path_str(key) } separate_provide_extern @@ -1596,6 +1591,11 @@ rustc_queries! { separate_provide_extern } + /// Lint against `extern fn` declarations having incompatible types. + query clashing_extern_declarations(_: ()) { + desc { "checking `extern fn` declarations are compatible" } + } + /// Identifies the entry-point (e.g., the `main` function) for a given /// crate, returning `None` if there is no entry point (such as for library crates). query entry_fn(_: ()) -> Option<(DefId, EntryFnType)> { diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 6ba13a76563..b4c6e0d970a 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -448,7 +448,7 @@ impl<'tcx> AdtDef<'tcx> { Res::Def(DefKind::Ctor(..), cid) => self.variant_with_ctor_id(cid), Res::Def(DefKind::Struct, _) | Res::Def(DefKind::Union, _) - | Res::Def(DefKind::TyAlias, _) + | Res::Def(DefKind::TyAlias { .. }, _) | Res::Def(DefKind::AssocTy, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5eef3e45f32..0b2d95506bf 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1062,7 +1062,7 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir().fn_decl_by_hir_id(hir_id) && let hir::TyKind::Path(hir::QPath::Resolved( None, - hir::Path { res: hir::def::Res::Def(DefKind::TyAlias, def_id), .. }, )) = hir_output.kind + hir::Path { res: hir::def::Res::Def(DefKind::TyAlias { .. }, def_id), .. }, )) = hir_output.kind && let Some(local_id) = def_id.as_local() && let Some(alias_ty) = self.hir().get_by_def_id(local_id).alias_ty() // it is type alias && let Some(alias_generics) = self.hir().get_by_def_id(local_id).generics() diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 8570f83dcc6..e71482326da 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -492,7 +492,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> { Alias(Opaque, AliasTy { def_id, .. }) => { let parent = self.tcx.parent(def_id); let parent_ty = self.tcx.type_of(parent).instantiate_identity(); - if let DefKind::TyAlias | DefKind::AssocTy = self.tcx.def_kind(parent) + if let DefKind::TyAlias { .. } | DefKind::AssocTy = self.tcx.def_kind(parent) && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *parent_ty.kind() && parent_opaque_def_id == def_id { @@ -576,7 +576,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> { Alias(Opaque, AliasTy { def_id, .. }) => { let parent = self.tcx.parent(def_id); let parent_ty = self.tcx.type_of(parent).instantiate_identity(); - if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent) + if let hir::def::DefKind::TyAlias { .. } | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent) && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *parent_ty.kind() && parent_opaque_def_id == def_id { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index d3fd49150ba..27ade16739d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -364,7 +364,7 @@ pub trait PrettyPrinter<'tcx>: self.write_str(get_local_name(&self, symbol, parent, parent_key).as_str())?; self.write_str("::")?; } else if let DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Trait - | DefKind::TyAlias | DefKind::Fn | DefKind::Const | DefKind::Static(_) = kind + | DefKind::TyAlias { .. } | DefKind::Fn | DefKind::Const | DefKind::Static(_) = kind { } else { // If not covered above, like for example items out of `impl` blocks, fallback. @@ -766,7 +766,7 @@ pub trait PrettyPrinter<'tcx>: let parent = self.tcx().parent(def_id); match self.tcx().def_kind(parent) { - DefKind::TyAlias | DefKind::AssocTy => { + DefKind::TyAlias { .. } | DefKind::AssocTy => { // NOTE: I know we should check for NO_QUERIES here, but it's alright. // `type_of` on a type alias or assoc type should never cause a cycle. if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, .. }) = @@ -2983,7 +2983,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N match child.res { def::Res::Def(DefKind::AssocTy, _) => {} - def::Res::Def(DefKind::TyAlias, _) => {} + def::Res::Def(DefKind::TyAlias { .. }, _) => {} def::Res::Def(defkind, def_id) => { if let Some(ns) = defkind.ns() { collect_fn(&child.ident, ns, def_id); diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a695febf087..e6baa624205 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1223,7 +1223,7 @@ impl<'tcx> AliasTy<'tcx> { DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent, DefKind::AssocTy => ty::Projection, DefKind::OpaqueTy => ty::Opaque, - DefKind::TyAlias => ty::Weak, + DefKind::TyAlias { .. } => ty::Weak, kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), } } @@ -1945,7 +1945,7 @@ impl<'tcx> Ty<'tcx> { (kind, tcx.def_kind(alias_ty.def_id)), (ty::Opaque, DefKind::OpaqueTy) | (ty::Projection | ty::Inherent, DefKind::AssocTy) - | (ty::Weak, DefKind::TyAlias) + | (ty::Weak, DefKind::TyAlias { .. }) ); Ty::new(tcx, Alias(kind, alias_ty)) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 90ecc8aa857..564f982f842 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -156,7 +156,7 @@ impl<'tcx> TyCtxt<'tcx> { | DefKind::Enum | DefKind::Trait | DefKind::OpaqueTy - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index b0961d91787..384a368434a 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -209,7 +209,7 @@ fn find_item_ty_spans( match ty.kind { hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { if let Res::Def(kind, def_id) = path.res - && kind != DefKind::TyAlias { + && !matches!(kind, DefKind::TyAlias { .. }) { let check_params = def_id.as_local().map_or(true, |def_id| { if def_id == needle { spans.push(ty.span); diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 4fdc3178c4e..099fefbf068 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -19,7 +19,7 @@ extern crate rustc_middle; mod build; mod check_unsafety; mod errors; -mod lints; +pub mod lints; pub mod thir; use rustc_middle::query::Providers; diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 3f0cc69ec59..7fb73b5c7b2 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -3,14 +3,18 @@ use rustc_data_structures::graph::iterate::{ NodeStatus, TriColorDepthFirstSearch, TriColorVisitor, }; use rustc_hir::def::DefKind; -use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Operand, TerminatorKind}; -use rustc_middle::ty::{self, Instance, TyCtxt}; +use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Terminator, TerminatorKind}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::ty::{GenericArg, GenericArgs}; use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION; use rustc_span::Span; use std::ops::ControlFlow; pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + check_call_recursion(tcx, body); +} + +fn check_call_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let def_id = body.source.def_id().expect_local(); if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) { @@ -23,7 +27,19 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { _ => &[], }; - let mut vis = Search { tcx, body, reachable_recursive_calls: vec![], trait_args }; + check_recursion(tcx, body, CallRecursion { trait_args }) + } +} + +fn check_recursion<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + classifier: impl TerminatorClassifier<'tcx>, +) { + let def_id = body.source.def_id().expect_local(); + + if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) { + let mut vis = Search { tcx, body, classifier, reachable_recursive_calls: vec![] }; if let Some(NonRecursive) = TriColorDepthFirstSearch::new(&body.basic_blocks).run_from_start(&mut vis) { @@ -46,20 +62,66 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { } } +/// Requires drop elaboration to have been performed first. +pub fn check_drop_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let def_id = body.source.def_id().expect_local(); + + // First check if `body` is an `fn drop()` of `Drop` + if let DefKind::AssocFn = tcx.def_kind(def_id) && + let Some(trait_ref) = tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) && + let Some(drop_trait) = tcx.lang_items().drop_trait() && drop_trait == trait_ref.instantiate_identity().def_id { + + // It was. Now figure out for what type `Drop` is implemented and then + // check for recursion. + if let ty::Ref(_, dropped_ty, _) = tcx.liberate_late_bound_regions( + def_id.to_def_id(), + tcx.fn_sig(def_id).instantiate_identity().input(0), + ).kind() { + check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty }); + } + } +} + +trait TerminatorClassifier<'tcx> { + fn is_recursive_terminator( + &self, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + terminator: &Terminator<'tcx>, + ) -> bool; +} + struct NonRecursive; -struct Search<'mir, 'tcx> { +struct Search<'mir, 'tcx, C: TerminatorClassifier<'tcx>> { tcx: TyCtxt<'tcx>, body: &'mir Body<'tcx>, - trait_args: &'tcx [GenericArg<'tcx>], + classifier: C, reachable_recursive_calls: Vec<Span>, } -impl<'mir, 'tcx> Search<'mir, 'tcx> { +struct CallRecursion<'tcx> { + trait_args: &'tcx [GenericArg<'tcx>], +} + +struct RecursiveDrop<'tcx> { + /// The type that `Drop` is implemented for. + drop_for: Ty<'tcx>, +} + +impl<'tcx> TerminatorClassifier<'tcx> for CallRecursion<'tcx> { /// Returns `true` if `func` refers to the function we are searching in. - fn is_recursive_call(&self, func: &Operand<'tcx>, args: &[Operand<'tcx>]) -> bool { - let Search { tcx, body, trait_args, .. } = *self; + fn is_recursive_terminator( + &self, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + terminator: &Terminator<'tcx>, + ) -> bool { + let TerminatorKind::Call { func, args, .. } = &terminator.kind else { + return false; + }; + // Resolving function type to a specific instance that is being called is expensive. To // avoid the cost we check the number of arguments first, which is sufficient to reject // most of calls as non-recursive. @@ -86,14 +148,30 @@ impl<'mir, 'tcx> Search<'mir, 'tcx> { // calling into an entirely different method (for example, a call from the default // method in the trait to `<A as Trait<B>>::method`, where `A` and/or `B` are // specific types). - return callee == caller && &call_args[..trait_args.len()] == trait_args; + return callee == caller && &call_args[..self.trait_args.len()] == self.trait_args; } false } } -impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> { +impl<'tcx> TerminatorClassifier<'tcx> for RecursiveDrop<'tcx> { + fn is_recursive_terminator( + &self, + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + terminator: &Terminator<'tcx>, + ) -> bool { + let TerminatorKind::Drop { place, .. } = &terminator.kind else { return false }; + + let dropped_ty = place.ty(body, tcx).ty; + dropped_ty == self.drop_for + } +} + +impl<'mir, 'tcx, C: TerminatorClassifier<'tcx>> TriColorVisitor<BasicBlocks<'tcx>> + for Search<'mir, 'tcx, C> +{ type BreakVal = NonRecursive; fn node_examined( @@ -138,10 +216,8 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> { fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow<Self::BreakVal> { // When we examine a node for the last time, remember it if it is a recursive call. let terminator = self.body[bb].terminator(); - if let TerminatorKind::Call { func, args, .. } = &terminator.kind { - if self.is_recursive_call(func, args) { - self.reachable_recursive_calls.push(terminator.source_info.span); - } + if self.classifier.is_recursive_terminator(self.tcx, self.body, terminator) { + self.reachable_recursive_calls.push(terminator.source_info.span); } ControlFlow::Continue(()) @@ -149,15 +225,14 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> { fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool { let terminator = self.body[bb].terminator(); - if terminator.unwind() == Some(&mir::UnwindAction::Cleanup(target)) - && terminator.successors().count() > 1 + let ignore_unwind = terminator.unwind() == Some(&mir::UnwindAction::Cleanup(target)) + && terminator.successors().count() > 1; + if ignore_unwind || self.classifier.is_recursive_terminator(self.tcx, self.body, terminator) { return true; } - // Don't traverse successors of recursive calls or false CFG edges. - match self.body[bb].terminator().kind { - TerminatorKind::Call { ref func, ref args, .. } => self.is_recursive_call(func, args), - TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target, + match &terminator.kind { + TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == &target, _ => false, } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3c3cbbf3614..c08fe54c39c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -439,7 +439,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { DefKind::Struct | DefKind::Ctor(CtorOf::Struct, ..) | DefKind::Union - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::AssocTy, _, ) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 8d78ec04821..17bb8fc37ad 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -839,7 +839,7 @@ impl Map { tail_elem: Option<TrackElem>, f: &mut impl FnMut(ValueIndex), ) { - if place.has_deref() { + if place.is_indirect_first_projection() { // We do not track indirect places. return; } diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index eca5f98a2c0..f1198d9bfd3 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -18,6 +18,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_middle = { path = "../rustc_middle" } rustc_const_eval = { path = "../rustc_const_eval" } +rustc_mir_build = { path = "../rustc_mir_build" } rustc_mir_dataflow = { path = "../rustc_mir_dataflow" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index d9e7339f1b2..75473ca53fb 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -60,7 +60,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag { let basic_blocks = body.basic_blocks.as_mut(); let local_decls = &body.local_decls; let needs_retag = |place: &Place<'tcx>| { - !place.has_deref() // we're not really interested in stores to "outside" locations, they are hard to keep track of anyway + !place.is_indirect_first_projection() // we're not really interested in stores to "outside" locations, they are hard to keep track of anyway && may_contain_reference(place.ty(&*local_decls, tcx).ty, /*depth*/ 3, tcx) && !local_decls[place.local].is_deref_temp() }; diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 47d9f52bfb5..9a3798eea3b 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -154,7 +154,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { if let Operand::Move(place) = *operand // A move out of a projection of a copy is equivalent to a copy of the original projection. - && !place.has_deref() + && !place.is_indirect_first_projection() && !self.fully_moved.contains(place.local) { *operand = Operand::Copy(place); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 734321e97d8..f99a51fea0b 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -338,38 +338,16 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { return shim::build_adt_ctor(tcx, def.to_def_id()); } - let context = tcx - .hir() - .body_const_context(def) - .expect("mir_for_ctfe should not be used for runtime functions"); - - let body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone(); + let body = tcx.mir_drops_elaborated_and_const_checked(def); + let body = match tcx.hir().body_const_context(def) { + // consts and statics do not have `optimized_mir`, so we can steal the body instead of + // cloning it. + Some(hir::ConstContext::Const | hir::ConstContext::Static(_)) => body.steal(), + Some(hir::ConstContext::ConstFn) => body.borrow().clone(), + None => bug!("`mir_for_ctfe` called on non-const {def:?}"), + }; let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const); - - match context { - // Do not const prop functions, either they get executed at runtime or exported to metadata, - // so we run const prop on them, or they don't, in which case we const evaluate some control - // flow paths of the function and any errors in those paths will get emitted as const eval - // errors. - hir::ConstContext::ConstFn => {} - // Static items always get evaluated, so we can just let const eval see if any erroneous - // control flow paths get executed. - hir::ConstContext::Static(_) => {} - // Associated constants get const prop run so we detect common failure situations in the - // crate that defined the constant. - // Technically we want to not run on regular const items, but oli-obk doesn't know how to - // conveniently detect that at this point without looking at the HIR. - hir::ConstContext::Const => { - pm::run_passes( - tcx, - &mut body, - &[&const_prop::ConstProp], - Some(MirPhase::Runtime(RuntimePhase::Optimized)), - ); - } - } - pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None); body @@ -446,6 +424,10 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & run_analysis_to_runtime_passes(tcx, &mut body); + // Now that drop elaboration has been performed, we can check for + // unconditional drop recursion. + rustc_mir_build::lints::check_drop_recursion(tcx, &body); + tcx.alloc_steal_mir(body) } diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index d31bf2072b1..a8b7a0dbb68 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -143,7 +143,7 @@ fn mark_used_by_default_parameters<'tcx>( | DefKind::Enum | DefKind::Variant | DefKind::Trait - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 5b3cc5d99cc..6eacbebe75f 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -428,6 +428,10 @@ passes_link_section = passes_macro_export = `#[macro_export]` only has an effect on macro definitions +passes_macro_export_on_decl_macro = + `#[macro_export]` has no effect on declarative macro definitions + .note = declarative macros follow the same exporting rules as regular items + passes_macro_use = `#[{$name}]` only has an effect on `extern crate` and modules diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index cbb030958c6..4f9b362e237 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2133,6 +2133,20 @@ impl CheckAttrVisitor<'_> { ); } } + } else { + // special case when `#[macro_export]` is applied to a macro 2.0 + let (macro_definition, _) = + self.tcx.hir().find(hir_id).unwrap().expect_item().expect_macro(); + let is_decl_macro = !macro_definition.macro_rules; + + if is_decl_macro { + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::MacroExport::OnDeclMacro, + ); + } } } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index fbe6fc3bee4..07b437f463f 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -87,7 +87,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { fn handle_res(&mut self, res: Res) { match res { - Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias, def_id) => { + Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias { .. }, def_id) => { self.check_def_id(def_id); } _ if self.in_pat => {} @@ -861,7 +861,7 @@ impl<'tcx> DeadVisitor<'tcx> { | DefKind::Fn | DefKind::Static(_) | DefKind::Const - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Union | DefKind::ForeignTy => self.warn_dead_code(def_id, "used"), diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 4f5514372d1..683717344ce 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -690,6 +690,10 @@ pub enum MacroExport { #[diag(passes_macro_export)] Normal, + #[diag(passes_macro_export_on_decl_macro)] + #[note] + OnDeclMacro, + #[diag(passes_invalid_macro_export_arguments)] UnknownItem { name: Symbol }, diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 794dbda3688..0463ee2914b 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -16,7 +16,7 @@ pub fn test_layout(tcx: TyCtxt<'_>) { for id in tcx.hir().items() { if matches!( tcx.def_kind(id.owner_id), - DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union + DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union ) { for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) { dump_layout_of(tcx, id.owner_id.def_id, attr); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index af9efb82beb..30a4235d371 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -583,7 +583,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { self.update(def_id, macro_ev, Level::Reachable); match def_kind { // No type privacy, so can be directly marked as reachable. - DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => { + DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias { .. } => { if vis.is_accessible_from(module, self.tcx) { self.update(def_id, macro_ev, Level::Reachable); } @@ -1992,8 +1992,8 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx, '_> { let def_kind = tcx.def_kind(def_id); match def_kind { - DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias => { - if let DefKind::TyAlias = def_kind { + DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias { .. } => { + if let DefKind::TyAlias { .. } = def_kind { self.check_unnameable(def_id, effective_vis); } self.check(def_id, item_visibility, effective_vis).generics().predicates().ty(); diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index bfc51da170d..1b124892441 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -592,7 +592,10 @@ pub(crate) fn report_cycle<'a, D: DepKind>( }); } - let alias = if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TyAlias)) { + let alias = if stack + .iter() + .all(|entry| matches!(entry.query.def_kind, Some(DefKind::TyAlias { .. }))) + { Some(crate::error::Alias::Ty) } else if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TraitAlias)) { Some(crate::error::Alias::Trait) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 2f432799022..a655667d01d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -278,7 +278,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { }; match self.r.resolve_path( &segments, - Some(TypeNS), + None, parent_scope, finalize.then(|| Finalize::new(id, path.span)), None, @@ -700,7 +700,10 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { // These items live in the type namespace. ItemKind::TyAlias(..) => { - let res = Res::Def(DefKind::TyAlias, def_id); + let res = Res::Def( + DefKind::TyAlias { lazy: self.r.tcx.features().lazy_type_alias }, + def_id, + ); self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); } @@ -948,7 +951,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { DefKind::Struct | DefKind::Union | DefKind::Variant - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::ForeignTy | DefKind::OpaqueTy | DefKind::TraitAlias diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7b590d16d8c..6007295b930 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -470,7 +470,7 @@ impl<'a> PathSource<'a> { | DefKind::Enum | DefKind::Trait | DefKind::TraitAlias - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::AssocTy | DefKind::TyParam | DefKind::OpaqueTy @@ -509,7 +509,7 @@ impl<'a> PathSource<'a> { DefKind::Struct | DefKind::Union | DefKind::Variant - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::AssocTy, _, ) | Res::SelfTyParam { .. } @@ -904,9 +904,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), &sig.decl.output, ); + + if let Some((async_node_id, span)) = sig.header.asyncness.opt_return_id() { + this.record_lifetime_params_for_impl_trait(async_node_id, span); + } }, ); - self.record_lifetime_params_for_async(fn_id, sig.header.asyncness.opt_return_id()); return; } FnKind::Fn(..) => { @@ -942,12 +945,14 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, .iter() .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)), &declaration.output, - ) + ); + + if let Some((async_node_id, span)) = async_node_id { + this.record_lifetime_params_for_impl_trait(async_node_id, span); + } }, ); - this.record_lifetime_params_for_async(fn_id, async_node_id); - if let Some(body) = body { // Ignore errors in function bodies if this is rustdoc // Be sure not to set this until the function signature has been resolved. @@ -1694,6 +1699,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Leave the responsibility to create the `LocalDefId` to lowering. let param = self.r.next_node_id(); let res = LifetimeRes::Fresh { param, binder }; + self.record_lifetime_param(param, res); // Record the created lifetime parameter so lowering can pick it up and add it to HIR. self.r @@ -1734,7 +1740,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { Res::Def(DefKind::Struct, def_id) | Res::Def(DefKind::Union, def_id) | Res::Def(DefKind::Enum, def_id) - | Res::Def(DefKind::TyAlias, def_id) + | Res::Def(DefKind::TyAlias { .. }, def_id) | Res::Def(DefKind::Trait, def_id) if i + 1 == proj_start => { @@ -3944,11 +3950,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { if path.len() > 1 && let Some(res) = result.full_res() + && let Some((&last_segment, prev_segs)) = path.split_last() + && prev_segs.iter().all(|seg| !seg.has_generic_args) && res != Res::Err && path[0].ident.name != kw::PathRoot && path[0].ident.name != kw::DollarCrate { - let last_segment = *path.last().unwrap(); let unqualified_result = { match self.resolve_path(&[last_segment], Some(ns), None) { PathResult::NonModule(path_res) => path_res.expect_full_res(), @@ -4325,39 +4332,32 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ) } - /// Construct the list of in-scope lifetime parameters for async lowering. + /// Construct the list of in-scope lifetime parameters for impl trait lowering. /// We include all lifetime parameters, either named or "Fresh". /// The order of those parameters does not matter, as long as it is /// deterministic. - fn record_lifetime_params_for_async( - &mut self, - fn_id: NodeId, - async_node_id: Option<(NodeId, Span)>, - ) { - if let Some((async_node_id, span)) = async_node_id { - let mut extra_lifetime_params = - self.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default(); - for rib in self.lifetime_ribs.iter().rev() { - extra_lifetime_params.extend( - rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res)), - ); - match rib.kind { - LifetimeRibKind::Item => break, - LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { - if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) { - extra_lifetime_params.extend(earlier_fresh); - } - } - LifetimeRibKind::Generics { .. } => {} - _ => { - // We are in a function definition. We should only find `Generics` - // and `AnonymousCreateParameter` inside the innermost `Item`. - span_bug!(span, "unexpected rib kind: {:?}", rib.kind) + fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId, span: Span) { + let mut extra_lifetime_params = vec![]; + + for rib in self.lifetime_ribs.iter().rev() { + extra_lifetime_params + .extend(rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res))); + match rib.kind { + LifetimeRibKind::Item => break, + LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { + if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) { + extra_lifetime_params.extend(earlier_fresh); } } + LifetimeRibKind::Generics { .. } => {} + _ => { + // We are in a function definition. We should only find `Generics` + // and `AnonymousCreateParameter` inside the innermost `Item`. + span_bug!(span, "unexpected rib kind: {:?}", rib.kind) + } } - self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params); } + self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params); } fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> Option<Res> { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 974580f815b..c34b7df9b46 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -555,7 +555,6 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } }) .collect::<Vec<_>>(); - let crate_def_id = CRATE_DEF_ID.to_def_id(); // Try to filter out intrinsics candidates, as long as we have // some other candidates to suggest. let intrinsic_candidates: Vec<_> = candidates @@ -566,8 +565,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .collect(); if candidates.is_empty() { // Put them back if we have no more candidates to suggest... - candidates.extend(intrinsic_candidates); + candidates = intrinsic_candidates; } + let crate_def_id = CRATE_DEF_ID.to_def_id(); if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) { let mut enum_candidates: Vec<_> = self .r @@ -1180,37 +1180,34 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { /// return the span of whole call and the span for all arguments expect the first one (`self`). fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> { let mut has_self_arg = None; - if let PathSource::Expr(Some(parent)) = source { - match &parent.kind { - ExprKind::Call(_, args) if !args.is_empty() => { - let mut expr_kind = &args[0].kind; - loop { - match expr_kind { - ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => { - if arg_name.segments[0].ident.name == kw::SelfLower { - let call_span = parent.span; - let tail_args_span = if args.len() > 1 { - Some(Span::new( - args[1].span.lo(), - args.last().unwrap().span.hi(), - call_span.ctxt(), - None, - )) - } else { - None - }; - has_self_arg = Some((call_span, tail_args_span)); - } - break; + if let PathSource::Expr(Some(parent)) = source + && let ExprKind::Call(_, args) = &parent.kind + && !args.is_empty() { + let mut expr_kind = &args[0].kind; + loop { + match expr_kind { + ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => { + if arg_name.segments[0].ident.name == kw::SelfLower { + let call_span = parent.span; + let tail_args_span = if args.len() > 1 { + Some(Span::new( + args[1].span.lo(), + args.last().unwrap().span.hi(), + call_span.ctxt(), + None, + )) + } else { + None + }; + has_self_arg = Some((call_span, tail_args_span)); } - ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind, - _ => break, + break; } + ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind, + _ => break, } } - _ => (), - } - }; + } has_self_arg } @@ -1220,15 +1217,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // where a brace being opened means a block is being started. Look // ahead for the next text to see if `span` is followed by a `{`. let sm = self.r.tcx.sess.source_map(); - let sp = sm.span_look_ahead(span, None, Some(50)); - let followed_by_brace = matches!(sm.span_to_snippet(sp), Ok(ref snippet) if snippet == "{"); - // In case this could be a struct literal that needs to be surrounded - // by parentheses, find the appropriate span. - let closing_span = sm.span_look_ahead(span, Some("}"), Some(50)); - let closing_brace: Option<Span> = sm - .span_to_snippet(closing_span) - .map_or(None, |s| if s == "}" { Some(span.to(closing_span)) } else { None }); - (followed_by_brace, closing_brace) + if let Some(followed_brace_span) = sm.span_look_ahead(span, "{", Some(50)) { + // In case this could be a struct literal that needs to be surrounded + // by parentheses, find the appropriate span. + let close_brace_span = sm.span_look_ahead(followed_brace_span, "}", Some(50)); + let closing_brace = close_brace_span.map(|sp| span.to(sp)); + (true, closing_brace) + } else { + (false, None) + } } /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment` @@ -1422,7 +1419,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => { err.span_label(span, fallback_label.to_string()); } - (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => { + (Res::Def(DefKind::TyAlias { .. }, def_id), PathSource::Trait(_)) => { err.span_label(span, "type aliases cannot be used as traits"); if self.r.tcx.sess.is_nightly_build() { let msg = "you might have meant to use `#![feature(trait_alias)]` instead of a \ @@ -1591,7 +1588,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err.span_label(span, fallback_label.to_string()); err.note("can't use `Self` as a constructor, you must use the implemented struct"); } - (Res::Def(DefKind::TyAlias | DefKind::AssocTy, _), _) if ns == ValueNS => { + (Res::Def(DefKind::TyAlias { .. } | DefKind::AssocTy, _), _) if ns == ValueNS => { err.note("can't use a type alias as a constructor"); } _ => return false, @@ -2407,7 +2404,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { should_continue = suggest(err, false, span, message, sugg); } } - LifetimeRibKind::Item => break, + LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy => break, _ => {} } if !should_continue { @@ -2513,7 +2510,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .lifetime_ribs .iter() .rev() - .take_while(|rib| !matches!(rib.kind, LifetimeRibKind::Item)) + .take_while(|rib| { + !matches!(rib.kind, LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy) + }) .flat_map(|rib| rib.bindings.iter()) .map(|(&ident, &res)| (ident, res)) .filter(|(ident, _)| ident.name != kw::UnderscoreLifetime) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 6a26a4a22ed..39541c845b3 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -68,6 +68,10 @@ impl<'tcx> Tables<'tcx> { self.def_ids[item.0] } + pub fn trait_def_id(&self, trait_def: &stable_mir::ty::TraitDef) -> DefId { + self.def_ids[trait_def.0] + } + pub fn crate_item(&mut self, did: DefId) -> stable_mir::CrateItem { stable_mir::CrateItem(self.create_def_id(did)) } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index c4bdec0ee28..d12de92db8a 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -41,6 +41,21 @@ impl<'tcx> Context for Tables<'tcx> { fn entry_fn(&mut self) -> Option<stable_mir::CrateItem> { Some(self.crate_item(self.tcx.entry_fn(())?.0)) } + + fn all_trait_decls(&mut self) -> stable_mir::TraitDecls { + self.tcx + .traits(LOCAL_CRATE) + .iter() + .map(|trait_def_id| self.trait_def(*trait_def_id)) + .collect() + } + + fn trait_decl(&mut self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl { + let def_id = self.trait_def_id(trait_def); + let trait_def = self.tcx.trait_def(def_id); + trait_def.stable(self) + } + fn mir_body(&mut self, item: &stable_mir::CrateItem) -> stable_mir::mir::Body { let def_id = self.item_def_id(item); let mir = self.tcx.optimized_mir(def_id); @@ -515,7 +530,7 @@ impl<'tcx> Stable<'tcx> for mir::RetagKind { } } -impl<'tcx> Stable<'tcx> for rustc_middle::ty::UserTypeAnnotationIndex { +impl<'tcx> Stable<'tcx> for ty::UserTypeAnnotationIndex { type T = usize; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { self.as_usize() @@ -826,7 +841,7 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> { type T = stable_mir::ty::FnSig; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { use rustc_target::spec::abi; - use stable_mir::ty::{Abi, FnSig, Unsafety}; + use stable_mir::ty::{Abi, FnSig}; FnSig { inputs_and_output: self @@ -835,10 +850,7 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> { .map(|ty| tables.intern_ty(ty)) .collect(), c_variadic: self.c_variadic, - unsafety: match self.unsafety { - hir::Unsafety::Normal => Unsafety::Normal, - hir::Unsafety::Unsafe => Unsafety::Unsafe, - }, + unsafety: self.unsafety.stable(tables), abi: match self.abi { abi::Abi::Rust => Abi::Rust, abi::Abi::C { unwind } => Abi::C { unwind }, @@ -1048,7 +1060,7 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> { } } -impl<'tcx> Stable<'tcx> for rustc_middle::ty::ParamTy { +impl<'tcx> Stable<'tcx> for ty::ParamTy { type T = stable_mir::ty::ParamTy; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { use stable_mir::ty::ParamTy; @@ -1056,10 +1068,80 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::ParamTy { } } -impl<'tcx> Stable<'tcx> for rustc_middle::ty::BoundTy { +impl<'tcx> Stable<'tcx> for ty::BoundTy { type T = stable_mir::ty::BoundTy; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { use stable_mir::ty::BoundTy; BoundTy { var: self.var.as_usize(), kind: self.kind.stable(tables) } } } + +impl<'tcx> Stable<'tcx> for mir::interpret::Allocation { + type T = stable_mir::ty::Allocation; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + let size = self.size(); + let mut bytes: Vec<Option<u8>> = self + .inspect_with_uninit_and_ptr_outside_interpreter(0..size.bytes_usize()) + .iter() + .copied() + .map(Some) + .collect(); + for (i, b) in bytes.iter_mut().enumerate() { + if !self.init_mask().get(rustc_target::abi::Size::from_bytes(i)) { + *b = None; + } + } + stable_mir::ty::Allocation { + bytes: bytes, + provenance: { + let mut ptrs = Vec::new(); + for (size, prov) in self.provenance().ptrs().iter() { + ptrs.push((size.bytes_usize(), opaque(prov))); + } + stable_mir::ty::ProvenanceMap { ptrs } + }, + align: self.align.bytes(), + mutability: self.mutability.stable(tables), + } + } +} + +impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind { + type T = stable_mir::ty::TraitSpecializationKind; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::TraitSpecializationKind; + + match self { + ty::trait_def::TraitSpecializationKind::None => TraitSpecializationKind::None, + ty::trait_def::TraitSpecializationKind::Marker => TraitSpecializationKind::Marker, + ty::trait_def::TraitSpecializationKind::AlwaysApplicable => { + TraitSpecializationKind::AlwaysApplicable + } + } + } +} + +impl<'tcx> Stable<'tcx> for ty::TraitDef { + type T = stable_mir::ty::TraitDecl; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::ty::TraitDecl; + + TraitDecl { + def_id: rustc_internal::trait_def(self.def_id), + unsafety: self.unsafety.stable(tables), + paren_sugar: self.paren_sugar, + has_auto_impl: self.has_auto_impl, + is_marker: self.is_marker, + is_coinductive: self.is_coinductive, + skip_array_during_method_dispatch: self.skip_array_during_method_dispatch, + specialization_kind: self.specialization_kind.stable(tables), + must_implement_one_of: self + .must_implement_one_of + .as_ref() + .map(|idents| idents.iter().map(|ident| opaque(ident)).collect()), + implement_via_object: self.implement_via_object, + deny_explicit_impl: self.deny_explicit_impl, + } + } +} diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs index 5e599a77bcd..d93f25249b9 100644 --- a/compiler/rustc_smir/src/stable_mir/mod.rs +++ b/compiler/rustc_smir/src/stable_mir/mod.rs @@ -15,7 +15,7 @@ use std::cell::Cell; use crate::rustc_smir::Tables; -use self::ty::{Ty, TyKind}; +use self::ty::{TraitDecl, TraitDef, Ty, TyKind}; pub mod mir; pub mod ty; @@ -32,6 +32,9 @@ pub type DefId = usize; /// A list of crate items. pub type CrateItems = Vec<CrateItem>; +/// A list of crate items. +pub type TraitDecls = Vec<TraitDef>; + /// Holds information about a crate. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Crate { @@ -84,6 +87,8 @@ pub trait Context { /// Retrieve all items of the local crate that have a MIR associated with them. fn all_local_items(&mut self) -> CrateItems; fn mir_body(&mut self, item: &CrateItem) -> mir::Body; + fn all_trait_decls(&mut self) -> TraitDecls; + fn trait_decl(&mut self, trait_def: &TraitDef) -> TraitDecl; /// Get information about the local crate. fn local_crate(&self) -> Crate; /// Retrieve a list of all external crates. diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 025225b8d19..c487db5b732 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -1,4 +1,4 @@ -use super::{mir::Mutability, with, DefId}; +use super::{mir::Mutability, mir::Safety, with, DefId}; use crate::rustc_internal::Opaque; #[derive(Copy, Clone, Debug)] @@ -11,6 +11,7 @@ impl Ty { } pub(crate) type Const = Opaque; +type Ident = Opaque; pub(crate) type Region = Opaque; type Span = Opaque; @@ -104,6 +105,12 @@ pub struct AliasDef(pub(crate) DefId); #[derive(Clone, PartialEq, Eq, Debug)] pub struct TraitDef(pub(crate) DefId); +impl TraitDef { + pub fn trait_decl(&self) -> TraitDecl { + with(|cx| cx.trait_decl(self)) + } +} + #[derive(Clone, Debug)] pub struct GenericArgs(pub Vec<GenericArgKind>); @@ -140,17 +147,11 @@ pub type PolyFnSig = Binder<FnSig>; pub struct FnSig { pub inputs_and_output: Vec<Ty>, pub c_variadic: bool, - pub unsafety: Unsafety, + pub unsafety: Safety, pub abi: Abi, } #[derive(Clone, PartialEq, Eq, Debug)] -pub enum Unsafety { - Unsafe, - Normal, -} - -#[derive(Clone, PartialEq, Eq, Debug)] pub enum Abi { Rust, C { unwind: bool }, @@ -242,3 +243,45 @@ pub struct BoundTy { pub var: usize, pub kind: BoundTyKind, } + +pub type Bytes = Vec<Option<u8>>; +pub type Size = usize; +pub type Prov = Opaque; +pub type Align = u64; +pub type InitMaskMaterialized = Vec<u64>; + +/// Stores the provenance information of pointers stored in memory. +#[derive(Clone, Debug)] +pub struct ProvenanceMap { + /// Provenance in this map applies from the given offset for an entire pointer-size worth of + /// bytes. Two entries in this map are always at least a pointer size apart. + pub ptrs: Vec<(Size, Prov)>, +} + +#[derive(Clone, Debug)] +pub struct Allocation { + pub bytes: Bytes, + pub provenance: ProvenanceMap, + pub align: Align, + pub mutability: Mutability, +} + +pub enum TraitSpecializationKind { + None, + Marker, + AlwaysApplicable, +} + +pub struct TraitDecl { + pub def_id: TraitDef, + pub unsafety: Safety, + pub paren_sugar: bool, + pub has_auto_impl: bool, + pub is_marker: bool, + pub is_coinductive: bool, + pub skip_array_during_method_dispatch: bool, + pub specialization_kind: TraitSpecializationKind, + pub must_implement_one_of: Option<Vec<Ident>>, + pub implement_via_object: bool, + pub deny_explicit_impl: bool, +} diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 86716da1712..983b2ab04a4 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -973,24 +973,21 @@ impl SourceMap { Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt(), None) } - /// Returns a new span to check next none-whitespace character or some specified expected character - /// If `expect` is none, the first span of non-whitespace character is returned. - /// If `expect` presented, the first span of the character `expect` is returned - /// Otherwise, the span reached to limit is returned. - pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option<usize>) -> Span { + /// Check whether span is followed by some specified expected string in limit scope + pub fn span_look_ahead(&self, span: Span, expect: &str, limit: Option<usize>) -> Option<Span> { let mut sp = span; for _ in 0..limit.unwrap_or(100_usize) { sp = self.next_point(sp); if let Ok(ref snippet) = self.span_to_snippet(sp) { - if expect.is_some_and(|es| snippet == es) { - break; + if snippet == expect { + return Some(sp); } - if expect.is_none() && snippet.chars().any(|c| !c.is_whitespace()) { + if snippet.chars().any(|c| !c.is_whitespace()) { break; } } } - sp + None } /// Finds the width of the character, either before or after the end of provided span, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 44820ae6f72..9ea9efb047c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -498,6 +498,7 @@ symbols! { cold, collapse_debuginfo, column, + compare_bytes, compare_exchange, compare_exchange_weak, compile_error, diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs index eb3f66ac308..dc233121f66 100644 --- a/compiler/rustc_target/src/spec/abi.rs +++ b/compiler/rustc_target/src/spec/abi.rs @@ -150,7 +150,8 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> { // Stable "Rust" | "C" | "C-unwind" | "cdecl" | "cdecl-unwind" | "stdcall" | "stdcall-unwind" | "fastcall" | "fastcall-unwind" | "aapcs" | "aapcs-unwind" | "win64" | "win64-unwind" - | "sysv64" | "sysv64-unwind" | "system" | "system-unwind" | "efiapi" => Ok(()), + | "sysv64" | "sysv64-unwind" | "system" | "system-unwind" | "efiapi" | "thiscall" + | "thiscall-unwind" => Ok(()), "rust-intrinsic" => Err(AbiDisabled::Unstable { feature: sym::intrinsics, explain: "intrinsics are subject to change", @@ -167,14 +168,6 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> { feature: sym::abi_vectorcall, explain: "vectorcall-unwind ABI is experimental and subject to change", }), - "thiscall" => Err(AbiDisabled::Unstable { - feature: sym::abi_thiscall, - explain: "thiscall is experimental and subject to change", - }), - "thiscall-unwind" => Err(AbiDisabled::Unstable { - feature: sym::abi_thiscall, - explain: "thiscall-unwind ABI is experimental and subject to change", - }), "rust-call" => Err(AbiDisabled::Unstable { feature: sym::unboxed_closures, explain: "rust-call ABI is subject to change", diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs index fbec44b716a..cd324c94bbe 100644 --- a/compiler/rustc_target/src/spec/avr_gnu_base.rs +++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs @@ -23,7 +23,7 @@ pub fn target(target_cpu: &'static str, mmcu: &'static str) -> Target { LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-lgcc"], ), - max_atomic_width: Some(0), + max_atomic_width: Some(16), atomic_cas: false, relocation_model: RelocModel::Static, ..TargetOptions::default() diff --git a/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs index 34934379c7e..4e105a03e28 100644 --- a/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs +++ b/compiler/rustc_target/src/spec/powerpc64_ibm_aix.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-ibm-aix".into(), pointer_width: 64, - data_layout: "E-m:a-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "E-m:a-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs index 08b27320730..e8fe55a00db 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-freebsd".into(), pointer_width: 64, - data_layout: "E-m:e-i64:64-n32:64".into(), + data_layout: "E-m:e-Fn32-i64:64-n32:64".into(), arch: "powerpc64".into(), options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs index ce64de861cd..7a0cc539f1a 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-gnu".into(), pointer_width: 64, - data_layout: "E-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs index 81286a668fe..f80b22828c1 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-musl".into(), pointer_width: 64, - data_layout: "E-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs index 7232dce3e96..3643f7b0c37 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_openbsd.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-openbsd".into(), pointer_width: 64, - data_layout: "E-m:e-i64:64-n32:64".into(), + data_layout: "E-m:e-Fn32-i64:64-n32:64".into(), arch: "powerpc64".into(), options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs index 10da7872c73..b0472e64e13 100644 --- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-gnu".into(), pointer_width: 64, - data_layout: "E-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: TargetOptions { endian: Endian::Big, ..base }, } diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs index 8c941e10651..342b1cf4f4c 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-freebsd".into(), pointer_width: 64, - data_layout: "e-m:e-i64:64-n32:64".into(), + data_layout: "e-m:e-Fn32-i64:64-n32:64".into(), arch: "powerpc64".into(), options: TargetOptions { mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs index fd896e086b5..815e3d2781c 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-linux-gnu".into(), pointer_width: 64, - data_layout: "e-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: TargetOptions { mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs index 3cffcf49772..0b9b78bcec8 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-linux-musl".into(), pointer_width: 64, - data_layout: "e-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: TargetOptions { mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs index 342f321bd5b..e036f5bdbad 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-freebsd13.0".into(), pointer_width: 32, - data_layout: "E-m:e-p:32:32-i64:64-n32".into(), + data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), arch: "powerpc".into(), options: TargetOptions { endian: Endian::Big, diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs index c8c61dc46ee..c8d6f8b9c67 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnu".into(), pointer_width: 32, - data_layout: "E-m:e-p:32:32-i64:64-n32".into(), + data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), arch: "powerpc".into(), options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs index 5c51ec91f71..fdaa9d366d9 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnuspe".into(), pointer_width: 32, - data_layout: "E-m:e-p:32:32-i64:64-n32".into(), + data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), arch: "powerpc".into(), options: TargetOptions { abi: "spe".into(), diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs index fc7d802cbf4..7fe708cf530 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-musl".into(), pointer_width: 32, - data_layout: "E-m:e-p:32:32-i64:64-n32".into(), + data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), arch: "powerpc".into(), options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs index 912149c79e4..6f8875ba7b4 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-netbsd".into(), pointer_width: 32, - data_layout: "E-m:e-p:32:32-i64:64-n32".into(), + data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), arch: "powerpc".into(), options: TargetOptions { endian: Endian::Big, mcount: "__mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs index dec85f9961b..280d36698b4 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_openbsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-openbsd".into(), pointer_width: 32, - data_layout: "E-m:e-p:32:32-i64:64-n32".into(), + data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), arch: "powerpc".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs index a8c1c2a6132..6f245e6ab62 100644 --- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnu".into(), pointer_width: 32, - data_layout: "E-m:e-p:32:32-i64:64-n32".into(), + data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), arch: "powerpc".into(), options: TargetOptions { endian: Endian::Big, features: "+secure-plt".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs index abb8d13daef..1d5a5e5c6ac 100644 --- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs +++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnuspe".into(), pointer_width: 32, - data_layout: "E-m:e-p:32:32-i64:64-n32".into(), + data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), arch: "powerpc".into(), options: TargetOptions { abi: "spe".into(), diff --git a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs index 6389d68641a..75a65a26849 100644 --- a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), - max_atomic_width: Some(32), + max_atomic_width: Some(0), atomic_cas: false, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs index a177a73483f..f2242bbe087 100644 --- a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), - max_atomic_width: Some(32), + max_atomic_width: Some(0), atomic_cas: false, features: "+m".into(), panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs index fd620696cb2..01e773fae97 100644 --- a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), - max_atomic_width: Some(32), + max_atomic_width: Some(0), atomic_cas: false, features: "+m,+c".into(), panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs index 12968abda08..b10e6264b73 100644 --- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.endian = Endian::Big; base.cpu = "v9".into(); - base.max_atomic_width = Some(64); + base.max_atomic_width = Some(32); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-mv8plus"]); Target { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 267f345c062..1391b51e67f 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -152,16 +152,12 @@ pub(super) trait GoalKind<'tcx>: let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { bug!("expected object type in `consider_object_bound_candidate`"); }; - ecx.add_goals( - structural_traits::predicates_for_object_candidate( - &ecx, - goal.param_env, - goal.predicate.trait_ref(tcx), - bounds, - ) - .into_iter() - .map(|pred| goal.with(tcx, pred)), - ); + ecx.add_goals(structural_traits::predicates_for_object_candidate( + &ecx, + goal.param_env, + goal.predicate.trait_ref(tcx), + bounds, + )); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 72ba4f59137..b882ec254e3 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::{def_id::DefId, Movability, Mutability}; use rustc_infer::traits::query::NoSolution; +use rustc_middle::traits::solve::Goal; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; @@ -345,7 +346,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( param_env: ty::ParamEnv<'tcx>, trait_ref: ty::TraitRef<'tcx>, object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, -) -> Vec<ty::Clause<'tcx>> { +) -> Vec<Goal<'tcx, ty::Predicate<'tcx>>> { let tcx = ecx.tcx(); let mut requirements = vec![]; requirements.extend( @@ -376,17 +377,22 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( } } - requirements.fold_with(&mut ReplaceProjectionWith { - ecx, - param_env, - mapping: replace_projection_with, - }) + let mut folder = + ReplaceProjectionWith { ecx, param_env, mapping: replace_projection_with, nested: vec![] }; + let folded_requirements = requirements.fold_with(&mut folder); + + folder + .nested + .into_iter() + .chain(folded_requirements.into_iter().map(|clause| Goal::new(tcx, param_env, clause))) + .collect() } struct ReplaceProjectionWith<'a, 'tcx> { ecx: &'a EvalCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>, + nested: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> { @@ -402,13 +408,12 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> { // but the where clauses we instantiated are not. We can solve this by instantiating // the binder at the usage site. let proj = self.ecx.instantiate_binder_with_infer(*replacement); - // FIXME: Technically this folder could be fallible? - let nested = self - .ecx - .eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty) - .expect("expected to be able to unify goal projection with dyn's projection"); - // FIXME: Technically we could register these too.. - assert!(nested.is_empty(), "did not expect unification to have any nested goals"); + // FIXME: Technically this equate could be fallible... + self.nested.extend( + self.ecx + .eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty) + .expect("expected to be able to unify goal projection with dyn's projection"), + ); proj.term.ty().unwrap() } else { ty.super_fold_with(self) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 5ec9ddfe64a..60c49f665a6 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -391,13 +391,19 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { debug!("rerunning goal to check result is stable"); self.search_graph.reset_encountered_overflow(encountered_overflow); let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); - let new_canonical_response = EvalCtxt::evaluate_canonical_goal( + let Ok(new_canonical_response) = EvalCtxt::evaluate_canonical_goal( self.tcx(), self.search_graph, canonical_goal, // FIXME(-Ztrait-solver=next): we do not track what happens in `evaluate_canonical_goal` &mut ProofTreeBuilder::new_noop(), - )?; + ) else { + bug!( + "goal went from {certainty:?} to error: re-canonicalized goal={canonical_goal:#?} \ + first_response={canonical_response:#?}, + second response was error" + ); + }; // We only check for modulo regions as we convert all regions in // the input to new existentials, even if they're expected to be // `'static` or a placeholder region. diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 75cf33d8194..e1980f4d7bb 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -58,7 +58,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } DefKind::AnonConst => self.normalize_anon_const(goal), DefKind::OpaqueTy => self.normalize_opaque_type(goal), - DefKind::TyAlias => self.normalize_weak_type(goal), + DefKind::TyAlias { .. } => self.normalize_weak_type(goal), kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)), } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 1c59f3ff6c7..2b8571796df 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1429,20 +1429,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Issue #109436, we need to add parentheses properly for method calls // for example, `foo.into()` should be `(&foo).into()` - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet( - self.tcx.sess.source_map().span_look_ahead(span, Some("."), Some(50)), - ) { - if snippet == "." { - err.multipart_suggestion_verbose( - sugg_msg, - vec![ - (span.shrink_to_lo(), format!("({sugg_prefix}")), - (span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MaybeIncorrect, - ); - return true; - } + if let Some(_) = + self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)) + { + err.multipart_suggestion_verbose( + sugg_msg, + vec![ + (span.shrink_to_lo(), format!("({sugg_prefix}")), + (span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); + return true; } // Issue #104961, we need to add parentheses properly for compound expressions diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 84746eba3ec..d3c4dc45923 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -22,7 +22,9 @@ impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> { assert!(!ty.is_ty_var(), "should have resolved vars before calling"); if self.infcx.next_trait_solver() { - while let ty::Alias(ty::Projection, projection_ty) = *ty.kind() { + while let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, projection_ty) = + *ty.kind() + { let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::NormalizeProjectionType, span: self.cause.span, diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 7eb1042d2f8..aa49a5561d1 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -128,7 +128,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' }, DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)), DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) { - DefKind::TyAlias => ty::List::empty(), + DefKind::TyAlias { .. } => ty::List::empty(), DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)), // Nested opaque types only occur in associated types: // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; ` @@ -145,7 +145,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' | DefKind::Enum | DefKind::Variant | DefKind::Trait - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::TyParam diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 06a30677d20..38768f0a05b 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -53,7 +53,9 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { fn parent(&self) -> Option<LocalDefId> { match self.tcx.def_kind(self.item) { - DefKind::AnonConst | DefKind::InlineConst | DefKind::Fn | DefKind::TyAlias => None, + DefKind::AnonConst | DefKind::InlineConst | DefKind::Fn | DefKind::TyAlias { .. } => { + None + } DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { Some(self.tcx.local_parent(self.item)) } @@ -116,7 +118,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { #[instrument(level = "trace", skip(self))] fn visit_nested_item(&mut self, id: rustc_hir::ItemId) { let id = id.owner_id.def_id; - if let DefKind::TyAlias = self.collector.tcx.def_kind(id) { + if let DefKind::TyAlias { .. } = self.collector.tcx.def_kind(id) { let items = self.collector.tcx.opaque_types_defined_by(id); self.collector.opaques.extend(items); } @@ -295,7 +297,7 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ collector.collect_body_and_predicate_taits(); } // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds` - DefKind::TyAlias | DefKind::AssocTy => { + DefKind::TyAlias { .. } | DefKind::AssocTy => { tcx.type_of(item).instantiate_identity().visit_with(&mut collector); } DefKind::OpaqueTy => { diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 84977409904..921ce850d1e 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -223,8 +223,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "this is a string"; /// let boxed_str = s.to_owned().into_boxed_str(); @@ -487,8 +485,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let string = String::from("birthday gift"); /// let boxed_str = string.clone().into_boxed_str(); @@ -602,8 +598,6 @@ impl str { /// /// # Examples /// -/// Basic usage: -/// /// ``` /// let smile_utf8 = Box::new([226, 152, 186]); /// let smile = unsafe { std::str::from_boxed_utf8_unchecked(smile_utf8) }; diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 9254786d129..ed43244ebda 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -388,8 +388,6 @@ pub struct String { /// /// # Examples /// -/// Basic usage: -/// /// ``` /// // some invalid bytes, in a vector /// let bytes = vec![0, 159]; @@ -412,9 +410,8 @@ pub struct FromUtf8Error { /// This type is the error type for the [`from_utf16`] method on [`String`]. /// /// [`from_utf16`]: String::from_utf16 -/// # Examples /// -/// Basic usage: +/// # Examples /// /// ``` /// // 𝄞mu<invalid>ic @@ -441,8 +438,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = String::new(); /// ``` @@ -472,8 +467,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::with_capacity(10); /// @@ -661,8 +654,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // 𝄞music /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075, @@ -704,8 +695,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // 𝄞mus<invalid>ic<invalid> /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075, @@ -784,8 +773,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// use std::mem; /// @@ -827,8 +814,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // some bytes, in a vector /// let sparkle_heart = vec![240, 159, 146, 150]; @@ -852,8 +837,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = String::from("hello"); /// let bytes = s.into_bytes(); @@ -871,8 +854,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = String::from("foo"); /// @@ -889,8 +870,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::from("foobar"); /// let s_mut_str = s.as_mut_str(); @@ -910,8 +889,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::from("foo"); /// @@ -966,8 +943,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = String::with_capacity(10); /// @@ -1157,8 +1132,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::from("foo"); /// @@ -1206,8 +1179,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::from("abc"); /// @@ -1235,8 +1206,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = String::from("hello"); /// @@ -1263,8 +1232,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::from("hello"); /// @@ -1287,8 +1254,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::from("abč"); /// @@ -1321,8 +1286,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::from("abç"); /// @@ -1514,8 +1477,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::with_capacity(3); /// @@ -1563,8 +1524,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::from("bar"); /// @@ -1595,8 +1554,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::from("hello"); /// @@ -1620,8 +1577,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = String::from("foo"); /// assert_eq!(a.len(), 3); @@ -1641,8 +1596,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut v = String::new(); /// assert!(v.is_empty()); @@ -1697,8 +1650,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::from("foo"); /// @@ -1734,8 +1685,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::from("α is alpha, β is beta"); /// let beta_offset = s.find('β').unwrap_or(s.len()); @@ -1784,8 +1733,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = String::from("α is alpha, β is beta"); /// let beta_offset = s.find('β').unwrap_or(s.len()); @@ -1834,8 +1781,6 @@ impl String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = String::from("hello"); /// @@ -1866,8 +1811,6 @@ impl String { /// /// # Examples /// - /// Simple usage: - /// /// ``` /// let x = String::from("bucket"); /// let static_ref: &'static mut str = x.leak(); @@ -1886,8 +1829,6 @@ impl FromUtf8Error { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // some invalid bytes, in a vector /// let bytes = vec![0, 159]; @@ -1910,8 +1851,6 @@ impl FromUtf8Error { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // some invalid bytes, in a vector /// let bytes = vec![0, 159]; @@ -1938,8 +1877,6 @@ impl FromUtf8Error { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // some invalid bytes, in a vector /// let bytes = vec![0, 159]; @@ -2490,8 +2427,6 @@ pub trait ToString { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let i = 5; /// let five = String::from("5"); @@ -2711,8 +2646,6 @@ impl From<Box<str>> for String { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s1: String = String::from("hello world"); /// let s2: Box<str> = s1.into_boxed_str(); @@ -2732,8 +2665,6 @@ impl From<String> for Box<str> { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s1: String = String::from("hello world"); /// let s2: Box<str> = Box::from(s1); @@ -2866,8 +2797,6 @@ impl From<String> for Vec<u8> { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s1 = String::from("hello world"); /// let v1 = Vec::from(s1); diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index a6d6230d3a6..d7ca9c22dad 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -86,6 +86,46 @@ /// } /// ``` /// +/// If we `derive`: +/// +/// ``` +/// #[derive(Copy, Clone)] +/// struct Generate<T>(fn() -> T); +/// ``` +/// +/// the auto-derived implementations will have unnecessary `T: Copy` and `T: Clone` bounds: +/// +/// ``` +/// # struct Generate<T>(fn() -> T); +/// +/// // Automatically derived +/// impl<T: Copy> Copy for Generate<T> { } +/// +/// // Automatically derived +/// impl<T: Clone> Clone for Generate<T> { +/// fn clone(&self) -> Generate<T> { +/// Generate(Clone::clone(&self.0)) +/// } +/// } +/// ``` +/// +/// The bounds are unnecessary because clearly the function itself should be +/// copy- and cloneable even if its return type is not: +/// +/// ```compile_fail,E0599 +/// #[derive(Copy, Clone)] +/// struct Generate<T>(fn() -> T); +/// +/// struct NotCloneable; +/// +/// fn generate_not_cloneable() -> NotCloneable { +/// NotCloneable +/// } +/// +/// Generate(generate_not_cloneable).clone(); // error: trait bounds were not satisfied +/// // Note: With the manual implementations the above line will compile. +/// ``` +/// /// ## Additional implementors /// /// In addition to the [implementors listed below][impls], diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index d042aaf3084..9ef2c7cde02 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2385,6 +2385,25 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn raw_eq<T>(a: &T, b: &T) -> bool; + /// Lexicographically compare `[left, left + bytes)` and `[right, right + bytes)` + /// as unsigned bytes, returning negative if `left` is less, zero if all the + /// bytes match, or positive if `right` is greater. + /// + /// This underlies things like `<[u8]>::cmp`, and will usually lower to `memcmp`. + /// + /// # Safety + /// + /// `left` and `right` must each be [valid] for reads of `bytes` bytes. + /// + /// Note that this applies to the whole range, not just until the first byte + /// that differs. That allows optimizations that can read in large chunks. + /// + /// [valid]: crate::ptr#safety + #[cfg(not(bootstrap))] + #[rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none")] + #[rustc_nounwind] + pub fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32; + /// See documentation of [`std::hint::black_box`] for details. /// /// [`std::hint::black_box`]: crate::hint::black_box @@ -2825,3 +2844,18 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) { write_bytes(dst, val, count) } } + +/// Backfill for bootstrap +#[cfg(bootstrap)] +pub unsafe fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32 { + extern "C" { + fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> crate::ffi::c_int; + } + + if bytes != 0 { + // SAFETY: Since bytes is non-zero, the caller has met `memcmp`'s requirements. + unsafe { memcmp(left, right, bytes).into() } + } else { + 0 + } +} diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index de638552fa3..be04dfe042e 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -361,6 +361,12 @@ macro_rules! impl_fold_via_try_fold { (rfold -> try_rfold) => { impl_fold_via_try_fold! { @internal rfold -> try_rfold } }; + (spec_fold -> spec_try_fold) => { + impl_fold_via_try_fold! { @internal spec_fold -> spec_try_fold } + }; + (spec_rfold -> spec_try_rfold) => { + impl_fold_via_try_fold! { @internal spec_rfold -> spec_try_rfold } + }; (@internal $fold:ident -> $try_fold:ident) => { #[inline] fn $fold<AAA, FFF>(mut self, init: AAA, fold: FFF) -> AAA diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 182d9f758ad..4c8af4eba78 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -379,4 +379,66 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { fn nth_back(&mut self, n: usize) -> Option<I::Item> { (**self).nth_back(n) } + fn rfold<B, F>(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.spec_rfold(init, f) + } + fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + self.spec_try_rfold(init, f) + } +} + +/// Helper trait to specialize `rfold` and `rtry_fold` for `&mut I where I: Sized` +trait DoubleEndedIteratorRefSpec: DoubleEndedIterator { + fn spec_rfold<B, F>(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B; + + fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>; +} + +impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIteratorRefSpec for &mut I { + default fn spec_rfold<B, F>(self, init: B, mut f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + let mut accum = init; + while let Some(x) = self.next_back() { + accum = f(accum, x); + } + accum + } + + default fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + let mut accum = init; + while let Some(x) = self.next_back() { + accum = f(accum, x)?; + } + try { accum } + } +} + +impl<I: DoubleEndedIterator> DoubleEndedIteratorRefSpec for &mut I { + impl_fold_via_try_fold! { spec_rfold -> spec_try_rfold } + + fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + (**self).try_rfold(init, f) + } } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 98835228308..cecc120a6e2 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -4018,4 +4018,66 @@ impl<I: Iterator + ?Sized> Iterator for &mut I { fn nth(&mut self, n: usize) -> Option<Self::Item> { (**self).nth(n) } + fn fold<B, F>(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.spec_fold(init, f) + } + fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + self.spec_try_fold(init, f) + } +} + +/// Helper trait to specialize `fold` and `try_fold` for `&mut I where I: Sized` +trait IteratorRefSpec: Iterator { + fn spec_fold<B, F>(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B; + + fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>; +} + +impl<I: Iterator + ?Sized> IteratorRefSpec for &mut I { + default fn spec_fold<B, F>(self, init: B, mut f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x); + } + accum + } + + default fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x)?; + } + try { accum } + } +} + +impl<I: Iterator> IteratorRefSpec for &mut I { + impl_fold_via_try_fold! { spec_fold -> spec_try_fold } + + fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + (**self).try_fold(init, f) + } } diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 45e5b76272e..14cc523b0c1 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -312,7 +312,6 @@ macro_rules! debug_assert_ne { /// let c = Ok("abc".to_string()); /// debug_assert_matches!(c, Ok(x) | Err(x) if x.len() < 100); /// ``` -#[macro_export] #[unstable(feature = "assert_matches", issue = "82775")] #[allow_internal_unstable(assert_matches)] #[rustc_macro_transparency = "semitransparent"] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 1020e655579..becb6330997 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1698,6 +1698,41 @@ impl<T> Option<T> { mem::replace(self, None) } + /// Takes the value out of the option, but only if the predicate evaluates to + /// `true` on a mutable reference to the value. + /// + /// In other words, replaces `self` with `None` if the predicate returns `true`. + /// This method operates similar to [`Option::take`] but conditional. + /// + /// # Examples + /// + /// ``` + /// #![feature(option_take_if)] + /// + /// let mut x = Some(42); + /// + /// let prev = x.take_if(|v| if *v == 42 { + /// *v += 1; + /// false + /// } else { + /// false + /// }); + /// assert_eq!(x, Some(43)); + /// assert_eq!(prev, None); + /// + /// let prev = x.take_if(|v| *v == 43); + /// assert_eq!(x, None); + /// assert_eq!(prev, Some(43)); + /// ``` + #[inline] + #[unstable(feature = "option_take_if", issue = "98934")] + pub fn take_if<P>(&mut self, predicate: P) -> Option<T> + where + P: FnOnce(&mut T) -> bool, + { + if self.as_mut().map_or(false, predicate) { self.take() } else { None } + } + /// Replaces the actual value in the option by the value given in parameter, /// returning the old value if present, /// leaving a [`Some`] in its place without deinitializing either one. diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 7601dd3c756..075347b80d0 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -1,22 +1,12 @@ //! Comparison traits for `[T]`. use crate::cmp::{self, BytewiseEq, Ordering}; -use crate::ffi; +use crate::intrinsics::compare_bytes; use crate::mem; use super::from_raw_parts; use super::memchr; -extern "C" { - /// Calls implementation provided memcmp. - /// - /// Interprets the data as u8. - /// - /// Returns 0 for equal, < 0 for less than and > 0 for greater - /// than. - fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> ffi::c_int; -} - #[stable(feature = "rust1", since = "1.0.0")] impl<A, B> PartialEq<[B]> for [A] where @@ -74,7 +64,8 @@ where } } -// Use memcmp for bytewise equality when the types allow +// When each element can be compared byte-wise, we can compare all the bytes +// from the whole size in one call to the intrinsics. impl<A, B> SlicePartialEq<B> for [A] where A: BytewiseEq<B>, @@ -88,7 +79,7 @@ where // The two slices have been checked to have the same size above. unsafe { let size = mem::size_of_val(self); - memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 + compare_bytes(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 } } } @@ -183,7 +174,7 @@ impl<A: Ord> SliceOrd for A { } } -// memcmp compares a sequence of unsigned bytes lexicographically. +// `compare_bytes` compares a sequence of unsigned bytes lexicographically. // this matches the order we want for [u8], but no others (not even [i8]). impl SliceOrd for u8 { #[inline] @@ -195,7 +186,7 @@ impl SliceOrd for u8 { // SAFETY: `left` and `right` are references and are thus guaranteed to be valid. // We use the minimum of both lengths which guarantees that both regions are // valid for reads in that interval. - let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize }; + let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize }; if order == 0 { order = diff; } diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 2e5459321a2..009014de5c2 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -19,7 +19,7 @@ #![feature(panic_unwind)] #![feature(staged_api)] #![feature(std_internals)] -#![feature(abi_thiscall)] +#![cfg_attr(bootstrap, feature(abi_thiscall))] #![feature(rustc_attrs)] #![panic_runtime] #![feature(panic_runtime)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 2f9cd7bc0ca..31481de8495 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -298,6 +298,7 @@ #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_write_slice)] +#![feature(offset_of)] #![feature(panic_can_unwind)] #![feature(panic_info_message)] #![feature(panic_internals)] diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index fbc7f04ce9a..7dc809a038b 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -7,17 +7,6 @@ use crate::ffi::{CStr, OsStr, OsString}; use crate::fmt; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "solaris", - target_os = "fuchsia", - target_os = "redox", - target_os = "illumos", - target_os = "nto", - target_os = "vita", -))] -use crate::mem::MaybeUninit; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; use crate::path::{Path, PathBuf}; use crate::ptr; @@ -712,22 +701,10 @@ impl Iterator for ReadDir { // requires the full extent of *entry_ptr to be in bounds of the same // allocation, which is not necessarily the case here. // - // Absent any other way to obtain a pointer to `(*entry_ptr).d_name` - // legally in Rust analogously to how it would be done in C, we instead - // need to make our own non-libc allocation that conforms to the weird - // imaginary definition of dirent64, and use that for a field offset - // computation. + // Instead we must access fields individually through their offsets. macro_rules! offset_ptr { ($entry_ptr:expr, $field:ident) => {{ - const OFFSET: isize = { - let delusion = MaybeUninit::<dirent64>::uninit(); - let entry_ptr = delusion.as_ptr(); - unsafe { - ptr::addr_of!((*entry_ptr).$field) - .cast::<u8>() - .offset_from(entry_ptr.cast::<u8>()) - } - }; + const OFFSET: isize = mem::offset_of!(dirent64, $field) as isize; if true { // Cast to the same type determined by the else branch. $entry_ptr.byte_offset(OFFSET).cast::<_>() diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index a7beb2a1767..15e8c1eb9f8 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -180,7 +180,7 @@ def p(msg): def err(msg): - print("configure: error: " + msg) + print("\nconfigure: ERROR: " + msg + "\n") sys.exit(1) def is_value_list(key): @@ -544,7 +544,14 @@ def write_config_toml(writer, section_order, targets, sections): def quit_if_file_exists(file): if os.path.isfile(file): - err("Existing '" + file + "' detected.") + msg = "Existing '{}' detected. Exiting".format(file) + + # If the output object directory isn't empty, we can get these errors + host_objdir = os.environ.get("OBJDIR_ON_HOST") + if host_objdir is not None: + msg += "\nIs objdir '{}' clean?".format(host_objdir) + + err(msg) if __name__ == "__main__": # If 'config.toml' already exists, exit the script at this point diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index 0613b999793..14ee5659ed5 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -1159,8 +1159,8 @@ impl Step for CrtBeginEnd { return out_dir; } - let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtbegin.c"); - let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtend.c"); + let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/builtins/crtbegin.c"); + let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/builtins/crtend.c"); if up_to_date(&crtbegin_src, &out_dir.join("crtbegin.o")) && up_to_date(&crtend_src, &out_dir.join("crtendS.o")) { diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 852f2e20935..b83b198780b 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -14,7 +14,8 @@ for example: ./src/ci/docker/run.sh x86_64-gnu ``` -Images will output artifacts in an `obj` dir at the root of a repository. +Images will output artifacts in an `obj` dir at the root of a repository. Note +that the script will overwrite the contents of this directory. To match conditions in rusts CI, also set the environment variable `DEPLOY=1`, e.g.: ``` diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig index 10075907beb..470cef1a84e 100644 --- a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.defconfig @@ -10,7 +10,7 @@ CT_ARCH_64=y CT_ARCH_ARCH="rv64gc" CT_KERNEL_LINUX=y CT_LINUX_V_4_20=y -CT_BINUTILS_V_2_32=y +CT_BINUTILS_V_2_36=y CT_GLIBC_V_2_29=y CT_GCC_V_8=y CT_CC_LANG_CXX=y diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index 9bc074237e6..670e37b9d01 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -135,8 +135,8 @@ ENV TARGETS=$TARGETS,x86_64-unknown-uefi # As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211 # we need asm in the search path for gcc-9 (for gnux32) but not in the search path of the # cross compilers. -# Luckily one of the folders is /usr/local/include so symlink /usr/include/asm-generic there -RUN ln -s /usr/include/asm-generic /usr/local/include/asm +# Luckily one of the folders is /usr/local/include so symlink /usr/include/x86_64-linux-gnu/asm there +RUN ln -s /usr/include/x86_64-linux-gnu/asm /usr/local/include/asm ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs \ --set target.wasm32-wasi.wasi-root=/wasm32-wasi \ diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index da9d68672c4..87db964a15f 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -266,6 +266,7 @@ docker \ --env BASE_COMMIT="$BASE_COMMIT" \ --env DIST_TRY_BUILD \ --env PR_CI_JOB \ + --env OBJDIR_ON_HOST="$objdir" \ --init \ --rm \ rust-ci \ diff --git a/src/ci/run.sh b/src/ci/run.sh index da1960fc057..b8cb758bf40 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -8,7 +8,7 @@ fi if [ "$NO_CHANGE_USER" = "" ]; then if [ "$LOCAL_USER_ID" != "" ]; then - useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user + id -u user &>/dev/null || useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user export HOME=/home/user unset LOCAL_USER_ID @@ -154,13 +154,25 @@ fi # check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure # Pipelines it happened that the certificates were marked as expired. datecheck() { - echo "::group::Clock drift check" + # If an error has happened, we do not want to start a new group, because that will collapse + # a previous group that might have contained the error log. + exit_code=$? + + if [ $exit_code -eq 0 ] + then + echo "::group::Clock drift check" + fi + echo -n " local time: " date echo -n " network time: " curl -fs --head http://ci-caches.rust-lang.org | grep ^Date: \ | sed 's/Date: //g' || true - echo "::endgroup::" + + if [ $exit_code -eq 0 ] + then + echo "::endgroup::" + fi } datecheck trap datecheck EXIT @@ -171,6 +183,9 @@ trap datecheck EXIT # sccache server at the start of the build, but no need to worry if this fails. SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true +# Our build may overwrite config.toml, so we remove it here +rm -f config.toml + $SRC/configure $RUST_CONFIGURE_ARGS retry make prepare diff --git a/src/doc/unstable-book/src/language-features/abi-thiscall.md b/src/doc/unstable-book/src/language-features/abi-thiscall.md deleted file mode 100644 index 73bc6eacf42..00000000000 --- a/src/doc/unstable-book/src/language-features/abi-thiscall.md +++ /dev/null @@ -1,12 +0,0 @@ -# `abi_thiscall` - -The tracking issue for this feature is: [#42202] - -[#42202]: https://github.com/rust-lang/rust/issues/42202 - ------------------------- - -The MSVC ABI on x86 Windows uses the `thiscall` calling convention for C++ -instance methods by default; it is identical to the usual (C) calling -convention on x86 Windows except that the first parameter of the method, -the `this` pointer, is passed in the ECX register. diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index c31d104f8cb..384010034e6 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -79,7 +79,7 @@ pub(crate) fn try_inline( build_impls(cx, did, attrs_without_docs, &mut ret); clean::UnionItem(build_union(cx, did)) } - Res::Def(DefKind::TyAlias, did) => { + Res::Def(DefKind::TyAlias { .. }, did) => { record_extern_fqn(cx, did, ItemType::Typedef); build_impls(cx, did, attrs_without_docs, &mut ret); clean::TypedefItem(build_type_alias(cx, did)) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a5efcc989f6..b6ba4c853d4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1706,7 +1706,7 @@ fn maybe_expand_private_type_alias<'tcx>( cx: &mut DocContext<'tcx>, path: &hir::Path<'tcx>, ) -> Option<Type> { - let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None }; + let Res::Def(DefKind::TyAlias { .. }, def_id) = path.res else { return None }; // Substitute private type aliases let def_id = def_id.as_local()?; let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id()) @@ -1970,7 +1970,7 @@ impl<'tcx> ContainerTy<'tcx> { let (DefKind::Struct | DefKind::Union | DefKind::Enum - | DefKind::TyAlias + | DefKind::TyAlias { .. } | DefKind::Trait | DefKind::AssocTy | DefKind::Variant) = tcx.def_kind(container) @@ -2709,7 +2709,7 @@ fn clean_impl<'tcx>( let for_ = clean_ty(impl_.self_ty, cx); let type_alias = for_.def_id(&cx.cache).and_then(|alias_def_id: DefId| match tcx.def_kind(alias_def_id) { - DefKind::TyAlias => Some(clean_middle_ty( + DefKind::TyAlias { .. } => Some(clean_middle_ty( ty::Binder::dummy(tcx.type_of(def_id).instantiate_identity()), cx, Some(def_id.to_def_id()), diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 944d0145de2..3c79ce57782 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -504,8 +504,22 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId { let (kind, did) = match res { Res::Def( - kind @ (AssocTy | AssocFn | AssocConst | Variant | Fn | TyAlias | Enum | Trait | Struct - | Union | Mod | ForeignTy | Const | Static(_) | Macro(..) | TraitAlias), + kind @ (AssocTy + | AssocFn + | AssocConst + | Variant + | Fn + | TyAlias { .. } + | Enum + | Trait + | Struct + | Union + | Mod + | ForeignTy + | Const + | Static(_) + | Macro(..) + | TraitAlias), did, ) => (kind.into(), did), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 12d620b5b18..d7da8120996 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -10,6 +10,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{HirId, Path}; use rustc_interface::interface; +use rustc_lint::{late_lint_mod, MissingDoc}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks}; @@ -262,8 +263,9 @@ pub(crate) fn create_config( parse_sess_created: None, register_lints: Some(Box::new(crate::lint::register_lints)), override_queries: Some(|_sess, providers, _external_providers| { + // We do not register late module lints, so this only runs `MissingDoc`. // Most lints will require typechecking, so just don't run them. - providers.lint_mod = |_, _| {}; + providers.lint_mod = |tcx, module_def_id| late_lint_mod(tcx, module_def_id, MissingDoc); // hack so that `used_trait_imports` won't try to call typeck providers.used_trait_imports = |_, _| { static EMPTY_SET: LazyLock<UnordSet<LocalDefId>> = LazyLock::new(UnordSet::default); @@ -317,9 +319,7 @@ pub(crate) fn run_global_ctxt( tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) }); tcx.sess.abort_if_errors(); - tcx.sess.time("missing_docs", || { - rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new); - }); + tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx)); tcx.sess.time("check_mod_attrs", || { tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module)) }); diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index a3017201cb1..a788935581f 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -115,7 +115,7 @@ impl From<DefKind> for ItemType { DefKind::Struct => Self::Struct, DefKind::Union => Self::Union, DefKind::Trait => Self::Trait, - DefKind::TyAlias => Self::Typedef, + DefKind::TyAlias { .. } => Self::Typedef, DefKind::TraitAlias => Self::TraitAlias, DefKind::Macro(kind) => match kind { MacroKind::Bang => ItemType::Macro, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 4de30e4ed9d..1b8d999024c 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -592,7 +592,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .unwrap_or(Vec::new()) } } - Res::Def(DefKind::TyAlias, did) => { + Res::Def(DefKind::TyAlias { .. }, did) => { // Resolve the link on the type the alias points to. // FIXME: if the associated item is defined directly on the type alias, // it will show up on its documentation page, we should link there instead. @@ -1865,7 +1865,12 @@ fn resolution_failure( } return; } - Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam + Trait + | TyAlias { .. } + | ForeignTy + | OpaqueTy + | TraitAlias + | TyParam | Static(_) => "associated item", Impl { .. } | GlobalAsm => unreachable!("not a path"), } diff --git a/src/llvm-project b/src/llvm-project -Subproject a7d11c453784a3f258c7269b5108c58592d27e1 +Subproject 7c612e1732f3976fcfe29526ad796cbb6174b82 diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 137bd9c9451..bc011a6c354 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1170,7 +1170,7 @@ fn referent_used_exactly_once<'tcx>( && let [location] = *local_assignments(mir, local).as_slice() && let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index) && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind - && !place.has_deref() + && !place.is_indirect_first_projection() // Ensure not in a loop (https://github.com/rust-lang/rust-clippy/issues/9710) && TriColorDepthFirstSearch::new(&mir.basic_blocks).run_from(location.block, &mut CycleDetector).is_none() { diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs index f95d2c2edb1..b00fa104f98 100644 --- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs +++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs @@ -50,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields { && fields .iter() .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit)) - && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..)) + && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias { .. }, ..)) { let expr_spans = fields .iter() diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 4cd8a8c3325..171b7faf219 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -286,7 +286,7 @@ pub fn is_wild(pat: &Pat<'_>) -> bool { /// Checks if the given `QPath` belongs to a type alias. pub fn is_ty_alias(qpath: &QPath<'_>) -> bool { match *qpath { - QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias | DefKind::AssocTy, ..)), + QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias { .. } | DefKind::AssocTy, ..)), QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) }, _ => false, } diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index 0669ea72eb3..06fd9529044 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -219,7 +219,7 @@ fn path_segment_certainty( // See the comment preceding `qpath_certainty`. `def_id` could refer to a type or a value. let certainty = lhs.join_clearing_def_ids(rhs); if resolves_to_type { - if cx.tcx.def_kind(def_id) == DefKind::TyAlias { + if let DefKind::TyAlias { .. } = cx.tcx.def_kind(def_id) { adt_def_id(cx.tcx.type_of(def_id).instantiate_identity()) .map_or(certainty, |def_id| certainty.with_def_id(def_id)) } else { diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index d2f258320f0..ff1d5cecb72 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -29,7 +29,7 @@ anyhow = "1" libc = "0.2" [target.'cfg(windows)'.dependencies] -miow = "0.5" +miow = "0.6" [target.'cfg(windows)'.dependencies.windows] version = "0.48.0" diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index c8a370085a0..7f73cac63cb 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -368,7 +368,6 @@ impl Checker { return; } // Search for intra-doc links that rustdoc didn't warn about - // FIXME(#77199, 77200) Rustdoc should just warn about these directly. // NOTE: only looks at one line at a time; in practice this should find most links for (i, line) in source.lines().enumerate() { for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) { diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs index a6e67ef8699..fa93c9e00b1 100644 --- a/src/tools/miri/src/concurrency/vector_clock.rs +++ b/src/tools/miri/src/concurrency/vector_clock.rs @@ -9,7 +9,7 @@ use std::{ /// A vector clock index, this is associated with a thread id /// but in some cases one vector index may be shared with -/// multiple thread ids if it safe to do so. +/// multiple thread ids if it's safe to do so. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct VectorIdx(u32); diff --git a/src/tools/miri/tests/fail/uninit_buffer.stderr b/src/tools/miri/tests/fail/uninit_buffer.stderr index 8da532cfff0..90210bf7f11 100644 --- a/src/tools/miri/tests/fail/uninit_buffer.stderr +++ b/src/tools/miri/tests/fail/uninit_buffer.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory --> RUSTLIB/core/src/slice/cmp.rs:LL:CC | -LL | let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory +LL | let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/uninit_buffer_with_provenance.stderr b/src/tools/miri/tests/fail/uninit_buffer_with_provenance.stderr index 210fc8e109a..701ec601369 100644 --- a/src/tools/miri/tests/fail/uninit_buffer_with_provenance.stderr +++ b/src/tools/miri/tests/fail/uninit_buffer_with_provenance.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> RUSTLIB/core/src/slice/cmp.rs:LL:CC | -LL | let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory +LL | let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/opt-dist/src/environment/linux.rs b/src/tools/opt-dist/src/environment/linux.rs index c2a328b1dbc..58b7e6d2306 100644 --- a/src/tools/opt-dist/src/environment/linux.rs +++ b/src/tools/opt-dist/src/environment/linux.rs @@ -14,7 +14,7 @@ impl Environment for LinuxEnvironment { Utf8PathBuf::from("/checkout") } - fn downloaded_llvm_dir(&self) -> Utf8PathBuf { + fn host_llvm_dir(&self) -> Utf8PathBuf { Utf8PathBuf::from("/rustroot") } diff --git a/src/tools/opt-dist/src/environment/mod.rs b/src/tools/opt-dist/src/environment/mod.rs index d28983d289c..a8650fad011 100644 --- a/src/tools/opt-dist/src/environment/mod.rs +++ b/src/tools/opt-dist/src/environment/mod.rs @@ -15,8 +15,8 @@ pub trait Environment { /// The rustc checkout, where the compiler source is located. fn checkout_path(&self) -> Utf8PathBuf; - /// Path to the downloaded host LLVM. - fn downloaded_llvm_dir(&self) -> Utf8PathBuf; + /// Path to the host LLVM used to compile LLVM in `src/llvm-project`. + fn host_llvm_dir(&self) -> Utf8PathBuf; /// Directory where the optimization artifacts (PGO/BOLT profiles, etc.) /// will be stored. diff --git a/src/tools/opt-dist/src/environment/windows.rs b/src/tools/opt-dist/src/environment/windows.rs index 12a63cbb03c..8a9733d6496 100644 --- a/src/tools/opt-dist/src/environment/windows.rs +++ b/src/tools/opt-dist/src/environment/windows.rs @@ -24,7 +24,7 @@ impl Environment for WindowsEnvironment { self.checkout_dir.clone() } - fn downloaded_llvm_dir(&self) -> Utf8PathBuf { + fn host_llvm_dir(&self) -> Utf8PathBuf { self.checkout_path().join("citools").join("clang-rust") } diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs index a9e88bdbb60..59c73fbd695 100644 --- a/src/tools/opt-dist/src/training.rs +++ b/src/tools/opt-dist/src/training.rs @@ -66,20 +66,32 @@ fn init_compiler_benchmarks( .workdir(&env.rustc_perf_dir()) } +/// Describes which `llvm-profdata` binary should be used for merging PGO profiles. +enum LlvmProfdata { + /// Use llvm-profdata from the host toolchain (i.e. from LLVM provided externally). + Host, + /// Use llvm-profdata from the target toolchain (i.e. from LLVM built from `src/llvm-project`). + Target, +} + fn merge_llvm_profiles( env: &dyn Environment, merged_path: &Utf8Path, profile_dir: &Utf8Path, + profdata: LlvmProfdata, ) -> anyhow::Result<()> { - cmd(&[ - env.downloaded_llvm_dir().join("bin/llvm-profdata").as_str(), - "merge", - "-o", - merged_path.as_str(), - profile_dir.as_str(), - ]) - .run() - .context("Cannot merge LLVM profiles")?; + let llvm_profdata = match profdata { + LlvmProfdata::Host => env.host_llvm_dir().join("bin/llvm-profdata"), + LlvmProfdata::Target => env + .build_artifacts() + .join("llvm") + .join("build") + .join(format!("bin/llvm-profdata{}", env.executable_extension())), + }; + + cmd(&[llvm_profdata.as_str(), "merge", "-o", merged_path.as_str(), profile_dir.as_str()]) + .run() + .context("Cannot merge LLVM profiles")?; Ok(()) } @@ -118,7 +130,7 @@ pub fn gather_llvm_profiles( let merged_profile = env.opt_artifacts().join("llvm-pgo.profdata"); log::info!("Merging LLVM PGO profiles to {merged_profile}"); - merge_llvm_profiles(env, &merged_profile, profile_root)?; + merge_llvm_profiles(env, &merged_profile, profile_root, LlvmProfdata::Host)?; log_profile_stats("LLVM", &merged_profile, profile_root)?; // We don't need the individual .profraw files now that they have been merged @@ -154,7 +166,7 @@ pub fn gather_rustc_profiles( let merged_profile = env.opt_artifacts().join("rustc-pgo.profdata"); log::info!("Merging Rustc PGO profiles to {merged_profile}"); - merge_llvm_profiles(env, &merged_profile, profile_root)?; + merge_llvm_profiles(env, &merged_profile, profile_root, LlvmProfdata::Target)?; log_profile_stats("Rustc", &merged_profile, profile_root)?; // We don't need the individual .profraw files now that they have been merged diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index c29446d8235..fae07111806 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -485,6 +485,7 @@ impl AttrsWithOwner { }, AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it), AttrDefId::ExternCrateId(it) => attrs_from_item_tree_loc(db, it), + AttrDefId::UseId(it) => attrs_from_item_tree_loc(db, it), }; let attrs = raw_attrs.filter(db.upcast(), def.krate(db)); @@ -570,6 +571,7 @@ impl AttrsWithOwner { }, AttrDefId::ExternBlockId(id) => any_has_attrs(db, id), AttrDefId::ExternCrateId(id) => any_has_attrs(db, id), + AttrDefId::UseId(id) => any_has_attrs(db, id), }; AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs)) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index 152c02743f7..3853a6ab3a5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -313,13 +313,7 @@ impl ExprCollector<'_> { let body = self.collect_labelled_block_opt(label, e.loop_body()); self.alloc_expr(Expr::Loop { body, label }, syntax_ptr) } - ast::Expr::WhileExpr(e) => { - let label = e.label().map(|label| self.collect_label(label)); - let body = self.collect_labelled_block_opt(label, e.loop_body()); - let condition = self.collect_expr_opt(e.condition()); - - self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr) - } + ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e), ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e), ast::Expr::CallExpr(e) => { let is_rustc_box = { @@ -731,6 +725,32 @@ impl ExprCollector<'_> { expr_id } + /// Desugar `ast::WhileExpr` from: `[opt_ident]: while <cond> <body>` into: + /// ```ignore (pseudo-rust) + /// [opt_ident]: loop { + /// if <cond> { + /// <body> + /// } + /// else { + /// break; + /// } + /// } + /// ``` + /// FIXME: Rustc wraps the condition in a construct equivalent to `{ let _t = <cond>; _t }` + /// to preserve drop semantics. We should probably do the same in future. + fn collect_while_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::WhileExpr) -> ExprId { + let label = e.label().map(|label| self.collect_label(label)); + let body = self.collect_labelled_block_opt(label, e.loop_body()); + let condition = self.collect_expr_opt(e.condition()); + let break_expr = + self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr.clone()); + let if_expr = self.alloc_expr( + Expr::If { condition, then_branch: body, else_branch: Some(break_expr) }, + syntax_ptr.clone(), + ); + self.alloc_expr(Expr::Loop { body: if_expr, label }, syntax_ptr) + } + /// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into: /// ```ignore (pseudo-rust) /// match IntoIterator::into_iter(<head>) { @@ -893,15 +913,14 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) } - fn collect_macro_call<F, T, U>( + fn collect_macro_call<T, U>( &mut self, mcall: ast::MacroCall, syntax_ptr: AstPtr<ast::MacroCall>, record_diagnostics: bool, - collector: F, + collector: impl FnOnce(&mut Self, Option<T>) -> U, ) -> U where - F: FnOnce(&mut Self, Option<T>) -> U, T: ast::AstNode, { // File containing the macro call. Expansion errors will be attached here. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs index eeaed87164d..5d71abe37cc 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs @@ -178,14 +178,6 @@ impl Printer<'_> { w!(self, "loop "); self.print_expr(*body); } - Expr::While { condition, body, label } => { - if let Some(lbl) = label { - w!(self, "{}: ", self.body[*lbl].name.display(self.db)); - } - w!(self, "while "); - self.print_expr(*condition); - self.print_expr(*body); - } Expr::Call { callee, args, is_assignee_expr: _ } => { self.print_expr(*callee); w!(self, "("); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs index 69741c445fb..2a90a09f25e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs @@ -228,11 +228,6 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope scopes.set_scope(expr, scope); compute_block_scopes(statements, *tail, body, scopes, &mut scope); } - Expr::While { condition, body: body_expr, label } => { - let mut scope = scopes.new_labeled_scope(*scope, make_label(label)); - compute_expr_scopes(*condition, body, scopes, &mut scope); - compute_expr_scopes(*body_expr, body, scopes, &mut scope); - } Expr::Loop { body: body_expr, label } => { let mut scope = scopes.new_labeled_scope(*scope, make_label(label)); compute_expr_scopes(*body_expr, body, scopes, &mut scope); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs index bb79e28f267..4cfd318a433 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs @@ -14,8 +14,8 @@ use crate::{ item_scope::ItemScope, nameres::DefMap, src::{HasChildSource, HasSource}, - AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, FieldId, ImplId, Lookup, MacroId, - ModuleDefId, ModuleId, TraitId, VariantId, + AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FieldId, ImplId, + Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId, VariantId, }; pub trait ChildBySource { @@ -91,6 +91,8 @@ impl ChildBySource for ItemScope { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { self.declarations().for_each(|item| add_module_def(db, res, file_id, item)); self.impls().for_each(|imp| add_impl(db, res, file_id, imp)); + self.extern_crate_decls().for_each(|ext| add_extern_crate(db, res, file_id, ext)); + self.use_decls().for_each(|ext| add_use(db, res, file_id, ext)); self.unnamed_consts().for_each(|konst| { let loc = konst.lookup(db); if loc.id.file_id() == file_id { @@ -167,6 +169,23 @@ impl ChildBySource for ItemScope { map[keys::IMPL].insert(loc.source(db).value, imp) } } + fn add_extern_crate( + db: &dyn DefDatabase, + map: &mut DynMap, + file_id: HirFileId, + ext: ExternCrateId, + ) { + let loc = ext.lookup(db); + if loc.id.file_id() == file_id { + map[keys::EXTERN_CRATE].insert(loc.source(db).value, ext) + } + } + fn add_use(db: &dyn DefDatabase, map: &mut DynMap, file_id: HirFileId, ext: UseId) { + let loc = ext.lookup(db); + if loc.id.file_id() == file_id { + map[keys::USE].insert(loc.source(db).value, ext) + } + } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 54fe9a2e844..91db68058b0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -2,6 +2,7 @@ pub mod adt; +use base_db::CrateId; use hir_expand::{ name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind, }; @@ -467,6 +468,7 @@ pub struct ExternCrateDeclData { pub name: Name, pub alias: Option<ImportAlias>, pub visibility: RawVisibility, + pub crate_id: Option<CrateId>, } impl ExternCrateDeclData { @@ -478,10 +480,21 @@ impl ExternCrateDeclData { let item_tree = loc.id.item_tree(db); let extern_crate = &item_tree[loc.id.value]; + let name = extern_crate.name.clone(); + let crate_id = if name == hir_expand::name![self] { + Some(loc.container.krate()) + } else { + db.crate_def_map(loc.container.krate()) + .extern_prelude() + .find(|&(prelude_name, ..)| *prelude_name == name) + .map(|(_, root)| root.krate()) + }; + Arc::new(Self { name: extern_crate.name.clone(), visibility: item_tree[extern_crate.visibility].clone(), alias: extern_crate.alias.clone(), + crate_id, }) } } 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 82e6dfb30c8..e34a6768f28 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -23,17 +23,17 @@ use crate::{ visibility::{self, Visibility}, AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, - FunctionLoc, GenericDefId, ImplId, ImplLoc, ImportId, ImportLoc, InTypeConstId, InTypeConstLoc, - LocalEnumVariantId, LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, MacroRulesLoc, - ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, - TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, + FunctionLoc, GenericDefId, ImplId, ImplLoc, InTypeConstId, InTypeConstLoc, LocalEnumVariantId, + LocalFieldId, Macro2Id, Macro2Loc, MacroRulesId, MacroRulesLoc, ProcMacroId, ProcMacroLoc, + StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, + TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, }; #[salsa::query_group(InternDatabaseStorage)] pub trait InternDatabase: SourceDatabase { // region: items #[salsa::interned] - fn intern_import(&self, loc: ImportLoc) -> ImportId; + fn intern_use(&self, loc: UseLoc) -> UseId; #[salsa::interned] fn intern_extern_crate(&self, loc: ExternCrateLoc) -> ExternCrateId; #[salsa::interned] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs index 4197d010608..d0f2bfab432 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs @@ -10,7 +10,7 @@ use crate::{ dyn_map::{DynMap, Policy}, ConstId, EnumId, EnumVariantId, ExternCrateId, FieldId, FunctionId, ImplId, LifetimeParamId, Macro2Id, MacroRulesId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, - TypeOrConstParamId, UnionId, + TypeOrConstParamId, UnionId, UseId, }; pub type Key<K, V> = crate::dyn_map::Key<K, V, AstPtrPolicy<K, V>>; @@ -26,6 +26,7 @@ pub const STRUCT: Key<ast::Struct, StructId> = Key::new(); pub const UNION: Key<ast::Union, UnionId> = Key::new(); pub const ENUM: Key<ast::Enum, EnumId> = Key::new(); pub const EXTERN_CRATE: Key<ast::ExternCrate, ExternCrateId> = Key::new(); +pub const USE: Key<ast::Use, UseId> = Key::new(); pub const VARIANT: Key<ast::Variant, EnumVariantId> = Key::new(); pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs index cc85bd893ac..6db8398bc98 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs @@ -164,18 +164,26 @@ impl Expander { return ExpandResult { value: None, err }; }; - Self::enter_expand_inner(db, call_id, err).map(|value| { - value.and_then(|InFile { file_id, value }| { - let parse = value.cast::<T>()?; - - self.recursion_depth += 1; - self.hygiene = Hygiene::new(db.upcast(), file_id); - let old_file_id = std::mem::replace(&mut self.current_file_id, file_id); - let mark = - Mark { file_id: old_file_id, bomb: DropBomb::new("expansion mark dropped") }; - Some((mark, parse)) - }) - }) + let res = Self::enter_expand_inner(db, call_id, err); + match res.err { + // If proc-macro is disabled or unresolved, we want to expand to a missing expression + // instead of an empty tree which might end up in an empty block. + Some(ExpandError::UnresolvedProcMacro(_)) => res.map(|_| None), + _ => res.map(|value| { + value.and_then(|InFile { file_id, value }| { + let parse = value.cast::<T>()?; + + self.recursion_depth += 1; + self.hygiene = Hygiene::new(db.upcast(), file_id); + let old_file_id = std::mem::replace(&mut self.current_file_id, file_id); + let mark = Mark { + file_id: old_file_id, + bomb: DropBomb::new("expansion mark dropped"), + }; + Some((mark, parse)) + }) + }), + } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index 8a140a1ec18..6591c92ac62 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -191,11 +191,6 @@ pub enum Expr { body: ExprId, label: Option<LabelId>, }, - While { - condition: ExprId, - body: ExprId, - label: Option<LabelId>, - }, Call { callee: ExprId, args: Box<[ExprId]>, @@ -379,10 +374,6 @@ impl Expr { } } Expr::Loop { body, .. } => f(*body), - Expr::While { condition, body, .. } => { - f(*condition); - f(*body); - } Expr::Call { callee, args, .. } => { f(*callee); args.iter().copied().for_each(f); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index 2ac1bcdc079..873accafb43 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -16,6 +16,7 @@ use syntax::ast; use crate::{ db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ExternCrateId, HasModule, ImplId, LocalModuleId, MacroId, ModuleDefId, ModuleId, TraitId, + UseId, }; #[derive(Copy, Clone, Debug)] @@ -113,6 +114,17 @@ impl ItemScope { self.declarations.iter().copied() } + pub fn extern_crate_decls( + &self, + ) -> impl Iterator<Item = ExternCrateId> + ExactSizeIterator + '_ { + self.extern_crate_decls.iter().copied() + } + + pub fn use_decls(&self) -> impl Iterator<Item = UseId> + ExactSizeIterator + '_ { + // FIXME: to be implemented + std::iter::empty() + } + pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ { self.impls.iter().copied() } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index 6f80bb6e07c..c9b0f75f1a8 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -188,7 +188,7 @@ impl ItemTree { fn shrink_to_fit(&mut self) { if let Some(data) = &mut self.data { let ItemTreeData { - imports, + uses, extern_crates, extern_blocks, functions, @@ -211,7 +211,7 @@ impl ItemTree { vis, } = &mut **data; - imports.shrink_to_fit(); + uses.shrink_to_fit(); extern_crates.shrink_to_fit(); extern_blocks.shrink_to_fit(); functions.shrink_to_fit(); @@ -262,7 +262,7 @@ static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(P #[derive(Default, Debug, Eq, PartialEq)] struct ItemTreeData { - imports: Arena<Import>, + uses: Arena<Use>, extern_crates: Arena<ExternCrate>, extern_blocks: Arena<ExternBlock>, functions: Arena<Function>, @@ -486,7 +486,7 @@ macro_rules! mod_items { } mod_items! { - Import in imports -> ast::Use, + Use in uses -> ast::Use, ExternCrate in extern_crates -> ast::ExternCrate, ExternBlock in extern_blocks -> ast::ExternBlock, Function in functions -> ast::Fn, @@ -541,7 +541,7 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { } #[derive(Debug, Clone, Eq, PartialEq)] -pub struct Import { +pub struct Use { pub visibility: RawVisibilityId, pub ast_id: FileAstId<ast::Use>, pub use_tree: UseTree, @@ -744,7 +744,7 @@ pub struct MacroDef { pub ast_id: FileAstId<ast::MacroDef>, } -impl Import { +impl Use { /// Maps a `UseTree` contained in this import back to its AST node. pub fn use_tree_to_ast( &self, @@ -870,7 +870,7 @@ macro_rules! impl_froms { impl ModItem { pub fn as_assoc_item(&self) -> Option<AssocItem> { match self { - ModItem::Import(_) + ModItem::Use(_) | ModItem::ExternCrate(_) | ModItem::ExternBlock(_) | ModItem::Struct(_) @@ -892,7 +892,7 @@ impl ModItem { pub fn ast_id(&self, tree: &ItemTree) -> FileAstId<ast::Item> { match self { - ModItem::Import(it) => tree[it.index].ast_id().upcast(), + ModItem::Use(it) => tree[it.index].ast_id().upcast(), ModItem::ExternCrate(it) => tree[it.index].ast_id().upcast(), ModItem::ExternBlock(it) => tree[it.index].ast_id().upcast(), ModItem::Function(it) => tree[it.index].ast_id().upcast(), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index 46633667ed3..7b898e62dba 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -502,13 +502,13 @@ impl<'a> Ctx<'a> { Some(id(self.data().impls.alloc(res))) } - fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Import>> { + fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> { let visibility = self.lower_visibility(use_item); let ast_id = self.source_ast_id_map.ast_id(use_item); let (use_tree, _) = lower_use_tree(self.db, self.hygiene(), use_item.use_tree()?)?; - let res = Import { visibility, ast_id, use_tree }; - Some(id(self.data().imports.alloc(res))) + let res = Use { visibility, ast_id, use_tree }; + Some(id(self.data().uses.alloc(res))) } fn lower_extern_crate( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index ddf668d20b0..da30830fe45 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -198,8 +198,8 @@ impl Printer<'_> { self.print_attrs_of(item); match item { - ModItem::Import(it) => { - let Import { visibility, use_tree, ast_id: _ } = &self.tree[it]; + ModItem::Use(it) => { + let Use { visibility, use_tree, ast_id: _ } = &self.tree[it]; self.print_visibility(*visibility); w!(self, "use "); self.print_use_tree(use_tree); 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 1e74e2dfcb4..1901db8a0f9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -88,8 +88,8 @@ use crate::{ builtin_type::BuiltinType, data::adt::VariantData, item_tree::{ - Const, Enum, ExternCrate, Function, Impl, Import, ItemTreeId, ItemTreeNode, MacroDef, - MacroRules, Static, Struct, Trait, TraitAlias, TypeAlias, Union, + Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, MacroDef, MacroRules, + Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, }, }; @@ -121,6 +121,12 @@ impl From<CrateRootModuleId> for ModuleDefId { } } +impl From<CrateId> for CrateRootModuleId { + fn from(krate: CrateId) -> Self { + CrateRootModuleId { krate } + } +} + impl TryFrom<ModuleId> for CrateRootModuleId { type Error = (); @@ -318,9 +324,9 @@ type ImplLoc = ItemLoc<Impl>; impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub struct ImportId(salsa::InternId); -type ImportLoc = ItemLoc<Import>; -impl_intern!(ImportId, ImportLoc, intern_import, lookup_intern_import); +pub struct UseId(salsa::InternId); +type UseLoc = ItemLoc<Use>; +impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct ExternCrateId(salsa::InternId); @@ -836,6 +842,7 @@ pub enum AttrDefId { GenericParamId(GenericParamId), ExternBlockId(ExternBlockId), ExternCrateId(ExternCrateId), + UseId(UseId), } impl_from!( @@ -1073,6 +1080,7 @@ impl AttrDefId { } AttrDefId::MacroId(it) => it.module(db).krate, AttrDefId::ExternCrateId(it) => it.lookup(db).container.krate, + AttrDefId::UseId(it) => it.lookup(db).container.krate, } } } @@ -1083,7 +1091,7 @@ pub trait AsMacroCall { &self, db: &dyn ExpandDatabase, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, + resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy, ) -> Option<MacroCallId> { self.as_call_id_with_errors(db, krate, resolver).ok()?.value } @@ -1092,7 +1100,7 @@ pub trait AsMacroCall { &self, db: &dyn ExpandDatabase, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, + resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy, ) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro>; } @@ -1101,7 +1109,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> { &self, db: &dyn ExpandDatabase, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, + resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy, ) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> { let expands_to = hir_expand::ExpandTo::from_call_site(self.value); let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); @@ -1112,12 +1120,13 @@ impl AsMacroCall for InFile<&ast::MacroCall> { return Ok(ExpandResult::only_err(ExpandError::other("malformed macro invocation"))); }; - macro_call_as_call_id_( + macro_call_as_call_id_with_eager( db, &AstIdWithPath::new(ast_id.file_id, ast_id.value, path), expands_to, krate, resolver, + resolver, ) } } @@ -1140,33 +1149,39 @@ fn macro_call_as_call_id( call: &AstIdWithPath<ast::MacroCall>, expand_to: ExpandTo, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, + resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy, ) -> Result<Option<MacroCallId>, UnresolvedMacro> { - macro_call_as_call_id_(db, call, expand_to, krate, resolver).map(|res| res.value) + macro_call_as_call_id_with_eager(db, call, expand_to, krate, resolver, resolver) + .map(|res| res.value) } -fn macro_call_as_call_id_( +fn macro_call_as_call_id_with_eager( db: &dyn ExpandDatabase, call: &AstIdWithPath<ast::MacroCall>, expand_to: ExpandTo, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, + resolver: impl FnOnce(path::ModPath) -> Option<MacroDefId>, + eager_resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, ) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> { let def = resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?; - let res = if let MacroDefKind::BuiltInEager(..) = def.kind { - let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db)); - expand_eager_macro_input(db, krate, macro_call, def, &resolver)? - } else { - ExpandResult { + let res = match def.kind { + MacroDefKind::BuiltInEager(..) => { + let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db)); + expand_eager_macro_input(db, krate, macro_call, def, &|path| { + eager_resolver(path).filter(MacroDefId::is_fn_like) + }) + } + _ if def.is_fn_like() => ExpandResult { value: Some(def.as_lazy_macro( db, krate, MacroCallKind::FnLike { ast_id: call.ast_id, expand_to }, )), err: None, - } + }, + _ => return Err(UnresolvedMacro { path: call.path.clone() }), }; Ok(res) } @@ -1251,6 +1266,7 @@ fn derive_macro_as_call_id( resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>, ) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> { let (macro_id, def_id) = resolver(item_attr.path.clone()) + .filter(|(_, def_id)| def_id.is_derive()) .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?; let call_id = def_id.as_lazy_macro( db.upcast(), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index b232651db96..1250cbb742c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -238,7 +238,7 @@ fn main() { /* error: expected expression */; /* error: expected expression, expected COMMA */; /* error: expected expression */::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(), ::core::fmt::Display::fmt), ]); - /* error: expected expression, expected R_PAREN */; + /* error: expected expression, expected expression */; ::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(5), ::core::fmt::Display::fmt), ]); } "##]], diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index b26f9867580..2170cadcf83 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -100,6 +100,30 @@ fn#19 main#20(#21)#21 {#22 } #[test] +fn eager_expands_with_unresolved_within() { + check( + r#" +#[rustc_builtin_macro] +#[macro_export] +macro_rules! format_args {} + +fn main(foo: ()) { + format_args!("{} {} {}", format_args!("{}", 0), foo, identity!(10), "bar") +} +"#, + expect![[r##" +#[rustc_builtin_macro] +#[macro_export] +macro_rules! format_args {} + +fn main(foo: ()) { + /* error: unresolved macro identity */::core::fmt::Arguments::new_v1(&["", " ", " ", ], &[::core::fmt::ArgumentV1::new(&(::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(0), ::core::fmt::Display::fmt), ])), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(foo), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(identity!(10)), ::core::fmt::Display::fmt), ]) +} +"##]], + ); +} + +#[test] fn token_mapping_eager() { check( r#" @@ -849,6 +873,37 @@ fn foo() { } #[test] +fn test_type_path_is_transcribed_as_expr_path() { + check( + r#" +macro_rules! m { + ($p:path) => { let $p; } +} +fn test() { + m!(S) + m!(S<i32>) + m!(S<S<i32>>) + m!(S<{ module::CONST < 42 }>) +} +"#, + expect![[r#" +macro_rules! m { + ($p:path) => { let $p; } +} +fn test() { + let S; + let S:: <i32> ; + let S:: <S:: <i32>> ; + let S:: < { + module::CONST<42 + } + > ; +} +"#]], + ); +} + +#[test] fn test_expr() { check( r#" 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 c048716d740..eef54fc492e 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 @@ -38,7 +38,7 @@ use crate::{ self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, MacroCall, MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId, }, - macro_call_as_call_id, macro_id_to_def_id, + macro_call_as_call_id, macro_call_as_call_id_with_eager, macro_id_to_def_id, nameres::{ diagnostics::DefDiagnostic, mod_resolution::ModDir, @@ -52,10 +52,10 @@ use crate::{ tt, visibility::{RawVisibility, Visibility}, AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId, - ExternBlockLoc, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, ImportLoc, Intern, - ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, - MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, - TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, + ExternBlockLoc, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId, + LocalModuleId, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, + ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc, + TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseLoc, }; static GLOB_RECURSION_LIMIT: Limit = Limit::new(100); @@ -146,7 +146,7 @@ impl PartialResolvedImport { #[derive(Clone, Debug, Eq, PartialEq)] enum ImportSource { - Import { id: ItemTreeId<item_tree::Import>, use_tree: Idx<ast::UseTree> }, + Use { id: ItemTreeId<item_tree::Use>, use_tree: Idx<ast::UseTree> }, ExternCrate(ItemTreeId<item_tree::ExternCrate>), } @@ -166,7 +166,7 @@ impl Import { db: &dyn DefDatabase, krate: CrateId, tree: &ItemTree, - id: ItemTreeId<item_tree::Import>, + id: ItemTreeId<item_tree::Use>, mut cb: impl FnMut(Self), ) { let it = &tree[id.value]; @@ -181,7 +181,7 @@ impl Import { kind, is_prelude, is_macro_use: false, - source: ImportSource::Import { id, use_tree: idx }, + source: ImportSource::Use { id, use_tree: idx }, }); }); } @@ -1474,7 +1474,7 @@ impl DefCollector<'_> { } for directive in &self.unresolved_imports { - if let ImportSource::Import { id: import, use_tree } = directive.import.source { + if let ImportSource::Use { id: import, use_tree } = directive.import.source { if matches!( (directive.import.path.segments().first(), &directive.import.path.kind), (Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate) @@ -1576,12 +1576,10 @@ impl ModCollector<'_, '_> { match item { ModItem::Mod(m) => self.collect_module(m, &attrs), - ModItem::Import(import_id) => { - let _import_id = ImportLoc { - container: module, - id: ItemTreeId::new(self.tree_id, import_id), - } - .intern(db); + ModItem::Use(import_id) => { + let _import_id = + UseLoc { container: module, id: ItemTreeId::new(self.tree_id, import_id) } + .intern(db); Import::from_use( db, krate, @@ -2187,7 +2185,7 @@ impl ModCollector<'_, '_> { // scopes without eager expansion. // Case 1: try to resolve macro calls with single-segment name and expand macro_rules - if let Ok(res) = macro_call_as_call_id( + if let Ok(res) = macro_call_as_call_id_with_eager( db.upcast(), &ast_id, mac.expand_to, @@ -2210,19 +2208,34 @@ impl ModCollector<'_, '_> { .map(|it| macro_id_to_def_id(self.def_collector.db, it)) }) }, - ) { - // Legacy macros need to be expanded immediately, so that any macros they produce - // are in scope. - if let Some(val) = res { - self.def_collector.collect_macro_expansion( + |path| { + let resolved_res = self.def_collector.def_map.resolve_path_fp_with_macro( + db, + ResolveMode::Other, self.module_id, - val, - self.macro_depth + 1, - container, + &path, + BuiltinShadowMode::Module, + Some(MacroSubNs::Bang), ); - } + resolved_res.resolved_def.take_macros().map(|it| macro_id_to_def_id(db, it)) + }, + ) { + // FIXME: if there were errors, this mightve been in the eager expansion from an + // unresolved macro, so we need to push this into late macro resolution. see fixme above + if res.err.is_none() { + // Legacy macros need to be expanded immediately, so that any macros they produce + // are in scope. + if let Some(val) = res.value { + self.def_collector.collect_macro_expansion( + self.module_id, + val, + self.macro_depth + 1, + container, + ); + } - return; + return; + } } // Case 2: resolve in module scope, expand during name resolution. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs index e82e97b628e..9cffb3c9f37 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs @@ -19,7 +19,7 @@ pub enum DefDiagnosticKind { UnresolvedExternCrate { ast: AstId<ast::ExternCrate> }, - UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> }, + UnresolvedImport { id: ItemTreeId<item_tree::Use>, index: Idx<ast::UseTree> }, UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions }, @@ -70,7 +70,7 @@ impl DefDiagnostic { pub(super) fn unresolved_import( container: LocalModuleId, - id: ItemTreeId<item_tree::Import>, + id: ItemTreeId<item_tree::Use>, index: Idx<ast::UseTree>, ) -> Self { Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs index 4931c36bbca..40d3a16540d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs @@ -213,17 +213,17 @@ pub type Ty = (); for (_, res) in module_data.scope.resolutions() { match res.values.or(res.types).unwrap().0 { - ModuleDefId::FunctionId(f) => drop(db.function_data(f)), + ModuleDefId::FunctionId(f) => _ = db.function_data(f), ModuleDefId::AdtId(adt) => match adt { - AdtId::StructId(it) => drop(db.struct_data(it)), - AdtId::UnionId(it) => drop(db.union_data(it)), - AdtId::EnumId(it) => drop(db.enum_data(it)), + AdtId::StructId(it) => _ = db.struct_data(it), + AdtId::UnionId(it) => _ = db.union_data(it), + AdtId::EnumId(it) => _ = db.enum_data(it), }, - ModuleDefId::ConstId(it) => drop(db.const_data(it)), - ModuleDefId::StaticId(it) => drop(db.static_data(it)), - ModuleDefId::TraitId(it) => drop(db.trait_data(it)), - ModuleDefId::TraitAliasId(it) => drop(db.trait_alias_data(it)), - ModuleDefId::TypeAliasId(it) => drop(db.type_alias_data(it)), + ModuleDefId::ConstId(it) => _ = db.const_data(it), + ModuleDefId::StaticId(it) => _ = db.static_data(it), + ModuleDefId::TraitId(it) => _ = db.trait_data(it), + ModuleDefId::TraitAliasId(it) => _ = db.trait_alias_data(it), + ModuleDefId::TypeAliasId(it) => _ = db.type_alias_data(it), ModuleDefId::EnumVariantId(_) | ModuleDefId::ModuleId(_) | ModuleDefId::MacroId(_) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 10f5702845e..b112c1070d4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -25,7 +25,7 @@ use crate::{ EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, - TypeAliasId, TypeOrConstParamId, TypeOwnerId, TypeParamId, VariantId, + TypeAliasId, TypeOrConstParamId, TypeOwnerId, TypeParamId, UseId, VariantId, }; #[derive(Debug, Clone)] @@ -1024,6 +1024,12 @@ impl HasResolver for ExternCrateId { } } +impl HasResolver for UseId { + fn resolver(self, db: &dyn DefDatabase) -> Resolver { + self.lookup(db).container.resolver(db) + } +} + impl HasResolver for TypeOwnerId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { match self { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 309c0930d1a..5292a5fa1b1 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -430,14 +430,13 @@ fn macro_arg_node( let loc = db.lookup_intern_macro_call(id); let arg = if let MacroDefKind::BuiltInEager(..) = loc.def.kind { let res = if let Some(EagerCallInfo { arg, .. }) = loc.eager.as_deref() { - Some(mbe::token_tree_to_syntax_node(&arg.0, mbe::TopEntryPoint::Expr).0) + Some(mbe::token_tree_to_syntax_node(&arg.0, mbe::TopEntryPoint::MacroEagerInput).0) } else { loc.kind .arg(db) .and_then(|arg| ast::TokenTree::cast(arg.value)) - .map(|tt| tt.reparse_as_expr().to_syntax()) + .map(|tt| tt.reparse_as_comma_separated_expr().to_syntax()) }; - match res { Some(res) if res.errors().is_empty() => res.syntax_node(), Some(res) => { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs index 876813eab5d..4110f284759 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs @@ -19,7 +19,7 @@ //! //! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros> use base_db::CrateId; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use syntax::{ted, Parse, SyntaxNode, TextRange, TextSize, WalkEvent}; use triomphe::Arc; @@ -29,7 +29,7 @@ use crate::{ hygiene::Hygiene, mod_path::ModPath, EagerCallInfo, ExpandError, ExpandResult, ExpandTo, InFile, MacroCallId, MacroCallKind, - MacroCallLoc, MacroDefId, MacroDefKind, UnresolvedMacro, + MacroCallLoc, MacroDefId, MacroDefKind, }; pub fn expand_eager_macro_input( @@ -38,7 +38,7 @@ pub fn expand_eager_macro_input( macro_call: InFile<ast::MacroCall>, def: MacroDefId, resolver: &dyn Fn(ModPath) -> Option<MacroDefId>, -) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> { +) -> ExpandResult<Option<MacroCallId>> { let ast_map = db.ast_id_map(macro_call.file_id); // the expansion which the ast id map is built upon has no whitespace, so the offsets are wrong as macro_call is from the token tree that has whitespace! let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(¯o_call.value)); @@ -71,41 +71,46 @@ pub fn expand_eager_macro_input( InFile::new(arg_id.as_file(), arg_exp.syntax_node()), krate, resolver, - )? + ) }; let err = parse_err.or(err); let Some((expanded_eager_input, mapping)) = expanded_eager_input else { - return Ok(ExpandResult { value: None, err }); + return ExpandResult { value: None, err }; }; - let og_tmap = mbe::syntax_node_to_token_map( - macro_call.value.token_tree().expect("macro_arg_text succeeded").syntax(), - ); - let (mut subtree, expanded_eager_input_token_map) = mbe::syntax_node_to_token_tree(&expanded_eager_input); - // The tokenmap and ids of subtree point into the expanded syntax node, but that is inaccessible from the outside - // so we need to remap them to the original input of the eager macro. - subtree.visit_ids(&|id| { - // Note: we discard all token ids of braces and the like here, but that's not too bad and only a temporary fix + let og_tmap = if let Some(tt) = macro_call.value.token_tree() { + let mut ids_used = FxHashSet::default(); + let mut og_tmap = mbe::syntax_node_to_token_map(tt.syntax()); + // The tokenmap and ids of subtree point into the expanded syntax node, but that is inaccessible from the outside + // so we need to remap them to the original input of the eager macro. + subtree.visit_ids(&mut |id| { + // Note: we discard all token ids of braces and the like here, but that's not too bad and only a temporary fix - if let Some(range) = - expanded_eager_input_token_map.first_range_by_token(id, syntax::SyntaxKind::TOMBSTONE) - { - // remap from expanded eager input to eager input expansion - if let Some(og_range) = mapping.get(&range) { - // remap from eager input expansion to original eager input - if let Some(&og_range) = ws_mapping.get(og_range) { - if let Some(og_token) = og_tmap.token_by_range(og_range) { - return og_token; + if let Some(range) = expanded_eager_input_token_map + .first_range_by_token(id, syntax::SyntaxKind::TOMBSTONE) + { + // remap from expanded eager input to eager input expansion + if let Some(og_range) = mapping.get(&range) { + // remap from eager input expansion to original eager input + if let Some(&og_range) = ws_mapping.get(og_range) { + if let Some(og_token) = og_tmap.token_by_range(og_range) { + ids_used.insert(og_token); + return og_token; + } } } } - } - tt::TokenId::UNSPECIFIED - }); + tt::TokenId::UNSPECIFIED + }); + og_tmap.filter(|id| ids_used.contains(&id)); + og_tmap + } else { + Default::default() + }; subtree.delimiter = crate::tt::Delimiter::unspecified(); let loc = MacroCallLoc { @@ -119,7 +124,7 @@ pub fn expand_eager_macro_input( kind: MacroCallKind::FnLike { ast_id: call_id, expand_to }, }; - Ok(ExpandResult { value: Some(db.intern_macro_call(loc)), err }) + ExpandResult { value: Some(db.intern_macro_call(loc)), err } } fn lazy_expand( @@ -145,13 +150,13 @@ fn eager_macro_recur( curr: InFile<SyntaxNode>, krate: CrateId, macro_resolver: &dyn Fn(ModPath) -> Option<MacroDefId>, -) -> Result<ExpandResult<Option<(SyntaxNode, FxHashMap<TextRange, TextRange>)>>, UnresolvedMacro> { +) -> ExpandResult<Option<(SyntaxNode, FxHashMap<TextRange, TextRange>)>> { let original = curr.value.clone_for_update(); let mut mapping = FxHashMap::default(); let mut replacements = Vec::new(); - // Note: We only report a single error inside of eager expansions + // FIXME: We only report a single error inside of eager expansions let mut error = None; let mut offset = 0i32; let apply_offset = |it: TextSize, offset: i32| { @@ -182,7 +187,14 @@ fn eager_macro_recur( } }; let def = match call.path().and_then(|path| ModPath::from_src(db, path, hygiene)) { - Some(path) => macro_resolver(path.clone()).ok_or(UnresolvedMacro { path })?, + Some(path) => match macro_resolver(path.clone()) { + Some(def) => def, + None => { + error = + Some(ExpandError::other(format!("unresolved macro {}", path.display(db)))); + continue; + } + }, None => { error = Some(ExpandError::other("malformed macro invocation")); continue; @@ -190,32 +202,31 @@ fn eager_macro_recur( }; let ExpandResult { value, err } = match def.kind { MacroDefKind::BuiltInEager(..) => { - let ExpandResult { value, err } = match expand_eager_macro_input( + let ExpandResult { value, err } = expand_eager_macro_input( db, krate, curr.with_value(call.clone()), def, macro_resolver, - ) { - Ok(it) => it, - Err(err) => return Err(err), - }; + ); match value { Some(call_id) => { let ExpandResult { value, err: err2 } = db.parse_macro_expansion(call_id.as_macro_file()); - let call_tt_start = - call.token_tree().unwrap().syntax().text_range().start(); - let call_start = apply_offset(call.syntax().text_range().start(), offset); - if let Some((_, arg_map, _)) = db.macro_arg(call_id).value.as_deref() { - mapping.extend(arg_map.entries().filter_map(|(tid, range)| { - value - .1 - .first_range_by_token(tid, syntax::SyntaxKind::TOMBSTONE) - .map(|r| (r + call_start, range + call_tt_start)) - })); - }; + if let Some(tt) = call.token_tree() { + let call_tt_start = tt.syntax().text_range().start(); + let call_start = + apply_offset(call.syntax().text_range().start(), offset); + if let Some((_, arg_map, _)) = db.macro_arg(call_id).value.as_deref() { + mapping.extend(arg_map.entries().filter_map(|(tid, range)| { + value + .1 + .first_range_by_token(tid, syntax::SyntaxKind::TOMBSTONE) + .map(|r| (r + call_start, range + call_tt_start)) + })); + } + } ExpandResult { value: Some(value.0.syntax_node().clone_for_update()), @@ -247,25 +258,27 @@ fn eager_macro_recur( parse.as_ref().map(|it| it.syntax_node()), krate, macro_resolver, - )?; + ); let err = err.or(error); - let call_tt_start = call.token_tree().unwrap().syntax().text_range().start(); - let call_start = apply_offset(call.syntax().text_range().start(), offset); - if let Some((_tt, arg_map, _)) = parse - .file_id - .macro_file() - .and_then(|id| db.macro_arg(id.macro_call_id).value) - .as_deref() - { - mapping.extend(arg_map.entries().filter_map(|(tid, range)| { - tm.first_range_by_token( - decl_mac.as_ref().map(|it| it.map_id_down(tid)).unwrap_or(tid), - syntax::SyntaxKind::TOMBSTONE, - ) - .map(|r| (r + call_start, range + call_tt_start)) - })); - }; + if let Some(tt) = call.token_tree() { + let call_tt_start = tt.syntax().text_range().start(); + let call_start = apply_offset(call.syntax().text_range().start(), offset); + if let Some((_tt, arg_map, _)) = parse + .file_id + .macro_file() + .and_then(|id| db.macro_arg(id.macro_call_id).value) + .as_deref() + { + mapping.extend(arg_map.entries().filter_map(|(tid, range)| { + tm.first_range_by_token( + decl_mac.as_ref().map(|it| it.map_id_down(tid)).unwrap_or(tid), + syntax::SyntaxKind::TOMBSTONE, + ) + .map(|r| (r + call_start, range + call_tt_start)) + })); + } + } // FIXME: Do we need to re-use _m here? ExpandResult { value: value.map(|(n, _m)| n), err } } @@ -275,7 +288,7 @@ fn eager_macro_recur( } // check if the whole original syntax is replaced if call.syntax() == &original { - return Ok(ExpandResult { value: value.zip(Some(mapping)), err: error }); + return ExpandResult { value: value.zip(Some(mapping)), err: error }; } if let Some(insert) = value { @@ -286,5 +299,5 @@ fn eager_macro_recur( } replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new)); - Ok(ExpandResult { value: Some((original, mapping)), err: error }) + ExpandResult { value: Some((original, mapping)), err: error } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index 54e74d50c87..ade4a592893 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -173,7 +173,7 @@ fn make_hygiene_info( db: &dyn ExpandDatabase, macro_file: MacroFile, loc: &MacroCallLoc, -) -> Option<HygieneInfo> { +) -> HygieneInfo { let def = loc.def.ast_id().left().and_then(|id| { let def_tt = match id.to_node(db) { ast::Macro::MacroRules(mac) => mac.token_tree()?, @@ -204,7 +204,7 @@ fn make_hygiene_info( )) }); - Some(HygieneInfo { + HygieneInfo { file: macro_file, attr_input_or_mac_def_start: attr_input_or_mac_def .map(|it| it.map(|tt| tt.syntax().text_range().start())), @@ -212,7 +212,7 @@ fn make_hygiene_info( macro_arg, macro_def, exp_map, - }) + } } impl HygieneFrame { @@ -221,8 +221,7 @@ impl HygieneFrame { None => (None, None, false), Some(macro_file) => { let loc = db.lookup_intern_macro_call(macro_file.macro_call_id); - let info = - make_hygiene_info(db, macro_file, &loc).map(|info| (loc.kind.file_id(), info)); + let info = Some((make_hygiene_info(db, macro_file, &loc), loc.kind.file_id())); match loc.def.kind { MacroDefKind::Declarative(_) => { (info, Some(loc.def.krate), loc.def.local_inner) @@ -236,17 +235,14 @@ impl HygieneFrame { } }; - let (calling_file, info) = match info { - None => { - return HygieneFrame { - expansion: None, - local_inner, - krate, - call_site: None, - def_site: None, - }; + let Some((info, calling_file)) = info else { + return HygieneFrame { + expansion: None, + local_inner, + krate, + call_site: None, + def_site: None, } - Some(it) => it, }; let def_site = info.attr_input_or_mac_def_start.map(|it| db.hygiene_frame(it.file_id)); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 9ed6c31ddde..1f1e20f49e3 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -415,6 +415,24 @@ impl MacroDefId { ) } + pub fn is_derive(&self) -> bool { + matches!( + self.kind, + MacroDefKind::BuiltInDerive(..) + | MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _) + ) + } + + pub fn is_fn_like(&self) -> bool { + matches!( + self.kind, + MacroDefKind::BuiltIn(..) + | MacroDefKind::ProcMacro(_, ProcMacroKind::FuncLike, _) + | MacroDefKind::BuiltInEager(..) + | MacroDefKind::Declarative(..) + ) + } + pub fn is_attribute_derive(&self) -> bool { matches!(self.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive()) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 98ebe557245..666955fa1c3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -1187,6 +1187,25 @@ fn pattern_matching_ergonomics() { } #[test] +fn destructing_assignment() { + check_number( + r#" + //- minicore: add + const fn f(i: &mut u8) -> &mut u8 { + *i += 1; + i + } + const GOAL: u8 = { + let mut i = 4; + _ = f(&mut i); + i + }; + "#, + 5, + ); +} + +#[test] fn let_else() { check_number( r#" @@ -1428,14 +1447,14 @@ fn builtin_derive_macro() { #[derive(Clone)] struct Y { field1: i32, - field2: u8, + field2: ((i32, u8), i64), } const GOAL: u8 = { - let x = X(2, Z::Foo(Y { field1: 4, field2: 5 }), 8); + let x = X(2, Z::Foo(Y { field1: 4, field2: ((32, 5), 12) }), 8); let x = x.clone(); let Z::Foo(t) = x.1; - t.field2 + t.field2.0 .1 }; "#, 5, @@ -1633,6 +1652,34 @@ const GOAL: i32 = { } #[test] +fn closure_capture_unsized_type() { + check_number( + r#" + //- minicore: fn, copy, slice, index, coerce_unsized + fn f<T: A>(x: &<T as A>::Ty) -> &<T as A>::Ty { + let c = || &*x; + c() + } + + trait A { + type Ty; + } + + impl A for i32 { + type Ty = [u8]; + } + + const GOAL: u8 = { + let k: &[u8] = &[1, 2, 3]; + let k = f::<i32>(k); + k[0] + k[1] + k[2] + } + "#, + 6, + ); +} + +#[test] fn closure_and_impl_fn() { check_number( r#" @@ -1718,6 +1765,24 @@ fn function_pointer_in_constants() { } #[test] +fn function_pointer_and_niche_optimization() { + check_number( + r#" + //- minicore: option + const GOAL: i32 = { + let f: fn(i32) -> i32 = |x| x + 2; + let init = Some(f); + match init { + Some(t) => t(3), + None => 222, + } + }; + "#, + 5, + ); +} + +#[test] fn function_pointer() { check_number( r#" @@ -2331,11 +2396,14 @@ fn const_loop() { fn const_transfer_memory() { check_number( r#" - const A1: &i32 = &2; - const A2: &i32 = &5; - const GOAL: i32 = *A1 + *A2; + //- minicore: slice, index, coerce_unsized + const A1: &i32 = &1; + const A2: &i32 = &10; + const A3: [&i32; 3] = [&1, &2, &100]; + const A4: (i32, &i32) = (1, &1000); + const GOAL: i32 = *A1 + *A2 + *A3[2] + *A4.1; "#, - 7, + 1111, ); } @@ -2521,12 +2589,16 @@ fn const_trait_assoc() { ); check_number( r#" - //- minicore: size_of + //- minicore: size_of, fn //- /a/lib.rs crate:a use core::mem::size_of; pub struct S<T>(T); impl<T> S<T> { - pub const X: usize = core::mem::size_of::<T>(); + pub const X: usize = { + let k: T; + let f = || core::mem::size_of::<T>(); + f() + }; } //- /main.rs crate:main deps:a use a::{S}; @@ -2602,9 +2674,9 @@ fn exec_limits() { } sum } - const GOAL: i32 = f(10000); + const GOAL: i32 = f(1000); "#, - 10000 * 10000, + 1000 * 1000, ); } @@ -2651,7 +2723,7 @@ fn unsized_field() { //- minicore: coerce_unsized, index, slice, transmute use core::mem::transmute; - struct Slice([u8]); + struct Slice([usize]); struct Slice2(Slice); impl Slice2 { @@ -2659,19 +2731,19 @@ fn unsized_field() { &self.0 } - fn as_bytes(&self) -> &[u8] { + fn as_bytes(&self) -> &[usize] { &self.as_inner().0 } } - const GOAL: u8 = unsafe { - let x: &[u8] = &[1, 2, 3]; + const GOAL: usize = unsafe { + let x: &[usize] = &[1, 2, 3]; let x: &Slice2 = transmute(x); let x = x.as_bytes(); - x[0] + x[1] + x[2] + x[0] + x[1] + x[2] + x.len() * 100 }; "#, - 6, + 306, ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs index 9253e31d77b..2855f789001 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -252,6 +252,28 @@ fn wrapping_add() { } #[test] +fn ptr_offset_from() { + check_number( + r#" + //- minicore: index, slice, coerce_unsized + extern "rust-intrinsic" { + pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize; + pub fn ptr_offset_from_unsigned<T>(ptr: *const T, base: *const T) -> usize; + } + + const GOAL: isize = { + let x = [1, 2, 3, 4, 5i32]; + let r1 = -ptr_offset_from(&x[0], &x[4]); + let r2 = ptr_offset_from(&x[3], &x[1]); + let r3 = ptr_offset_from_unsigned(&x[3], &x[0]) as isize; + r3 * 100 + r2 * 10 + r1 + }; + "#, + 324, + ); +} + +#[test] fn saturating() { check_number( r#" @@ -438,6 +460,8 @@ fn atomic() { pub fn atomic_nand_seqcst<T: Copy>(dst: *mut T, src: T) -> T; pub fn atomic_or_release<T: Copy>(dst: *mut T, src: T) -> T; pub fn atomic_xor_seqcst<T: Copy>(dst: *mut T, src: T) -> T; + pub fn atomic_fence_seqcst(); + pub fn atomic_singlethreadfence_acqrel(); } fn should_not_reach() { @@ -452,6 +476,7 @@ fn atomic() { if (30, true) != atomic_cxchg_release_seqcst(&mut y, 30, 40) { should_not_reach(); } + atomic_fence_seqcst(); if (40, false) != atomic_cxchg_release_seqcst(&mut y, 30, 50) { should_not_reach(); } @@ -459,6 +484,7 @@ fn atomic() { should_not_reach(); } let mut z = atomic_xsub_seqcst(&mut x, -200); + atomic_singlethreadfence_acqrel(); atomic_xor_seqcst(&mut x, 1024); atomic_load_seqcst(&x) + z * 3 + atomic_load_seqcst(&y) * 2 }; 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 5aaa2bcc7c2..a94a962c1f8 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 @@ -176,6 +176,7 @@ impl<'a> DeclValidator<'a> { AttrDefId::ImplId(iid) => Some(iid.lookup(self.db.upcast()).container.into()), AttrDefId::ExternBlockId(id) => Some(id.lookup(self.db.upcast()).container.into()), AttrDefId::ExternCrateId(id) => Some(id.lookup(self.db.upcast()).container.into()), + AttrDefId::UseId(id) => Some(id.lookup(self.db.upcast()).container.into()), // These warnings should not explore macro definitions at all AttrDefId::MacroId(_) => None, AttrDefId::AdtId(aid) => match aid { 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 96787959e1f..1b4ee4613d6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -48,22 +48,15 @@ use crate::{ }; pub trait HirWrite: fmt::Write { - fn start_location_link(&mut self, location: ModuleDefId); - fn end_location_link(&mut self); + fn start_location_link(&mut self, _location: ModuleDefId) {} + fn end_location_link(&mut self) {} } // String will ignore link metadata -impl HirWrite for String { - fn start_location_link(&mut self, _: ModuleDefId) {} - - fn end_location_link(&mut self) {} -} +impl HirWrite for String {} // `core::Formatter` will ignore metadata -impl HirWrite for fmt::Formatter<'_> { - fn start_location_link(&mut self, _: ModuleDefId) {} - fn end_location_link(&mut self) {} -} +impl HirWrite for fmt::Formatter<'_> {} pub struct HirFormatter<'a> { pub db: &'a dyn HirDatabase, @@ -885,6 +878,13 @@ impl HirDisplay for Ty { TyKind::FnDef(def, parameters) => { let def = from_chalk(db, *def); let sig = db.callable_item_signature(def).substitute(Interner, parameters); + + if f.display_target.is_source_code() { + // `FnDef` is anonymous and there's no surface syntax for it. Show it as a + // function pointer type. + return sig.hir_fmt(f); + } + f.start_location_link(def.into()); match def { CallableDefId::FunctionId(ff) => { 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 0a617dae7d4..b4915dbf0f9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -13,6 +13,15 @@ //! to certain types. To record this, we use the union-find implementation from //! the `ena` crate, which is extracted from rustc. +mod cast; +pub(crate) mod closure; +mod coerce; +mod expr; +mod mutability; +mod pat; +mod path; +pub(crate) mod unify; + use std::{convert::identity, ops::Index}; use chalk_ir::{ @@ -60,15 +69,8 @@ pub use coerce::could_coerce; #[allow(unreachable_pub)] pub use unify::could_unify; -pub(crate) use self::closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy}; - -pub(crate) mod unify; -mod path; -mod expr; -mod pat; -mod coerce; -pub(crate) mod closure; -mod mutability; +use cast::CastCheck; +pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy}; /// The entry point of type inference. pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { @@ -508,6 +510,8 @@ pub(crate) struct InferenceContext<'a> { diverges: Diverges, breakables: Vec<BreakableContext>, + deferred_cast_checks: Vec<CastCheck>, + // fields related to closure capture current_captures: Vec<CapturedItemWithoutTy>, current_closure: Option<ClosureId>, @@ -582,7 +586,8 @@ impl<'a> InferenceContext<'a> { resolver, diverges: Diverges::Maybe, breakables: Vec::new(), - current_captures: vec![], + deferred_cast_checks: Vec::new(), + current_captures: Vec::new(), current_closure: None, deferred_closures: FxHashMap::default(), closure_dependencies: FxHashMap::default(), @@ -594,7 +599,7 @@ impl<'a> InferenceContext<'a> { // used this function for another workaround, mention it here. If you really need this function and believe that // there is no problem in it being `pub(crate)`, remove this comment. pub(crate) fn resolve_all(self) -> InferenceResult { - let InferenceContext { mut table, mut result, .. } = self; + let InferenceContext { mut table, mut result, deferred_cast_checks, .. } = self; // Destructure every single field so whenever new fields are added to `InferenceResult` we // don't forget to handle them here. let InferenceResult { @@ -622,6 +627,13 @@ impl<'a> InferenceContext<'a> { table.fallback_if_possible(); + // Comment from rustc: + // Even though coercion casts provide type hints, we check casts after fallback for + // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. + for cast in deferred_cast_checks { + cast.check(&mut table); + } + // FIXME resolve obligations as well (use Guidance if necessary) table.resolve_obligations_as_possible(); 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 new file mode 100644 index 00000000000..9e1c74b16fa --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs @@ -0,0 +1,46 @@ +//! Type cast logic. Basically coercion + additional casts. + +use crate::{infer::unify::InferenceTable, Interner, Ty, TyExt, TyKind}; + +#[derive(Clone, Debug)] +pub(super) struct CastCheck { + expr_ty: Ty, + cast_ty: Ty, +} + +impl CastCheck { + pub(super) fn new(expr_ty: Ty, cast_ty: Ty) -> Self { + Self { expr_ty, cast_ty } + } + + pub(super) fn check(self, table: &mut InferenceTable<'_>) { + // FIXME: This function currently only implements the bits that influence the type + // inference. We should return the adjustments on success and report diagnostics on error. + let expr_ty = table.resolve_ty_shallow(&self.expr_ty); + let cast_ty = table.resolve_ty_shallow(&self.cast_ty); + + if expr_ty.contains_unknown() || cast_ty.contains_unknown() { + return; + } + + if table.coerce(&expr_ty, &cast_ty).is_ok() { + return; + } + + if check_ref_to_ptr_cast(expr_ty, cast_ty, table) { + // Note that this type of cast is actually split into a coercion to a + // pointer type and a cast: + // &[T; N] -> *[T; N] -> *T + return; + } + + // FIXME: Check other kinds of non-coercion casts and report error if any? + } +} + +fn check_ref_to_ptr_cast(expr_ty: Ty, cast_ty: Ty, table: &mut InferenceTable<'_>) -> bool { + let Some((expr_inner_ty, _, _)) = expr_ty.as_reference() else { return false; }; + let Some((cast_inner_ty, _)) = cast_ty.as_raw_ptr() else { return false; }; + let TyKind::Array(expr_elt_ty, _) = expr_inner_ty.kind(Interner) else { return false; }; + table.coerce(expr_elt_ty, cast_inner_ty).is_ok() +} 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 972e5321a47..1781f6c58f1 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 @@ -488,10 +488,6 @@ impl InferenceContext<'_> { self.consume_expr(*tail); } } - Expr::While { condition, body, label: _ } => { - self.consume_expr(*condition); - self.consume_expr(*body); - } Expr::Call { callee, args, is_assignee_expr: _ } => { self.consume_expr(*callee); self.consume_exprs(args.iter().copied()); 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 72e6443beb7..8cbdae62526 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 @@ -46,8 +46,8 @@ use crate::{ }; use super::{ - coerce::auto_deref_adjust_steps, find_breakable, BreakableContext, Diverges, Expectation, - InferenceContext, InferenceDiagnostic, TypeMismatch, + cast::CastCheck, coerce::auto_deref_adjust_steps, find_breakable, BreakableContext, Diverges, + Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch, }; impl InferenceContext<'_> { @@ -198,19 +198,6 @@ impl InferenceContext<'_> { None => self.result.standard_types.never.clone(), } } - &Expr::While { condition, body, label } => { - self.with_breakable_ctx(BreakableKind::Loop, None, label, |this| { - this.infer_expr( - condition, - &Expectation::HasType(this.result.standard_types.bool_.clone()), - ); - this.infer_expr(body, &Expectation::HasType(TyBuilder::unit())); - }); - - // the body may not run, so it diverging doesn't mean we diverge - self.diverges = Diverges::Maybe; - TyBuilder::unit() - } Expr::Closure { body, args, ret_type, arg_types, closure_kind, capture_by: _ } => { assert_eq!(args.len(), arg_types.len()); @@ -574,16 +561,8 @@ impl InferenceContext<'_> { } Expr::Cast { expr, type_ref } => { let cast_ty = self.make_ty(type_ref); - // FIXME: propagate the "castable to" expectation - let inner_ty = self.infer_expr_no_expect(*expr); - match (inner_ty.kind(Interner), cast_ty.kind(Interner)) { - (TyKind::Ref(_, _, inner), TyKind::Raw(_, cast)) => { - // FIXME: record invalid cast diagnostic in case of mismatch - self.unify(inner, cast); - } - // FIXME check the other kinds of cast... - _ => (), - } + let expr_ty = self.infer_expr(*expr, &Expectation::Castable(cast_ty.clone())); + self.deferred_cast_checks.push(CastCheck::new(expr_ty, cast_ty.clone())); cast_ty } Expr::Ref { expr, rawness, mutability } => { @@ -1592,7 +1571,7 @@ impl InferenceContext<'_> { output: Ty, inputs: Vec<Ty>, ) -> Vec<Ty> { - if let Some(expected_ty) = expected_output.to_option(&mut self.table) { + if let Some(expected_ty) = expected_output.only_has_type(&mut self.table) { self.table.fudge_inference(|table| { if table.try_unify(&expected_ty, &output).is_ok() { table.resolve_with_fallback(inputs, &|var, kind, _, _| match kind { 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 f517bc2c09f..396ca0044ff 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 @@ -69,10 +69,6 @@ impl InferenceContext<'_> { self.infer_mut_expr(*tail, Mutability::Not); } } - &Expr::While { condition: c, body, label: _ } => { - self.infer_mut_expr(c, Mutability::Not); - self.infer_mut_expr(body, Mutability::Not); - } Expr::MethodCall { receiver: it, method_name: _, args, generic_args: _ } | Expr::Call { callee: it, args, is_assignee_expr: _ } => { self.infer_mut_not_expr_iter(args.iter().copied().chain(Some(*it))); 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 ffc7a6f2ebd..b15339d4434 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -14,7 +14,7 @@ use triomphe::Arc; use crate::{ consteval::try_const_usize, db::HirDatabase, infer::normalize, layout::adt::struct_variant_idx, - utils::ClosureSubst, Interner, Substitution, TraitEnvironment, Ty, + utils::ClosureSubst, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, }; pub use self::{ @@ -279,7 +279,15 @@ pub fn layout_of_ty_query( // return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr))); // } - let unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone()); + let mut unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone()); + if let TyKind::AssociatedType(id, subst) = unsized_part.kind(Interner) { + unsized_part = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy { + associated_ty_id: *id, + substitution: subst.clone(), + })) + .intern(Interner); + } + unsized_part = normalize(db, trait_env.clone(), unsized_part); let metadata = match unsized_part.kind(Interner) { TyKind::Slice(_) | TyKind::Str => { scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false)) @@ -362,8 +370,16 @@ pub fn layout_of_ty_query( return Err(LayoutError::NotImplemented) } TyKind::Error => return Err(LayoutError::HasErrorType), - TyKind::AssociatedType(_, _) - | TyKind::Alias(_) + TyKind::AssociatedType(id, subst) => { + // Try again with `TyKind::Alias` to normalize the associated type. + let ty = TyKind::Alias(chalk_ir::AliasTy::Projection(ProjectionTy { + associated_ty_id: *id, + substitution: subst.clone(), + })) + .intern(Interner); + return db.layout_of_ty(ty, trait_env); + } + TyKind::Alias(_) | TyKind::Placeholder(_) | TyKind::BoundVar(_) | TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 922e49d281d..4723c25ed08 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -234,6 +234,7 @@ impl Place { self.local == child.local && child.projection.starts_with(&self.projection) } + /// The place itself is not included fn iterate_over_parents(&self) -> impl Iterator<Item = Place> + '_ { (0..self.projection.len()) .map(|x| &self.projection[0..x]) 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 7bd2756c14f..9e30eed56f3 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 @@ -1,6 +1,13 @@ //! This module provides a MIR interpreter, which is used in const eval. -use std::{borrow::Cow, cell::RefCell, collections::HashMap, fmt::Write, iter, mem, ops::Range}; +use std::{ + borrow::Cow, + cell::RefCell, + collections::{HashMap, HashSet}, + fmt::Write, + iter, mem, + ops::Range, +}; use base_db::{CrateId, FileId}; use chalk_ir::Mutability; @@ -39,7 +46,8 @@ use crate::{ use super::{ return_slot, AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError, - MirSpan, Operand, Place, ProjectionElem, Rvalue, StatementKind, TerminatorKind, UnOp, + MirSpan, Operand, Place, PlaceElem, ProjectionElem, Rvalue, StatementKind, TerminatorKind, + UnOp, }; mod shim; @@ -68,18 +76,22 @@ pub struct VTableMap { } impl VTableMap { + const OFFSET: usize = 1000; // We should add some offset to ids to make 0 (null) an invalid id. + fn id(&mut self, ty: Ty) -> usize { if let Some(it) = self.ty_to_id.get(&ty) { return *it; } - let id = self.id_to_ty.len(); + let id = self.id_to_ty.len() + VTableMap::OFFSET; self.id_to_ty.push(ty.clone()); self.ty_to_id.insert(ty, id); id } pub(crate) fn ty(&self, id: usize) -> Result<&Ty> { - self.id_to_ty.get(id).ok_or(MirEvalError::InvalidVTableId(id)) + id.checked_sub(VTableMap::OFFSET) + .and_then(|id| self.id_to_ty.get(id)) + .ok_or(MirEvalError::InvalidVTableId(id)) } fn ty_of_bytes(&self, bytes: &[u8]) -> Result<&Ty> { @@ -116,13 +128,18 @@ impl TlsData { } struct StackFrame { - body: Arc<MirBody>, locals: Locals, destination: Option<BasicBlockId>, prev_stack_ptr: usize, span: (MirSpan, DefWithBodyId), } +#[derive(Clone)] +enum MirOrDynIndex { + Mir(Arc<MirBody>), + Dyn(usize), +} + pub struct Evaluator<'a> { db: &'a dyn HirDatabase, trait_env: Arc<TraitEnvironment>, @@ -141,6 +158,17 @@ pub struct Evaluator<'a> { stdout: Vec<u8>, stderr: Vec<u8>, layout_cache: RefCell<FxHashMap<Ty, Arc<Layout>>>, + projected_ty_cache: RefCell<FxHashMap<(Ty, PlaceElem), Ty>>, + not_special_fn_cache: RefCell<FxHashSet<FunctionId>>, + mir_or_dyn_index_cache: RefCell<FxHashMap<(FunctionId, Substitution), MirOrDynIndex>>, + /// Constantly dropping and creating `Locals` is very costly. We store + /// old locals that we normaly want to drop here, to reuse their allocations + /// later. + unused_locals_store: RefCell<FxHashMap<DefWithBodyId, Vec<Locals>>>, + cached_ptr_size: usize, + cached_fn_trait_func: Option<FunctionId>, + cached_fn_mut_trait_func: Option<FunctionId>, + cached_fn_once_trait_func: Option<FunctionId>, crate_id: CrateId, // FIXME: This is a workaround, see the comment on `interpret_mir` assert_placeholder_ty_is_unused: bool, @@ -313,6 +341,7 @@ pub enum MirEvalError { InvalidVTableId(usize), CoerceUnsizedError(Ty), LangItemNotFound(LangItem), + BrokenLayout(Layout), } impl MirEvalError { @@ -399,6 +428,7 @@ impl MirEvalError { | MirEvalError::TargetDataLayoutNotAvailable | MirEvalError::CoerceUnsizedError(_) | MirEvalError::LangItemNotFound(_) + | MirEvalError::BrokenLayout(_) | MirEvalError::InvalidVTableId(_) => writeln!(f, "{:?}", err)?, } Ok(()) @@ -433,6 +463,7 @@ impl std::fmt::Debug for MirEvalError { Self::CoerceUnsizedError(arg0) => { f.debug_tuple("CoerceUnsizedError").field(arg0).finish() } + Self::BrokenLayout(arg0) => f.debug_tuple("BrokenLayout").field(arg0).finish(), Self::InvalidVTableId(arg0) => f.debug_tuple("InvalidVTableId").field(arg0).finish(), Self::NotSupported(arg0) => f.debug_tuple("NotSupported").field(arg0).finish(), Self::InvalidConst(arg0) => { @@ -464,8 +495,16 @@ impl DropFlags { fn remove_place(&mut self, p: &Place) -> bool { // FIXME: replace parents with parts + if let Some(parent) = p.iterate_over_parents().find(|it| self.need_drop.contains(&it)) { + self.need_drop.remove(&parent); + return true; + } self.need_drop.remove(p) } + + fn clear(&mut self) { + self.need_drop.clear(); + } } #[derive(Debug)] @@ -508,6 +547,11 @@ pub fn interpret_mir( ) } +#[cfg(test)] +const EXECUTION_LIMIT: usize = 100_000; +#[cfg(not(test))] +const EXECUTION_LIMIT: usize = 10_000_000; + impl Evaluator<'_> { pub fn new<'a>( db: &'a dyn HirDatabase, @@ -531,9 +575,29 @@ impl Evaluator<'_> { stderr: vec![], assert_placeholder_ty_is_unused, stack_depth_limit: 100, - execution_limit: 1000_000, + execution_limit: EXECUTION_LIMIT, memory_limit: 1000_000_000, // 2GB, 1GB for stack and 1GB for heap layout_cache: RefCell::new(HashMap::default()), + projected_ty_cache: RefCell::new(HashMap::default()), + not_special_fn_cache: RefCell::new(HashSet::default()), + mir_or_dyn_index_cache: RefCell::new(HashMap::default()), + unused_locals_store: RefCell::new(HashMap::default()), + cached_ptr_size: match db.target_data_layout(crate_id) { + Some(it) => it.pointer_size.bytes_usize(), + None => 8, + }, + cached_fn_trait_func: db + .lang_item(crate_id, LangItem::Fn) + .and_then(|x| x.as_trait()) + .and_then(|x| db.trait_data(x).method_by_name(&name![call])), + cached_fn_mut_trait_func: db + .lang_item(crate_id, LangItem::FnMut) + .and_then(|x| x.as_trait()) + .and_then(|x| db.trait_data(x).method_by_name(&name![call_mut])), + cached_fn_once_trait_func: db + .lang_item(crate_id, LangItem::FnOnce) + .and_then(|x| x.as_trait()) + .and_then(|x| db.trait_data(x).method_by_name(&name![call_once])), } } @@ -554,10 +618,34 @@ impl Evaluator<'_> { } fn ptr_size(&self) -> usize { - match self.db.target_data_layout(self.crate_id) { - Some(it) => it.pointer_size.bytes_usize(), - None => 8, + self.cached_ptr_size + } + + fn projected_ty(&self, ty: Ty, proj: PlaceElem) -> Ty { + let pair = (ty, proj); + if let Some(r) = self.projected_ty_cache.borrow().get(&pair) { + return r.clone(); } + let (ty, proj) = pair; + let r = proj.projected_ty( + ty.clone(), + self.db, + |c, subst, f| { + let (def, _) = self.db.lookup_intern_closure(c.into()); + let infer = self.db.infer(def); + let (captures, _) = infer.closure_info(&c); + let parent_subst = ClosureSubst(subst).parent_subst(); + captures + .get(f) + .expect("broken closure field") + .ty + .clone() + .substitute(Interner, parent_subst) + }, + self.crate_id, + ); + self.projected_ty_cache.borrow_mut().insert((ty, proj), r.clone()); + r } fn place_addr_and_ty_and_metadata<'a>( @@ -570,23 +658,7 @@ impl Evaluator<'_> { let mut metadata: Option<IntervalOrOwned> = None; // locals are always sized for proj in &*p.projection { let prev_ty = ty.clone(); - ty = proj.projected_ty( - ty, - self.db, - |c, subst, f| { - let (def, _) = self.db.lookup_intern_closure(c.into()); - let infer = self.db.infer(def); - let (captures, _) = infer.closure_info(&c); - let parent_subst = ClosureSubst(subst).parent_subst(); - captures - .get(f) - .expect("broken closure field") - .ty - .clone() - .substitute(Interner, parent_subst) - }, - self.crate_id, - ); + ty = self.projected_ty(ty, proj.clone()); match proj { ProjectionElem::Deref => { metadata = if self.size_align_of(&ty, locals)?.is_none() { @@ -680,8 +752,10 @@ impl Evaluator<'_> { .offset(u32::from(f.local_id.into_raw()) as usize) .bytes_usize(); addr = addr.offset(offset); - // FIXME: support structs with unsized fields - metadata = None; + // Unsized field metadata is equal to the metadata of the struct + if self.size_align_of(&ty, locals)?.is_some() { + metadata = None; + } } ProjectionElem::OpaqueCast(_) => not_supported!("opaque cast"), } @@ -702,9 +776,7 @@ impl Evaluator<'_> { } fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result<Arc<Layout>> { - self.db.layout_of_adt(adt, subst.clone(), self.trait_env.clone()).map_err(|e| { - MirEvalError::LayoutError(e, TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner)) - }) + self.layout(&TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner)) } fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals) -> Result<Ty> { @@ -740,18 +812,18 @@ impl Evaluator<'_> { return Err(MirEvalError::StackOverflow); } let mut current_block_idx = body.start_block; - let (mut locals, prev_stack_ptr) = self.create_locals_for_body(body.clone(), None)?; + let (mut locals, prev_stack_ptr) = self.create_locals_for_body(&body, None)?; self.fill_locals_for_body(&body, &mut locals, args)?; let prev_code_stack = mem::take(&mut self.code_stack); let span = (MirSpan::Unknown, body.owner); - self.code_stack.push(StackFrame { body, locals, destination: None, prev_stack_ptr, span }); + self.code_stack.push(StackFrame { locals, destination: None, prev_stack_ptr, span }); 'stack: loop { let Some(mut my_stack_frame) = self.code_stack.pop() else { not_supported!("missing stack frame"); }; let e = (|| { let mut locals = &mut my_stack_frame.locals; - let body = &*my_stack_frame.body; + let body = locals.body.clone(); loop { let current_block = &body.basic_blocks[current_block_idx]; if let Some(it) = self.execution_limit.checked_sub(1) { @@ -820,7 +892,7 @@ impl Evaluator<'_> { locals.drop_flags.add_place(destination.clone()); if let Some(stack_frame) = stack_frame { self.code_stack.push(my_stack_frame); - current_block_idx = stack_frame.body.start_block; + current_block_idx = stack_frame.locals.body.start_block; self.code_stack.push(stack_frame); return Ok(None); } else { @@ -861,18 +933,24 @@ impl Evaluator<'_> { let my_code_stack = mem::replace(&mut self.code_stack, prev_code_stack); let mut error_stack = vec![]; for frame in my_code_stack.into_iter().rev() { - if let DefWithBodyId::FunctionId(f) = frame.body.owner { + if let DefWithBodyId::FunctionId(f) = frame.locals.body.owner { error_stack.push((Either::Left(f), frame.span.0, frame.span.1)); } } return Err(MirEvalError::InFunction(Box::new(e), error_stack)); } }; + let return_interval = my_stack_frame.locals.ptr[return_slot()]; + self.unused_locals_store + .borrow_mut() + .entry(my_stack_frame.locals.body.owner) + .or_default() + .push(my_stack_frame.locals); match my_stack_frame.destination { None => { self.code_stack = prev_code_stack; self.stack_depth_limit += 1; - return Ok(my_stack_frame.locals.ptr[return_slot()].get(self)?.to_vec()); + return Ok(return_interval.get(self)?.to_vec()); } Some(bb) => { // We don't support const promotion, so we can't truncate the stack yet. @@ -910,39 +988,45 @@ impl Evaluator<'_> { fn create_locals_for_body( &mut self, - body: Arc<MirBody>, + body: &Arc<MirBody>, destination: Option<Interval>, ) -> Result<(Locals, usize)> { let mut locals = - Locals { ptr: ArenaMap::new(), body: body.clone(), drop_flags: DropFlags::default() }; - let (locals_ptr, stack_size) = { + match self.unused_locals_store.borrow_mut().entry(body.owner).or_default().pop() { + None => Locals { + ptr: ArenaMap::new(), + body: body.clone(), + drop_flags: DropFlags::default(), + }, + Some(mut l) => { + l.drop_flags.clear(); + l.body = body.clone(); + l + } + }; + let stack_size = { let mut stack_ptr = self.stack.len(); - let addr = body - .locals - .iter() - .map(|(id, it)| { - if id == return_slot() { - if let Some(destination) = destination { - return Ok((id, destination)); - } - } - let (size, align) = self.size_align_of_sized( - &it.ty, - &locals, - "no unsized local in extending stack", - )?; - while stack_ptr % align != 0 { - stack_ptr += 1; + for (id, it) in body.locals.iter() { + if id == return_slot() { + if let Some(destination) = destination { + locals.ptr.insert(id, destination); + continue; } - let my_ptr = stack_ptr; - stack_ptr += size; - Ok((id, Interval { addr: Stack(my_ptr), size })) - }) - .collect::<Result<ArenaMap<LocalId, _>>>()?; - let stack_size = stack_ptr - self.stack.len(); - (addr, stack_size) + } + let (size, align) = self.size_align_of_sized( + &it.ty, + &locals, + "no unsized local in extending stack", + )?; + while stack_ptr % align != 0 { + stack_ptr += 1; + } + let my_ptr = stack_ptr; + stack_ptr += size; + locals.ptr.insert(id, Interval { addr: Stack(my_ptr), size }); + } + stack_ptr - self.stack.len() }; - locals.ptr = locals_ptr; let prev_stack_pointer = self.stack.len(); if stack_size > self.memory_limit { return Err(MirEvalError::Panic(format!( @@ -1543,12 +1627,18 @@ impl Evaluator<'_> { ) -> Result<Vec<u8>> { let mut result = vec![0; size]; if let Some((offset, size, value)) = tag { - result[offset..offset + size].copy_from_slice(&value.to_le_bytes()[0..size]); + match result.get_mut(offset..offset + size) { + Some(it) => it.copy_from_slice(&value.to_le_bytes()[0..size]), + None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())), + } } for (i, op) in values.enumerate() { let offset = variant_layout.fields.offset(i).bytes_usize(); let op = op.get(&self)?; - result[offset..offset + op.len()].copy_from_slice(op); + match result.get_mut(offset..offset + op.len()) { + Some(it) => it.copy_from_slice(op), + None => return Err(MirEvalError::BrokenLayout(variant_layout.clone())), + } } Ok(result) } @@ -1671,6 +1761,11 @@ impl Evaluator<'_> { } fn size_align_of(&self, ty: &Ty, locals: &Locals) -> Result<Option<(usize, usize)>> { + if let Some(layout) = self.layout_cache.borrow().get(ty) { + return Ok(layout + .is_sized() + .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize))); + } if let DefWithBodyId::VariantId(f) = locals.body.owner { if let Some((adt, _)) = ty.as_adt() { if AdtId::from(f.parent) == adt { @@ -1731,16 +1826,15 @@ impl Evaluator<'_> { } fn detect_fn_trait(&self, def: FunctionId) -> Option<FnTrait> { - use LangItem::*; - let ItemContainerId::TraitId(parent) = self.db.lookup_intern_function(def).container else { - return None; - }; - let l = self.db.lang_attr(parent.into())?; - match l { - FnOnce => Some(FnTrait::FnOnce), - FnMut => Some(FnTrait::FnMut), - Fn => Some(FnTrait::Fn), - _ => None, + let def = Some(def); + if def == self.cached_fn_trait_func { + Some(FnTrait::Fn) + } else if def == self.cached_fn_mut_trait_func { + Some(FnTrait::FnMut) + } else if def == self.cached_fn_once_trait_func { + Some(FnTrait::FnOnce) + } else { + None } } @@ -1796,6 +1890,17 @@ impl Evaluator<'_> { } } } + chalk_ir::TyKind::Array(inner, len) => { + let len = match try_const_usize(this.db, &len) { + Some(it) => it as usize, + None => not_supported!("non evaluatable array len in patching addresses"), + }; + let size = this.size_of_sized(inner, locals, "inner of array")?; + for i in 0..len { + let offset = i * size; + rec(this, &bytes[offset..offset + size], inner, locals, mm)?; + } + } chalk_ir::TyKind::Tuple(_, subst) => { let layout = this.layout(ty)?; for (id, ty) in subst.iter(Interner).enumerate() { @@ -1904,10 +2009,31 @@ impl Evaluator<'_> { AdtId::UnionId(_) => (), AdtId::EnumId(_) => (), }, + TyKind::Tuple(_, subst) => { + for (id, ty) in subst.iter(Interner).enumerate() { + let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument + let offset = layout.fields.offset(id).bytes_usize(); + self.patch_addresses(patch_map, old_vtable, addr.offset(offset), ty, locals)?; + } + } + TyKind::Array(inner, len) => { + let len = match try_const_usize(self.db, &len) { + Some(it) => it as usize, + None => not_supported!("non evaluatable array len in patching addresses"), + }; + let size = self.size_of_sized(inner, locals, "inner of array")?; + for i in 0..len { + self.patch_addresses( + patch_map, + old_vtable, + addr.offset(i * size), + inner, + locals, + )?; + } + } TyKind::AssociatedType(_, _) | TyKind::Scalar(_) - | TyKind::Tuple(_, _) - | TyKind::Array(_, _) | TyKind::Slice(_) | TyKind::Raw(_, _) | TyKind::OpaqueType(_, _) @@ -2051,6 +2177,40 @@ impl Evaluator<'_> { } } + fn get_mir_or_dyn_index( + &self, + def: FunctionId, + generic_args: Substitution, + locals: &Locals, + span: MirSpan, + ) -> Result<MirOrDynIndex> { + let pair = (def, generic_args); + if let Some(r) = self.mir_or_dyn_index_cache.borrow().get(&pair) { + return Ok(r.clone()); + } + let (def, generic_args) = pair; + let r = if let Some(self_ty_idx) = + is_dyn_method(self.db, self.trait_env.clone(), def, generic_args.clone()) + { + MirOrDynIndex::Dyn(self_ty_idx) + } else { + let (imp, generic_args) = + self.db.lookup_impl_method(self.trait_env.clone(), def, generic_args.clone()); + let mir_body = self + .db + .monomorphized_mir_body(imp.into(), generic_args, self.trait_env.clone()) + .map_err(|e| { + MirEvalError::InFunction( + Box::new(MirEvalError::MirLowerError(imp, e)), + vec![(Either::Left(imp), span, locals.body.owner)], + ) + })?; + MirOrDynIndex::Mir(mir_body) + }; + self.mir_or_dyn_index_cache.borrow_mut().insert((def, generic_args), r.clone()); + Ok(r) + } + fn exec_fn_with_args( &mut self, def: FunctionId, @@ -2072,93 +2232,76 @@ impl Evaluator<'_> { return Ok(None); } let arg_bytes = args.iter().map(|it| IntervalOrOwned::Borrowed(it.interval)); - if let Some(self_ty_idx) = - is_dyn_method(self.db, self.trait_env.clone(), def, generic_args.clone()) - { - // In the layout of current possible receiver, which at the moment of writing this code is one of - // `&T`, `&mut T`, `Box<T>`, `Rc<T>`, `Arc<T>`, and `Pin<P>` where `P` is one of possible recievers, - // the vtable is exactly in the `[ptr_size..2*ptr_size]` bytes. So we can use it without branching on - // the type. - let first_arg = arg_bytes.clone().next().unwrap(); - let first_arg = first_arg.get(self)?; - let ty = - self.vtable_map.ty_of_bytes(&first_arg[self.ptr_size()..self.ptr_size() * 2])?; - let mut args_for_target = args.to_vec(); - args_for_target[0] = IntervalAndTy { - interval: args_for_target[0].interval.slice(0..self.ptr_size()), - ty: ty.clone(), - }; - let ty = GenericArgData::Ty(ty.clone()).intern(Interner); - let generics_for_target = Substitution::from_iter( - Interner, - generic_args.iter(Interner).enumerate().map(|(i, it)| { - if i == self_ty_idx { - &ty - } else { - it - } - }), - ); - return self.exec_fn_with_args( - def, - &args_for_target, - generics_for_target, + match self.get_mir_or_dyn_index(def, generic_args.clone(), locals, span)? { + MirOrDynIndex::Dyn(self_ty_idx) => { + // In the layout of current possible receiver, which at the moment of writing this code is one of + // `&T`, `&mut T`, `Box<T>`, `Rc<T>`, `Arc<T>`, and `Pin<P>` where `P` is one of possible recievers, + // the vtable is exactly in the `[ptr_size..2*ptr_size]` bytes. So we can use it without branching on + // the type. + let first_arg = arg_bytes.clone().next().unwrap(); + let first_arg = first_arg.get(self)?; + let ty = self + .vtable_map + .ty_of_bytes(&first_arg[self.ptr_size()..self.ptr_size() * 2])?; + let mut args_for_target = args.to_vec(); + args_for_target[0] = IntervalAndTy { + interval: args_for_target[0].interval.slice(0..self.ptr_size()), + ty: ty.clone(), + }; + let ty = GenericArgData::Ty(ty.clone()).intern(Interner); + let generics_for_target = Substitution::from_iter( + Interner, + generic_args.iter(Interner).enumerate().map(|(i, it)| { + if i == self_ty_idx { + &ty + } else { + it + } + }), + ); + return self.exec_fn_with_args( + def, + &args_for_target, + generics_for_target, + locals, + destination, + target_bb, + span, + ); + } + MirOrDynIndex::Mir(body) => self.exec_looked_up_function( + body, locals, + def, + arg_bytes, + span, destination, target_bb, - span, - ); + ), } - let (imp, generic_args) = - self.db.lookup_impl_method(self.trait_env.clone(), def, generic_args); - self.exec_looked_up_function( - generic_args, - locals, - imp, - arg_bytes, - span, - destination, - target_bb, - ) } fn exec_looked_up_function( &mut self, - generic_args: Substitution, + mir_body: Arc<MirBody>, locals: &Locals, - imp: FunctionId, + def: FunctionId, arg_bytes: impl Iterator<Item = IntervalOrOwned>, span: MirSpan, destination: Interval, target_bb: Option<BasicBlockId>, ) -> Result<Option<StackFrame>> { - let def = imp.into(); - let mir_body = self - .db - .monomorphized_mir_body(def, generic_args, self.trait_env.clone()) - .map_err(|e| { - MirEvalError::InFunction( - Box::new(MirEvalError::MirLowerError(imp, e)), - vec![(Either::Left(imp), span, locals.body.owner)], - ) - })?; Ok(if let Some(target_bb) = target_bb { let (mut locals, prev_stack_ptr) = - self.create_locals_for_body(mir_body.clone(), Some(destination))?; + self.create_locals_for_body(&mir_body, Some(destination))?; self.fill_locals_for_body(&mir_body, &mut locals, arg_bytes.into_iter())?; let span = (span, locals.body.owner); - Some(StackFrame { - body: mir_body, - locals, - destination: Some(target_bb), - prev_stack_ptr, - span, - }) + Some(StackFrame { locals, destination: Some(target_bb), prev_stack_ptr, span }) } else { let result = self.interpret_mir(mir_body, arg_bytes).map_err(|e| { MirEvalError::InFunction( Box::new(e), - vec![(Either::Left(imp), span, locals.body.owner)], + vec![(Either::Left(def), span, locals.body.owner)], ) })?; destination.write_from_bytes(self, &result)?; @@ -2330,16 +2473,15 @@ impl Evaluator<'_> { // we can ignore drop in them. return Ok(()); }; - let (impl_drop_candidate, subst) = self.db.lookup_impl_method( - self.trait_env.clone(), - drop_fn, - Substitution::from1(Interner, ty.clone()), - ); - if impl_drop_candidate != drop_fn { + + let generic_args = Substitution::from1(Interner, ty.clone()); + if let Ok(MirOrDynIndex::Mir(body)) = + self.get_mir_or_dyn_index(drop_fn, generic_args, locals, span) + { self.exec_looked_up_function( - subst, + body, locals, - impl_drop_candidate, + drop_fn, [IntervalOrOwned::Owned(addr.to_bytes())].into_iter(), span, Interval { addr: Address::Invalid(0), size: 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 9ad6087cad9..b2e29fd34b5 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 @@ -36,6 +36,9 @@ impl Evaluator<'_> { destination: Interval, span: MirSpan, ) -> Result<bool> { + if self.not_special_fn_cache.borrow().contains(&def) { + return Ok(false); + } let function_data = self.db.function_data(def); let is_intrinsic = match &function_data.abi { Some(abi) => *abi == Interned::new_str("rust-intrinsic"), @@ -124,9 +127,88 @@ impl Evaluator<'_> { destination.write_from_bytes(self, &result)?; return Ok(true); } + if let ItemContainerId::TraitId(t) = def.lookup(self.db.upcast()).container { + if self.db.lang_attr(t.into()) == Some(LangItem::Clone) { + let [self_ty] = generic_args.as_slice(Interner) else { + not_supported!("wrong generic arg count for clone"); + }; + let Some(self_ty) = self_ty.ty(Interner) else { + not_supported!("wrong generic arg kind for clone"); + }; + // Clone has special impls for tuples and function pointers + if matches!(self_ty.kind(Interner), TyKind::Function(_) | TyKind::Tuple(..)) { + self.exec_clone(def, args, self_ty.clone(), locals, destination, span)?; + return Ok(true); + } + // Return early to prevent caching clone as non special fn. + return Ok(false); + } + } + self.not_special_fn_cache.borrow_mut().insert(def); Ok(false) } + /// Clone has special impls for tuples and function pointers + fn exec_clone( + &mut self, + def: FunctionId, + args: &[IntervalAndTy], + self_ty: Ty, + locals: &Locals, + destination: Interval, + span: MirSpan, + ) -> Result<()> { + match self_ty.kind(Interner) { + TyKind::Function(_) => { + let [arg] = args else { + not_supported!("wrong arg count for clone"); + }; + let addr = Address::from_bytes(arg.get(self)?)?; + return destination + .write_from_interval(self, Interval { addr, size: destination.size }); + } + TyKind::Tuple(_, subst) => { + let [arg] = args else { + not_supported!("wrong arg count for clone"); + }; + let addr = Address::from_bytes(arg.get(self)?)?; + let layout = self.layout(&self_ty)?; + for (i, ty) in subst.iter(Interner).enumerate() { + let ty = ty.assert_ty_ref(Interner); + let size = self.layout(ty)?.size.bytes_usize(); + let tmp = self.heap_allocate(self.ptr_size(), self.ptr_size())?; + let arg = IntervalAndTy { + interval: Interval { addr: tmp, size: self.ptr_size() }, + ty: TyKind::Ref(Mutability::Not, static_lifetime(), ty.clone()) + .intern(Interner), + }; + let offset = layout.fields.offset(i).bytes_usize(); + self.write_memory(tmp, &addr.offset(offset).to_bytes())?; + self.exec_clone( + def, + &[arg], + ty.clone(), + locals, + destination.slice(offset..offset + size), + span, + )?; + } + } + _ => { + self.exec_fn_with_args( + def, + args, + Substitution::from1(Interner, self_ty), + locals, + destination, + None, + span, + )?; + } + } + Ok(()) + } + fn exec_alloc_fn( &mut self, alloc_fn: &str, @@ -618,12 +700,15 @@ impl Evaluator<'_> { else { return Err(MirEvalError::TypeError("type_name generic arg is not provided")); }; - let Ok(ty_name) = ty.display_source_code( + let ty_name = match ty.display_source_code( self.db, locals.body.owner.module(self.db.upcast()), true, - ) else { - not_supported!("fail in generating type_name using source code display"); + ) { + Ok(ty_name) => ty_name, + // Fallback to human readable display in case of `Err`. Ideally we want to use `display_source_code` to + // render full paths. + Err(_) => ty.display(self.db).to_string(), }; let len = ty_name.len(); let addr = self.heap_allocate(len, 1)?; @@ -679,7 +764,22 @@ impl Evaluator<'_> { let ans = lhs.wrapping_add(rhs); destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]) } - "wrapping_sub" | "unchecked_sub" | "ptr_offset_from_unsigned" | "ptr_offset_from" => { + "ptr_offset_from_unsigned" | "ptr_offset_from" => { + let [lhs, rhs] = args else { + return Err(MirEvalError::TypeError("wrapping_sub args are not provided")); + }; + let lhs = i128::from_le_bytes(pad16(lhs.get(self)?, false)); + let rhs = i128::from_le_bytes(pad16(rhs.get(self)?, false)); + let ans = lhs.wrapping_sub(rhs); + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) + else { + return Err(MirEvalError::TypeError("ptr_offset_from generic arg is not provided")); + }; + let size = self.size_of_sized(ty, locals, "ptr_offset_from arg")? as i128; + let ans = ans / size; + destination.write_from_bytes(self, &ans.to_le_bytes()[0..destination.size]) + } + "wrapping_sub" | "unchecked_sub" => { let [lhs, rhs] = args else { return Err(MirEvalError::TypeError("wrapping_sub args are not provided")); }; @@ -1057,7 +1157,14 @@ impl Evaluator<'_> { _span: MirSpan, ) -> Result<()> { // We are a single threaded runtime with no UB checking and no optimization, so - // we can implement these as normal functions. + // we can implement atomic intrinsics as normal functions. + + if name.starts_with("singlethreadfence_") || name.starts_with("fence_") { + return Ok(()); + } + + // The rest of atomic intrinsics have exactly one generic arg + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else { return Err(MirEvalError::TypeError("atomic intrinsic generic arg is not provided")); }; 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 93f4b699147..46165cf3d69 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 @@ -183,6 +183,50 @@ fn main() { } #[test] +fn drop_struct_field() { + check_pass( + r#" +//- minicore: drop, add, option, cell, builtin_impls + +use core::cell::Cell; + +fn should_not_reach() { + _ // FIXME: replace this function with panic when that works +} + +struct X<'a>(&'a Cell<i32>); +impl<'a> Drop for X<'a> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1) + } +} + +struct Tuple<'a>(X<'a>, X<'a>, X<'a>); + +fn main() { + let s = Cell::new(0); + { + let x0 = X(&s); + let xt = Tuple(x0, X(&s), X(&s)); + let x1 = xt.1; + if s.get() != 0 { + should_not_reach(); + } + drop(xt.0); + if s.get() != 1 { + should_not_reach(); + } + } + // FIXME: this should be 3 + if s.get() != 2 { + should_not_reach(); + } +} +"#, + ); +} + +#[test] fn drop_in_place() { check_pass( r#" @@ -614,6 +658,50 @@ fn main() { } #[test] +fn self_with_capital_s() { + check_pass( + r#" +//- minicore: fn, add, copy + +struct S1; + +impl S1 { + fn f() { + Self; + } +} + +struct S2 { + f1: i32, +} + +impl S2 { + fn f() { + Self { f1: 5 }; + } +} + +struct S3(i32); + +impl S3 { + fn f() { + Self(2); + Self; + let this = Self; + this(2); + } +} + +fn main() { + S1::f(); + S2::f(); + S3::f(); +} + "#, + ); +} + +#[test] fn syscalls() { check_pass( r#" 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 9f25175a3a9..718df8331e2 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 @@ -486,13 +486,10 @@ impl<'ctx> MirLowerCtx<'ctx> { ); Ok(Some(current)) } - ValueNs::FunctionId(_) | ValueNs::StructId(_) => { + ValueNs::FunctionId(_) | ValueNs::StructId(_) | ValueNs::ImplSelf(_) => { // It's probably a unit struct or a zero sized function, so no action is needed. Ok(Some(current)) } - it => { - not_supported!("unknown name {it:?} in value name space"); - } } } Expr::If { condition, then_branch, else_branch } => { @@ -585,36 +582,6 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(()) }) } - Expr::While { condition, body, label } => { - self.lower_loop(current, place, *label, expr_id.into(), |this, begin| { - let scope = this.push_drop_scope(); - let Some((discr, to_switch)) = - this.lower_expr_to_some_operand(*condition, begin)? - else { - return Ok(()); - }; - let fail_cond = this.new_basic_block(); - let after_cond = this.new_basic_block(); - this.set_terminator( - to_switch, - TerminatorKind::SwitchInt { - discr, - targets: SwitchTargets::static_if(1, after_cond, fail_cond), - }, - expr_id.into(), - ); - let fail_cond = this.drop_until_scope(this.drop_scopes.len() - 1, fail_cond); - let end = this.current_loop_end()?; - this.set_goto(fail_cond, end, expr_id.into()); - if let Some((_, block)) = this.lower_expr_as_place(after_cond, *body, true)? { - let block = scope.pop_and_drop(this, block); - this.set_goto(block, begin, expr_id.into()); - } else { - scope.pop_assume_dropped(this); - } - Ok(()) - }) - } Expr::Call { callee, args, .. } => { if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) { let ty = chalk_ir::TyKind::FnDef( @@ -660,6 +627,11 @@ impl<'ctx> MirLowerCtx<'ctx> { expr_id.into(), ) } + TyKind::Closure(_, _) => { + not_supported!( + "method resolution not emitted for closure (Are Fn traits available?)" + ); + } TyKind::Error => { return Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id)) } @@ -1026,18 +998,7 @@ impl<'ctx> MirLowerCtx<'ctx> { self.push_assignment(current, lhs_place, r_value, expr_id.into()); return Ok(Some(current)); } else { - let Some((lhs_place, current)) = - self.lower_expr_as_place(current, *lhs, false)? - else { - return Ok(None); - }; - let Some((rhs_op, current)) = - self.lower_expr_to_some_operand(*rhs, current)? - else { - return Ok(None); - }; - self.push_assignment(current, lhs_place, rhs_op.into(), expr_id.into()); - return Ok(Some(current)); + return self.lower_assignment(current, *lhs, *rhs, expr_id.into()); } } let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)? @@ -1283,6 +1244,30 @@ impl<'ctx> MirLowerCtx<'ctx> { } } + fn lower_assignment( + &mut self, + current: BasicBlockId, + lhs: ExprId, + rhs: ExprId, + span: MirSpan, + ) -> Result<Option<BasicBlockId>> { + let Some((rhs_op, current)) = + self.lower_expr_to_some_operand(rhs, current)? + else { + return Ok(None); + }; + if matches!(&self.body.exprs[lhs], Expr::Underscore) { + return Ok(Some(current)); + } + let Some((lhs_place, current)) = + self.lower_expr_as_place(current, lhs, false)? + else { + return Ok(None); + }; + self.push_assignment(current, lhs_place, rhs_op.into(), span); + Ok(Some(current)) + } + fn placeholder_subst(&mut self) -> Substitution { let placeholder_subst = match self.owner.as_generic_def_id() { Some(it) => TyBuilder::placeholder_subst(self.db, it), 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 425432479e8..e75b037e38d 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 @@ -227,3 +227,22 @@ fn f(a: impl Foo<i8, Assoc<i16> = i32>) { "#, ); } + +#[test] +fn fn_def_is_shown_as_fn_ptr() { + check_types_source_code( + r#" +fn foo(_: i32) -> i64 { 42 } +struct S<T>(T); +enum E { A(usize) } +fn test() { + let f = foo; + //^ fn(i32) -> i64 + let f = S::<i8>; + //^ fn(i8) -> S<i8> + let f = E::A; + //^ fn(usize) -> E +} +"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs index b71c457f015..1e6e946a13f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs @@ -209,6 +209,8 @@ fn expr_macro_def_expanded_in_various_places() { 104..105 '_': IntoIterator::Item<isize> 117..119 '{}': () 124..134 '|| spam!()': impl Fn() -> isize + 140..156 'while ...!() {}': ! + 140..156 'while ...!() {}': () 140..156 'while ...!() {}': () 154..156 '{}': () 161..174 'break spam!()': ! @@ -300,6 +302,8 @@ fn expr_macro_rules_expanded_in_various_places() { 118..119 '_': IntoIterator::Item<isize> 131..133 '{}': () 138..148 '|| spam!()': impl Fn() -> isize + 154..170 'while ...!() {}': ! + 154..170 'while ...!() {}': () 154..170 'while ...!() {}': () 168..170 '{}': () 175..188 'break spam!()': ! diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs index 59046c0435a..5d809b82392 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs @@ -412,17 +412,23 @@ fn diverging_expression_3_break() { 355..654 '{ ...; }; }': () 398..399 'x': u32 407..433 '{ whil...; }; }': u32 + 409..430 'while ...eak; }': ! + 409..430 'while ...eak; }': () 409..430 'while ...eak; }': () 415..419 'true': bool 420..430 '{ break; }': () 422..427 'break': ! 537..538 'x': u32 546..564 '{ whil... {}; }': u32 + 548..561 'while true {}': ! + 548..561 'while true {}': () 548..561 'while true {}': () 554..558 'true': bool 559..561 '{}': () 615..616 'x': u32 624..651 '{ whil...; }; }': u32 + 626..648 'while ...urn; }': ! + 626..648 'while ...urn; }': () 626..648 'while ...urn; }': () 632..636 'true': bool 637..648 '{ return; }': () 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 8b95110233f..6ea059065e9 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 @@ -1267,6 +1267,8 @@ fn test() { "#, expect![[r#" 10..59 '{ ... } }': () + 16..57 'while ... }': ! + 16..57 'while ... }': () 16..57 'while ... }': () 22..30 '{ true }': bool 24..28 'true': bool @@ -1978,3 +1980,23 @@ fn x(a: [i32; 4]) { "#, ); } + +#[test] +fn dont_unify_on_casts() { + // #15246 + check_types( + r#" +fn unify(_: [bool; 1]) {} +fn casted(_: *const bool) {} +fn default<T>() -> T { loop {} } + +fn test() { + let foo = default(); + //^^^ [bool; 1] + + casted(&foo as *const _); + unify(foo); +} +"#, + ); +} 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 a0ff628435f..2ad7946c8ac 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 @@ -3513,7 +3513,6 @@ fn func() { ); } -// FIXME #[test] fn castable_to() { check_infer( @@ -3538,10 +3537,10 @@ fn func() { 120..122 '{}': () 138..184 '{ ...0]>; }': () 148..149 'x': Box<[i32; 0]> - 152..160 'Box::new': fn new<[{unknown}; 0]>([{unknown}; 0]) -> Box<[{unknown}; 0]> - 152..164 'Box::new([])': Box<[{unknown}; 0]> + 152..160 'Box::new': fn new<[i32; 0]>([i32; 0]) -> Box<[i32; 0]> + 152..164 'Box::new([])': Box<[i32; 0]> 152..181 'Box::n...2; 0]>': Box<[i32; 0]> - 161..163 '[]': [{unknown}; 0] + 161..163 '[]': [i32; 0] "#]], ); } @@ -3578,6 +3577,21 @@ fn f<T>(t: Ark<T>) { } #[test] +fn ref_to_array_to_ptr_cast() { + check_types( + r#" +fn default<T>() -> T { loop {} } +fn foo() { + let arr = [default()]; + //^^^ [i32; 1] + let ref_to_arr = &arr; + let casted = ref_to_arr as *const i32; +} +"#, + ); +} + +#[test] fn const_dependent_on_local() { check_types( r#" diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index cf8db2a5a24..0f2fb2c8118 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -12,9 +12,9 @@ use hir_ty::db::HirDatabase; use syntax::{ast, AstNode}; use crate::{ - Adt, AssocItem, Const, ConstParam, Enum, Field, Function, GenericParam, Impl, LifetimeParam, - Macro, Module, ModuleDef, Static, Struct, Trait, TraitAlias, TypeAlias, TypeParam, Union, - Variant, + Adt, AssocItem, Const, ConstParam, Enum, ExternCrateDecl, Field, Function, GenericParam, Impl, + LifetimeParam, Macro, Module, ModuleDef, Static, Struct, Trait, TraitAlias, TypeAlias, + TypeParam, Union, Variant, }; pub trait HasAttrs { @@ -120,6 +120,39 @@ impl HasAttrs for AssocItem { } } +impl HasAttrs for ExternCrateDecl { + fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner { + let def = AttrDefId::ExternCrateId(self.into()); + db.attrs_with_owner(def) + } + fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> { + let crate_docs = self.resolved_crate(db)?.root_module().attrs(db).docs().map(String::from); + let def = AttrDefId::ExternCrateId(self.into()); + let decl_docs = db.attrs(def).docs().map(String::from); + match (decl_docs, crate_docs) { + (None, None) => None, + (Some(decl_docs), None) => Some(decl_docs), + (None, Some(crate_docs)) => Some(crate_docs), + (Some(mut decl_docs), Some(crate_docs)) => { + decl_docs.push('\n'); + decl_docs.push('\n'); + decl_docs += &crate_docs; + Some(decl_docs) + } + } + .map(Documentation::new) + } + fn resolve_doc_path( + self, + db: &dyn HirDatabase, + link: &str, + ns: Option<Namespace>, + ) -> Option<ModuleDef> { + let def = AttrDefId::ExternCrateId(self.into()); + resolve_doc_path(db, def, link, ns).map(ModuleDef::from) + } +} + /// Resolves the item `link` points to in the scope of `def`. fn resolve_doc_path( db: &dyn HirDatabase, @@ -140,6 +173,7 @@ fn resolve_doc_path( AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()), AttrDefId::ImplId(it) => it.resolver(db.upcast()), AttrDefId::ExternBlockId(it) => it.resolver(db.upcast()), + AttrDefId::UseId(it) => it.resolver(db.upcast()), AttrDefId::MacroId(it) => it.resolver(db.upcast()), AttrDefId::ExternCrateId(it) => it.resolver(db.upcast()), AttrDefId::GenericParamId(it) => match it { diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs index f3a0608944b..936581bfe32 100644 --- a/src/tools/rust-analyzer/crates/hir/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir/src/db.rs @@ -10,8 +10,3 @@ pub use hir_expand::db::{ MacroExpandQuery, ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, }; pub use hir_ty::db::*; - -#[test] -fn hir_database_is_object_safe() { - fn _assert_object_safe(_: &dyn HirDatabase) {} -} diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 4de9c872ad6..9dfb98e459b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -18,9 +18,9 @@ use hir_ty::{ }; use crate::{ - Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Enum, Field, Function, GenericParam, - HasCrate, HasVisibility, LifetimeParam, Macro, Module, Static, Struct, Trait, TraitAlias, - TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant, + Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, Field, + Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module, Static, Struct, + Trait, TraitAlias, TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant, }; impl HirDisplay for Function { @@ -238,6 +238,18 @@ impl HirDisplay for Type { } } +impl HirDisplay for ExternCrateDecl { + fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; + f.write_str("extern crate ")?; + write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; + if let Some(alias) = self.alias(f.db) { + write!(f, " as {alias}",)?; + } + Ok(()) + } +} + impl HirDisplay for GenericParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { match self { diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs index de23902199f..fc4bbffdb83 100644 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs @@ -15,7 +15,7 @@ use crate::{ }; macro_rules! from_id { - ($(($id:path, $ty:path)),*) => {$( + ($(($id:path, $ty:path)),* $(,)?) => {$( impl From<$id> for $ty { fn from(id: $id) -> $ty { $ty { id } @@ -47,7 +47,8 @@ from_id![ (hir_def::TypeParamId, crate::TypeParam), (hir_def::ConstParamId, crate::ConstParam), (hir_def::LifetimeParamId, crate::LifetimeParam), - (hir_def::MacroId, crate::Macro) + (hir_def::MacroId, crate::Macro), + (hir_def::ExternCrateId, crate::ExternCrateDecl), ]; impl From<AdtId> for Adt { diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index b46a3856d45..31cf8ba3364 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -11,9 +11,9 @@ use hir_expand::{HirFileId, InFile}; use syntax::ast; use crate::{ - db::HirDatabase, Adt, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam, - LocalSource, Macro, Module, Static, Struct, Trait, TraitAlias, TypeAlias, TypeOrConstParam, - Union, Variant, + db::HirDatabase, Adt, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl, + LifetimeParam, LocalSource, Macro, Module, Static, Struct, Trait, TraitAlias, TypeAlias, + TypeOrConstParam, Union, Variant, }; pub trait HasSource { @@ -207,3 +207,11 @@ impl HasSource for LocalSource { Some(self.source) } } + +impl HasSource for ExternCrateDecl { + type Ast = ast::ExternCrate; + + fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { + Some(self.id.lookup(db.upcast()).source(db.upcast())) + } +} diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index b094bb7a068..bf041b61f2f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -48,14 +48,15 @@ use hir_def::{ layout::{self, ReprOptions, TargetDataLayout}, macro_id_to_def_id, nameres::{self, diagnostics::DefDiagnostic}, + path::ImportAlias, per_ns::PerNs, resolver::{HasResolver, Resolver}, src::HasSource as _, - AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, - EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, InTypeConstId, ItemContainerId, - LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, - StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, - UnionId, + AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, + EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, HasModule, ImplId, + InTypeConstId, ItemContainerId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, Lookup, + MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, + TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{name::name, MacroCallKind}; use hir_ty::{ @@ -200,9 +201,8 @@ impl Crate { db.crate_graph().transitive_rev_deps(self.id).map(|id| Crate { id }) } - pub fn root_module(self, db: &dyn HirDatabase) -> Module { - let def_map = db.crate_def_map(self.id); - Module { id: def_map.crate_root().into() } + pub fn root_module(self) -> Module { + Module { id: CrateRootModuleId::from(self.id).into() } } pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> { @@ -247,7 +247,7 @@ impl Crate { /// Try to get the root URL of the documentation of a crate. pub fn get_html_root_url(self: &Crate, db: &dyn HirDatabase) -> Option<String> { // Look for #![doc(html_root_url = "...")] - let attrs = db.attrs(AttrDefId::ModuleId(self.root_module(db).into())); + let attrs = db.attrs(AttrDefId::ModuleId(self.root_module().into())); let doc_url = attrs.by_key("doc").find_string_value_in_tt("html_root_url"); doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/") } @@ -2129,6 +2129,47 @@ impl HasVisibility for Function { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ExternCrateDecl { + pub(crate) id: ExternCrateId, +} + +impl ExternCrateDecl { + pub fn module(self, db: &dyn HirDatabase) -> Module { + self.id.module(db.upcast()).into() + } + + pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option<Crate> { + db.extern_crate_decl_data(self.id).crate_id.map(Into::into) + } + + pub fn name(self, db: &dyn HirDatabase) -> Name { + db.extern_crate_decl_data(self.id).name.clone() + } + + pub fn alias(self, db: &dyn HirDatabase) -> Option<ImportAlias> { + db.extern_crate_decl_data(self.id).alias.clone() + } + + /// Returns the name under which this crate is made accessible, taking `_` into account. + pub fn alias_or_name(self, db: &dyn HirDatabase) -> Option<Name> { + let extern_crate_decl_data = db.extern_crate_decl_data(self.id); + match &extern_crate_decl_data.alias { + Some(ImportAlias::Underscore) => None, + Some(ImportAlias::Alias(alias)) => Some(alias.clone()), + None => Some(extern_crate_decl_data.name.clone()), + } + } +} + +impl HasVisibility for ExternCrateDecl { + fn visibility(&self, db: &dyn HirDatabase) -> Visibility { + db.extern_crate_decl_data(self.id) + .visibility + .resolve(db.upcast(), &self.id.resolver(db.upcast())) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct InTypeConst { pub(crate) id: InTypeConstId, } @@ -4715,6 +4756,12 @@ pub trait HasContainer { fn container(&self, db: &dyn HirDatabase) -> ItemContainer; } +impl HasContainer for ExternCrateDecl { + fn container(&self, db: &dyn HirDatabase) -> ItemContainer { + container_id_to_hir(self.id.lookup(db.upcast()).container.into()) + } +} + impl HasContainer for Module { fn container(&self, db: &dyn HirDatabase) -> ItemContainer { // FIXME: handle block expressions as modules (their parent is in a different DefMap) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 39a3e1c4489..e99d2984c36 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -15,11 +15,7 @@ use hir_def::{ type_ref::Mutability, AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId, }; -use hir_expand::{ - db::ExpandDatabase, - name::{known, AsName}, - ExpansionInfo, MacroCallId, -}; +use hir_expand::{db::ExpandDatabase, name::AsName, ExpansionInfo, MacroCallId}; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; @@ -439,10 +435,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_path(path) } - pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> { - self.imp.resolve_extern_crate(extern_crate) - } - pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> { self.imp.resolve_variant(record_lit).map(VariantDef::from) } @@ -1242,18 +1234,6 @@ impl<'db> SemanticsImpl<'db> { self.analyze(path.syntax())?.resolve_path(self.db, path) } - fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> { - let krate = self.scope(extern_crate.syntax())?.krate(); - let name = extern_crate.name_ref()?.as_name(); - if name == known::SELF_PARAM { - return Some(krate); - } - krate - .dependencies(self.db) - .into_iter() - .find_map(|dep| (dep.name == name).then_some(dep.krate)) - } - fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> { self.analyze(record_lit.syntax())?.resolve_variant(self.db, record_lit) } @@ -1603,6 +1583,7 @@ to_def_impls![ (crate::Local, ast::SelfParam, self_param_to_def), (crate::Label, ast::Label, label_to_def), (crate::Adt, ast::Adt, adt_to_def), + (crate::ExternCrateDecl, ast::ExternCrate, extern_crate_to_def), ]; fn find_root(node: &SyntaxNode) -> SyntaxNode { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index b971ca62387..aabda365560 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -93,9 +93,9 @@ use hir_def::{ DynMap, }, hir::{BindingId, LabelId}, - AdtId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, - GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId, StaticId, StructId, - TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, + AdtId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FieldId, + FunctionId, GenericDefId, GenericParamId, ImplId, LifetimeParamId, MacroId, ModuleId, StaticId, + StructId, TraitAliasId, TraitId, TypeAliasId, TypeParamId, UnionId, UseId, VariantId, }; use hir_expand::{attrs::AttrId, name::AsName, HirFileId, MacroCallId}; use rustc_hash::FxHashMap; @@ -203,6 +203,16 @@ impl SourceToDefCtx<'_, '_> { ) -> Option<EnumVariantId> { self.to_def(src, keys::VARIANT) } + pub(super) fn extern_crate_to_def( + &mut self, + src: InFile<ast::ExternCrate>, + ) -> Option<ExternCrateId> { + self.to_def(src, keys::EXTERN_CRATE) + } + #[allow(dead_code)] + pub(super) fn use_to_def(&mut self, src: InFile<ast::Use>) -> Option<UseId> { + self.to_def(src, keys::USE) + } pub(super) fn adt_to_def( &mut self, InFile { file_id, value }: InFile<ast::Adt>, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index d07c6372628..6aca716bb60 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -3,7 +3,10 @@ use syntax::ast::{self, make, AstNode}; use crate::{ assist_context::{AssistContext, Assists}, - utils::{add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, DefaultMethods}, + utils::{ + add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, DefaultMethods, + IgnoreAssocItems, + }, AssistId, AssistKind, }; @@ -43,6 +46,7 @@ pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext<'_ acc, ctx, DefaultMethods::No, + IgnoreAssocItems::DocHiddenAttrPresent, "add_impl_missing_members", "Implement missing members", ) @@ -87,6 +91,7 @@ pub(crate) fn add_missing_default_members( acc, ctx, DefaultMethods::Only, + IgnoreAssocItems::DocHiddenAttrPresent, "add_impl_default_members", "Implement default members", ) @@ -96,6 +101,7 @@ fn add_missing_impl_members_inner( acc: &mut Assists, ctx: &AssistContext<'_>, mode: DefaultMethods, + ignore_items: IgnoreAssocItems, assist_id: &'static str, label: &'static str, ) -> Option<()> { @@ -115,10 +121,21 @@ fn add_missing_impl_members_inner( let trait_ref = impl_.trait_ref(ctx.db())?; let trait_ = trait_ref.trait_(); + let mut ign_item = ignore_items; + + if let IgnoreAssocItems::DocHiddenAttrPresent = ignore_items { + // Relax condition for local crates. + let db = ctx.db(); + if trait_.module(db).krate().origin(db).is_local() { + ign_item = IgnoreAssocItems::No; + } + } + let missing_items = filter_assoc_items( &ctx.sema, &ide_db::traits::get_missing_assoc_items(&ctx.sema, &impl_def), mode, + ign_item, ); if missing_items.is_empty() { @@ -1966,4 +1983,169 @@ impl AnotherTrait<i32> for () { "#, ); } + + #[test] + fn doc_hidden_default_impls_ignored() { + // doc(hidden) attr is ignored trait and impl both belong to the local crate. + check_assist( + add_missing_default_members, + r#" +struct Foo; +trait Trait { + #[doc(hidden)] + fn func_with_default_impl() -> u32 { + 42 + } + fn another_default_impl() -> u32 { + 43 + } +} +impl Tra$0it for Foo {}"#, + r#" +struct Foo; +trait Trait { + #[doc(hidden)] + fn func_with_default_impl() -> u32 { + 42 + } + fn another_default_impl() -> u32 { + 43 + } +} +impl Trait for Foo { + $0fn func_with_default_impl() -> u32 { + 42 + } + + fn another_default_impl() -> u32 { + 43 + } +}"#, + ) + } + + #[test] + fn doc_hidden_default_impls_lang_crates() { + // Not applicable because Eq has a single method and this has a #[doc(hidden)] attr set. + check_assist_not_applicable( + add_missing_default_members, + r#" +//- minicore: eq +use core::cmp::Eq; +struct Foo; +impl E$0q for Foo { /* $0 */ } +"#, + ) + } + + #[test] + fn doc_hidden_default_impls_lib_crates() { + check_assist( + add_missing_default_members, + r#" + //- /main.rs crate:a deps:b + struct B; + impl b::Exte$0rnTrait for B {} + //- /lib.rs crate:b new_source_root:library + pub trait ExternTrait { + #[doc(hidden)] + fn hidden_default() -> Option<()> { + todo!() + } + + fn unhidden_default() -> Option<()> { + todo!() + } + + fn unhidden_nondefault() -> Option<()>; + } + "#, + r#" + struct B; + impl b::ExternTrait for B { + $0fn unhidden_default() -> Option<()> { + todo!() + } + } + "#, + ) + } + + #[test] + fn doc_hidden_default_impls_local_crates() { + check_assist( + add_missing_default_members, + r#" +trait LocalTrait { + #[doc(hidden)] + fn no_skip_default() -> Option<()> { + todo!() + } + fn no_skip_default_2() -> Option<()> { + todo!() + } +} + +struct B; +impl Loc$0alTrait for B {} + "#, + r#" +trait LocalTrait { + #[doc(hidden)] + fn no_skip_default() -> Option<()> { + todo!() + } + fn no_skip_default_2() -> Option<()> { + todo!() + } +} + +struct B; +impl LocalTrait for B { + $0fn no_skip_default() -> Option<()> { + todo!() + } + + fn no_skip_default_2() -> Option<()> { + todo!() + } +} + "#, + ) + } + + #[test] + fn doc_hidden_default_impls_workspace_crates() { + check_assist( + add_missing_default_members, + r#" +//- /lib.rs crate:b new_source_root:local +trait LocalTrait { + #[doc(hidden)] + fn no_skip_default() -> Option<()> { + todo!() + } + fn no_skip_default_2() -> Option<()> { + todo!() + } +} + +//- /main.rs crate:a deps:b +struct B; +impl b::Loc$0alTrait for B {} + "#, + r#" +struct B; +impl b::LocalTrait for B { + $0fn no_skip_default() -> Option<()> { + todo!() + } + + fn no_skip_default_2() -> Option<()> { + todo!() + } +} + "#, + ) + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index ac0b74ee8e7..3b162d7c4d8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -37,9 +37,9 @@ use crate::{utils, AssistContext, AssistId, AssistKind, Assists}; pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let match_expr = ctx.find_node_at_offset_with_descend::<ast::MatchExpr>()?; let match_arm_list = match_expr.match_arm_list()?; - let target_range = ctx.sema.original_range(match_expr.syntax()).range; + let arm_list_range = ctx.sema.original_range_opt(match_arm_list.syntax())?; - if let None = cursor_at_trivial_match_arm_list(ctx, &match_expr, &match_arm_list) { + if cursor_at_trivial_match_arm_list(ctx, &match_expr, &match_arm_list).is_none() { let arm_list_range = ctx.sema.original_range(match_arm_list.syntax()).range; let cursor_in_range = arm_list_range.contains_range(ctx.selection_trimmed()); if cursor_in_range { @@ -198,7 +198,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) acc.add( AssistId("add_missing_match_arms", AssistKind::QuickFix), "Fill match arms", - target_range, + ctx.sema.original_range(match_expr.syntax()).range, |edit| { let new_match_arm_list = match_arm_list.clone_for_update(); @@ -262,9 +262,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) // Just replace the element that the original range came from let old_place = { // Find the original element - let old_file_range = ctx.sema.original_range(match_arm_list.syntax()); - let file = ctx.sema.parse(old_file_range.file_id); - let old_place = file.syntax().covering_element(old_file_range.range); + let file = ctx.sema.parse(arm_list_range.file_id); + let old_place = file.syntax().covering_element(arm_list_range.range); // Make `old_place` mut match old_place { @@ -1922,4 +1921,24 @@ fn foo(t: E) { }"#, ); } + + #[test] + fn not_applicable_when_match_arm_list_cannot_be_upmapped() { + check_assist_not_applicable( + add_missing_match_arms, + r#" +macro_rules! foo { + ($($t:tt)*) => { + $($t)* {} + } +} + +enum E { A } + +fn main() { + foo!(match E::A$0); +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs index acf82e4b257..36f68d17677 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs @@ -42,7 +42,9 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti let name_ref = ast::NameRef::cast(ident.parent()?)?; let def = match NameRefClass::classify(&ctx.sema, &name_ref)? { NameRefClass::Definition(def) => def, - NameRefClass::FieldShorthand { .. } => return None, + NameRefClass::FieldShorthand { .. } | NameRefClass::ExternCrateShorthand { .. } => { + return None + } }; let fun = match def { Definition::Function(it) => it, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs index b1b0f587cd3..6a5b11f5425 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs @@ -1,3 +1,6 @@ +use hir::Semantics; +use ide_db::RootDatabase; +use stdx::format_to; use syntax::ast::{self, AstNode}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -24,6 +27,7 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro( acc: &mut Assists, ctx: &AssistContext<'_>, ) -> Option<()> { + use ArmBodyExpression::*; let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?; let match_arm_list = match_expr.match_arm_list()?; let mut arms = match_arm_list.arms(); @@ -33,21 +37,20 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro( cov_mark::hit!(non_two_arm_match); return None; } - let first_arm_expr = first_arm.expr(); - let second_arm_expr = second_arm.expr(); + let first_arm_expr = first_arm.expr()?; + let second_arm_expr = second_arm.expr()?; + let first_arm_body = is_bool_literal_expr(&ctx.sema, &first_arm_expr)?; + let second_arm_body = is_bool_literal_expr(&ctx.sema, &second_arm_expr)?; - let invert_matches = if is_bool_literal_expr(&first_arm_expr, true) - && is_bool_literal_expr(&second_arm_expr, false) - { - false - } else if is_bool_literal_expr(&first_arm_expr, false) - && is_bool_literal_expr(&second_arm_expr, true) - { - true - } else { + if !matches!( + (&first_arm_body, &second_arm_body), + (Literal(true), Literal(false)) + | (Literal(false), Literal(true)) + | (Expression(_), Literal(false)) + ) { cov_mark::hit!(non_invert_bool_literal_arms); return None; - }; + } let target_range = ctx.sema.original_range(match_expr.syntax()).range; let expr = match_expr.expr()?; @@ -59,28 +62,55 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro( |builder| { let mut arm_str = String::new(); if let Some(pat) = &first_arm.pat() { - arm_str += &pat.to_string(); + format_to!(arm_str, "{pat}"); } if let Some(guard) = &first_arm.guard() { arm_str += &format!(" {guard}"); } - if invert_matches { - builder.replace(target_range, format!("!matches!({expr}, {arm_str})")); - } else { - builder.replace(target_range, format!("matches!({expr}, {arm_str})")); - } + + let replace_with = match (first_arm_body, second_arm_body) { + (Literal(true), Literal(false)) => { + format!("matches!({expr}, {arm_str})") + } + (Literal(false), Literal(true)) => { + format!("!matches!({expr}, {arm_str})") + } + (Expression(body_expr), Literal(false)) => { + arm_str.push_str(match &first_arm.guard() { + Some(_) => " && ", + _ => " if ", + }); + format!("matches!({expr}, {arm_str}{body_expr})") + } + _ => { + unreachable!() + } + }; + builder.replace(target_range, replace_with); }, ) } -fn is_bool_literal_expr(expr: &Option<ast::Expr>, expect_bool: bool) -> bool { - if let Some(ast::Expr::Literal(lit)) = expr { +enum ArmBodyExpression { + Literal(bool), + Expression(ast::Expr), +} + +fn is_bool_literal_expr( + sema: &Semantics<'_, RootDatabase>, + expr: &ast::Expr, +) -> Option<ArmBodyExpression> { + if let ast::Expr::Literal(lit) = expr { if let ast::LiteralKind::Bool(b) = lit.kind() { - return b == expect_bool; + return Some(ArmBodyExpression::Literal(b)); } } - return false; + if !sema.type_of_expr(expr)?.original.is_bool() { + return None; + } + + Some(ArmBodyExpression::Expression(expr.clone())) } #[cfg(test)] @@ -122,21 +152,6 @@ fn foo(a: Option<u32>) -> bool { } #[test] - fn not_applicable_non_bool_literal_arms() { - cov_mark::check!(non_invert_bool_literal_arms); - check_assist_not_applicable( - convert_two_arm_bool_match_to_matches_macro, - r#" -fn foo(a: Option<u32>) -> bool { - match a$0 { - Some(val) => val == 3, - _ => false - } -} - "#, - ); - } - #[test] fn not_applicable_both_false_arms() { cov_mark::check!(non_invert_bool_literal_arms); check_assist_not_applicable( @@ -291,4 +306,40 @@ fn main() { }", ); } + + #[test] + fn convert_non_literal_bool() { + check_assist( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn main() { + match 0$0 { + a @ 0..15 => a == 0, + _ => false, + } +} +"#, + r#" +fn main() { + matches!(0, a @ 0..15 if a == 0) +} +"#, + ); + check_assist( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn main() { + match 0$0 { + a @ 0..15 if thing() => a == 0, + _ => false, + } +} +"#, + r#" +fn main() { + matches!(0, a @ 0..15 if thing() && a == 0) +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index ea71d165e6a..f30ca2552d3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -114,7 +114,7 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option<TupleDat let usages = ctx.sema.to_def(&ident_pat).map(|def| { Definition::Local(def) .usages(&ctx.sema) - .in_scope(SearchScope::single_file(ctx.file_id())) + .in_scope(&SearchScope::single_file(ctx.file_id())) .all() }); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs index 3aff5c9144f..9beb616d99b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs @@ -120,7 +120,7 @@ fn find_parent_and_path( fn def_is_referenced_in(def: Definition, ctx: &AssistContext<'_>) -> bool { let search_scope = SearchScope::single_file(ctx.file_id()); - def.usages(&ctx.sema).in_scope(search_scope).at_least_one() + def.usages(&ctx.sema).in_scope(&search_scope).at_least_one() } #[derive(Debug, Clone)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index e9db38aca0f..b8b781ea48d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -384,7 +384,7 @@ impl LocalUsages { Self( Definition::Local(var) .usages(&ctx.sema) - .in_scope(SearchScope::single_file(ctx.file_id())) + .in_scope(&SearchScope::single_file(ctx.file_id())) .all(), ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs index de37f5f130f..6839c5820dc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs @@ -478,7 +478,7 @@ impl Module { let selection_range = ctx.selection_trimmed(); let curr_file_id = ctx.file_id(); let search_scope = SearchScope::single_file(curr_file_id); - let usage_res = def.usages(&ctx.sema).in_scope(search_scope).all(); + let usage_res = def.usages(&ctx.sema).in_scope(&search_scope).all(); let file = ctx.sema.parse(curr_file_id); let mut exists_inside_sel = false; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs index 860372941f7..7e4f140a28f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_new.rs @@ -15,6 +15,7 @@ use crate::{ // Generates default implementation from new method. // // ``` +// # //- minicore: default // struct Example { _inner: () } // // impl Example { @@ -54,6 +55,7 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<' } let impl_ = fn_node.syntax().ancestors().find_map(ast::Impl::cast)?; + let self_ty = impl_.self_ty()?; if is_default_implemented(ctx, &impl_) { cov_mark::hit!(default_block_is_already_present); cov_mark::hit!(struct_in_module_with_default); @@ -70,15 +72,19 @@ pub(crate) fn generate_default_from_new(acc: &mut Assists, ctx: &AssistContext<' let default_code = " fn default() -> Self { Self::new() }"; - let code = generate_trait_impl_text_from_impl(&impl_, "Default", default_code); + let code = generate_trait_impl_text_from_impl(&impl_, self_ty, "Default", default_code); builder.insert(insert_location.end(), code); }, ) } // FIXME: based on from utils::generate_impl_text_inner -fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: &str) -> String { - let impl_ty = impl_.self_ty().unwrap(); +fn generate_trait_impl_text_from_impl( + impl_: &ast::Impl, + self_ty: ast::Type, + trait_text: &str, + code: &str, +) -> String { let generic_params = impl_.generic_param_list().map(|generic_params| { let lifetime_params = generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam); @@ -109,7 +115,7 @@ fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code: if let Some(generic_params) = &generic_params { format_to!(buf, "{generic_params}") } - format_to!(buf, " {trait_text} for {impl_ty}"); + format_to!(buf, " {trait_text} for {self_ty}"); match impl_.where_clause() { Some(where_clause) => { @@ -136,7 +142,9 @@ fn is_default_implemented(ctx: &AssistContext<'_>, impl_: &Impl) -> bool { let default = FamousDefs(&ctx.sema, krate).core_default_Default(); let default_trait = match default { Some(value) => value, - None => return false, + // Return `true` to avoid providing the assist because it makes no sense + // to impl `Default` when it's missing. + None => return true, }; ty.impls_trait(db, default_trait, &[]) @@ -480,6 +488,7 @@ impl Example { check_assist_not_applicable( generate_default_from_new, r#" +//- minicore: default struct Example { _inner: () } impl Example { @@ -655,4 +664,23 @@ mod test { "#, ); } + + #[test] + fn not_applicable_when_default_lang_item_is_missing() { + check_assist_not_applicable( + generate_default_from_new, + r#" +struct S; +impl S { + fn new$0() -> Self {} +} +"#, + ); + } + + #[test] + fn not_applicable_for_missing_self_ty() { + // Regression test for #15398. + check_assist_not_applicable(generate_default_from_new, "impl { fn new$0() -> Self {} }"); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs index 185f47184d4..f4fa6a74c6b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -213,7 +213,9 @@ impl Struct { // continue; // } let signature = delegee.signature(db); - let delegate = generate_impl(ctx, self, &field.ty, &field.name, delegee); + let Some(delegate) = generate_impl(ctx, self, &field.ty, &field.name, delegee) else { + continue; + }; acc.add_group( &GroupLabel("Delegate trait impl for field...".to_owned()), @@ -237,7 +239,7 @@ fn generate_impl( field_ty: &ast::Type, field_name: &String, delegee: &Delegee, -) -> ast::Impl { +) -> Option<ast::Impl> { let delegate: ast::Impl; let source: ast::Impl; let genpar: Option<ast::GenericParamList>; @@ -247,7 +249,7 @@ fn generate_impl( match delegee { Delegee::Bound(delegee) => { - let in_file = ctx.sema.source(delegee.0.to_owned()).unwrap(); + let in_file = ctx.sema.source(delegee.0.to_owned())?; let source: ast::Trait = in_file.value; delegate = make::impl_trait( @@ -293,15 +295,15 @@ fn generate_impl( None => {} }; - let target = ctx.sema.scope(strukt.strukt.syntax()).unwrap(); - let source = ctx.sema.scope(source.syntax()).unwrap(); + let target = ctx.sema.scope(strukt.strukt.syntax())?; + let source = ctx.sema.scope(source.syntax())?; let transform = PathTransform::trait_impl(&target, &source, delegee.0, delegate.clone()); transform.apply(&delegate.syntax()); } Delegee::Impls(delegee) => { - let in_file = ctx.sema.source(delegee.1.to_owned()).unwrap(); + let in_file = ctx.sema.source(delegee.1.to_owned())?; source = in_file.value; delegate = make::impl_trait( delegee.0.is_unsafe(db), @@ -341,8 +343,8 @@ fn generate_impl( } }); - let target = ctx.sema.scope(strukt.strukt.syntax()).unwrap(); - let source = ctx.sema.scope(source.syntax()).unwrap(); + let target = ctx.sema.scope(strukt.strukt.syntax())?; + let source = ctx.sema.scope(source.syntax())?; let transform = PathTransform::trait_impl(&target, &source, delegee.0, delegate.clone()); @@ -350,7 +352,7 @@ fn generate_impl( } } - delegate + Some(delegate) } fn process_assoc_item( @@ -359,19 +361,19 @@ fn process_assoc_item( base_name: &str, ) -> Option<ast::AssocItem> { match item { - AssocItem::Const(c) => Some(const_assoc_item(c, qual_path_ty)), - AssocItem::Fn(f) => Some(func_assoc_item(f, qual_path_ty, base_name)), + AssocItem::Const(c) => const_assoc_item(c, qual_path_ty), + AssocItem::Fn(f) => func_assoc_item(f, qual_path_ty, base_name), AssocItem::MacroCall(_) => { // FIXME : Handle MacroCall case. - // return Some(macro_assoc_item(mac, qual_path_ty)); + // macro_assoc_item(mac, qual_path_ty) None } - AssocItem::TypeAlias(ta) => Some(ty_assoc_item(ta, qual_path_ty)), + AssocItem::TypeAlias(ta) => ty_assoc_item(ta, qual_path_ty), } } -fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> AssocItem { - let path_expr_segment = make::path_from_text(item.name().unwrap().to_string().as_str()); +fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> Option<AssocItem> { + let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str()); // We want rhs of the const assignment to be a qualified path // The general case for const assigment can be found [here](`https://doc.rust-lang.org/reference/items/constant-items.html`) @@ -380,19 +382,19 @@ fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> AssocI // FIXME : We can't rely on `make::path_qualified` for now but it would be nice to replace the following with it. // make::path_qualified(qual_path_ty, path_expr_segment.as_single_segment().unwrap()); let qualpath = qualpath(qual_path_ty, path_expr_segment); - let inner = make::item_const( - item.visibility(), - item.name().unwrap(), - item.ty().unwrap(), - make::expr_path(qualpath), - ) - .clone_for_update(); + let inner = + make::item_const(item.visibility(), item.name()?, item.ty()?, make::expr_path(qualpath)) + .clone_for_update(); - AssocItem::Const(inner) + Some(AssocItem::Const(inner)) } -fn func_assoc_item(item: syntax::ast::Fn, qual_path_ty: Path, base_name: &str) -> AssocItem { - let path_expr_segment = make::path_from_text(item.name().unwrap().to_string().as_str()); +fn func_assoc_item( + item: syntax::ast::Fn, + qual_path_ty: Path, + base_name: &str, +) -> Option<AssocItem> { + let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str()); let qualpath = qualpath(qual_path_ty, path_expr_segment); let call = match item.param_list() { @@ -415,7 +417,7 @@ fn func_assoc_item(item: syntax::ast::Fn, qual_path_ty: Path, base_name: &str) - if param_count > 0 { // Add SelfParam and a TOKEN::COMMA ted::insert_all( - Position::after(args.l_paren_token().unwrap()), + Position::after(args.l_paren_token()?), vec![ NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()), NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)), @@ -425,7 +427,7 @@ fn func_assoc_item(item: syntax::ast::Fn, qual_path_ty: Path, base_name: &str) - } else { // Add SelfParam only ted::insert( - Position::after(args.l_paren_token().unwrap()), + Position::after(args.l_paren_token()?), NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()), ); } @@ -444,10 +446,10 @@ fn func_assoc_item(item: syntax::ast::Fn, qual_path_ty: Path, base_name: &str) - let body = make::block_expr(vec![], Some(call)).clone_for_update(); let func = make::fn_( item.visibility(), - item.name().unwrap(), + item.name()?, item.generic_param_list(), item.where_clause(), - item.param_list().unwrap(), + item.param_list()?, body, item.ret_type(), item.async_token().is_some(), @@ -456,14 +458,14 @@ fn func_assoc_item(item: syntax::ast::Fn, qual_path_ty: Path, base_name: &str) - ) .clone_for_update(); - AssocItem::Fn(func.indent(edit::IndentLevel(1)).clone_for_update()) + Some(AssocItem::Fn(func.indent(edit::IndentLevel(1)).clone_for_update())) } -fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> AssocItem { - let path_expr_segment = make::path_from_text(item.name().unwrap().to_string().as_str()); +fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> Option<AssocItem> { + let path_expr_segment = make::path_from_text(item.name()?.to_string().as_str()); let qualpath = qualpath(qual_path_ty, path_expr_segment); let ty = make::ty_path(qualpath); - let ident = item.name().unwrap().to_string(); + let ident = item.name()?.to_string(); let alias = make::ty_alias( ident.as_str(), @@ -474,7 +476,7 @@ fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> AssocItem ) .clone_for_update(); - AssocItem::TypeAlias(alias) + Some(AssocItem::TypeAlias(alias)) } fn qualpath(qual_path_ty: ast::Path, path_expr_seg: ast::Path) -> ast::Path { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index 8085572497a..5b13e01b133 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -1878,7 +1878,6 @@ where #[test] fn add_function_with_fn_arg() { - // FIXME: The argument in `bar` is wrong. check_assist( generate_function, r" @@ -1899,7 +1898,7 @@ fn foo() { bar(Baz::new); } -fn bar(new: fn) ${0:-> _} { +fn bar(new: fn() -> Baz) ${0:-> _} { todo!() } ", diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 67036029f5e..ffab58509b1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -80,7 +80,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) -> let is_recursive_fn = usages .clone() - .in_scope(SearchScope::file_range(FileRange { + .in_scope(&SearchScope::file_range(FileRange { file_id: def_file, range: func_body.syntax().text_range(), })) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs index 5aa8e56f562..5d956b1a5e8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs @@ -37,11 +37,10 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let unexpanded = ctx.find_node_at_offset::<ast::MacroCall>()?; let expanded = insert_ws_into(ctx.sema.expand(&unexpanded)?.clone_for_update()); - let text_range = unexpanded.syntax().text_range(); acc.add( - AssistId("inline_macro", AssistKind::RefactorRewrite), + AssistId("inline_macro", AssistKind::RefactorInline), format!("Inline macro"), text_range, |builder| builder.replace(text_range, expanded.to_string()), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs index e1849eb71d5..22d536b5afc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs @@ -82,17 +82,19 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> return None; } - let usages = - Definition::Const(def).usages(&ctx.sema).in_scope(SearchScope::file_range(FileRange { - file_id: ctx.file_id(), - range: parent_fn.syntax().text_range(), - })); - acc.add( AssistId("move_const_to_impl", crate::AssistKind::RefactorRewrite), "Move const to impl block", const_.syntax().text_range(), |builder| { + let usages = Definition::Const(def) + .usages(&ctx.sema) + .in_scope(&SearchScope::file_range(FileRange { + file_id: ctx.file_id(), + range: parent_fn.syntax().text_range(), + })) + .all(); + let range_to_delete = match const_.syntax().next_sibling_or_token() { Some(s) if matches!(s.kind(), SyntaxKind::WHITESPACE) => { // Remove following whitespaces too. @@ -103,7 +105,7 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> builder.delete(range_to_delete); let const_ref = format!("Self::{}", name.display(ctx.db())); - for range in usages.all().file_ranges().map(|it| it.range) { + for range in usages.file_ranges().map(|it| it.range) { builder.replace(range, const_ref.clone()); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs new file mode 100644 index 00000000000..dd4839351fb --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs @@ -0,0 +1,739 @@ +use std::collections::{hash_map::Entry, HashMap}; + +use hir::{InFile, Module, ModuleSource}; +use ide_db::{ + base_db::FileRange, + defs::Definition, + search::{FileReference, ReferenceCategory, SearchScope}, + RootDatabase, +}; +use syntax::{ast, AstNode}; +use text_edit::TextRange; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: remove_unused_imports +// +// Removes any use statements in the current selection that are unused. +// +// ``` +// struct X(); +// mod foo { +// use super::X$0; +// } +// ``` +// -> +// ``` +// struct X(); +// mod foo { +// } +// ``` +pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + // First, grab the uses that intersect with the current selection. + let selected_el = match ctx.covering_element() { + syntax::NodeOrToken::Node(n) => n, + syntax::NodeOrToken::Token(t) => t.parent()?, + }; + + // This applies to all uses that are selected, or are ancestors of our selection. + let uses_up = selected_el.ancestors().skip(1).filter_map(ast::Use::cast); + let uses_down = selected_el + .descendants() + .filter(|x| x.text_range().intersect(ctx.selection_trimmed()).is_some()) + .filter_map(ast::Use::cast); + let uses = uses_up.chain(uses_down).collect::<Vec<_>>(); + + // Maps use nodes to the scope that we should search through to find + let mut search_scopes = HashMap::<Module, Vec<SearchScope>>::new(); + + // iterator over all unused use trees + let mut unused = uses + .into_iter() + .flat_map(|u| u.syntax().descendants().filter_map(ast::UseTree::cast)) + .filter(|u| u.use_tree_list().is_none()) + .filter_map(|u| { + // Find any uses trees that are unused + + let use_module = ctx.sema.scope(&u.syntax()).map(|s| s.module())?; + let scope = match search_scopes.entry(use_module) { + Entry::Occupied(o) => o.into_mut(), + Entry::Vacant(v) => v.insert(module_search_scope(ctx.db(), use_module)), + }; + + // Gets the path associated with this use tree. If there isn't one, then ignore this use tree. + let path = if let Some(path) = u.path() { + path + } else if u.star_token().is_some() { + // This case maps to the situation where the * token is braced. + // In this case, the parent use tree's path is the one we should use to resolve the glob. + match u.syntax().ancestors().skip(1).find_map(ast::UseTree::cast) { + Some(parent_u) if parent_u.path().is_some() => parent_u.path().unwrap(), + _ => return None, + } + } else { + return None; + }; + + // Get the actual definition associated with this use item. + let res = match ctx.sema.resolve_path(&path) { + Some(x) => x, + None => { + return None; + } + }; + + let def = match res { + hir::PathResolution::Def(d) => Definition::from(d), + _ => return None, + }; + + if u.star_token().is_some() { + // Check if any of the children of this module are used + let def_mod = match def { + Definition::Module(module) => module, + _ => return None, + }; + + if !def_mod + .scope(ctx.db(), Some(use_module)) + .iter() + .filter_map(|(_, x)| match x { + hir::ScopeDef::ModuleDef(d) => Some(Definition::from(*d)), + _ => None, + }) + .any(|d| used_once_in_scope(ctx, d, scope)) + { + return Some(u); + } + } else if let Definition::Trait(ref t) = def { + // If the trait or any item is used. + if !std::iter::once(def) + .chain(t.items(ctx.db()).into_iter().map(Definition::from)) + .any(|d| used_once_in_scope(ctx, d, scope)) + { + return Some(u); + } + } else { + if !used_once_in_scope(ctx, def, &scope) { + return Some(u); + } + } + + None + }) + .peekable(); + + // Peek so we terminate early if an unused use is found. Only do the rest of the work if the user selects the assist. + if unused.peek().is_some() { + acc.add( + AssistId("remove_unused_imports", AssistKind::QuickFix), + "Remove all the unused imports", + selected_el.text_range(), + |builder| { + let unused: Vec<ast::UseTree> = unused.map(|x| builder.make_mut(x)).collect(); + for node in unused { + node.remove_recursive(); + } + }, + ) + } else { + None + } +} + +fn used_once_in_scope(ctx: &AssistContext<'_>, def: Definition, scopes: &Vec<SearchScope>) -> bool { + let mut found = false; + + for scope in scopes { + let mut search_non_import = |_, r: FileReference| { + // The import itself is a use; we must skip that. + if r.category != Some(ReferenceCategory::Import) { + found = true; + true + } else { + false + } + }; + def.usages(&ctx.sema).in_scope(scope).search(&mut search_non_import); + if found { + break; + } + } + + found +} + +/// Build a search scope spanning the given module but none of its submodules. +fn module_search_scope(db: &RootDatabase, module: hir::Module) -> Vec<SearchScope> { + let (file_id, range) = { + let InFile { file_id, value } = module.definition_source(db); + if let Some((file_id, call_source)) = file_id.original_call_node(db) { + (file_id, Some(call_source.text_range())) + } else { + ( + file_id.original_file(db), + match value { + ModuleSource::SourceFile(_) => None, + ModuleSource::Module(it) => Some(it.syntax().text_range()), + ModuleSource::BlockExpr(it) => Some(it.syntax().text_range()), + }, + ) + } + }; + + fn split_at_subrange(first: TextRange, second: TextRange) -> (TextRange, Option<TextRange>) { + let intersect = first.intersect(second); + if let Some(intersect) = intersect { + let start_range = TextRange::new(first.start(), intersect.start()); + + if intersect.end() < first.end() { + (start_range, Some(TextRange::new(intersect.end(), first.end()))) + } else { + (start_range, None) + } + } else { + (first, None) + } + } + + let mut scopes = Vec::new(); + if let Some(range) = range { + let mut ranges = vec![range]; + + for child in module.children(db) { + let rng = match child.definition_source(db).value { + ModuleSource::SourceFile(_) => continue, + ModuleSource::Module(it) => it.syntax().text_range(), + ModuleSource::BlockExpr(_) => continue, + }; + let mut new_ranges = Vec::new(); + for old_range in ranges.iter_mut() { + let split = split_at_subrange(old_range.clone(), rng); + *old_range = split.0; + new_ranges.extend(split.1); + } + + ranges.append(&mut new_ranges); + } + + for range in ranges { + scopes.push(SearchScope::file_range(FileRange { file_id, range })); + } + } else { + scopes.push(SearchScope::single_file(file_id)); + } + + scopes +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn remove_unused() { + check_assist( + remove_unused_imports, + r#" +struct X(); +struct Y(); +mod z { + $0use super::X; + use super::Y;$0 +} +"#, + r#" +struct X(); +struct Y(); +mod z { +} +"#, + ); + } + + #[test] + fn remove_unused_is_precise() { + check_assist( + remove_unused_imports, + r#" +struct X(); +mod z { +$0use super::X;$0 + +fn w() { + struct X(); + let x = X(); +} +} +"#, + r#" +struct X(); +mod z { + +fn w() { + struct X(); + let x = X(); +} +} +"#, + ); + } + + #[test] + fn trait_name_use_is_use() { + check_assist_not_applicable( + remove_unused_imports, + r#" +struct X(); +trait Y { + fn f(); +} + +impl Y for X { + fn f() {} +} +mod z { +$0use super::X; +use super::Y;$0 + +fn w() { + X::f(); +} +} +"#, + ); + } + + #[test] + fn trait_item_use_is_use() { + check_assist_not_applicable( + remove_unused_imports, + r#" +struct X(); +trait Y { + fn f(self); +} + +impl Y for X { + fn f(self) {} +} +mod z { +$0use super::X; +use super::Y;$0 + +fn w() { + let x = X(); + x.f(); +} +} +"#, + ); + } + + #[test] + fn ranamed_trait_item_use_is_use() { + check_assist_not_applicable( + remove_unused_imports, + r#" +struct X(); +trait Y { + fn f(self); +} + +impl Y for X { + fn f(self) {} +} +mod z { +$0use super::X; +use super::Y as Z;$0 + +fn w() { + let x = X(); + x.f(); +} +} +"#, + ); + } + + #[test] + fn ranamed_underscore_trait_item_use_is_use() { + check_assist_not_applicable( + remove_unused_imports, + r#" +struct X(); +trait Y { + fn f(self); +} + +impl Y for X { + fn f(self) {} +} +mod z { +$0use super::X; +use super::Y as _;$0 + +fn w() { + let x = X(); + x.f(); +} +} +"#, + ); + } + + #[test] + fn dont_remove_used() { + check_assist_not_applicable( + remove_unused_imports, + r#" +struct X(); +struct Y(); +mod z { +$0use super::X; +use super::Y;$0 + +fn w() { + let x = X(); + let y = Y(); +} +} +"#, + ); + } + + #[test] + fn remove_unused_in_braces() { + check_assist( + remove_unused_imports, + r#" +struct X(); +struct Y(); +mod z { + $0use super::{X, Y};$0 + + fn w() { + let x = X(); + } +} +"#, + r#" +struct X(); +struct Y(); +mod z { + use super::{X}; + + fn w() { + let x = X(); + } +} +"#, + ); + } + + #[test] + fn remove_unused_under_cursor() { + check_assist( + remove_unused_imports, + r#" +struct X(); +mod z { + use super::X$0; +} +"#, + r#" +struct X(); +mod z { +} +"#, + ); + } + + #[test] + fn remove_multi_use_block() { + check_assist( + remove_unused_imports, + r#" +struct X(); +$0mod y { + use super::X; +} +mod z { + use super::X; +}$0 +"#, + r#" +struct X(); +mod y { +} +mod z { +} +"#, + ); + } + + #[test] + fn remove_nested() { + check_assist( + remove_unused_imports, + r#" +struct X(); +mod y { + struct Y(); + mod z { + use crate::{X, y::Y}$0; + fn f() { + let x = X(); + } + } +} +"#, + r#" +struct X(); +mod y { + struct Y(); + mod z { + use crate::{X}; + fn f() { + let x = X(); + } + } +} +"#, + ); + } + + #[test] + fn remove_nested_first_item() { + check_assist( + remove_unused_imports, + r#" +struct X(); +mod y { + struct Y(); + mod z { + use crate::{X, y::Y}$0; + fn f() { + let y = Y(); + } + } +} +"#, + r#" +struct X(); +mod y { + struct Y(); + mod z { + use crate::{y::Y}; + fn f() { + let y = Y(); + } + } +} +"#, + ); + } + + #[test] + fn remove_nested_all_unused() { + check_assist( + remove_unused_imports, + r#" +struct X(); +mod y { + struct Y(); + mod z { + use crate::{X, y::Y}$0; + } +} +"#, + r#" +struct X(); +mod y { + struct Y(); + mod z { + } +} +"#, + ); + } + + #[test] + fn remove_unused_glob() { + check_assist( + remove_unused_imports, + r#" +struct X(); +struct Y(); +mod z { + use super::*$0; +} +"#, + r#" +struct X(); +struct Y(); +mod z { +} +"#, + ); + } + + #[test] + fn remove_unused_braced_glob() { + check_assist( + remove_unused_imports, + r#" +struct X(); +struct Y(); +mod z { + use super::{*}$0; +} +"#, + r#" +struct X(); +struct Y(); +mod z { +} +"#, + ); + } + + #[test] + fn dont_remove_used_glob() { + check_assist_not_applicable( + remove_unused_imports, + r#" +struct X(); +struct Y(); +mod z { + use super::*$0; + + fn f() { + let x = X(); + } +} +"#, + ); + } + + #[test] + fn only_remove_from_selection() { + check_assist( + remove_unused_imports, + r#" +struct X(); +struct Y(); +mod z { + $0use super::X;$0 + use super::Y; +} +mod w { + use super::Y; +} +"#, + r#" +struct X(); +struct Y(); +mod z { + use super::Y; +} +mod w { + use super::Y; +} +"#, + ); + } + + #[test] + fn test_several_files() { + check_assist( + remove_unused_imports, + r#" +//- /foo.rs +pub struct X(); +pub struct Y(); + +//- /main.rs +$0use foo::X; +use foo::Y; +$0 +mod foo; +mod z { + use crate::foo::X; +} +"#, + r#" + +mod foo; +mod z { + use crate::foo::X; +} +"#, + ); + } + + #[test] + fn use_in_submodule_doesnt_count() { + check_assist( + remove_unused_imports, + r#" +struct X(); +mod z { + use super::X$0; + + mod w { + use crate::X; + + fn f() { + let x = X(); + } + } +} +"#, + r#" +struct X(); +mod z { + + mod w { + use crate::X; + + fn f() { + let x = X(); + } + } +} +"#, + ); + } + + #[test] + fn use_in_submodule_file_doesnt_count() { + check_assist( + remove_unused_imports, + r#" +//- /z/foo.rs +use crate::X; +fn f() { + let x = X(); +} + +//- /main.rs +pub struct X(); + +mod z { + use crate::X$0; + mod foo; +} +"#, + r#" +pub struct X(); + +mod z { + mod foo; +} +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index c03bc2f41d5..ac45581b7b4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -10,7 +10,7 @@ use crate::{ assist_context::{AssistContext, Assists, SourceChangeBuilder}, utils::{ add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, - generate_trait_impl_text, render_snippet, Cursor, DefaultMethods, + generate_trait_impl_text, render_snippet, Cursor, DefaultMethods, IgnoreAssocItems, }, AssistId, AssistKind, }; @@ -172,7 +172,17 @@ fn impl_def_from_trait( ) -> Option<(ast::Impl, ast::AssocItem)> { let trait_ = trait_?; let target_scope = sema.scope(annotated_name.syntax())?; - let trait_items = filter_assoc_items(sema, &trait_.items(sema.db), DefaultMethods::No); + + // Keep assoc items of local crates even if they have #[doc(hidden)] attr. + let ignore_items = if trait_.module(sema.db).krate().origin(sema.db).is_local() { + IgnoreAssocItems::No + } else { + IgnoreAssocItems::DocHiddenAttrPresent + }; + + let trait_items = + filter_assoc_items(sema, &trait_.items(sema.db), DefaultMethods::No, ignore_items); + if trait_items.is_empty() { return None; } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs index e7b62d49bb8..c7c0be4c7d4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs @@ -157,7 +157,7 @@ fn find_usages( file_id: FileId, ) -> UsageSearchResult { let file_range = FileRange { file_id, range: fn_.syntax().text_range() }; - type_param_def.usages(sema).in_scope(SearchScope::file_range(file_range)).all() + type_param_def.usages(sema).in_scope(&SearchScope::file_range(file_range)).all() } fn check_valid_usages(usages: &UsageSearchResult, param_list_range: TextRange) -> bool { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index a82f1f9dd8b..2ebb5ef9b19 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -184,6 +184,7 @@ mod handlers { mod raw_string; mod remove_dbg; mod remove_mut; + mod remove_unused_imports; mod remove_unused_param; mod remove_parentheses; mod reorder_fields; @@ -294,6 +295,7 @@ mod handlers { raw_string::make_usual_string, raw_string::remove_hash, remove_mut::remove_mut, + remove_unused_imports::remove_unused_imports, remove_unused_param::remove_unused_param, remove_parentheses::remove_parentheses, reorder_fields::reorder_fields, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs index 344f2bfcce1..cc3e251a8f2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs @@ -132,8 +132,13 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) { .filter(|it| !it.source_file_edits.is_empty() || !it.file_system_edits.is_empty()) .expect("Assist did not contain any source changes"); let mut actual = before; - if let Some(source_file_edit) = source_change.get_source_edit(file_id) { + if let Some((source_file_edit, snippet_edit)) = + source_change.get_source_and_snippet_edit(file_id) + { source_file_edit.apply(&mut actual); + if let Some(snippet_edit) = snippet_edit { + snippet_edit.apply(&mut actual); + } } actual }; @@ -191,9 +196,12 @@ fn check_with_config( && source_change.file_system_edits.len() == 0; let mut buf = String::new(); - for (file_id, edit) in source_change.source_file_edits { + for (file_id, (edit, snippet_edit)) in source_change.source_file_edits { let mut text = db.file_text(file_id).as_ref().to_owned(); edit.apply(&mut text); + if let Some(snippet_edit) = snippet_edit { + snippet_edit.apply(&mut text); + } if !skip_header { let sr = db.file_source_root(file_id); let sr = db.source_root(sr); @@ -485,18 +493,21 @@ pub fn test_some_range(a: int) -> bool { source_file_edits: { FileId( 0, - ): TextEdit { - indels: [ - Indel { - insert: "let $0var_name = 5;\n ", - delete: 45..45, - }, - Indel { - insert: "var_name", - delete: 59..60, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "let $0var_name = 5;\n ", + delete: 45..45, + }, + Indel { + insert: "var_name", + delete: 59..60, + }, + ], + }, + None, + ), }, file_system_edits: [], is_snippet: true, @@ -544,18 +555,21 @@ pub fn test_some_range(a: int) -> bool { source_file_edits: { FileId( 0, - ): TextEdit { - indels: [ - Indel { - insert: "let $0var_name = 5;\n ", - delete: 45..45, - }, - Indel { - insert: "var_name", - delete: 59..60, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "let $0var_name = 5;\n ", + delete: 45..45, + }, + Indel { + insert: "var_name", + delete: 59..60, + }, + ], + }, + None, + ), }, file_system_edits: [], is_snippet: true, @@ -581,18 +595,21 @@ pub fn test_some_range(a: int) -> bool { source_file_edits: { FileId( 0, - ): TextEdit { - indels: [ - Indel { - insert: "fun_name()", - delete: 59..60, - }, - Indel { - insert: "\n\nfn $0fun_name() -> i32 {\n 5\n}", - delete: 110..110, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "fun_name()", + delete: 59..60, + }, + Indel { + insert: "\n\nfn $0fun_name() -> i32 {\n 5\n}", + delete: 110..110, + }, + ], + }, + None, + ), }, file_system_edits: [], is_snippet: true, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 4d47a199b7c..6eadc3dbcbc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -952,6 +952,7 @@ fn doctest_generate_default_from_new() { check_doc_test( "generate_default_from_new", r#####" +//- minicore: default struct Example { _inner: () } impl Example { @@ -2234,6 +2235,24 @@ fn main() { } #[test] +fn doctest_remove_unused_imports() { + check_doc_test( + "remove_unused_imports", + r#####" +struct X(); +mod foo { + use super::X$0; +} +"#####, + r#####" +struct X(); +mod foo { +} +"#####, + ) +} + +#[test] fn doctest_remove_unused_param() { check_doc_test( "remove_unused_param", diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 03d8553506f..a262570d94e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -3,7 +3,7 @@ use std::ops; pub(crate) use gen_trait_fn_body::gen_trait_fn_body; -use hir::{db::HirDatabase, HirDisplay, InFile, Semantics}; +use hir::{db::HirDatabase, HasAttrs as HirHasAttrs, HirDisplay, InFile, Semantics}; use ide_db::{ famous_defs::FamousDefs, path_transform::PathTransform, syntax_helpers::insert_whitespace_into_node::insert_ws_into, RootDatabase, SnippetCap, @@ -84,6 +84,12 @@ pub fn test_related_attribute(fn_def: &ast::Fn) -> Option<ast::Attr> { }) } +#[derive(Clone, Copy, PartialEq)] +pub enum IgnoreAssocItems { + DocHiddenAttrPresent, + No, +} + #[derive(Copy, Clone, PartialEq)] pub enum DefaultMethods { Only, @@ -94,11 +100,16 @@ pub fn filter_assoc_items( sema: &Semantics<'_, RootDatabase>, items: &[hir::AssocItem], default_methods: DefaultMethods, + ignore_items: IgnoreAssocItems, ) -> Vec<InFile<ast::AssocItem>> { return items .iter() - // Note: This throws away items with no source. .copied() + .filter(|assoc_item| { + !(ignore_items == IgnoreAssocItems::DocHiddenAttrPresent + && assoc_item.attrs(sema.db).has_doc_hidden()) + }) + // Note: This throws away items with no source. .filter_map(|assoc_item| { let item = match assoc_item { hir::AssocItem::Function(it) => sema.source(it)?.map(ast::AssocItem::Fn), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index e850f7bfdf3..0309952c29a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -427,9 +427,26 @@ impl Builder { let insert_text = self.insert_text.unwrap_or_else(|| label.to_string()); if !self.doc_aliases.is_empty() { - let doc_aliases = self.doc_aliases.into_iter().join(", "); + let doc_aliases = self.doc_aliases.iter().join(", "); label = SmolStr::from(format!("{label} (alias {doc_aliases})")); - lookup = SmolStr::from(format!("{lookup} {doc_aliases}")); + let lookup_doc_aliases = self + .doc_aliases + .iter() + // Don't include aliases in `lookup` that aren't valid identifiers as including + // them results in weird completion filtering behavior e.g. `Partial>` matching + // `PartialOrd` because it has an alias of ">". + .filter(|alias| { + let mut chars = alias.chars(); + chars.next().is_some_and(char::is_alphabetic) + && chars.all(|c| c.is_alphanumeric() || c == '_') + }) + // Deliberately concatenated without separators as adding separators e.g. + // `alias1, alias2` results in LSP clients continuing to display the completion even + // after typing a comma or space. + .join(""); + if !lookup_doc_aliases.is_empty() { + lookup = SmolStr::from(format!("{lookup}{lookup_doc_aliases}")); + } } if let [import_edit] = &*self.imports_to_add { // snippets can have multiple imports, but normal completions only have up to one diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs index 3824720839e..e80a289049f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs @@ -1280,3 +1280,26 @@ fn here_we_go() { "#]], ); } + +#[test] +fn completion_filtering_excludes_non_identifier_doc_aliases() { + check_edit( + "PartialOrdcmporder", + r#" +#[doc(alias = ">")] +#[doc(alias = "cmp")] +#[doc(alias = "order")] +trait PartialOrd {} + +struct Foo<T: Partial$0 +"#, + r#" +#[doc(alias = ">")] +#[doc(alias = "cmp")] +#[doc(alias = "order")] +trait PartialOrd {} + +struct Foo<T: PartialOrd +"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 760834bfafc..5e4562d9c58 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -7,10 +7,10 @@ use arrayvec::ArrayVec; use hir::{ - Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, Field, - Function, GenericParam, HasVisibility, Impl, Label, Local, Macro, Module, ModuleDef, Name, - PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TypeAlias, Variant, - Visibility, + Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, + ExternCrateDecl, Field, Function, GenericParam, HasVisibility, Impl, Label, Local, Macro, + Module, ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, + TypeAlias, Variant, Visibility, }; use stdx::impl_from; use syntax::{ @@ -42,6 +42,7 @@ pub enum Definition { DeriveHelper(DeriveHelper), BuiltinAttr(BuiltinAttr), ToolModule(ToolModule), + ExternCrateDecl(ExternCrateDecl), } impl Definition { @@ -73,6 +74,7 @@ impl Definition { Definition::Local(it) => it.module(db), Definition::GenericParam(it) => it.module(db), Definition::Label(it) => it.module(db), + Definition::ExternCrateDecl(it) => it.module(db), Definition::DeriveHelper(it) => it.derive().module(db), Definition::BuiltinAttr(_) | Definition::BuiltinType(_) | Definition::ToolModule(_) => { return None @@ -93,6 +95,7 @@ impl Definition { Definition::TraitAlias(it) => it.visibility(db), Definition::TypeAlias(it) => it.visibility(db), Definition::Variant(it) => it.visibility(db), + Definition::ExternCrateDecl(it) => it.visibility(db), Definition::BuiltinType(_) => Visibility::Public, Definition::Macro(_) => return None, Definition::BuiltinAttr(_) @@ -127,6 +130,7 @@ impl Definition { Definition::BuiltinAttr(_) => return None, // FIXME Definition::ToolModule(_) => return None, // FIXME Definition::DeriveHelper(it) => it.name(db), + Definition::ExternCrateDecl(it) => return it.alias_or_name(db), }; Some(name) } @@ -196,6 +200,10 @@ impl IdentClass { res.push(Definition::Local(local_ref)); res.push(Definition::Field(field_ref)); } + IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { decl, krate }) => { + res.push(Definition::ExternCrateDecl(decl)); + res.push(Definition::Module(krate.root_module())); + } IdentClass::Operator( OperatorClass::Await(func) | OperatorClass::Prefix(func) @@ -222,6 +230,10 @@ impl IdentClass { res.push(Definition::Local(local_ref)); res.push(Definition::Field(field_ref)); } + IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { decl, krate }) => { + res.push(Definition::ExternCrateDecl(decl)); + res.push(Definition::Module(krate.root_module())); + } IdentClass::Operator(_) => (), } res @@ -310,6 +322,7 @@ impl NameClass { ast::Item::Enum(it) => Definition::Adt(hir::Adt::Enum(sema.to_def(&it)?)), ast::Item::Struct(it) => Definition::Adt(hir::Adt::Struct(sema.to_def(&it)?)), ast::Item::Union(it) => Definition::Adt(hir::Adt::Union(sema.to_def(&it)?)), + ast::Item::ExternCrate(it) => Definition::ExternCrateDecl(sema.to_def(&it)?), _ => return None, }; Some(definition) @@ -346,10 +359,8 @@ impl NameClass { let path = use_tree.path()?; sema.resolve_path(&path).map(Definition::from) } else { - let extern_crate = rename.syntax().parent().and_then(ast::ExternCrate::cast)?; - let krate = sema.resolve_extern_crate(&extern_crate)?; - let root_module = krate.root_module(sema.db); - Some(Definition::Module(root_module)) + sema.to_def(&rename.syntax().parent().and_then(ast::ExternCrate::cast)?) + .map(Definition::ExternCrateDecl) } } } @@ -427,7 +438,19 @@ impl OperatorClass { #[derive(Debug)] pub enum NameRefClass { Definition(Definition), - FieldShorthand { local_ref: Local, field_ref: Field }, + FieldShorthand { + local_ref: Local, + field_ref: Field, + }, + /// The specific situation where we have an extern crate decl without a rename + /// Here we have both a declaration and a reference. + /// ```rs + /// extern crate foo; + /// ``` + ExternCrateShorthand { + decl: ExternCrateDecl, + krate: Crate, + }, } impl NameRefClass { @@ -513,10 +536,14 @@ impl NameRefClass { } None }, - ast::ExternCrate(extern_crate) => { - let krate = sema.resolve_extern_crate(&extern_crate)?; - let root_module = krate.root_module(sema.db); - Some(NameRefClass::Definition(Definition::Module(root_module))) + ast::ExternCrate(extern_crate_ast) => { + let extern_crate = sema.to_def(&extern_crate_ast)?; + let krate = extern_crate.resolved_crate(sema.db)?; + Some(if extern_crate_ast.rename().is_some() { + NameRefClass::Definition(Definition::Module(krate.root_module())) + } else { + NameRefClass::ExternCrateShorthand { krate, decl: extern_crate } + }) }, _ => None } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs index c8341fed1c7..b63dde2c21e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs @@ -167,7 +167,7 @@ impl FamousDefs<'_, '_> { lang_crate => lang_crate, }; let std_crate = self.find_lang_crate(lang_crate)?; - let mut module = std_crate.root_module(db); + let mut module = std_crate.root_module(); for segment in path { module = module.children(db).find_map(|child| { let name = child.name(db)?; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index e488300b41c..49b37024a5e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -931,22 +931,6 @@ $ cat $(find -name '*.s') "##, }, Lint { - label: "abi_thiscall", - description: r##"# `abi_thiscall` - -The tracking issue for this feature is: [#42202] - -[#42202]: https://github.com/rust-lang/rust/issues/42202 - ------------------------- - -The MSVC ABI on x86 Windows uses the `thiscall` calling convention for C++ -instance methods by default; it is identical to the usual (C) calling -convention on x86 Windows except that the first parameter of the method, -the `this` pointer, is passed in the ECX register. -"##, - }, - Lint { label: "allocator_api", description: r##"# `allocator_api` diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index 52a23b4b8f3..aa0bb7cce69 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -82,8 +82,9 @@ impl Definition { } /// Textual range of the identifier which will change when renaming this - /// `Definition`. Note that some definitions, like builtin types, can't be - /// renamed. + /// `Definition`. Note that builtin types can't be + /// renamed and extern crate names will report its range, though a rename will introduce + /// an alias instead. pub fn range_for_rename(self, sema: &Semantics<'_, RootDatabase>) -> Option<FileRange> { let res = match self { Definition::Macro(mac) => { @@ -146,6 +147,16 @@ impl Definition { let lifetime = src.value.lifetime()?; src.with_value(lifetime.syntax()).original_file_range_opt(sema.db) } + Definition::ExternCrateDecl(it) => { + let src = it.source(sema.db)?; + if let Some(rename) = src.value.rename() { + let name = rename.name()?; + src.with_value(name.syntax()).original_file_range_opt(sema.db) + } else { + let name = src.value.name_ref()?; + src.with_value(name.syntax()).original_file_range_opt(sema.db) + } + } Definition::BuiltinType(_) => return None, Definition::SelfType(_) => return None, Definition::BuiltinAttr(_) => return None, @@ -526,6 +537,9 @@ fn source_edit_from_def( TextRange::new(range.start() + syntax::TextSize::from(1), range.end()), new_name.strip_prefix('\'').unwrap_or(new_name).to_owned(), ), + Definition::ExternCrateDecl(decl) if decl.alias(sema.db).is_none() => { + (TextRange::empty(range.end()), format!(" as {new_name}")) + } _ => (range, new_name.to_owned()), }; edit.replace(range, new_name); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index f3c0f79c589..d5abd099126 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -127,7 +127,7 @@ impl SearchScope { } /// Build a search scope spanning the given module and all its submodules. - fn module_and_children(db: &RootDatabase, module: hir::Module) -> SearchScope { + pub fn module_and_children(db: &RootDatabase, module: hir::Module) -> SearchScope { let mut entries = IntMap::default(); let (file_id, range) = { @@ -329,7 +329,7 @@ impl Definition { pub struct FindUsages<'a> { def: Definition, sema: &'a Semantics<'a, RootDatabase>, - scope: Option<SearchScope>, + scope: Option<&'a SearchScope>, /// The container of our definition should it be an assoc item assoc_item_container: Option<hir::AssocItemContainer>, /// whether to search for the `Self` type of the definition @@ -338,7 +338,7 @@ pub struct FindUsages<'a> { search_self_mod: bool, } -impl FindUsages<'_> { +impl<'a> FindUsages<'a> { /// Enable searching for `Self` when the definition is a type or `self` for modules. pub fn include_self_refs(mut self) -> Self { self.include_self_kw_refs = def_to_ty(self.sema, &self.def); @@ -347,12 +347,12 @@ impl FindUsages<'_> { } /// Limit the search to a given [`SearchScope`]. - pub fn in_scope(self, scope: SearchScope) -> Self { + pub fn in_scope(self, scope: &'a SearchScope) -> Self { self.set_scope(Some(scope)) } /// Limit the search to a given [`SearchScope`]. - pub fn set_scope(mut self, scope: Option<SearchScope>) -> Self { + pub fn set_scope(mut self, scope: Option<&'a SearchScope>) -> Self { assert!(self.scope.is_none()); self.scope = scope; self @@ -376,7 +376,7 @@ impl FindUsages<'_> { res } - fn search(&self, sink: &mut dyn FnMut(FileId, FileReference) -> bool) { + pub fn search(&self, sink: &mut dyn FnMut(FileId, FileReference) -> bool) { let _p = profile::span("FindUsages:search"); let sema = self.sema; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs index fad0ca51a02..39763479c65 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs @@ -7,17 +7,17 @@ use std::{collections::hash_map::Entry, iter, mem}; use crate::SnippetCap; use base_db::{AnchoredPathBuf, FileId}; +use itertools::Itertools; use nohash_hasher::IntMap; use stdx::never; use syntax::{ - algo, ast, ted, AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, - TextSize, + algo, AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize, }; use text_edit::{TextEdit, TextEditBuilder}; #[derive(Default, Debug, Clone)] pub struct SourceChange { - pub source_file_edits: IntMap<FileId, TextEdit>, + pub source_file_edits: IntMap<FileId, (TextEdit, Option<SnippetEdit>)>, pub file_system_edits: Vec<FileSystemEdit>, pub is_snippet: bool, } @@ -26,7 +26,7 @@ impl SourceChange { /// Creates a new SourceChange with the given label /// from the edits. pub fn from_edits( - source_file_edits: IntMap<FileId, TextEdit>, + source_file_edits: IntMap<FileId, (TextEdit, Option<SnippetEdit>)>, file_system_edits: Vec<FileSystemEdit>, ) -> Self { SourceChange { source_file_edits, file_system_edits, is_snippet: false } @@ -34,7 +34,7 @@ impl SourceChange { pub fn from_text_edit(file_id: FileId, edit: TextEdit) -> Self { SourceChange { - source_file_edits: iter::once((file_id, edit)).collect(), + source_file_edits: iter::once((file_id, (edit, None))).collect(), ..Default::default() } } @@ -42,12 +42,31 @@ impl SourceChange { /// Inserts a [`TextEdit`] for the given [`FileId`]. This properly handles merging existing /// edits for a file if some already exist. pub fn insert_source_edit(&mut self, file_id: FileId, edit: TextEdit) { + self.insert_source_and_snippet_edit(file_id, edit, None) + } + + /// Inserts a [`TextEdit`] and potentially a [`SnippetEdit`] for the given [`FileId`]. + /// This properly handles merging existing edits for a file if some already exist. + pub fn insert_source_and_snippet_edit( + &mut self, + file_id: FileId, + edit: TextEdit, + snippet_edit: Option<SnippetEdit>, + ) { match self.source_file_edits.entry(file_id) { Entry::Occupied(mut entry) => { - never!(entry.get_mut().union(edit).is_err(), "overlapping edits for same file"); + let value = entry.get_mut(); + never!(value.0.union(edit).is_err(), "overlapping edits for same file"); + never!( + value.1.is_some() && snippet_edit.is_some(), + "overlapping snippet edits for same file" + ); + if value.1.is_none() { + value.1 = snippet_edit; + } } Entry::Vacant(entry) => { - entry.insert(edit); + entry.insert((edit, snippet_edit)); } } } @@ -56,7 +75,10 @@ impl SourceChange { self.file_system_edits.push(edit); } - pub fn get_source_edit(&self, file_id: FileId) -> Option<&TextEdit> { + pub fn get_source_and_snippet_edit( + &self, + file_id: FileId, + ) -> Option<&(TextEdit, Option<SnippetEdit>)> { self.source_file_edits.get(&file_id) } @@ -70,7 +92,18 @@ impl SourceChange { impl Extend<(FileId, TextEdit)> for SourceChange { fn extend<T: IntoIterator<Item = (FileId, TextEdit)>>(&mut self, iter: T) { - iter.into_iter().for_each(|(file_id, edit)| self.insert_source_edit(file_id, edit)); + self.extend(iter.into_iter().map(|(file_id, edit)| (file_id, (edit, None)))) + } +} + +impl Extend<(FileId, (TextEdit, Option<SnippetEdit>))> for SourceChange { + fn extend<T: IntoIterator<Item = (FileId, (TextEdit, Option<SnippetEdit>))>>( + &mut self, + iter: T, + ) { + iter.into_iter().for_each(|(file_id, (edit, snippet_edit))| { + self.insert_source_and_snippet_edit(file_id, edit, snippet_edit) + }); } } @@ -82,6 +115,8 @@ impl Extend<FileSystemEdit> for SourceChange { impl From<IntMap<FileId, TextEdit>> for SourceChange { fn from(source_file_edits: IntMap<FileId, TextEdit>) -> SourceChange { + let source_file_edits = + source_file_edits.into_iter().map(|(file_id, edit)| (file_id, (edit, None))).collect(); SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false } } } @@ -94,6 +129,65 @@ impl FromIterator<(FileId, TextEdit)> for SourceChange { } } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SnippetEdit(Vec<(u32, TextRange)>); + +impl SnippetEdit { + pub fn new(snippets: Vec<Snippet>) -> Self { + let mut snippet_ranges = snippets + .into_iter() + .zip(1..) + .with_position() + .map(|pos| { + let (snippet, index) = match pos { + itertools::Position::First(it) | itertools::Position::Middle(it) => it, + // last/only snippet gets index 0 + itertools::Position::Last((snippet, _)) + | itertools::Position::Only((snippet, _)) => (snippet, 0), + }; + + let range = match snippet { + Snippet::Tabstop(pos) => TextRange::empty(pos), + Snippet::Placeholder(range) => range, + }; + (index, range) + }) + .collect_vec(); + + snippet_ranges.sort_by_key(|(_, range)| range.start()); + + // Ensure that none of the ranges overlap + let disjoint_ranges = snippet_ranges + .iter() + .zip(snippet_ranges.iter().skip(1)) + .all(|((_, left), (_, right))| left.end() <= right.start() || left == right); + stdx::always!(disjoint_ranges); + + SnippetEdit(snippet_ranges) + } + + /// Inserts all of the snippets into the given text. + pub fn apply(&self, text: &mut String) { + // Start from the back so that we don't have to adjust ranges + for (index, range) in self.0.iter().rev() { + if range.is_empty() { + // is a tabstop + text.insert_str(range.start().into(), &format!("${index}")); + } else { + // is a placeholder + text.insert(range.end().into(), '}'); + text.insert_str(range.start().into(), &format!("${{{index}:")); + } + } + } + + /// Gets the underlying snippet index + text range + /// Tabstops are represented by an empty range, and placeholders use the range that they were given + pub fn into_edit_ranges(self) -> Vec<(u32, TextRange)> { + self.0 + } +} + pub struct SourceChangeBuilder { pub edit: TextEditBuilder, pub file_id: FileId, @@ -152,24 +246,19 @@ impl SourceChangeBuilder { } fn commit(&mut self) { - // Render snippets first so that they get bundled into the tree diff - if let Some(mut snippets) = self.snippet_builder.take() { - // Last snippet always has stop index 0 - let last_stop = snippets.places.pop().unwrap(); - last_stop.place(0); - - for (index, stop) in snippets.places.into_iter().enumerate() { - stop.place(index + 1) - } - } + let snippet_edit = self.snippet_builder.take().map(|builder| { + SnippetEdit::new( + builder.places.into_iter().map(PlaceSnippet::finalize_position).collect_vec(), + ) + }); if let Some(tm) = self.mutated_tree.take() { - algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit) + algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit); } let edit = mem::take(&mut self.edit).finish(); - if !edit.is_empty() { - self.source_change.insert_source_edit(self.file_id, edit); + if !edit.is_empty() || snippet_edit.is_some() { + self.source_change.insert_source_and_snippet_edit(self.file_id, edit, snippet_edit); } } @@ -275,6 +364,16 @@ impl SourceChangeBuilder { pub fn finish(mut self) -> SourceChange { self.commit(); + + // Only one file can have snippet edits + stdx::never!(self + .source_change + .source_file_edits + .iter() + .filter(|(_, (_, snippet_edit))| snippet_edit.is_some()) + .at_most_one() + .is_err()); + mem::take(&mut self.source_change) } } @@ -296,6 +395,13 @@ impl From<FileSystemEdit> for SourceChange { } } +pub enum Snippet { + /// A tabstop snippet (e.g. `$0`). + Tabstop(TextSize), + /// A placeholder snippet (e.g. `${0:placeholder}`). + Placeholder(TextRange), +} + enum PlaceSnippet { /// Place a tabstop before an element Before(SyntaxElement), @@ -306,57 +412,11 @@ enum PlaceSnippet { } impl PlaceSnippet { - /// Places the snippet before or over an element with the given tab stop index - fn place(self, order: usize) { - // ensure the target element is still attached - match &self { - PlaceSnippet::Before(element) - | PlaceSnippet::After(element) - | PlaceSnippet::Over(element) => { - // element should still be in the tree, but if it isn't - // then it's okay to just ignore this place - if stdx::never!(element.parent().is_none()) { - return; - } - } - } - + fn finalize_position(self) -> Snippet { match self { - PlaceSnippet::Before(element) => { - ted::insert_raw(ted::Position::before(&element), Self::make_tab_stop(order)); - } - PlaceSnippet::After(element) => { - ted::insert_raw(ted::Position::after(&element), Self::make_tab_stop(order)); - } - PlaceSnippet::Over(element) => { - let position = ted::Position::before(&element); - element.detach(); - - let snippet = ast::SourceFile::parse(&format!("${{{order}:_}}")) - .syntax_node() - .clone_for_update(); - - let placeholder = - snippet.descendants().find_map(ast::UnderscoreExpr::cast).unwrap(); - ted::replace(placeholder.syntax(), element); - - ted::insert_raw(position, snippet); - } + PlaceSnippet::Before(it) => Snippet::Tabstop(it.text_range().start()), + PlaceSnippet::After(it) => Snippet::Tabstop(it.text_range().end()), + PlaceSnippet::Over(it) => Snippet::Placeholder(it.text_range()), } } - - fn make_tab_stop(order: usize) -> SyntaxNode { - let stop = ast::SourceFile::parse(&format!("stop!(${order})")) - .syntax_node() - .descendants() - .find_map(ast::TokenTree::cast) - .unwrap() - .syntax() - .clone_for_update(); - - stop.first_token().unwrap().detach(); - stop.last_token().unwrap().detach(); - - stop - } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs index 937e2f96642..f54cdd63bbb 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -51,6 +51,9 @@ macro_rules! compile_error { () => {} } compile_error!("compile_error macro works"); //^^^^^^^^^^^^^ error: compile_error macro works + + compile_error! { "compile_error macro braced works" } +//^^^^^^^^^^^^^ error: compile_error macro braced works "#, ); } @@ -77,7 +80,7 @@ macro_rules! m { fn f() { m!(); - //^^^^ error: unresolved macro `$crate::private::concat!` + //^^^^ error: unresolved macro $crate::private::concat } //- /core.rs crate:core diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index bb0e36ff3a1..acc31cd117a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -208,7 +208,7 @@ fn get_default_constructor( } let krate = ctx.sema.to_module_def(d.file.original_file(ctx.sema.db))?.krate(); - let module = krate.root_module(ctx.sema.db); + let module = krate.root_module(); // Look for a ::new() associated function let has_new_func = ty diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs index 4ac9d0a9fb7..ee0e0354906 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs @@ -49,8 +49,11 @@ fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { let file_id = *source_change.source_file_edits.keys().next().unwrap(); let mut actual = db.file_text(file_id).to_string(); - for edit in source_change.source_file_edits.values() { + for (edit, snippet_edit) in source_change.source_file_edits.values() { edit.apply(&mut actual); + if let Some(snippet_edit) = snippet_edit { + snippet_edit.apply(&mut actual); + } } actual }; diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs index 96c193bd539..ca76d0a87b9 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs @@ -121,7 +121,7 @@ impl MatchFinder<'_> { // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two // lookups in the case of a cache hit. if usage_cache.find(&definition).is_none() { - let usages = definition.usages(&self.sema).in_scope(self.search_scope()).all(); + let usages = definition.usages(&self.sema).in_scope(&self.search_scope()).all(); usage_cache.usages.push((definition, usages)); return &usage_cache.usages.last().unwrap().1; } diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index c90ba212535..d240127f376 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -153,6 +153,9 @@ pub(crate) fn external_docs( NameRefClass::FieldShorthand { local_ref: _, field_ref } => { Definition::Field(field_ref) } + NameRefClass::ExternCrateShorthand { decl, .. } => { + Definition::ExternCrateDecl(decl) + } }, ast::Name(name) => match NameClass::classify(sema, &name)? { NameClass::Definition(it) | NameClass::ConstReference(it) => it, @@ -209,6 +212,7 @@ pub(crate) fn resolve_doc_path_for_def( Definition::Macro(it) => it.resolve_doc_path(db, link, ns), Definition::Field(it) => it.resolve_doc_path(db, link, ns), Definition::SelfType(it) => it.resolve_doc_path(db, link, ns), + Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns), Definition::BuiltinAttr(_) | Definition::ToolModule(_) | Definition::BuiltinType(_) @@ -617,6 +621,9 @@ fn filename_and_frag_for_def( // FIXME fragment numbering return Some((adt, file, Some(String::from("impl")))); } + Definition::ExternCrateDecl(it) => { + format!("{}/index.html", it.name(db).display(db.upcast())) + } Definition::Local(_) | Definition::GenericParam(_) | Definition::Label(_) diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs index e70bc2ec541..c39c696cfd9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs @@ -37,11 +37,15 @@ pub(crate) fn goto_declaration( match parent { ast::NameRef(name_ref) => match NameRefClass::classify(&sema, &name_ref)? { NameRefClass::Definition(it) => Some(it), - NameRefClass::FieldShorthand { field_ref, .. } => return field_ref.try_to_nav(db), + NameRefClass::FieldShorthand { field_ref, .. } => + return field_ref.try_to_nav(db), + NameRefClass::ExternCrateShorthand { decl, .. } => + return decl.try_to_nav(db), }, ast::Name(name) => match NameClass::classify(&sema, &name)? { NameClass::Definition(it) | NameClass::ConstReference(it) => Some(it), - NameClass::PatFieldShorthand { field_ref, .. } => return field_ref.try_to_nav(db), + NameClass::PatFieldShorthand { field_ref, .. } => + return field_ref.try_to_nav(db), }, _ => None } @@ -53,6 +57,7 @@ pub(crate) fn goto_declaration( Definition::Const(c) => c.as_assoc_item(db), Definition::TypeAlias(ta) => ta.as_assoc_item(db), Definition::Function(f) => f.as_assoc_item(db), + Definition::ExternCrateDecl(it) => return it.try_to_nav(db), _ => None, }?; @@ -211,4 +216,30 @@ fn main() { "#, ); } + + #[test] + fn goto_decl_for_extern_crate() { + check( + r#" +//- /main.rs crate:main deps:std +extern crate std$0; + /// ^^^ +//- /std/lib.rs crate:std +// empty +"#, + ) + } + + #[test] + fn goto_decl_for_renamed_extern_crate() { + check( + r#" +//- /main.rs crate:main deps:std +extern crate std as abc$0; + /// ^^^ +//- /std/lib.rs crate:std +// empty +"#, + ) + } } 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 4e641357e37..21471ab2a03 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -1,6 +1,9 @@ use std::mem::discriminant; -use crate::{doc_links::token_as_doc_comment, FilePosition, NavigationTarget, RangeInfo, TryToNav}; +use crate::{ + doc_links::token_as_doc_comment, navigation_target::ToNav, FilePosition, NavigationTarget, + RangeInfo, TryToNav, +}; use hir::{AsAssocItem, AssocItem, Semantics}; use ide_db::{ base_db::{AnchoredPath, FileId, FileLoader}, @@ -73,6 +76,13 @@ pub(crate) fn goto_definition( .definitions() .into_iter() .flat_map(|def| { + if let Definition::ExternCrateDecl(crate_def) = def { + return crate_def + .resolved_crate(db) + .map(|it| it.root_module().to_nav(sema.db)) + .into_iter() + .collect(); + } try_filter_trait_item_definition(sema, &def) .unwrap_or_else(|| def_to_nav(sema.db, def)) }) diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs index a1a119629a9..37166bdbd0c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs @@ -34,54 +34,50 @@ pub(crate) fn goto_implementation( _ => 0, })?; let range = original_token.text_range(); - let navs = sema - .descend_into_macros(original_token) - .into_iter() - .filter_map(|token| token.parent().and_then(ast::NameLike::cast)) - .filter_map(|node| match &node { - ast::NameLike::Name(name) => { - NameClass::classify(&sema, name).map(|class| match class { - NameClass::Definition(it) | NameClass::ConstReference(it) => it, - NameClass::PatFieldShorthand { local_def, field_ref: _ } => { - Definition::Local(local_def) + let navs = + sema.descend_into_macros(original_token) + .into_iter() + .filter_map(|token| token.parent().and_then(ast::NameLike::cast)) + .filter_map(|node| match &node { + ast::NameLike::Name(name) => { + NameClass::classify(&sema, name).and_then(|class| match class { + NameClass::Definition(it) | NameClass::ConstReference(it) => Some(it), + NameClass::PatFieldShorthand { .. } => None, + }) + } + ast::NameLike::NameRef(name_ref) => NameRefClass::classify(&sema, name_ref) + .and_then(|class| match class { + NameRefClass::Definition(def) => Some(def), + NameRefClass::FieldShorthand { .. } + | NameRefClass::ExternCrateShorthand { .. } => None, + }), + ast::NameLike::Lifetime(_) => None, + }) + .unique() + .filter_map(|def| { + let navs = match def { + Definition::Trait(trait_) => impls_for_trait(&sema, trait_), + Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)), + Definition::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)), + Definition::BuiltinType(builtin) => impls_for_ty(&sema, builtin.ty(sema.db)), + Definition::Function(f) => { + let assoc = f.as_assoc_item(sema.db)?; + let name = assoc.name(sema.db)?; + let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?; + impls_for_trait_item(&sema, trait_, name) } - }) - } - ast::NameLike::NameRef(name_ref) => { - NameRefClass::classify(&sema, name_ref).map(|class| match class { - NameRefClass::Definition(def) => def, - NameRefClass::FieldShorthand { local_ref, field_ref: _ } => { - Definition::Local(local_ref) + Definition::Const(c) => { + let assoc = c.as_assoc_item(sema.db)?; + let name = assoc.name(sema.db)?; + let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?; + impls_for_trait_item(&sema, trait_, name) } - }) - } - ast::NameLike::Lifetime(_) => None, - }) - .unique() - .filter_map(|def| { - let navs = match def { - Definition::Trait(trait_) => impls_for_trait(&sema, trait_), - Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)), - Definition::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)), - Definition::BuiltinType(builtin) => impls_for_ty(&sema, builtin.ty(sema.db)), - Definition::Function(f) => { - let assoc = f.as_assoc_item(sema.db)?; - let name = assoc.name(sema.db)?; - let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?; - impls_for_trait_item(&sema, trait_, name) - } - Definition::Const(c) => { - let assoc = c.as_assoc_item(sema.db)?; - let name = assoc.name(sema.db)?; - let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?; - impls_for_trait_item(&sema, trait_, name) - } - _ => return None, - }; - Some(navs) - }) - .flatten() - .collect(); + _ => return None, + }; + Some(navs) + }) + .flatten() + .collect(); Some(RangeInfo { range, info: navs }) } 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 7e545491f8e..43e89a334bf 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -100,10 +100,7 @@ fn highlight_closure_captures( .flat_map(|local| { let usages = Definition::Local(local) .usages(sema) - .set_scope(Some(SearchScope::file_range(FileRange { - file_id, - range: search_range, - }))) + .in_scope(&SearchScope::file_range(FileRange { file_id, range: search_range })) .include_self_refs() .all() .references @@ -139,7 +136,7 @@ fn highlight_references( .iter() .filter_map(|&d| { d.usages(sema) - .set_scope(Some(SearchScope::single_file(file_id))) + .in_scope(&SearchScope::single_file(file_id)) .include_self_refs() .all() .references @@ -183,7 +180,7 @@ fn highlight_references( .filter_map(|item| { Definition::from(item) .usages(sema) - .set_scope(Some(SearchScope::file_range(FileRange { + .set_scope(Some(&SearchScope::file_range(FileRange { file_id, range: trait_item_use_scope.text_range(), }))) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 5ef6ac94807..40659e6c263 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -9,7 +9,7 @@ use either::Either; use hir::{db::DefDatabase, HasSource, LangItem, Semantics}; use ide_db::{ base_db::FileRange, - defs::{Definition, IdentClass, OperatorClass}, + defs::{Definition, IdentClass, NameRefClass, OperatorClass}, famous_defs::FamousDefs, helpers::pick_best_token, FxIndexSet, RootDatabase, @@ -186,7 +186,20 @@ fn hover_simple( // rendering poll is very confusing return None; } - Some(class.definitions().into_iter().zip(iter::once(node).cycle())) + if let IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { + decl, + .. + }) = class + { + return Some(vec![(Definition::ExternCrateDecl(decl), node)]); + } + Some( + class + .definitions() + .into_iter() + .zip(iter::once(node).cycle()) + .collect::<Vec<_>>(), + ) }) .flatten() .unique_by(|&(def, _)| def) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index ef33386a7e9..a33a6ee1816 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -257,7 +257,7 @@ pub(super) fn keyword( let KeywordHint { description, keyword_mod, actions } = keyword_hints(sema, token, parent); let doc_owner = find_std_module(&famous_defs, &keyword_mod)?; - let docs = doc_owner.attrs(sema.db).docs()?; + let docs = doc_owner.docs(sema.db)?; let markup = process_markup( sema.db, Definition::Module(doc_owner), @@ -472,6 +472,7 @@ pub(super) fn definition( } Definition::GenericParam(it) => label_and_docs(db, it), Definition::Label(it) => return Some(Markup::fenced_block(&it.name(db).display(db))), + Definition::ExternCrateDecl(it) => label_and_docs(db, it), // FIXME: We should be able to show more info about these Definition::BuiltinAttr(it) => return render_builtin_attr(db, it), Definition::ToolModule(it) => return Some(Markup::fenced_block(&it.name(db))), @@ -620,7 +621,7 @@ where D: HasAttrs + HirDisplay, { let label = def.display(db).to_string(); - let docs = def.attrs(db).docs(); + let docs = def.docs(db); (label, docs) } @@ -645,7 +646,7 @@ where ) { format_to!(label, "{layout}"); } - let docs = def.attrs(db).docs(); + let docs = def.docs(db); (label, docs) } @@ -677,7 +678,7 @@ where ) { format_to!(label, "{layout}"); } - let docs = def.attrs(db).docs(); + let docs = def.docs(db); (label, docs) } @@ -696,7 +697,7 @@ where } else { def.display(db).to_string() }; - let docs = def.attrs(db).docs(); + let docs = def.docs(db); (label, docs) } @@ -727,14 +728,14 @@ fn builtin(famous_defs: &FamousDefs<'_, '_>, builtin: hir::BuiltinType) -> Optio // std exposes prim_{} modules with docstrings on the root to document the builtins let primitive_mod = format!("prim_{}", builtin.name().display(famous_defs.0.db)); let doc_owner = find_std_module(famous_defs, &primitive_mod)?; - let docs = doc_owner.attrs(famous_defs.0.db).docs()?; + let docs = doc_owner.docs(famous_defs.0.db)?; markup(Some(docs.into()), builtin.name().display(famous_defs.0.db).to_string(), None) } fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::Module> { let db = famous_defs.0.db; let std_crate = famous_defs.std()?; - let std_root_module = std_crate.root_module(db); + let std_root_module = std_crate.root_module(); std_root_module.children(db).find(|module| { module.name(db).map_or(false, |module| module.display(db).to_string() == name) }) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 00e21433daa..ddc71dffa8a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -1616,6 +1616,9 @@ fn test_hover_extern_crate() { check( r#" //- /main.rs crate:main deps:std +//! Crate docs + +/// Decl docs! extern crate st$0d; //- /std/lib.rs crate:std //! Standard library for this test @@ -1624,23 +1627,32 @@ extern crate st$0d; //! abc123 "#, expect![[r#" - *std* + *std* - ```rust - extern crate std - ``` + ```rust + main + ``` - --- + ```rust + extern crate std + ``` + + --- - Standard library for this test + Decl docs! - Printed? - abc123 - "#]], + Standard library for this test + + Printed? + abc123 + "#]], ); check( r#" //- /main.rs crate:main deps:std +//! Crate docs + +/// Decl docs! extern crate std as ab$0c; //- /std/lib.rs crate:std //! Standard library for this test @@ -1649,19 +1661,25 @@ extern crate std as ab$0c; //! abc123 "#, expect![[r#" - *abc* + *abc* - ```rust - extern crate std - ``` + ```rust + main + ``` - --- + ```rust + extern crate std as abc + ``` - Standard library for this test + --- - Printed? - abc123 - "#]], + Decl docs! + + Standard library for this test + + Printed? + abc123 + "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 0ad4c6c47e6..bf77d55d58e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -127,7 +127,7 @@ pub use ide_db::{ label::Label, line_index::{LineCol, LineIndex}, search::{ReferenceCategory, SearchScope}, - source_change::{FileSystemEdit, SourceChange}, + source_change::{FileSystemEdit, SnippetEdit, SourceChange}, symbol_index::Query, RootDatabase, SymbolKind, }; diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index d486a794e13..17f3771b1a5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -177,6 +177,17 @@ pub(crate) fn def_to_moniker( }); } + // Qualify locals/parameters by their parent definition name. + if let Definition::Local(it) = def { + let parent_name = it.parent(db).name(db); + if let Some(name) = parent_name { + description.push(MonikerDescriptor { + name: name.display(db).to_string(), + desc: MonikerDescriptorKind::Method, + }); + } + } + let name_desc = match def { // These are handled by top-level guard (for performance). Definition::GenericParam(_) @@ -247,6 +258,10 @@ pub(crate) fn def_to_moniker( name: s.name(db).display(db).to_string(), desc: MonikerDescriptorKind::Meta, }, + Definition::ExternCrateDecl(m) => MonikerDescriptor { + name: m.name(db).display(db).to_string(), + desc: MonikerDescriptorKind::Namespace, + }, }; description.push(name_desc); diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index c7abecb4f1e..d1479dd1e58 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -102,7 +102,7 @@ impl NavigationTarget { full_range, SymbolKind::Module, ); - res.docs = module.attrs(db).docs(); + res.docs = module.docs(db); res.description = Some(module.display(db).to_string()); return res; } @@ -217,6 +217,7 @@ impl TryToNav for Definition { Definition::Trait(it) => it.try_to_nav(db), Definition::TraitAlias(it) => it.try_to_nav(db), Definition::TypeAlias(it) => it.try_to_nav(db), + Definition::ExternCrateDecl(it) => Some(it.try_to_nav(db)?), Definition::BuiltinType(_) => None, Definition::ToolModule(_) => None, Definition::BuiltinAttr(_) => None, @@ -375,6 +376,30 @@ impl TryToNav for hir::Impl { } } +impl TryToNav for hir::ExternCrateDecl { + fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { + let src = self.source(db)?; + let InFile { file_id, value } = src; + let focus = value + .rename() + .map_or_else(|| value.name_ref().map(Either::Left), |it| it.name().map(Either::Right)); + let (file_id, full_range, focus_range) = + orig_range_with_focus(db, file_id, value.syntax(), focus); + let mut res = NavigationTarget::from_syntax( + file_id, + self.alias_or_name(db).unwrap_or_else(|| self.name(db)).to_smol_str(), + focus_range, + full_range, + SymbolKind::Module, + ); + + res.docs = self.docs(db); + res.description = Some(self.display(db).to_string()); + res.container_name = container_name(db, *self); + Some(res) + } +} + impl TryToNav for hir::Field { fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { let src = self.source(db)?; diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index fdc5261ac38..813f9ed943f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -74,7 +74,7 @@ pub(crate) fn find_all_refs( } }); let mut usages = - def.usages(sema).set_scope(search_scope.clone()).include_self_refs().all(); + def.usages(sema).set_scope(search_scope.as_ref()).include_self_refs().all(); if literal_search { retain_adt_literal_usages(&mut usages, def, sema); @@ -137,6 +137,9 @@ pub(crate) fn find_defs<'a>( NameRefClass::FieldShorthand { local_ref, field_ref: _ } => { Definition::Local(local_ref) } + NameRefClass::ExternCrateShorthand { decl, .. } => { + Definition::ExternCrateDecl(decl) + } } } ast::NameLike::Name(name) => match NameClass::classify(sema, &name)? { diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index e10c4638102..dae8e71e8a0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -145,7 +145,14 @@ fn find_definitions( if name .syntax() .parent() - .map_or(false, |it| ast::Rename::can_cast(it.kind())) => + .map_or(false, |it| ast::Rename::can_cast(it.kind())) + // FIXME: uncomment this once we resolve to usages to extern crate declarations + // && name + // .syntax() + // .ancestors() + // .nth(2) + // .map_or(true, |it| !ast::ExternCrate::can_cast(it.kind())) + => { bail!("Renaming aliases is currently unsupported") } @@ -165,7 +172,12 @@ fn find_definitions( NameRefClass::FieldShorthand { local_ref, field_ref: _ } => { Definition::Local(local_ref) } + NameRefClass::ExternCrateShorthand { decl, .. } => { + Definition::ExternCrateDecl(decl) + } }) + // FIXME: uncomment this once we resolve to usages to extern crate declarations + .filter(|def| !matches!(def, Definition::ExternCrateDecl(..))) .ok_or_else(|| format_err!("No references found at position")) .and_then(|def| { // if the name differs from the definitions name it has to be an alias @@ -367,7 +379,7 @@ mod tests { let mut file_id: Option<FileId> = None; for edit in source_change.source_file_edits { file_id = Some(edit.0); - for indel in edit.1.into_iter() { + for indel in edit.1 .0.into_iter() { text_edit_builder.replace(indel.delete, indel.insert); } } @@ -895,14 +907,17 @@ mod foo$0; source_file_edits: { FileId( 1, - ): TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 4..7, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "foo2", + delete: 4..7, + }, + ], + }, + None, + ), }, file_system_edits: [ MoveFile { @@ -944,24 +959,30 @@ use crate::foo$0::FooContent; source_file_edits: { FileId( 0, - ): TextEdit { - indels: [ - Indel { - insert: "quux", - delete: 8..11, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "quux", + delete: 8..11, + }, + ], + }, + None, + ), FileId( 2, - ): TextEdit { - indels: [ - Indel { - insert: "quux", - delete: 11..14, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "quux", + delete: 11..14, + }, + ], + }, + None, + ), }, file_system_edits: [ MoveFile { @@ -997,14 +1018,17 @@ mod fo$0o; source_file_edits: { FileId( 0, - ): TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 4..7, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "foo2", + delete: 4..7, + }, + ], + }, + None, + ), }, file_system_edits: [ MoveDir { @@ -1047,14 +1071,17 @@ mod outer { mod fo$0o; } source_file_edits: { FileId( 0, - ): TextEdit { - indels: [ - Indel { - insert: "bar", - delete: 16..19, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "bar", + delete: 16..19, + }, + ], + }, + None, + ), }, file_system_edits: [ MoveFile { @@ -1120,24 +1147,30 @@ pub mod foo$0; source_file_edits: { FileId( 0, - ): TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 27..30, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "foo2", + delete: 27..30, + }, + ], + }, + None, + ), FileId( 1, - ): TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 8..11, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "foo2", + delete: 8..11, + }, + ], + }, + None, + ), }, file_system_edits: [ MoveFile { @@ -1187,14 +1220,17 @@ mod quux; source_file_edits: { FileId( 0, - ): TextEdit { - indels: [ - Indel { - insert: "foo2", - delete: 4..7, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "foo2", + delete: 4..7, + }, + ], + }, + None, + ), }, file_system_edits: [ MoveFile { @@ -1325,18 +1361,21 @@ pub fn baz() {} source_file_edits: { FileId( 0, - ): TextEdit { - indels: [ - Indel { - insert: "r#fn", - delete: 4..7, - }, - Indel { - insert: "r#fn", - delete: 22..25, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "r#fn", + delete: 4..7, + }, + Indel { + insert: "r#fn", + delete: 22..25, + }, + ], + }, + None, + ), }, file_system_edits: [ MoveFile { @@ -1395,18 +1434,21 @@ pub fn baz() {} source_file_edits: { FileId( 0, - ): TextEdit { - indels: [ - Indel { - insert: "foo", - delete: 4..8, - }, - Indel { - insert: "foo", - delete: 23..27, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "foo", + delete: 4..8, + }, + Indel { + insert: "foo", + delete: 23..27, + }, + ], + }, + None, + ), }, file_system_edits: [ MoveFile { @@ -2487,4 +2529,109 @@ fn main() { ", ) } + + #[test] + fn extern_crate() { + check_prepare( + r" +//- /lib.rs crate:main deps:foo +extern crate foo$0; +use foo as qux; +//- /foo.rs crate:foo +", + expect![[r#"No references found at position"#]], + ); + // FIXME: replace above check_prepare with this once we resolve to usages to extern crate declarations + // check( + // "bar", + // r" + // //- /lib.rs crate:main deps:foo + // extern crate foo$0; + // use foo as qux; + // //- /foo.rs crate:foo + // ", + // r" + // extern crate foo as bar; + // use bar as qux; + // ", + // ); + } + + #[test] + fn extern_crate_rename() { + check_prepare( + r" +//- /lib.rs crate:main deps:foo +extern crate foo as qux$0; +use qux as frob; +//- /foo.rs crate:foo +", + expect!["Renaming aliases is currently unsupported"], + ); + // FIXME: replace above check_prepare with this once we resolve to usages to extern crate + // declarations + // check( + // "bar", + // r" + // //- /lib.rs crate:main deps:foo + // extern crate foo as qux$0; + // use qux as frob; + // //- /foo.rs crate:foo + // ", + // r" + // extern crate foo as bar; + // use bar as frob; + // ", + // ); + } + + #[test] + fn extern_crate_self() { + check_prepare( + r" +extern crate self$0; +use self as qux; +", + expect!["No references found at position"], + ); + // FIXME: replace above check_prepare with this once we resolve to usages to extern crate declarations + // check( + // "bar", + // r" + // extern crate self$0; + // use self as qux; + // ", + // r" + // extern crate self as bar; + // use self as qux; + // ", + // ); + } + + #[test] + fn extern_crate_self_rename() { + check_prepare( + r" +//- /lib.rs crate:main deps:foo +extern crate self as qux$0; +use qux as frob; +//- /foo.rs crate:foo +", + expect!["Renaming aliases is currently unsupported"], + ); + // FIXME: replace above check_prepare with this once we resolve to usages to extern crate declarations + // check( + // "bar", + // r" + // //- /lib.rs crate:main deps:foo + // extern crate self as qux$0; + // use qux as frob; + // //- /foo.rs crate:foo + // ", + // r" + // extern crate self as bar; + // use bar as frob; + // ", + // ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 9fa0e6449b8..5f87a78551d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -232,7 +232,7 @@ fn find_related_tests( for def in defs { let defs = def .usages(sema) - .set_scope(search_scope.clone()) + .set_scope(search_scope.as_ref()) .all() .references .into_values() @@ -309,7 +309,7 @@ pub(crate) fn runnable_fn( ) -> Option<Runnable> { let name = def.name(sema.db).to_smol_str(); - let root = def.module(sema.db).krate().root_module(sema.db); + let root = def.module(sema.db).krate().root_module(); let kind = if name == "main" && def.module(sema.db) == root { RunnableKind::Bin diff --git a/src/tools/rust-analyzer/crates/ide/src/ssr.rs b/src/tools/rust-analyzer/crates/ide/src/ssr.rs index deaf3c9c416..d8d81869a2f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/ssr.rs +++ b/src/tools/rust-analyzer/crates/ide/src/ssr.rs @@ -126,14 +126,17 @@ mod tests { source_file_edits: { FileId( 0, - ): TextEdit { - indels: [ - Indel { - insert: "3", - delete: 33..34, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "3", + delete: 33..34, + }, + ], + }, + None, + ), }, file_system_edits: [], is_snippet: false, @@ -163,24 +166,30 @@ mod tests { source_file_edits: { FileId( 0, - ): TextEdit { - indels: [ - Indel { - insert: "3", - delete: 33..34, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "3", + delete: 33..34, + }, + ], + }, + None, + ), FileId( 1, - ): TextEdit { - indels: [ - Indel { - insert: "3", - delete: 11..12, - }, - ], - }, + ): ( + TextEdit { + indels: [ + Indel { + insert: "3", + delete: 11..12, + }, + ], + }, + None, + ), }, file_system_edits: [], is_snippet: false, diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 59e8300dcdb..d8696198d3b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -88,7 +88,7 @@ pub struct StaticIndexedFile { fn all_modules(db: &dyn HirDatabase) -> Vec<Module> { let mut worklist: Vec<_> = - Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect(); + Crate::all(db).into_iter().map(|krate| krate.root_module()).collect(); let mut modules = Vec::new(); while let Some(module) = worklist.pop() { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index 3c40246a69d..8e96bfa01ad 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -269,7 +269,26 @@ fn highlight_name_ref( h } - NameRefClass::FieldShorthand { .. } => SymbolKind::Field.into(), + NameRefClass::FieldShorthand { field_ref, .. } => { + highlight_def(sema, krate, field_ref.into()) + } + NameRefClass::ExternCrateShorthand { decl, krate: resolved_krate } => { + let mut h = HlTag::Symbol(SymbolKind::Module).into(); + + if resolved_krate != krate { + h |= HlMod::Library + } + let is_public = decl.visibility(db) == hir::Visibility::Public; + if is_public { + h |= HlMod::Public + } + let is_from_builtin_crate = resolved_krate.is_builtin(db); + if is_from_builtin_crate { + h |= HlMod::DefaultLibrary; + } + h |= HlMod::CrateRoot; + h + } }; h.tag = match name_ref.token_kind() { @@ -474,6 +493,14 @@ fn highlight_def( } h } + Definition::ExternCrateDecl(extern_crate) => { + let mut highlight = + Highlight::new(HlTag::Symbol(SymbolKind::Module)) | HlMod::CrateRoot; + if extern_crate.alias(db).is_none() { + highlight |= HlMod::Library; + } + highlight + } Definition::Label(_) => Highlight::new(HlTag::Symbol(SymbolKind::Label)), Definition::BuiltinAttr(_) => Highlight::new(HlTag::Symbol(SymbolKind::BuiltinAttr)), Definition::ToolModule(_) => Highlight::new(HlTag::Symbol(SymbolKind::ToolModule)), diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index 901df147d32..2657a641482 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -288,7 +288,7 @@ fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::Stri fn module_def_to_hl_tag(def: Definition) -> HlTag { let symbol = match def { - Definition::Module(_) => SymbolKind::Module, + Definition::Module(_) | Definition::ExternCrateDecl(_) => SymbolKind::Module, Definition::Function(_) => SymbolKind::Function, Definition::Adt(hir::Adt::Struct(_)) => SymbolKind::Struct, Definition::Adt(hir::Adt::Enum(_)) => SymbolKind::Enum, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html index b15f7bca72b..88a008796b3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html @@ -44,5 +44,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> <pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">std</span><span class="semicolon">;</span> -<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">alloc</span> <span class="keyword">as</span> <span class="module crate_root default_library declaration library">abc</span><span class="semicolon">;</span> +<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">alloc</span> <span class="keyword">as</span> <span class="module crate_root declaration">abc</span><span class="semicolon">;</span> +<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="unresolved_reference">unresolved</span> <span class="keyword">as</span> <span class="module crate_root declaration">definitely_unresolved</span><span class="semicolon">;</span> </code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html index fd3b39855e2..2043752bc74 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html @@ -43,7 +43,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; } .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> -<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="self_keyword crate_root public">self</span><span class="semicolon">;</span> +<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="self_keyword crate_root">self</span><span class="semicolon">;</span> <span class="keyword">use</span> <span class="keyword crate_root public">crate</span><span class="semicolon">;</span> <span class="keyword">use</span> <span class="self_keyword crate_root public">self</span><span class="semicolon">;</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html index c5fcec75680..06b66b302ae 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html @@ -90,8 +90,18 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="brace">}</span> +<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">concat</span> <span class="brace">{</span><span class="brace">}</span> +<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">include</span> <span class="brace">{</span><span class="brace">}</span> +<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">format_args</span> <span class="brace">{</span><span class="brace">}</span> + +<span class="macro">include</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">concat</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"foo/"</span><span class="comma macro">,</span> <span class="string_literal macro">"foo.rs"</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> - <span class="unresolved_reference">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, {}!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="macro">dont_color_me_braces</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="macro">noop</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro macro">noop</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> -<span class="brace">}</span></code></pre> \ No newline at end of file +<span class="brace">}</span> +</code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index dcac8eb7368..3ac8aa9cc9d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -178,5 +178,5 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="macro unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"mov eax, </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">concat</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">backslash</span><span class="comma macro">,</span> <span class="none macro">format_args</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="none macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="none macro">toho</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="none macro">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="none macro">format_args</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="none macro">toho</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="brace">}</span></code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs index 696aa590025..8749d355c85 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs @@ -48,6 +48,7 @@ fn macros() { check_highlighting( r#" //- proc_macros: mirror +//- /lib.rs crate:lib proc_macros::mirror! { { ,i32 :x pub @@ -95,11 +96,23 @@ macro without_args { } } +#[rustc_builtin_macro] +macro_rules! concat {} +#[rustc_builtin_macro] +macro_rules! include {} +#[rustc_builtin_macro] +macro_rules! format_args {} + +include!(concat!("foo/", "foo.rs")); + fn main() { - println!("Hello, {}!", 92); + format_args!("Hello, {}!", 92); dont_color_me_braces!(); noop!(noop!(1)); } +//- /foo/foo.rs crate:foo +mod foo {} +use self::foo as bar; "#, expect_file!["./test_data/highlight_macros.html"], false, @@ -791,6 +804,7 @@ fn test_extern_crate() { //- /main.rs crate:main deps:std,alloc extern crate std; extern crate alloc as abc; +extern crate unresolved as definitely_unresolved; //- /std/lib.rs crate:std pub struct S; //- /alloc/lib.rs crate:alloc diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander.rs b/src/tools/rust-analyzer/crates/mbe/src/expander.rs index 8e2181e977e..f2d89d3efe5 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander.rs @@ -123,4 +123,14 @@ enum Fragment { /// proc-macro delimiter=none. As we later discovered, "none" delimiters are /// tricky to handle in the parser, and rustc doesn't handle those either. Expr(tt::TokenTree), + /// There are roughly two types of paths: paths in expression context, where a + /// separator `::` between an identifier and its following generic argument list + /// is mandatory, and paths in type context, where `::` can be omitted. + /// + /// Unlike rustc, we need to transform the parsed fragments back into tokens + /// during transcription. When the matched path fragment is a type-context path + /// and is trasncribed as an expression-context path, verbatim transcription + /// would cause a syntax error. We need to fix it up just before transcribing; + /// see `transcriber::fix_up_and_push_path_tt()`. + Path(tt::TokenTree), } diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs index 1a7b7eed295..1471af98b75 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs @@ -742,7 +742,11 @@ fn match_meta_var( is_2021: bool, ) -> ExpandResult<Option<Fragment>> { let fragment = match kind { - MetaVarKind::Path => parser::PrefixEntryPoint::Path, + MetaVarKind::Path => { + return input + .expect_fragment(parser::PrefixEntryPoint::Path) + .map(|it| it.map(Fragment::Path)); + } MetaVarKind::Ty => parser::PrefixEntryPoint::Ty, MetaVarKind::Pat if is_2021 => parser::PrefixEntryPoint::PatTop, MetaVarKind::Pat => parser::PrefixEntryPoint::Pat, @@ -771,7 +775,7 @@ fn match_meta_var( .expect_fragment(parser::PrefixEntryPoint::Expr) .map(|tt| tt.map(Fragment::Expr)); } - _ => { + MetaVarKind::Ident | MetaVarKind::Tt | MetaVarKind::Lifetime | MetaVarKind::Literal => { let tt_result = match kind { MetaVarKind::Ident => input .expect_ident() @@ -799,7 +803,7 @@ fn match_meta_var( }) .map_err(|()| ExpandError::binding_error("expected literal")) } - _ => Err(ExpandError::UnexpectedToken), + _ => unreachable!(), }; return tt_result.map(|it| Some(Fragment::Tokens(it))).into(); } diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs index 6161af18587..cdac2f1e3bb 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs @@ -400,7 +400,8 @@ fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) { } buf.push(tt.into()) } - Fragment::Tokens(tt) | Fragment::Expr(tt) => buf.push(tt), + Fragment::Path(tt::TokenTree::Subtree(tt)) => fix_up_and_push_path_tt(buf, tt), + Fragment::Tokens(tt) | Fragment::Expr(tt) | Fragment::Path(tt) => buf.push(tt), } } @@ -411,6 +412,45 @@ fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) { } } +/// Inserts the path separator `::` between an identifier and its following generic +/// argument list, and then pushes into the buffer. See [`Fragment::Path`] for why +/// we need this fixup. +fn fix_up_and_push_path_tt(buf: &mut Vec<tt::TokenTree>, subtree: tt::Subtree) { + stdx::always!(matches!(subtree.delimiter.kind, tt::DelimiterKind::Invisible)); + let mut prev_was_ident = false; + // Note that we only need to fix up the top-level `TokenTree`s because the + // context of the paths in the descendant `Subtree`s won't be changed by the + // mbe transcription. + for tt in subtree.token_trees { + if prev_was_ident { + // Pedantically, `(T) -> U` in `FnOnce(T) -> U` is treated as a generic + // argument list and thus needs `::` between it and `FnOnce`. However in + // today's Rust this type of path *semantically* cannot appear as a + // top-level expression-context path, so we can safely ignore it. + if let tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '<', .. })) = tt { + buf.push( + tt::Leaf::Punct(tt::Punct { + char: ':', + spacing: tt::Spacing::Joint, + span: tt::Span::unspecified(), + }) + .into(), + ); + buf.push( + tt::Leaf::Punct(tt::Punct { + char: ':', + spacing: tt::Spacing::Alone, + span: tt::Span::unspecified(), + }) + .into(), + ); + } + } + prev_was_ident = matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Ident(_))); + buf.push(tt); + } +} + /// Handles `${count(t, depth)}`. `our_depth` is the recursion depth and `count_depth` is the depth /// defined by the metavar expression. fn count( diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs index 665bce474a6..9d886a1c979 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs @@ -28,7 +28,6 @@ use crate::{ tt_iter::TtIter, }; -// FIXME: we probably should re-think `token_tree_to_syntax_node` interfaces pub use self::tt::{Delimiter, DelimiterKind, Punct}; pub use ::parser::TopEntryPoint; diff --git a/src/tools/rust-analyzer/crates/mbe/src/token_map.rs b/src/tools/rust-analyzer/crates/mbe/src/token_map.rs index 9b2df89f9c7..73a27df5dbc 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/token_map.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/token_map.rs @@ -117,4 +117,8 @@ impl TokenMap { TokenTextRange::Delimiter(_) => None, }) } + + pub fn filter(&mut self, id: impl Fn(tt::TokenId) -> bool) { + self.entries.retain(|&(tid, _)| id(tid)); + } } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs index a868419821d..333318f53b7 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs @@ -165,6 +165,40 @@ pub(crate) mod entry { } m.complete(p, ERROR); } + + pub(crate) fn eager_macro_input(p: &mut Parser<'_>) { + let m = p.start(); + + let closing_paren_kind = match p.current() { + T!['{'] => T!['}'], + T!['('] => T![')'], + T!['['] => T![']'], + _ => { + p.error("expected `{`, `[`, `(`"); + while !p.at(EOF) { + p.bump_any(); + } + m.complete(p, ERROR); + return; + } + }; + p.bump_any(); + while !p.at(EOF) && !p.at(closing_paren_kind) { + expressions::expr(p); + if !p.at(EOF) && !p.at(closing_paren_kind) { + p.expect(T![,]); + } + } + p.expect(closing_paren_kind); + if p.at(EOF) { + m.complete(p, MACRO_EAGER_INPUT); + return; + } + while !p.at(EOF) { + p.bump_any(); + } + m.complete(p, ERROR); + } } } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs index 1c056819f4b..4e850b1f74d 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -328,9 +328,6 @@ fn macro_rules(p: &mut Parser<'_>, m: Marker) { p.bump_remap(T![macro_rules]); p.expect(T![!]); - if p.at(IDENT) { - name(p); - } // Special-case `macro_rules! try`. // This is a hack until we do proper edition support @@ -340,6 +337,8 @@ fn macro_rules(p: &mut Parser<'_>, m: Marker) { let m = p.start(); p.bump_remap(IDENT); m.complete(p, NAME); + } else { + name(p); } match p.current() { diff --git a/src/tools/rust-analyzer/crates/parser/src/lib.rs b/src/tools/rust-analyzer/crates/parser/src/lib.rs index 1aba1f7674f..c155e8aaf67 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lib.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lib.rs @@ -75,6 +75,8 @@ pub enum TopEntryPoint { /// Edge case -- macros generally don't expand to attributes, with the /// exception of `cfg_attr` which does! MetaItem, + /// Edge case 2 -- eager macros expand their input to a delimited list of comma separated expressions + MacroEagerInput, } impl TopEntryPoint { @@ -87,6 +89,7 @@ impl TopEntryPoint { TopEntryPoint::Type => grammar::entry::top::type_, TopEntryPoint::Expr => grammar::entry::top::expr, TopEntryPoint::MetaItem => grammar::entry::top::meta_item, + TopEntryPoint::MacroEagerInput => grammar::entry::top::eager_macro_input, }; let mut p = parser::Parser::new(input); entry_point(&mut p); diff --git a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs index 6e3ae656b02..53cdad64992 100644 --- a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs +++ b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs @@ -223,7 +223,8 @@ fn n_attached_trivias<'a>( ) -> usize { match kind { CONST | ENUM | FN | IMPL | MACRO_CALL | MACRO_DEF | MACRO_RULES | MODULE | RECORD_FIELD - | STATIC | STRUCT | TRAIT | TUPLE_FIELD | TYPE_ALIAS | UNION | USE | VARIANT => { + | STATIC | STRUCT | TRAIT | TUPLE_FIELD | TYPE_ALIAS | UNION | USE | VARIANT + | EXTERN_CRATE => { let mut res = 0; let mut trivias = trivias.enumerate().peekable(); diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index a8fbcfacf7e..48f407623d8 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -262,6 +262,7 @@ pub enum SyntaxKind { TYPE_BOUND_LIST, MACRO_ITEMS, MACRO_STMTS, + MACRO_EAGER_INPUT, #[doc(hidden)] __LAST, } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs index 1980d4c78bb..fe18451d384 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs @@ -17,7 +17,10 @@ use token_stream::TokenStreamBuilder; mod symbol; pub use symbol::*; -use std::ops::{Bound, Range}; +use std::{ + iter, + ops::{Bound, Range}, +}; use crate::tt; @@ -80,9 +83,7 @@ impl server::TokenStream for RustAnalyzer { stream.is_empty() } fn from_str(&mut self, src: &str) -> Self::TokenStream { - use std::str::FromStr; - - Self::TokenStream::from_str(src).expect("cannot parse string") + src.parse().expect("cannot parse string") } fn to_string(&mut self, stream: &Self::TokenStream) -> String { stream.to_string() @@ -101,7 +102,7 @@ impl server::TokenStream for RustAnalyzer { }, }; let tree = TokenTree::from(group); - Self::TokenStream::from_iter(vec![tree]) + Self::TokenStream::from_iter(iter::once(tree)) } bridge::TokenTree::Ident(ident) => { @@ -111,7 +112,7 @@ impl server::TokenStream for RustAnalyzer { let ident: tt::Ident = tt::Ident { text, span: ident.span }; let leaf = tt::Leaf::from(ident); let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) + Self::TokenStream::from_iter(iter::once(tree)) } bridge::TokenTree::Literal(literal) => { @@ -123,7 +124,7 @@ impl server::TokenStream for RustAnalyzer { let literal = tt::Literal { text, span: literal.0.span }; let leaf = tt::Leaf::from(literal); let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) + Self::TokenStream::from_iter(iter::once(tree)) } bridge::TokenTree::Punct(p) => { @@ -134,7 +135,7 @@ impl server::TokenStream for RustAnalyzer { }; let leaf = tt::Leaf::from(punct); let tree = TokenTree::from(leaf); - Self::TokenStream::from_iter(vec![tree]) + Self::TokenStream::from_iter(iter::once(tree)) } } } @@ -355,12 +356,12 @@ impl server::Server for RustAnalyzer { } fn intern_symbol(ident: &str) -> Self::Symbol { - // FIXME: should be self.interner once the proc-macro api allows is + // FIXME: should be `self.interner` once the proc-macro api allows it. Symbol::intern(&SYMBOL_INTERNER, &::tt::SmolStr::from(ident)) } fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) { - // FIXME: should be self.interner once the proc-macro api allows is + // FIXME: should be `self.interner` once the proc-macro api allows it. f(symbol.text(&SYMBOL_INTERNER).as_str()) } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 33d7b5ed878..f446a7c0596 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -128,7 +128,7 @@ impl flags::AnalysisStats { let mut visited_modules = FxHashSet::default(); let mut visit_queue = Vec::new(); for krate in krates { - let module = krate.root_module(db); + let module = krate.root_module(); let file_id = module.definition_source_file_id(db); let file_id = file_id.original_file(db); let source_root = db.file_source_root(file_id); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs index 0db5fb4740e..8541be715a9 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs @@ -80,7 +80,7 @@ impl flags::Diagnostics { fn all_modules(db: &dyn HirDatabase) -> Vec<Module> { let mut worklist: Vec<_> = - Crate::all(db).into_iter().map(|krate| krate.root_module(db)).collect(); + Crate::all(db).into_iter().map(|krate| krate.root_module()).collect(); let mut modules = Vec::new(); while let Some(module) = worklist.pop() { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs index b63a266a57a..e1704199151 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs @@ -76,7 +76,7 @@ fn all_modules(db: &dyn HirDatabase) -> Vec<Module> { let mut worklist: Vec<_> = Crate::all(db) .into_iter() .filter(|x| x.origin(db).is_local()) - .map(|krate| krate.root_module(db)) + .map(|krate| krate.root_module()) .collect(); let mut modules = Vec::new(); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs index 4579aca3021..44337f955e5 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -417,6 +417,44 @@ pub mod module { } #[test] + fn symbol_for_param() { + check_symbol( + r#" +//- /lib.rs crate:main deps:foo +use foo::example_mod::func; +fn main() { + func(42); +} +//- /foo/lib.rs crate:foo@0.1.0,https://a.b/foo.git library +pub mod example_mod { + pub fn func(x$0: usize) {} +} +"#, + "rust-analyzer cargo foo 0.1.0 example_mod/func().(x)", + ); + } + + #[test] + fn symbol_for_closure_param() { + check_symbol( + r#" +//- /lib.rs crate:main deps:foo +use foo::example_mod::func; +fn main() { + func(); +} +//- /foo/lib.rs crate:foo@0.1.0,https://a.b/foo.git library +pub mod example_mod { + pub fn func() { + let f = |x$0: usize| {}; + } +} +"#, + "rust-analyzer cargo foo 0.1.0 example_mod/func().(x)", + ); + } + + #[test] fn local_symbol_for_local() { check_symbol( r#" 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 aad74b7466a..5f1f731cffb 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 @@ -353,7 +353,8 @@ pub(crate) fn handle_on_type_formatting( }; // This should be a single-file edit - let (_, text_edit) = edit.source_file_edits.into_iter().next().unwrap(); + let (_, (text_edit, snippet_edit)) = edit.source_file_edits.into_iter().next().unwrap(); + stdx::never!(snippet_edit.is_none(), "on type formatting shouldn't use structured snippets"); let change = to_proto::snippet_text_edit_vec(&line_index, edit.is_snippet, text_edit); Ok(Some(change)) 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 18d9151d4aa..0a2bb822475 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -114,6 +114,11 @@ impl GlobalState { if self.proc_macro_clients.iter().any(|it| it.is_err()) { status.health = lsp_ext::Health::Warning; message.push_str("Failed to spawn one or more proc-macro servers.\n\n"); + for err in self.proc_macro_clients.iter() { + if let Err(err) = err { + format_to!(message, "- {err}\n"); + } + } } if !self.config.cargo_autoreload() && self.is_quiescent() diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs index 7a89533a5e9..7b32180e3eb 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs @@ -10,8 +10,8 @@ use ide::{ CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, Markup, NavigationTarget, ReferenceCategory, - RenameError, Runnable, Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, - TextEdit, TextRange, TextSize, + RenameError, Runnable, Severity, SignatureHelp, SnippetEdit, SourceChange, StructureNodeKind, + SymbolKind, TextEdit, TextRange, TextSize, }; use itertools::Itertools; use serde_json::to_value; @@ -22,7 +22,7 @@ use crate::{ config::{CallInfoConfig, Config}, global_state::GlobalStateSnapshot, line_index::{LineEndings, LineIndex, PositionEncoding}, - lsp_ext, + lsp_ext::{self, SnippetTextEdit}, lsp_utils::invalid_params_error, semantic_tokens::{self, standard_fallback_type}, }; @@ -885,16 +885,136 @@ fn outside_workspace_annotation_id() -> String { String::from("OutsideWorkspace") } +fn merge_text_and_snippet_edits( + line_index: &LineIndex, + edit: TextEdit, + snippet_edit: SnippetEdit, +) -> Vec<SnippetTextEdit> { + let mut edits: Vec<SnippetTextEdit> = vec![]; + let mut snippets = snippet_edit.into_edit_ranges().into_iter().peekable(); + let mut text_edits = edit.into_iter(); + + while let Some(current_indel) = text_edits.next() { + let new_range = { + let insert_len = + TextSize::try_from(current_indel.insert.len()).unwrap_or(TextSize::from(u32::MAX)); + TextRange::at(current_indel.delete.start(), insert_len) + }; + + // insert any snippets before the text edit + for (snippet_index, snippet_range) in + snippets.take_while_ref(|(_, range)| range.end() < new_range.start()) + { + let snippet_range = if !stdx::always!( + snippet_range.is_empty(), + "placeholder range {:?} is before current text edit range {:?}", + snippet_range, + new_range + ) { + // only possible for tabstops, so make sure it's an empty/insert range + TextRange::empty(snippet_range.start()) + } else { + snippet_range + }; + + let range = range(&line_index, snippet_range); + let new_text = format!("${snippet_index}"); + + edits.push(SnippetTextEdit { + range, + new_text, + insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET), + annotation_id: None, + }) + } + + if snippets.peek().is_some_and(|(_, range)| new_range.intersect(*range).is_some()) { + // at least one snippet edit intersects this text edit, + // so gather all of the edits that intersect this text edit + let mut all_snippets = snippets + .take_while_ref(|(_, range)| new_range.intersect(*range).is_some()) + .collect_vec(); + + // ensure all of the ranges are wholly contained inside of the new range + all_snippets.retain(|(_, range)| { + stdx::always!( + new_range.contains_range(*range), + "found placeholder range {:?} which wasn't fully inside of text edit's new range {:?}", range, new_range + ) + }); + + let mut text_edit = text_edit(line_index, current_indel); + + // escape out snippet text + stdx::replace(&mut text_edit.new_text, '\\', r"\\"); + stdx::replace(&mut text_edit.new_text, '$', r"\$"); + + // ...and apply! + for (index, range) in all_snippets.iter().rev() { + let start = (range.start() - new_range.start()).into(); + let end = (range.end() - new_range.start()).into(); + + if range.is_empty() { + text_edit.new_text.insert_str(start, &format!("${index}")); + } else { + text_edit.new_text.insert(end, '}'); + text_edit.new_text.insert_str(start, &format!("${{{index}:")); + } + } + + edits.push(SnippetTextEdit { + range: text_edit.range, + new_text: text_edit.new_text, + insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET), + annotation_id: None, + }) + } else { + // snippet edit was beyond the current one + // since it wasn't consumed, it's available for the next pass + edits.push(snippet_text_edit(line_index, false, current_indel)); + } + } + + // insert any remaining tabstops + edits.extend(snippets.map(|(snippet_index, snippet_range)| { + let snippet_range = if !stdx::always!( + snippet_range.is_empty(), + "found placeholder snippet {:?} without a text edit", + snippet_range + ) { + TextRange::empty(snippet_range.start()) + } else { + snippet_range + }; + + let range = range(&line_index, snippet_range); + let new_text = format!("${snippet_index}"); + + SnippetTextEdit { + range, + new_text, + insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET), + annotation_id: None, + } + })); + + edits +} + pub(crate) fn snippet_text_document_edit( snap: &GlobalStateSnapshot, is_snippet: bool, file_id: FileId, edit: TextEdit, + snippet_edit: Option<SnippetEdit>, ) -> Cancellable<lsp_ext::SnippetTextDocumentEdit> { let text_document = optional_versioned_text_document_identifier(snap, file_id); let line_index = snap.file_line_index(file_id)?; - let mut edits: Vec<_> = - edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect(); + let mut edits = if let Some(snippet_edit) = snippet_edit { + merge_text_and_snippet_edits(&line_index, edit, snippet_edit) + } else { + edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect() + }; if snap.analysis.is_library_file(file_id)? && snap.config.change_annotation_support() { for edit in &mut edits { @@ -974,8 +1094,14 @@ pub(crate) fn snippet_workspace_edit( let ops = snippet_text_document_ops(snap, op)?; document_changes.extend_from_slice(&ops); } - for (file_id, edit) in source_change.source_file_edits { - let edit = snippet_text_document_edit(snap, source_change.is_snippet, file_id, edit)?; + for (file_id, (edit, snippet_edit)) in source_change.source_file_edits { + let edit = snippet_text_document_edit( + snap, + source_change.is_snippet, + file_id, + edit, + snippet_edit, + )?; document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit)); } let mut workspace_edit = lsp_ext::SnippetWorkspaceEdit { @@ -1414,7 +1540,9 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError { #[cfg(test)] mod tests { + use expect_test::{expect, Expect}; use ide::{Analysis, FilePosition}; + use ide_db::source_change::Snippet; use test_utils::extract_offset; use triomphe::Arc; @@ -1484,6 +1612,481 @@ fn bar(_: usize) {} assert!(!docs.contains("use crate::bar")); } + fn check_rendered_snippets(edit: TextEdit, snippets: SnippetEdit, expect: Expect) { + let text = r#"/* place to put all ranges in */"#; + let line_index = LineIndex { + index: Arc::new(ide::LineIndex::new(text)), + endings: LineEndings::Unix, + encoding: PositionEncoding::Utf8, + }; + + let res = merge_text_and_snippet_edits(&line_index, edit, snippets); + expect.assert_debug_eq(&res); + } + + #[test] + fn snippet_rendering_only_tabstops() { + let edit = TextEdit::builder().finish(); + let snippets = SnippetEdit::new(vec![ + Snippet::Tabstop(0.into()), + Snippet::Tabstop(0.into()), + Snippet::Tabstop(1.into()), + Snippet::Tabstop(1.into()), + ]); + + check_rendered_snippets( + edit, + snippets, + expect![[r#" + [ + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + new_text: "$1", + insert_text_format: Some( + Snippet, + ), + annotation_id: None, + }, + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + new_text: "$2", + insert_text_format: Some( + Snippet, + ), + annotation_id: None, + }, + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 1, + }, + end: Position { + line: 0, + character: 1, + }, + }, + new_text: "$3", + insert_text_format: Some( + Snippet, + ), + annotation_id: None, + }, + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 1, + }, + end: Position { + line: 0, + character: 1, + }, + }, + new_text: "$0", + insert_text_format: Some( + Snippet, + ), + annotation_id: None, + }, + ] + "#]], + ); + } + + #[test] + fn snippet_rendering_only_text_edits() { + let mut edit = TextEdit::builder(); + edit.insert(0.into(), "abc".to_owned()); + edit.insert(3.into(), "def".to_owned()); + let edit = edit.finish(); + let snippets = SnippetEdit::new(vec![]); + + check_rendered_snippets( + edit, + snippets, + expect![[r#" + [ + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + new_text: "abc", + insert_text_format: None, + annotation_id: None, + }, + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 3, + }, + end: Position { + line: 0, + character: 3, + }, + }, + new_text: "def", + insert_text_format: None, + annotation_id: None, + }, + ] + "#]], + ); + } + + #[test] + fn snippet_rendering_tabstop_after_text_edit() { + let mut edit = TextEdit::builder(); + edit.insert(0.into(), "abc".to_owned()); + let edit = edit.finish(); + let snippets = SnippetEdit::new(vec![Snippet::Tabstop(7.into())]); + + check_rendered_snippets( + edit, + snippets, + expect![[r#" + [ + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + new_text: "abc", + insert_text_format: None, + annotation_id: None, + }, + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 7, + }, + end: Position { + line: 0, + character: 7, + }, + }, + new_text: "$0", + insert_text_format: Some( + Snippet, + ), + annotation_id: None, + }, + ] + "#]], + ); + } + + #[test] + fn snippet_rendering_tabstops_before_text_edit() { + let mut edit = TextEdit::builder(); + edit.insert(2.into(), "abc".to_owned()); + let edit = edit.finish(); + let snippets = + SnippetEdit::new(vec![Snippet::Tabstop(0.into()), Snippet::Tabstop(0.into())]); + + check_rendered_snippets( + edit, + snippets, + expect![[r#" + [ + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + new_text: "$1", + insert_text_format: Some( + Snippet, + ), + annotation_id: None, + }, + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + new_text: "$0", + insert_text_format: Some( + Snippet, + ), + annotation_id: None, + }, + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 2, + }, + end: Position { + line: 0, + character: 2, + }, + }, + new_text: "abc", + insert_text_format: None, + annotation_id: None, + }, + ] + "#]], + ); + } + + #[test] + fn snippet_rendering_tabstops_between_text_edits() { + let mut edit = TextEdit::builder(); + edit.insert(0.into(), "abc".to_owned()); + edit.insert(7.into(), "abc".to_owned()); + let edit = edit.finish(); + let snippets = + SnippetEdit::new(vec![Snippet::Tabstop(4.into()), Snippet::Tabstop(4.into())]); + + check_rendered_snippets( + edit, + snippets, + expect![[r#" + [ + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + new_text: "abc", + insert_text_format: None, + annotation_id: None, + }, + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 4, + }, + end: Position { + line: 0, + character: 4, + }, + }, + new_text: "$1", + insert_text_format: Some( + Snippet, + ), + annotation_id: None, + }, + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 4, + }, + end: Position { + line: 0, + character: 4, + }, + }, + new_text: "$0", + insert_text_format: Some( + Snippet, + ), + annotation_id: None, + }, + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 7, + }, + end: Position { + line: 0, + character: 7, + }, + }, + new_text: "abc", + insert_text_format: None, + annotation_id: None, + }, + ] + "#]], + ); + } + + #[test] + fn snippet_rendering_multiple_tabstops_in_text_edit() { + let mut edit = TextEdit::builder(); + edit.insert(0.into(), "abcdefghijkl".to_owned()); + let edit = edit.finish(); + let snippets = SnippetEdit::new(vec![ + Snippet::Tabstop(0.into()), + Snippet::Tabstop(5.into()), + Snippet::Tabstop(12.into()), + ]); + + check_rendered_snippets( + edit, + snippets, + expect![[r#" + [ + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + new_text: "$1abcde$2fghijkl$0", + insert_text_format: Some( + Snippet, + ), + annotation_id: None, + }, + ] + "#]], + ); + } + + #[test] + fn snippet_rendering_multiple_placeholders_in_text_edit() { + let mut edit = TextEdit::builder(); + edit.insert(0.into(), "abcdefghijkl".to_owned()); + let edit = edit.finish(); + let snippets = SnippetEdit::new(vec![ + Snippet::Placeholder(TextRange::new(0.into(), 3.into())), + Snippet::Placeholder(TextRange::new(5.into(), 7.into())), + Snippet::Placeholder(TextRange::new(10.into(), 12.into())), + ]); + + check_rendered_snippets( + edit, + snippets, + expect![[r#" + [ + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + new_text: "${1:abc}de${2:fg}hij${0:kl}", + insert_text_format: Some( + Snippet, + ), + annotation_id: None, + }, + ] + "#]], + ); + } + + #[test] + fn snippet_rendering_escape_snippet_bits() { + // only needed for snippet formats + let mut edit = TextEdit::builder(); + edit.insert(0.into(), r"abc\def$".to_owned()); + edit.insert(8.into(), r"ghi\jkl$".to_owned()); + let edit = edit.finish(); + let snippets = + SnippetEdit::new(vec![Snippet::Placeholder(TextRange::new(0.into(), 3.into()))]); + + check_rendered_snippets( + edit, + snippets, + expect![[r#" + [ + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + new_text: "${0:abc}\\\\def\\$", + insert_text_format: Some( + Snippet, + ), + annotation_id: None, + }, + SnippetTextEdit { + range: Range { + start: Position { + line: 0, + character: 8, + }, + end: Position { + line: 0, + character: 8, + }, + }, + new_text: "ghi\\jkl$", + insert_text_format: None, + annotation_id: None, + }, + ] + "#]], + ); + } + // `Url` is not able to parse windows paths on unix machines. #[test] #[cfg(target_os = "windows")] diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index b096c997448..138ddd20897 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -72,6 +72,12 @@ TokenTree = MacroItems = Item* +MacroEagerInput = + '(' (Expr (',' Expr)* ','?)? ')' +| '{' (Expr (',' Expr)* ','?)? '}' +| '[' (Expr (',' Expr)* ','?)? ']' + + MacroStmts = statements:Stmt* Expr? diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 606804aea25..a150d9e6c07 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -380,6 +380,26 @@ impl Removable for ast::UseTree { } impl ast::UseTree { + /// Deletes the usetree node represented by the input. Recursively removes parents, including use nodes that become empty. + pub fn remove_recursive(self) { + let parent = self.syntax().parent(); + + self.remove(); + + if let Some(u) = parent.clone().and_then(ast::Use::cast) { + if u.use_tree().is_none() { + u.remove(); + } + } else if let Some(u) = parent.and_then(ast::UseTreeList::cast) { + if u.use_trees().next().is_none() { + let parent = u.syntax().parent().and_then(ast::UseTree::cast); + if let Some(u) = parent { + u.remove_recursive(); + } + } + } + } + pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList { match self.use_tree_list() { Some(it) => it, @@ -487,6 +507,22 @@ impl Removable for ast::Use { } } } + let prev_ws = self + .syntax() + .prev_sibling_or_token() + .and_then(|it| it.into_token()) + .and_then(ast::Whitespace::cast); + if let Some(prev_ws) = prev_ws { + let ws_text = prev_ws.syntax().text(); + let prev_newline = ws_text.rfind('\n').map(|x| x + 1).unwrap_or(0); + let rest = &ws_text[0..prev_newline]; + if rest.is_empty() { + ted::remove(prev_ws.syntax()); + } else { + ted::replace(prev_ws.syntax(), make::tokens::whitespace(rest)); + } + } + ted::remove(self.syntax()); } } 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 e520801ea2e..0b27faa535d 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 @@ -198,6 +198,20 @@ impl ast::HasModuleItem for MacroItems {} impl MacroItems {} #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct MacroEagerInput { + pub(crate) syntax: SyntaxNode, +} +impl MacroEagerInput { + pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) } + pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } + pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } + pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } + pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct MacroStmts { pub(crate) syntax: SyntaxNode, } @@ -1922,6 +1936,17 @@ impl AstNode for MacroItems { } fn syntax(&self) -> &SyntaxNode { &self.syntax } } +impl AstNode for MacroEagerInput { + fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EAGER_INPUT } + fn cast(syntax: SyntaxNode) -> Option<Self> { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} impl AstNode for MacroStmts { fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_STMTS } fn cast(syntax: SyntaxNode) -> Option<Self> { @@ -4360,6 +4385,11 @@ impl std::fmt::Display for MacroItems { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for MacroEagerInput { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for MacroStmts { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs index bed240a6d73..4cd668a0cd5 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs @@ -172,7 +172,7 @@ impl SourceFile { } impl ast::TokenTree { - pub fn reparse_as_expr(self) -> Parse<ast::Expr> { + pub fn reparse_as_comma_separated_expr(self) -> Parse<ast::MacroEagerInput> { let tokens = self.syntax().descendants_with_tokens().filter_map(NodeOrToken::into_token); let mut parser_input = parser::Input::default(); @@ -203,7 +203,7 @@ impl ast::TokenTree { } } - let parser_output = parser::TopEntryPoint::Expr.parse(&parser_input); + let parser_output = parser::TopEntryPoint::MacroEagerInput.parse(&parser_input); let mut tokens = self.syntax().descendants_with_tokens().filter_map(NodeOrToken::into_token); diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs b/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs index c5783b91a0f..e4db33f1c69 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/tests/ast_src.rs @@ -216,6 +216,7 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc { // macro related "MACRO_ITEMS", "MACRO_STMTS", + "MACRO_EAGER_INPUT", ], }; diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs index 1b8d4ba42a5..b5a72bec079 100644 --- a/src/tools/rust-analyzer/crates/tt/src/lib.rs +++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs @@ -65,12 +65,12 @@ pub mod token_id { } impl TokenTree { pub const fn empty() -> Self { - Self::Subtree(Subtree { delimiter: Delimiter::unspecified(), token_trees: vec![] }) + Self::Subtree(Subtree::empty()) } } impl Subtree { - pub fn visit_ids(&mut self, f: &impl Fn(TokenId) -> TokenId) { + pub fn visit_ids(&mut self, f: &mut impl FnMut(TokenId) -> TokenId) { self.delimiter.open = f(self.delimiter.open); self.delimiter.close = f(self.delimiter.close); self.token_trees.iter_mut().for_each(|tt| match tt { @@ -122,7 +122,6 @@ impl_from!(Literal<Span>, Punct<Span>, Ident<Span> for Leaf); #[derive(Clone, PartialEq, Eq, Hash)] pub struct Subtree<Span> { - // FIXME, this should not be Option pub delimiter: Delimiter<Span>, pub token_trees: Vec<TokenTree<Span>>, } diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc index 2cf985adabc..5dafd1a4c8c 100644 --- a/src/tools/rust-analyzer/docs/user/manual.adoc +++ b/src/tools/rust-analyzer/docs/user/manual.adoc @@ -949,6 +949,29 @@ Or it is possible to specify vars more granularly: You can use any valid regular expression as a mask. Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively. +If needed, you can set different values for different platforms: +```jsonc +"rust-analyzer.runnables.extraEnv": [ + { + "platform": "win32", // windows only + env: { + "APP_DATA": "windows specific data" + } + }, + { + "platform": ["linux"], + "env": { + "APP_DATA": "linux data", + } + }, + { // for all platforms + "env": { + "APP_COMMON_DATA": "xxx", + } + } +] +``` + ==== Compiler feedback from external commands Instead of relying on the built-in `cargo check`, you can configure Code to run a command in the background and use the `$rustc-watch` problem matcher to generate inline error markers from its output. diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 1c94f13d745..20fe781ae9e 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -18,7 +18,7 @@ "devDependencies": { "@tsconfig/strictest": "^2.0.1", "@types/node": "~16.11.7", - "@types/vscode": "~1.78.1", + "@types/vscode": "~1.75", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vscode/test-electron": "^2.3.3", @@ -32,7 +32,7 @@ "typescript": "^5.1.6" }, "engines": { - "vscode": "^1.78.0" + "vscode": "^1.75.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -565,9 +565,9 @@ "dev": true }, "node_modules/@types/vscode": { - "version": "1.78.1", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.78.1.tgz", - "integrity": "sha512-wEA+54axejHu7DhcUfnFBan1IqFD1gBDxAFz8LoX06NbNDMRJv/T6OGthOs52yZccasKfN588EyffHWABkR0fg==", + "version": "1.75.1", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.75.1.tgz", + "integrity": "sha512-emg7wdsTFzdi+elvoyoA+Q8keEautdQHyY5LNmHVM4PTpY8JgOTVADrGVyXGepJ6dVW2OS5/xnLUWh+nZxvdiA==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index a4897899cab..76d7e91f381 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -26,7 +26,7 @@ } }, "engines": { - "vscode": "^1.78.0" + "vscode": "^1.75.0" }, "enabledApiProposals": [], "scripts": { @@ -53,7 +53,7 @@ "devDependencies": { "@tsconfig/strictest": "^2.0.1", "@types/node": "~16.11.7", - "@types/vscode": "~1.78.1", + "@types/vscode": "~1.75", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vscode/test-electron": "^2.3.3", @@ -328,6 +328,15 @@ "items": { "type": "object", "properties": { + "platform": { + "type": [ + "null", + "string", + "array" + ], + "default": null, + "markdownDescription": "Platform(s) filter like \"win32\" or [\"linux\", \"win32\"]. See [process.platform](https://nodejs.org/api/process.html#processplatform) values." + }, "mask": { "type": "string", "description": "Runnable name mask" diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index a047f9659a9..0e64054c11d 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -6,10 +6,12 @@ import type { Env } from "./client"; import { log } from "./util"; import { expectNotUndefined, unwrapUndefinable } from "./undefinable"; -export type RunnableEnvCfg = - | undefined - | Record<string, string> - | { mask?: string; env: Record<string, string> }[]; +export type RunnableEnvCfgItem = { + mask?: string; + env: Record<string, string>; + platform?: string | string[]; +}; +export type RunnableEnvCfg = undefined | Record<string, string> | RunnableEnvCfgItem[]; export class Config { readonly extensionId = "rust-lang.rust-analyzer"; diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts index ac144cbebb2..16c14ca54f2 100644 --- a/src/tools/rust-analyzer/editors/code/src/ctx.ts +++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts @@ -414,7 +414,7 @@ export class Ctx { statusBar.tooltip.appendText(status.message ?? "Ready"); statusBar.color = undefined; statusBar.backgroundColor = undefined; - statusBar.command = "rust-analyzer.stopServer"; + statusBar.command = "rust-analyzer.openLogs"; this.dependencies?.refresh(); break; case "warning": @@ -442,14 +442,16 @@ export class Ctx { statusBar.tooltip.appendMarkdown( "\n\n[Start server](command:rust-analyzer.startServer)", ); - statusBar.color = undefined; - statusBar.backgroundColor = undefined; + statusBar.color = new vscode.ThemeColor("statusBarItem.warningForeground"); + statusBar.backgroundColor = new vscode.ThemeColor( + "statusBarItem.warningBackground", + ); statusBar.command = "rust-analyzer.startServer"; statusBar.text = `$(stop-circle) rust-analyzer`; return; } if (statusBar.tooltip.value) { - statusBar.tooltip.appendText("\n\n"); + statusBar.tooltip.appendMarkdown("\n\n---\n\n"); } statusBar.tooltip.appendMarkdown("\n\n[Open logs](command:rust-analyzer.openLogs)"); statusBar.tooltip.appendMarkdown( diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts index c893d390554..57881803a6a 100644 --- a/src/tools/rust-analyzer/editors/code/src/run.ts +++ b/src/tools/rust-analyzer/editors/code/src/run.ts @@ -5,7 +5,7 @@ import * as tasks from "./tasks"; import type { CtxInit } from "./ctx"; import { makeDebugConfig } from "./debug"; -import type { Config, RunnableEnvCfg } from "./config"; +import type { Config, RunnableEnvCfg, RunnableEnvCfgItem } from "./config"; import { unwrapUndefinable } from "./undefinable"; const quickPickButtons = [ @@ -112,11 +112,21 @@ export function prepareEnv( } Object.assign(env, process.env as { [key: string]: string }); + const platform = process.platform; + + const checkPlatform = (it: RunnableEnvCfgItem) => { + if (it.platform) { + const platforms = Array.isArray(it.platform) ? it.platform : [it.platform]; + return platforms.indexOf(platform) >= 0; + } + return true; + }; if (runnableEnvCfg) { if (Array.isArray(runnableEnvCfg)) { for (const it of runnableEnvCfg) { - if (!it.mask || new RegExp(it.mask).test(runnable.label)) { + const masked = !it.mask || new RegExp(it.mask).test(runnable.label); + if (masked && checkPlatform(it)) { Object.assign(env, it.env); } } diff --git a/src/tools/rust-analyzer/triagebot.toml b/src/tools/rust-analyzer/triagebot.toml index a910e012b73..f0cd3539975 100644 --- a/src/tools/rust-analyzer/triagebot.toml +++ b/src/tools/rust-analyzer/triagebot.toml @@ -9,3 +9,7 @@ allow-unauthenticated = [ [autolabel."S-waiting-on-review"] new_pr = true + +[no-merges] +exclude_labels = ["sync"] +labels = ["has-merge-commits", "S-waiting-on-author"] diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs index 5f8eaebf531..67b745373f0 100644 --- a/src/tools/tidy/src/fluent_alphabetical.rs +++ b/src/tools/tidy/src/fluent_alphabetical.rs @@ -23,7 +23,7 @@ fn check_alphabetic(filename: &str, fluent: &str, bad: &mut bool) { tidy_error!( bad, "{filename}: message `{}` appears before `{}`, but is alphabetically later than it -run tidy with `--bless` to sort the file correctly", +run `./x.py test tidy --bless` to sort the file correctly", name.as_str(), next.as_str() ); diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 930b7408390..3414924007b 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -10,7 +10,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: usize = 1893; +const ISSUES_ENTRY_LIMIT: usize = 1891; const ROOT_ENTRY_LIMIT: usize = 866; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ diff --git a/tests/codegen/box-maybe-uninit-llvm14.rs b/tests/codegen/box-maybe-uninit-llvm14.rs deleted file mode 100644 index c9f88fb3fe4..00000000000 --- a/tests/codegen/box-maybe-uninit-llvm14.rs +++ /dev/null @@ -1,34 +0,0 @@ -// compile-flags: -O - -// Once we're done with llvm 14 and earlier, this test can be deleted. - -#![crate_type = "lib"] - -use std::mem::MaybeUninit; - -// Boxing a `MaybeUninit` value should not copy junk from the stack -#[no_mangle] -pub fn box_uninitialized() -> Box<MaybeUninit<usize>> { - // CHECK-LABEL: @box_uninitialized - // CHECK-NOT: store - // CHECK-NOT: alloca - // CHECK-NOT: memcpy - // CHECK-NOT: memset - Box::new(MaybeUninit::uninit()) -} - -// https://github.com/rust-lang/rust/issues/58201 -#[no_mangle] -pub fn box_uninitialized2() -> Box<MaybeUninit<[usize; 1024 * 1024]>> { - // CHECK-LABEL: @box_uninitialized2 - // CHECK-NOT: store - // CHECK-NOT: alloca - // CHECK-NOT: memcpy - // CHECK-NOT: memset - Box::new(MaybeUninit::uninit()) -} - -// Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc -// from the CHECK-NOT above. We don't check the attributes here because we can't rely -// on all of them being set until LLVM 15. -// CHECK: declare {{(dso_local )?}}noalias{{.*}} @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+.*}} noundef) diff --git a/tests/codegen/c-variadic-copy.rs b/tests/codegen/cffi/c-variadic-copy.rs index 4c61c4fcf68..4c61c4fcf68 100644 --- a/tests/codegen/c-variadic-copy.rs +++ b/tests/codegen/cffi/c-variadic-copy.rs diff --git a/tests/codegen/c-variadic-opt.rs b/tests/codegen/cffi/c-variadic-opt.rs index 969dce80f58..969dce80f58 100644 --- a/tests/codegen/c-variadic-opt.rs +++ b/tests/codegen/cffi/c-variadic-opt.rs diff --git a/tests/codegen/c-variadic.rs b/tests/codegen/cffi/c-variadic.rs index cab32652210..cab32652210 100644 --- a/tests/codegen/c-variadic.rs +++ b/tests/codegen/cffi/c-variadic.rs diff --git a/tests/codegen/ffi-const.rs b/tests/codegen/cffi/ffi-const.rs index 93720503480..93720503480 100644 --- a/tests/codegen/ffi-const.rs +++ b/tests/codegen/cffi/ffi-const.rs diff --git a/tests/codegen/ffi-out-of-bounds-loads.rs b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs index 099726b2f08..099726b2f08 100644 --- a/tests/codegen/ffi-out-of-bounds-loads.rs +++ b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs diff --git a/tests/codegen/ffi-pure.rs b/tests/codegen/cffi/ffi-pure.rs index 2ed73581358..2ed73581358 100644 --- a/tests/codegen/ffi-pure.rs +++ b/tests/codegen/cffi/ffi-pure.rs diff --git a/tests/codegen/ffi-returns-twice.rs b/tests/codegen/cffi/ffi-returns-twice.rs index 0fbe03f0bb6..0fbe03f0bb6 100644 --- a/tests/codegen/ffi-returns-twice.rs +++ b/tests/codegen/cffi/ffi-returns-twice.rs diff --git a/tests/codegen/enum-bounds-check-derived-idx.rs b/tests/codegen/enum/enum-bounds-check-derived-idx.rs index aa66c2ed08e..aa66c2ed08e 100644 --- a/tests/codegen/enum-bounds-check-derived-idx.rs +++ b/tests/codegen/enum/enum-bounds-check-derived-idx.rs diff --git a/tests/codegen/enum-bounds-check-issue-13926.rs b/tests/codegen/enum/enum-bounds-check-issue-13926.rs index b26945bc549..b26945bc549 100644 --- a/tests/codegen/enum-bounds-check-issue-13926.rs +++ b/tests/codegen/enum/enum-bounds-check-issue-13926.rs diff --git a/tests/codegen/enum-bounds-check-issue-82871.rs b/tests/codegen/enum/enum-bounds-check-issue-82871.rs index 32fdc4a5f4f..32fdc4a5f4f 100644 --- a/tests/codegen/enum-bounds-check-issue-82871.rs +++ b/tests/codegen/enum/enum-bounds-check-issue-82871.rs diff --git a/tests/codegen/enum-bounds-check.rs b/tests/codegen/enum/enum-bounds-check.rs index 17322d5911b..17322d5911b 100644 --- a/tests/codegen/enum-bounds-check.rs +++ b/tests/codegen/enum/enum-bounds-check.rs diff --git a/tests/codegen/enum-debug-clike.rs b/tests/codegen/enum/enum-debug-clike.rs index 1e369a2c4e6..1e369a2c4e6 100644 --- a/tests/codegen/enum-debug-clike.rs +++ b/tests/codegen/enum/enum-debug-clike.rs diff --git a/tests/codegen/enum-debug-niche-2.rs b/tests/codegen/enum/enum-debug-niche-2.rs index 4b607d50574..4b607d50574 100644 --- a/tests/codegen/enum-debug-niche-2.rs +++ b/tests/codegen/enum/enum-debug-niche-2.rs diff --git a/tests/codegen/enum-debug-niche.rs b/tests/codegen/enum/enum-debug-niche.rs index b718a6854dd..b718a6854dd 100644 --- a/tests/codegen/enum-debug-niche.rs +++ b/tests/codegen/enum/enum-debug-niche.rs diff --git a/tests/codegen/enum-debug-tagged.rs b/tests/codegen/enum/enum-debug-tagged.rs index 095c49ac3ac..095c49ac3ac 100644 --- a/tests/codegen/enum-debug-tagged.rs +++ b/tests/codegen/enum/enum-debug-tagged.rs diff --git a/tests/codegen/enum-discriminant-value.rs b/tests/codegen/enum/enum-discriminant-value.rs index cc14c212002..cc14c212002 100644 --- a/tests/codegen/enum-discriminant-value.rs +++ b/tests/codegen/enum/enum-discriminant-value.rs diff --git a/tests/codegen/enum-match.rs b/tests/codegen/enum/enum-match.rs index 5548cd25147..5548cd25147 100644 --- a/tests/codegen/enum-match.rs +++ b/tests/codegen/enum/enum-match.rs diff --git a/tests/codegen/enum-u128.rs b/tests/codegen/enum/enum-u128.rs index f50d360ac9f..f50d360ac9f 100644 --- a/tests/codegen/enum-u128.rs +++ b/tests/codegen/enum/enum-u128.rs diff --git a/tests/codegen/intrinsics/compare_bytes.rs b/tests/codegen/intrinsics/compare_bytes.rs new file mode 100644 index 00000000000..e69224d818c --- /dev/null +++ b/tests/codegen/intrinsics/compare_bytes.rs @@ -0,0 +1,34 @@ +// revisions: INT32 INT16 +// compile-flags: -O +// [INT32] ignore-16bit +// [INT16] only-16bit + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::compare_bytes; + +#[no_mangle] +// CHECK-LABEL: @bytes_cmp( +pub unsafe fn bytes_cmp(a: *const u8, b: *const u8, n: usize) -> i32 { + // INT32: %[[TEMP:.+]] = tail call i32 @memcmp(ptr %a, ptr %b, {{i32|i64}} %n) + // INT32-NOT: sext + // INT32: ret i32 %[[TEMP]] + + // INT16: %[[TEMP1:.+]] = tail call i16 @memcmp(ptr %a, ptr %b, i16 %n) + // INT16: %[[TEMP2:.+]] = sext i16 %[[TEMP1]] to i32 + // INT16: ret i32 %[[TEMP2]] + compare_bytes(a, b, n) +} + +// Ensure that, even though there's an `sext` emitted by the intrinsic, +// that doesn't end up pessiming checks against zero. +#[no_mangle] +// CHECK-LABEL: @bytes_eq( +pub unsafe fn bytes_eq(a: *const u8, b: *const u8, n: usize) -> bool { + // CHECK: call {{.+}} @{{bcmp|memcmp}}(ptr %a, ptr %b, {{i16|i32|i64}} %n) + // CHECK-NOT: sext + // INT32: icmp eq i32 + // INT16: icmp eq i16 + compare_bytes(a, b, n) == 0_i32 +} diff --git a/tests/codegen/i686-macosx-deployment-target.rs b/tests/codegen/macos/i686-macosx-deployment-target.rs index 17258a264a5..17258a264a5 100644 --- a/tests/codegen/i686-macosx-deployment-target.rs +++ b/tests/codegen/macos/i686-macosx-deployment-target.rs diff --git a/tests/codegen/i686-no-macosx-deployment-target.rs b/tests/codegen/macos/i686-no-macosx-deployment-target.rs index 043040a95e3..043040a95e3 100644 --- a/tests/codegen/i686-no-macosx-deployment-target.rs +++ b/tests/codegen/macos/i686-no-macosx-deployment-target.rs diff --git a/tests/codegen/x86_64-macosx-deployment-target.rs b/tests/codegen/macos/x86_64-macosx-deployment-target.rs index 8e673d11d98..8e673d11d98 100644 --- a/tests/codegen/x86_64-macosx-deployment-target.rs +++ b/tests/codegen/macos/x86_64-macosx-deployment-target.rs diff --git a/tests/codegen/x86_64-no-macosx-deployment-target.rs b/tests/codegen/macos/x86_64-no-macosx-deployment-target.rs index 25ae6924de0..25ae6924de0 100644 --- a/tests/codegen/x86_64-no-macosx-deployment-target.rs +++ b/tests/codegen/macos/x86_64-no-macosx-deployment-target.rs diff --git a/tests/codegen/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs index e05bbc26e83..e05bbc26e83 100644 --- a/tests/codegen/naked-functions.rs +++ b/tests/codegen/naked-fn/naked-functions.rs diff --git a/tests/codegen/naked-nocoverage.rs b/tests/codegen/naked-fn/naked-nocoverage.rs index 3c755e49c6d..3c755e49c6d 100644 --- a/tests/codegen/naked-nocoverage.rs +++ b/tests/codegen/naked-fn/naked-nocoverage.rs diff --git a/tests/codegen/naked-noinline.rs b/tests/codegen/naked-fn/naked-noinline.rs index 5cfb500c0ef..5cfb500c0ef 100644 --- a/tests/codegen/naked-noinline.rs +++ b/tests/codegen/naked-fn/naked-noinline.rs diff --git a/tests/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs b/tests/codegen/sanitizer/cfi-add-canonical-jump-tables-flag.rs index 1ee8bdfc3ab..1ee8bdfc3ab 100644 --- a/tests/codegen/sanitizer-cfi-add-canonical-jump-tables-flag.rs +++ b/tests/codegen/sanitizer/cfi-add-canonical-jump-tables-flag.rs diff --git a/tests/codegen/sanitizer-cfi-add-enable-split-lto-unit-flag.rs b/tests/codegen/sanitizer/cfi-add-enable-split-lto-unit-flag.rs index 68c91384b82..68c91384b82 100644 --- a/tests/codegen/sanitizer-cfi-add-enable-split-lto-unit-flag.rs +++ b/tests/codegen/sanitizer/cfi-add-enable-split-lto-unit-flag.rs diff --git a/tests/codegen/sanitizer-cfi-emit-type-checks-attr-no-sanitize.rs b/tests/codegen/sanitizer/cfi-emit-type-checks-attr-no-sanitize.rs index 2b61c9078fd..a3cd16e3dd5 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-checks-attr-no-sanitize.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-checks-attr-no-sanitize.rs @@ -8,7 +8,7 @@ #[no_sanitize(cfi)] pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: sanitizer_cfi_emit_type_checks_attr_no_sanitize::foo + // CHECK-LABEL: cfi_emit_type_checks_attr_no_sanitize::foo // CHECK: Function Attrs: {{.*}} // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} // CHECK: start: diff --git a/tests/codegen/sanitizer-cfi-emit-type-checks.rs b/tests/codegen/sanitizer/cfi-emit-type-checks.rs index f0fe5de9f66..f0fe5de9f66 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-checks.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-checks.rs diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-attr-cfi-encoding.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-attr-cfi-encoding.rs index 084d8bf803c..084d8bf803c 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-attr-cfi-encoding.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-attr-cfi-encoding.rs diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-id-itanium-cxx-abi.rs index 63e63c5d4aa..da608e180c5 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-id-itanium-cxx-abi.rs @@ -521,15 +521,15 @@ pub fn foo149(_: Type14<Bar>, _: Type14<Bar>, _: Type14<Bar>) { } // CHECK: ![[TYPE66]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EEE"} // CHECK: ![[TYPE67]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_E"} // CHECK: ![[TYPE68]] = !{i64 0, !"_ZTSFvu3refIu5sliceIu3i32EES1_S1_E"} -// CHECK: ![[TYPE69]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EEE"} -// CHECK: ![[TYPE70]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_E"} -// CHECK: ![[TYPE71]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32EES1_S1_E"} -// CHECK: ![[TYPE72]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EEE"} -// CHECK: ![[TYPE73]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_E"} -// CHECK: ![[TYPE74]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi5Enum1Iu3i32EES1_S1_E"} -// CHECK: ![[TYPE75]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EEE"} -// CHECK: ![[TYPE76]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_E"} -// CHECK: ![[TYPE77]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Union1Iu3i32EES1_S1_E"} +// CHECK: ![[TYPE69]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME:[0-9]{1,2}[a-z_]{1,99}]]7Struct1Iu3i32EEE"} +// CHECK: ![[TYPE70]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]7Struct1Iu3i32EES1_E"} +// CHECK: ![[TYPE71]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]7Struct1Iu3i32EES1_S1_E"} +// CHECK: ![[TYPE72]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]5Enum1Iu3i32EEE"} +// CHECK: ![[TYPE73]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]5Enum1Iu3i32EES1_E"} +// CHECK: ![[TYPE74]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]5Enum1Iu3i32EES1_S1_E"} +// CHECK: ![[TYPE75]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Union1Iu3i32EEE"} +// CHECK: ![[TYPE76]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Union1Iu3i32EES1_E"} +// CHECK: ![[TYPE77]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Union1Iu3i32EES1_S1_E"} // CHECK: ![[TYPE78]] = !{i64 0, !"_ZTSFvP5type1E"} // CHECK: ![[TYPE79]] = !{i64 0, !"_ZTSFvP5type1S0_E"} // CHECK: ![[TYPE80]] = !{i64 0, !"_ZTSFvP5type1S0_S0_E"} @@ -560,45 +560,45 @@ pub fn foo149(_: Type14<Bar>, _: Type14<Bar>, _: Type14<Bar>) { } // CHECK: ![[TYPE105]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} // CHECK: ![[TYPE106]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"} // CHECK: ![[TYPE107]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"} -// CHECK: ![[TYPE108]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvEE"} -// CHECK: ![[TYPE109]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_E"} -// CHECK: ![[TYPE110]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_S1_E"} -// CHECK: ![[TYPE111]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}E"} -// CHECK: ![[TYPE112]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_E"} -// CHECK: ![[TYPE113]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_S_E"} -// CHECK: ![[TYPE114]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooE"} -// CHECK: ![[TYPE115]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_E"} -// CHECK: ![[TYPE116]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_S_E"} -// CHECK: ![[TYPE117]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooE"} -// CHECK: ![[TYPE118]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_E"} -// CHECK: ![[TYPE119]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_S_E"} -// CHECK: ![[TYPE120]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooE"} -// CHECK: ![[TYPE121]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_E"} -// CHECK: ![[TYPE122]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_S_E"} -// CHECK: ![[TYPE123]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32EE"} -// CHECK: ![[TYPE124]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_E"} -// CHECK: ![[TYPE125]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_S0_E"} -// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu5paramEu6regionEu3i32EE"} -// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu5paramEu6regionEu3i32ES4_E"} -// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu5paramEu6regionEu3i32ES4_S4_E"} -// CHECK: ![[TYPE129]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_EE"} -// CHECK: ![[TYPE130]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_E"} -// CHECK: ![[TYPE131]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_S0_E"} -// CHECK: ![[TYPE132]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_EE"} -// CHECK: ![[TYPE133]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_E"} -// CHECK: ![[TYPE134]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi7Struct1Iu3i32ES_ES1_S1_E"} -// CHECK: ![[TYPE135]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EEE"} -// CHECK: ![[TYPE136]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_E"} -// CHECK: ![[TYPE137]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn13QuxIu3i32Lu5usize32EES2_S2_E"} -// CHECK: ![[TYPE138]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_EE"} -// CHECK: ![[TYPE139]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_E"} -// CHECK: ![[TYPE140]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_S0_E"} -// CHECK: ![[TYPE141]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooE"} -// CHECK: ![[TYPE142]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_E"} -// CHECK: ![[TYPE143]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3FooS_S_E"} +// CHECK: ![[TYPE108]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvEE"} +// CHECK: ![[TYPE109]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_E"} +// CHECK: ![[TYPE110]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NCNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn111{{[{}][{}]}}closure{{[}][}]}}Iu2i8PFvvEvES1_S1_E"} +// CHECK: ![[TYPE111]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}E"} +// CHECK: ![[TYPE112]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_E"} +// CHECK: ![[TYPE113]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn13Foo15{{[{}][{}]}}constructor{{[}][}]}}S_S_E"} +// CHECK: ![[TYPE114]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn110{{[{}][{}]}}extern{{[}][}]}}3fooE"} +// CHECK: ![[TYPE115]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_E"} +// CHECK: ![[TYPE116]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn110{{[{}][{}]}}extern{{[}][}]}}3fooS_S_E"} +// CHECK: ![[TYPE117]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooE"} +// CHECK: ![[TYPE118]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_E"} +// CHECK: ![[TYPE119]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn1s0_11{{[{}][{}]}}closure{{[}][}]}}3FooS_S_E"} +// CHECK: ![[TYPE120]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn112{{[{}][{}]}}constant{{[}][}]}}3FooE"} +// CHECK: ![[TYPE121]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_E"} +// CHECK: ![[TYPE122]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn112{{[{}][{}]}}constant{{[}][}]}}3FooS_S_E"} +// CHECK: ![[TYPE123]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32EE"} +// CHECK: ![[TYPE124]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_E"} +// CHECK: ![[TYPE125]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_S0_E"} +// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait1Iu5paramEu6regionEu3i32EE"} +// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait1Iu5paramEu6regionEu3i32ES4_E"} +// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait1Iu5paramEu6regionEu3i32ES4_S4_E"} +// CHECK: ![[TYPE129]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu3i32S_EE"} +// CHECK: ![[TYPE130]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu3i32S_ES0_E"} +// CHECK: ![[TYPE131]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu3i32S_ES0_S0_E"} +// CHECK: ![[TYPE132]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]7Struct1Iu3i32ES_EE"} +// CHECK: ![[TYPE133]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]7Struct1Iu3i32ES_ES1_E"} +// CHECK: ![[TYPE134]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]6Trait13fooIu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]7Struct1Iu3i32ES_ES1_S1_E"} +// CHECK: ![[TYPE135]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn13QuxIu3i32Lu5usize32EEE"} +// CHECK: ![[TYPE136]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn13QuxIu3i32Lu5usize32EES2_E"} +// CHECK: ![[TYPE137]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn13QuxIu3i32Lu5usize32EES2_S2_E"} +// CHECK: ![[TYPE138]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_EE"} +// CHECK: ![[TYPE139]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_E"} +// CHECK: ![[TYPE140]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NcNtNvC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3fn15Quuux15{{[{}][{}]}}constructor{{[}][}]}}Iu6regionS_ES0_S0_E"} +// CHECK: ![[TYPE141]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3FooE"} +// CHECK: ![[TYPE142]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3FooS_E"} +// CHECK: ![[TYPE143]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3FooS_S_E"} // CHECK: ![[TYPE144]] = !{i64 0, !"_ZTSFvu3refIvEE"} // CHECK: ![[TYPE145]] = !{i64 0, !"_ZTSFvu3refIvES_E"} // CHECK: ![[TYPE146]] = !{i64 0, !"_ZTSFvu3refIvES_S_E"} -// CHECK: ![[TYPE147]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarE"} -// CHECK: ![[TYPE148]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarS_E"} -// CHECK: ![[TYPE149]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3BarS_S_E"} +// CHECK: ![[TYPE147]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3BarE"} +// CHECK: ![[TYPE148]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3BarS_E"} +// CHECK: ![[TYPE149]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtC{{[[:print:]]+}}_[[ITANIUMED_FILENAME]]3BarS_S_E"} diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs index d200ed9798a..d200ed9798a 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-generalized.rs diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs index cdefec17a1c..cdefec17a1c 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-normalized-generalized.rs diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs index f360b33ddcf..f360b33ddcf 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi-normalized.rs diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi.rs index 3cb817b212d..3cb817b212d 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-itanium-cxx-abi.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-itanium-cxx-abi.rs diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-trait-objects.rs index b69e57261a8..b69e57261a8 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-trait-objects.rs diff --git a/tests/codegen/sanitizer-cfi-generalize-pointers.rs b/tests/codegen/sanitizer/cfi-generalize-pointers.rs index 677ebdb27ec..677ebdb27ec 100644 --- a/tests/codegen/sanitizer-cfi-generalize-pointers.rs +++ b/tests/codegen/sanitizer/cfi-generalize-pointers.rs diff --git a/tests/codegen/sanitizer-cfi-normalize-integers.rs b/tests/codegen/sanitizer/cfi-normalize-integers.rs index aa3913cb8e7..aa3913cb8e7 100644 --- a/tests/codegen/sanitizer-cfi-normalize-integers.rs +++ b/tests/codegen/sanitizer/cfi-normalize-integers.rs diff --git a/tests/codegen/sanitizer-kasan-emits-instrumentation.rs b/tests/codegen/sanitizer/kasan-emits-instrumentation.rs index d6e3f2719df..783bc47b9d0 100644 --- a/tests/codegen/sanitizer-kasan-emits-instrumentation.rs +++ b/tests/codegen/sanitizer/kasan-emits-instrumentation.rs @@ -25,7 +25,7 @@ trait Copy {} impl Copy for u8 {} -// CHECK-LABEL: ; sanitizer_kasan_emits_instrumentation::unsanitized +// CHECK-LABEL: ; kasan_emits_instrumentation::unsanitized // CHECK-NEXT: ; Function Attrs: // CHECK-NOT: sanitize_address // CHECK: start: @@ -36,7 +36,7 @@ pub fn unsanitized(b: &mut u8) -> u8 { *b } -// CHECK-LABEL: ; sanitizer_kasan_emits_instrumentation::sanitized +// CHECK-LABEL: ; kasan_emits_instrumentation::sanitized // CHECK-NEXT: ; Function Attrs: // CHECK: sanitize_address // CHECK: start: diff --git a/tests/codegen/sanitizer-kcfi-add-kcfi-flag.rs b/tests/codegen/sanitizer/kcfi-add-kcfi-flag.rs index c2eb852aec3..c2eb852aec3 100644 --- a/tests/codegen/sanitizer-kcfi-add-kcfi-flag.rs +++ b/tests/codegen/sanitizer/kcfi-add-kcfi-flag.rs diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-attr-no-sanitize.rs b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-attr-no-sanitize.rs index bb317e4a2fa..001fc956aaa 100644 --- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-attr-no-sanitize.rs +++ b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-attr-no-sanitize.rs @@ -20,7 +20,7 @@ impl Copy for i32 {} #[no_sanitize(kcfi)] pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 { - // CHECK-LABEL: sanitizer_kcfi_emit_kcfi_operand_bundle_attr_no_sanitize::foo + // CHECK-LABEL: kcfi_emit_kcfi_operand_bundle_attr_no_sanitize::foo // CHECK: Function Attrs: {{.*}} // CHECK-LABEL: define{{.*}}foo{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} // CHECK: start: diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs index 29e4df3511f..29e4df3511f 100644 --- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs +++ b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-generalized.rs diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs index 84d678a33ba..84d678a33ba 100644 --- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs +++ b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized-generalized.rs diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs index 761c37a9e06..761c37a9e06 100644 --- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs +++ b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi-normalized.rs diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs index 83cda0ef136..83cda0ef136 100644 --- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs +++ b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle-itanium-cxx-abi.rs diff --git a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle.rs b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle.rs index e1d617b5ee1..e1d617b5ee1 100644 --- a/tests/codegen/sanitizer-kcfi-emit-kcfi-operand-bundle.rs +++ b/tests/codegen/sanitizer/kcfi-emit-kcfi-operand-bundle.rs diff --git a/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer/kcfi-emit-type-metadata-trait-objects.rs index 7aed137f215..7aed137f215 100644 --- a/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs +++ b/tests/codegen/sanitizer/kcfi-emit-type-metadata-trait-objects.rs diff --git a/tests/codegen/sanitizer-memory-track-orgins.rs b/tests/codegen/sanitizer/memory-track-origins.rs index 4bd50508d15..4bd50508d15 100644 --- a/tests/codegen/sanitizer-memory-track-orgins.rs +++ b/tests/codegen/sanitizer/memory-track-origins.rs diff --git a/tests/codegen/sanitizer_memtag_attr_check.rs b/tests/codegen/sanitizer/memtag-attr-check.rs index 2fd362656d4..2fd362656d4 100644 --- a/tests/codegen/sanitizer_memtag_attr_check.rs +++ b/tests/codegen/sanitizer/memtag-attr-check.rs diff --git a/tests/codegen/sanitizer-no-sanitize-inlining.rs b/tests/codegen/sanitizer/no-sanitize-inlining.rs index f4af60baefe..f4af60baefe 100644 --- a/tests/codegen/sanitizer-no-sanitize-inlining.rs +++ b/tests/codegen/sanitizer/no-sanitize-inlining.rs diff --git a/tests/codegen/sanitizer-no-sanitize.rs b/tests/codegen/sanitizer/no-sanitize.rs index fb9d249da03..783b568e279 100644 --- a/tests/codegen/sanitizer-no-sanitize.rs +++ b/tests/codegen/sanitizer/no-sanitize.rs @@ -7,7 +7,7 @@ #![crate_type="lib"] #![feature(no_sanitize)] -// CHECK-LABEL: ; sanitizer_no_sanitize::unsanitized +// CHECK-LABEL: ; no_sanitize::unsanitized // CHECK-NEXT: ; Function Attrs: // CHECK-NOT: sanitize_address // CHECK: start: @@ -18,7 +18,7 @@ pub fn unsanitized(b: &mut u8) -> u8 { *b } -// CHECK-LABEL: ; sanitizer_no_sanitize::sanitized +// CHECK-LABEL: ; no_sanitize::sanitized // CHECK-NEXT: ; Function Attrs: // CHECK: sanitize_address // CHECK: start: diff --git a/tests/codegen/sanitizer-safestack-attr-check.rs b/tests/codegen/sanitizer/safestack-attr-check.rs index b73ed00e730..b73ed00e730 100644 --- a/tests/codegen/sanitizer-safestack-attr-check.rs +++ b/tests/codegen/sanitizer/safestack-attr-check.rs diff --git a/tests/codegen/sanitizer-recover.rs b/tests/codegen/sanitizer/sanitizer-recover.rs index 7b00fcf8e1b..7b00fcf8e1b 100644 --- a/tests/codegen/sanitizer-recover.rs +++ b/tests/codegen/sanitizer/sanitizer-recover.rs diff --git a/tests/codegen/sanitizer_scs_attr_check.rs b/tests/codegen/sanitizer/scs-attr-check.rs index a885d911717..a885d911717 100644 --- a/tests/codegen/sanitizer_scs_attr_check.rs +++ b/tests/codegen/sanitizer/scs-attr-check.rs diff --git a/tests/codegen/simd-wide-sum.rs b/tests/codegen/simd/simd-wide-sum.rs index 3116f9597bc..3116f9597bc 100644 --- a/tests/codegen/simd-wide-sum.rs +++ b/tests/codegen/simd/simd-wide-sum.rs diff --git a/tests/codegen/simd_arith_offset.rs b/tests/codegen/simd/simd_arith_offset.rs index 1ee73de1186..1ee73de1186 100644 --- a/tests/codegen/simd_arith_offset.rs +++ b/tests/codegen/simd/simd_arith_offset.rs diff --git a/tests/codegen/swap-simd-types.rs b/tests/codegen/simd/swap-simd-types.rs index 3472a42b0e6..3472a42b0e6 100644 --- a/tests/codegen/swap-simd-types.rs +++ b/tests/codegen/simd/swap-simd-types.rs diff --git a/tests/codegen/unpadded-simd.rs b/tests/codegen/simd/unpadded-simd.rs index eb44dbd9313..eb44dbd9313 100644 --- a/tests/codegen/unpadded-simd.rs +++ b/tests/codegen/simd/unpadded-simd.rs diff --git a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs index 7e81367fc5b..0a02755a2cd 100644 --- a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs +++ b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs @@ -1,7 +1,7 @@ // needs-llvm-components: x86 // compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes #![no_core] -#![feature(no_core, lang_items, c_unwind, abi_thiscall)] +#![feature(no_core, lang_items, c_unwind)] #[lang="sized"] trait Sized { } diff --git a/tests/codegen/vec-calloc-llvm14.rs b/tests/codegen/vec-calloc-llvm14.rs deleted file mode 100644 index 08302796c41..00000000000 --- a/tests/codegen/vec-calloc-llvm14.rs +++ /dev/null @@ -1,144 +0,0 @@ -// compile-flags: -O -// only-x86_64 -// ignore-debug - -#![crate_type = "lib"] - -// CHECK-LABEL: @vec_zero_bytes -#[no_mangle] -pub fn vec_zero_bytes(n: usize) -> Vec<u8> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - // CHECK-NOT: call {{.*}}llvm.memset - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - // CHECK-NOT: call {{.*}}llvm.memset - - // CHECK: ret void - vec![0; n] -} - -// CHECK-LABEL: @vec_one_bytes -#[no_mangle] -pub fn vec_one_bytes(n: usize) -> Vec<u8> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: call {{.*}}__rust_alloc( - // CHECK: call {{.*}}llvm.memset - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: ret void - vec![1; n] -} - -// CHECK-LABEL: @vec_zero_scalar -#[no_mangle] -pub fn vec_zero_scalar(n: usize) -> Vec<i32> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![0; n] -} - -// CHECK-LABEL: @vec_one_scalar -#[no_mangle] -pub fn vec_one_scalar(n: usize) -> Vec<i32> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: call {{.*}}__rust_alloc( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: ret void - vec![1; n] -} - -// CHECK-LABEL: @vec_zero_rgb48 -#[no_mangle] -pub fn vec_zero_rgb48(n: usize) -> Vec<[u16; 3]> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![[0, 0, 0]; n] -} - -// CHECK-LABEL: @vec_zero_array_16 -#[no_mangle] -pub fn vec_zero_array_16(n: usize) -> Vec<[i64; 16]> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![[0_i64; 16]; n] -} - -// CHECK-LABEL: @vec_zero_tuple -#[no_mangle] -pub fn vec_zero_tuple(n: usize) -> Vec<(i16, u8, char)> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: call {{.*}}__rust_alloc_zeroed( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc( - - // CHECK: ret void - vec![(0, 0, '\0'); n] -} - -// CHECK-LABEL: @vec_non_zero_tuple -#[no_mangle] -pub fn vec_non_zero_tuple(n: usize) -> Vec<(i16, u8, char)> { - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: call {{.*}}__rust_alloc( - - // CHECK-NOT: call {{.*}}alloc::vec::from_elem - // CHECK-NOT: call {{.*}}reserve - // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - - // CHECK: ret void - vec![(0, 0, 'A'); n] -} diff --git a/tests/run-make/pretty-print-with-dep-file/Makefile b/tests/run-make/pretty-print-with-dep-file/Makefile new file mode 100644 index 00000000000..fa8089eb6a5 --- /dev/null +++ b/tests/run-make/pretty-print-with-dep-file/Makefile @@ -0,0 +1,9 @@ +include ../tools.mk + +all: + $(RUSTC) --emit=dep-info -Zunpretty=expanded with-dep.rs + $(CGREP) "with-dep.rs" < $(TMPDIR)/with-dep.d + -rm $(TMPDIR)/with-dep.d + + $(RUSTC) --emit=dep-info -Zunpretty=normal with-dep.rs + ! test -f $(TMPDIR)/with-dep.d diff --git a/tests/run-make/pretty-print-with-dep-file/with-dep.rs b/tests/run-make/pretty-print-with-dep-file/with-dep.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/tests/run-make/pretty-print-with-dep-file/with-dep.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/unknown-mod-stdin/Makefile b/tests/run-make/unknown-mod-stdin/Makefile new file mode 100644 index 00000000000..c1931765382 --- /dev/null +++ b/tests/run-make/unknown-mod-stdin/Makefile @@ -0,0 +1,15 @@ +# ignore-windows + +include ../tools.mk + +all: + echo 'mod unknown;' | $(RUSTC) --crate-type rlib - >$(TMPDIR)/unknown-mod.stdout 2>$(TMPDIR)/unknown-mod.stderr || echo "failed successfully" + +# Bless like this: RUSTC_BLESS_TEST=1 ./x.py test tests/run-make/unknown-mod-stdin +ifdef RUSTC_BLESS_TEST + cp "$(TMPDIR)"/unknown-mod.stdout unknown-mod.stdout + cp "$(TMPDIR)"/unknown-mod.stderr unknown-mod.stderr +else + $(DIFF) unknown-mod.stdout "$(TMPDIR)"/unknown-mod.stdout + $(DIFF) unknown-mod.stderr "$(TMPDIR)"/unknown-mod.stderr +endif diff --git a/tests/run-make/unknown-mod-stdin/unknown-mod.stderr b/tests/run-make/unknown-mod-stdin/unknown-mod.stderr new file mode 100644 index 00000000000..d7258fe4f68 --- /dev/null +++ b/tests/run-make/unknown-mod-stdin/unknown-mod.stderr @@ -0,0 +1,11 @@ +error[E0583]: file not found for module `unknown` + --> <anon>:1:1 + | +1 | mod unknown; + | ^^^^^^^^^^^^ + | + = help: to create the module `unknown`, create file "unknown.rs" or "unknown/mod.rs" + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0583`. diff --git a/tests/run-make/unknown-mod-stdin/unknown-mod.stdout b/tests/run-make/unknown-mod-stdin/unknown-mod.stdout new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/tests/run-make/unknown-mod-stdin/unknown-mod.stdout diff --git a/tests/rustdoc-gui/scrape-examples-toggle.goml b/tests/rustdoc-gui/scrape-examples-toggle.goml index 9cec6d2bbe8..f742b3186e5 100644 --- a/tests/rustdoc-gui/scrape-examples-toggle.goml +++ b/tests/rustdoc-gui/scrape-examples-toggle.goml @@ -28,18 +28,18 @@ define-function: ( call-function: ("check-color", { "theme": "ayu", - "toggle_line_color": "rgb(153, 153, 153)", - "toggle_line_hover_color": "rgb(197, 197, 197)", + "toggle_line_color": "#999", + "toggle_line_hover_color": "#c5c5c5", }) call-function: ("check-color", { "theme": "dark", - "toggle_line_color": "rgb(153, 153, 153)", - "toggle_line_hover_color": "rgb(197, 197, 197)", + "toggle_line_color": "#999", + "toggle_line_hover_color": "#c5c5c5", }) call-function: ("check-color", { "theme": "light", - "toggle_line_color": "rgb(204, 204, 204)", - "toggle_line_hover_color": "rgb(153, 153, 153)", + "toggle_line_color": "#ccc", + "toggle_line_hover_color": "#999", }) // Toggling all docs will close additional examples diff --git a/tests/rustdoc-gui/search-error.goml b/tests/rustdoc-gui/search-error.goml index d21905e90ae..70aeda1769a 100644 --- a/tests/rustdoc-gui/search-error.goml +++ b/tests/rustdoc-gui/search-error.goml @@ -20,20 +20,20 @@ call-function: ( "check-colors", { "theme": "ayu", - "error_background": "rgb(79, 76, 76)", + "error_background": "#4f4c4c", }, ) call-function: ( "check-colors", { "theme": "dark", - "error_background": "rgb(72, 72, 72)", + "error_background": "#484848", }, ) call-function: ( "check-colors", { "theme": "light", - "error_background": "rgb(208, 204, 204)", + "error_background": "#d0cccc", }, ) diff --git a/tests/ui/abi/stack-protector.rs b/tests/ui/abi/stack-protector.rs index 24bd2e21943..e94aa816d90 100644 --- a/tests/ui/abi/stack-protector.rs +++ b/tests/ui/abi/stack-protector.rs @@ -40,6 +40,8 @@ fn vulnerable_function() { // Overwrite the on-stack return address with the address of `malicious_code()`, // thereby jumping to that function when returning from `vulnerable_function()`. unsafe { fill(stackaddr, bad_code_ptr, 20); } + // Capture the address, so the write is not optimized away. + std::hint::black_box(stackaddr); } // Use an uninlined function with its own stack frame to make sure that we don't diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index e86a73ea60f..980457eeab5 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -1,53 +1,53 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:26:1 + --> $DIR/unsupported.rs:25:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:27:1 | LL | extern "amdgpu-kernel" fn amdgpu() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:29:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:32:1 + --> $DIR/unsupported.rs:31:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:35:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:38:1 + --> $DIR/unsupported.rs:37:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:40:1 + --> $DIR/unsupported.rs:39:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 + --> $DIR/unsupported.rs:42:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:47:1 + --> $DIR/unsupported.rs:46:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index f7569c8cdd7..450abd94886 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -1,47 +1,47 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:26:1 + --> $DIR/unsupported.rs:25:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:27:1 | LL | extern "amdgpu-kernel" fn amdgpu() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:29:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:35:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:38:1 + --> $DIR/unsupported.rs:37:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:40:1 + --> $DIR/unsupported.rs:39:1 | LL | extern "x86-interrupt" fn x86() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 + --> $DIR/unsupported.rs:42:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:47:1 + --> $DIR/unsupported.rs:46:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index 7ca93516db9..0340382a452 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -1,35 +1,35 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:26:1 + --> $DIR/unsupported.rs:25:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:27:1 | LL | extern "amdgpu-kernel" fn amdgpu() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:29:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:32:1 + --> $DIR/unsupported.rs:31:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:35:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:38:1 + --> $DIR/unsupported.rs:37:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index 6427a5695c0..bcd95f1ed4c 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -15,7 +15,6 @@ abi_ptx, abi_msp430_interrupt, abi_avr_interrupt, - abi_thiscall, abi_amdgpu_kernel, wasm_abi, abi_x86_interrupt diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 26023a4584e..29eed8505b9 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -1,47 +1,47 @@ error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:26:1 + --> $DIR/unsupported.rs:25:1 | LL | extern "ptx-kernel" fn ptx() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:28:1 + --> $DIR/unsupported.rs:27:1 | LL | extern "amdgpu-kernel" fn amdgpu() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"wasm"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:30:1 + --> $DIR/unsupported.rs:29:1 | LL | extern "wasm" fn wasm() {} | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"aapcs"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:32:1 + --> $DIR/unsupported.rs:31:1 | LL | extern "aapcs" fn aapcs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:36:1 + --> $DIR/unsupported.rs:35:1 | LL | extern "msp430-interrupt" fn msp430() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:38:1 + --> $DIR/unsupported.rs:37:1 | LL | extern "avr-interrupt" fn avr() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"thiscall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:43:1 + --> $DIR/unsupported.rs:42:1 | LL | extern "thiscall" fn thiscall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:47:1 + --> $DIR/unsupported.rs:46:1 | LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/attributes/macro_export_on_decl_macro.rs b/tests/ui/attributes/macro_export_on_decl_macro.rs new file mode 100644 index 00000000000..e6fe66ac6c3 --- /dev/null +++ b/tests/ui/attributes/macro_export_on_decl_macro.rs @@ -0,0 +1,9 @@ +// Using #[macro_export] on a decl macro has no effect and should warn + +#![feature(decl_macro)] +#![deny(unused)] + +#[macro_export] //~ ERROR `#[macro_export]` has no effect on declarative macro definitions +pub macro foo() {} + +fn main() {} diff --git a/tests/ui/attributes/macro_export_on_decl_macro.stderr b/tests/ui/attributes/macro_export_on_decl_macro.stderr new file mode 100644 index 00000000000..565e07919bc --- /dev/null +++ b/tests/ui/attributes/macro_export_on_decl_macro.stderr @@ -0,0 +1,16 @@ +error: `#[macro_export]` has no effect on declarative macro definitions + --> $DIR/macro_export_on_decl_macro.rs:6:1 + | +LL | #[macro_export] + | ^^^^^^^^^^^^^^^ + | + = note: declarative macros follow the same exporting rules as regular items +note: the lint level is defined here + --> $DIR/macro_export_on_decl_macro.rs:4:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]` + +error: aborting due to previous error + diff --git a/tests/ui/const-generics/lifetime-in-const-param.rs b/tests/ui/const-generics/lifetime-in-const-param.rs new file mode 100644 index 00000000000..be90dbb213e --- /dev/null +++ b/tests/ui/const-generics/lifetime-in-const-param.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/113462 + +struct S2<'b>(&'b ()); + +struct S<'a, const N: S2>(&'a ()); +//~^ ERROR missing lifetime specifier [E0106] +//~| ERROR `S2<'_>` is forbidden as the type of a const generic parameter + +fn main() {} diff --git a/tests/ui/const-generics/lifetime-in-const-param.stderr b/tests/ui/const-generics/lifetime-in-const-param.stderr new file mode 100644 index 00000000000..8fd9068e8ef --- /dev/null +++ b/tests/ui/const-generics/lifetime-in-const-param.stderr @@ -0,0 +1,18 @@ +error[E0106]: missing lifetime specifier + --> $DIR/lifetime-in-const-param.rs:5:23 + | +LL | struct S<'a, const N: S2>(&'a ()); + | ^^ expected named lifetime parameter + +error: `S2<'_>` is forbidden as the type of a const generic parameter + --> $DIR/lifetime-in-const-param.rs:5:23 + | +LL | struct S<'a, const N: S2>(&'a ()); + | ^^ + | + = note: the only supported types are integers, `bool` and `char` + = help: more complex types are supported with `#![feature(adt_const_params)]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/const_prop/ice-issue-111353.rs b/tests/ui/const_prop/ice-issue-111353.rs new file mode 100644 index 00000000000..99d1b792fea --- /dev/null +++ b/tests/ui/const_prop/ice-issue-111353.rs @@ -0,0 +1,7 @@ +// build-pass +#![crate_type = "lib"] +#![feature(unsized_fn_params)] + +pub fn f(mut x: [i32]) { + x[0] = 1; +} diff --git a/tests/ui/const_prop/ice-issue-96944.rs b/tests/ui/const_prop/ice-issue-96944.rs new file mode 100644 index 00000000000..74baffddd8b --- /dev/null +++ b/tests/ui/const_prop/ice-issue-96944.rs @@ -0,0 +1,26 @@ +// build-pass +#![crate_type = "lib"] +#![allow(arithmetic_overflow)] + +pub trait BitSplit { + type Half; + fn merge(halves: [Self::Half; 2]) -> Self; +} + +macro_rules! impl_ints { + ($int:ty => $half:ty; $mask:expr) => { + impl BitSplit for $int { + type Half = $half; + #[inline] + fn merge(halves: [Self::Half; 2]) -> Self { + const HALF_SIZE: usize = std::mem::size_of::<$half>() * 8; + (halves[0] << HALF_SIZE) as $int | halves[1] as $int + } + } + }; +} + +impl_ints!(u128 => u64; 0x0000_0000_0000_0000_FFFF_FFFF_FFFF_FFFF); +impl_ints!( u64 => u32; 0x0000_0000_FFFF_FFFF); +impl_ints!( u32 => u16; 0x0000_FFFF); +impl_ints!( u16 => u8; 0x00FF); diff --git a/tests/ui/consts/const-compare-bytes-ub.rs b/tests/ui/consts/const-compare-bytes-ub.rs new file mode 100644 index 00000000000..2b4062fd22b --- /dev/null +++ b/tests/ui/consts/const-compare-bytes-ub.rs @@ -0,0 +1,41 @@ +// check-fail + +#![feature(core_intrinsics)] +#![feature(const_intrinsic_compare_bytes)] +use std::intrinsics::compare_bytes; +use std::mem::MaybeUninit; + +fn main() { + const LHS_NULL: i32 = unsafe { + compare_bytes(0 as *const u8, 2 as *const u8, 0) + //~^ ERROR evaluation of constant value failed + }; + const RHS_NULL: i32 = unsafe { + compare_bytes(1 as *const u8, 0 as *const u8, 0) + //~^ ERROR evaluation of constant value failed + }; + const DANGLING_PTR_NON_ZERO_LENGTH: i32 = unsafe { + compare_bytes(1 as *const u8, 2 as *const u8, 1) + //~^ ERROR evaluation of constant value failed + }; + const LHS_OUT_OF_BOUNDS: i32 = unsafe { + compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4) + //~^ ERROR evaluation of constant value failed + }; + const RHS_OUT_OF_BOUNDS: i32 = unsafe { + compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4) + //~^ ERROR evaluation of constant value failed + }; + const LHS_UNINIT: i32 = unsafe { + compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1) + //~^ ERROR evaluation of constant value failed + }; + const RHS_UNINIT: i32 = unsafe { + compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1) + //~^ ERROR evaluation of constant value failed + }; + const WITH_PROVENANCE: i32 = unsafe { + compare_bytes([&1].as_ptr().cast(), [&2].as_ptr().cast(), std::mem::size_of::<usize>()) + //~^ ERROR evaluation of constant value failed + }; +} diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr new file mode 100644 index 00000000000..54fafded07b --- /dev/null +++ b/tests/ui/consts/const-compare-bytes-ub.stderr @@ -0,0 +1,54 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-compare-bytes-ub.rs:10:9 + | +LL | compare_bytes(0 as *const u8, 2 as *const u8, 0) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) + +error[E0080]: evaluation of constant value failed + --> $DIR/const-compare-bytes-ub.rs:14:9 + | +LL | compare_bytes(1 as *const u8, 0 as *const u8, 0) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) + +error[E0080]: evaluation of constant value failed + --> $DIR/const-compare-bytes-ub.rs:18:9 + | +LL | compare_bytes(1 as *const u8, 2 as *const u8, 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: 0x1[noalloc] is a dangling pointer (it has no provenance) + +error[E0080]: evaluation of constant value failed + --> $DIR/const-compare-bytes-ub.rs:22:9 + | +LL | compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc6 has size 3, so pointer to 4 bytes starting at offset 0 is out-of-bounds + +error[E0080]: evaluation of constant value failed + --> $DIR/const-compare-bytes-ub.rs:26:9 + | +LL | compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc13 has size 3, so pointer to 4 bytes starting at offset 0 is out-of-bounds + +error[E0080]: evaluation of constant value failed + --> $DIR/const-compare-bytes-ub.rs:30:9 + | +LL | compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc17[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/const-compare-bytes-ub.rs:34:9 + | +LL | compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc25[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/const-compare-bytes-ub.rs:38:9 + | +LL | compare_bytes([&1].as_ptr().cast(), [&2].as_ptr().cast(), std::mem::size_of::<usize>()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-compare-bytes.rs b/tests/ui/consts/const-compare-bytes.rs new file mode 100644 index 00000000000..74e29f81386 --- /dev/null +++ b/tests/ui/consts/const-compare-bytes.rs @@ -0,0 +1,27 @@ +// run-pass + +#![feature(core_intrinsics)] +#![feature(const_intrinsic_compare_bytes)] +use std::intrinsics::compare_bytes; + +fn main() { + const A: i32 = unsafe { + compare_bytes(1 as *const u8, 2 as *const u8, 0) + }; + assert_eq!(A, 0); + + const B: i32 = unsafe { + compare_bytes([1, 2].as_ptr(), [1, 3].as_ptr(), 1) + }; + assert_eq!(B, 0); + + const C: i32 = unsafe { + compare_bytes([1, 2, 9].as_ptr(), [1, 3, 8].as_ptr(), 2) + }; + assert!(C < 0); + + const D: i32 = unsafe { + compare_bytes([1, 3, 8].as_ptr(), [1, 2, 9].as_ptr(), 2) + }; + assert!(D > 0); +} diff --git a/tests/ui/extern/extern-thiscall.rs b/tests/ui/extern/extern-thiscall.rs index 717df57ec48..c491c156af5 100644 --- a/tests/ui/extern/extern-thiscall.rs +++ b/tests/ui/extern/extern-thiscall.rs @@ -1,8 +1,6 @@ // run-pass // only-x86 -#![feature(abi_thiscall)] - trait A { extern "thiscall" fn test1(i: i32); } diff --git a/tests/ui/feature-gates/feature-gate-thiscall.rs b/tests/ui/feature-gates/feature-gate-thiscall.rs deleted file mode 100644 index 97a732bcff7..00000000000 --- a/tests/ui/feature-gates/feature-gate-thiscall.rs +++ /dev/null @@ -1,38 +0,0 @@ -// gate-test-abi_thiscall -// needs-llvm-components: x86 -// compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -#![no_core] -#![feature(no_core, lang_items)] -#[lang="sized"] -trait Sized { } - -// Test that the "thiscall" ABI is feature-gated, and cannot be used when -// the `abi_thiscall` feature gate is not used. - -extern "thiscall-unwind" fn fu() {} //~ ERROR thiscall-unwind ABI is experimental -extern "thiscall" fn f() {} //~ ERROR thiscall is experimental - -trait T { - extern "thiscall" fn m(); //~ ERROR thiscall is experimental - extern "thiscall-unwind" fn mu(); //~ ERROR thiscall-unwind ABI is experimental - - extern "thiscall" fn dm() {} //~ ERROR thiscall is experimental - extern "thiscall-unwind" fn dmu() {} //~ ERROR thiscall-unwind ABI is experimental -} - -struct S; -impl T for S { - extern "thiscall" fn m() {} //~ ERROR thiscall is experimental - extern "thiscall-unwind" fn mu() {} //~ ERROR thiscall-unwind ABI is experimental -} - -impl S { - extern "thiscall" fn im() {} //~ ERROR thiscall is experimental - extern "thiscall-unwind" fn imu() {} //~ ERROR thiscall-unwind ABI is experimental -} - -type TA = extern "thiscall" fn(); //~ ERROR thiscall is experimental -type TAU = extern "thiscall-unwind" fn(); //~ ERROR thiscall-unwind ABI is experimental - -extern "thiscall" {} //~ ERROR thiscall is experimental -extern "thiscall-unwind" {} //~ ERROR thiscall-unwind ABI is experimental diff --git a/tests/ui/feature-gates/feature-gate-thiscall.stderr b/tests/ui/feature-gates/feature-gate-thiscall.stderr deleted file mode 100644 index 346e45952cd..00000000000 --- a/tests/ui/feature-gates/feature-gate-thiscall.stderr +++ /dev/null @@ -1,115 +0,0 @@ -error[E0658]: thiscall-unwind ABI is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:12:8 - | -LL | extern "thiscall-unwind" fn fu() {} - | ^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:13:8 - | -LL | extern "thiscall" fn f() {} - | ^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:16:12 - | -LL | extern "thiscall" fn m(); - | ^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall-unwind ABI is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:17:12 - | -LL | extern "thiscall-unwind" fn mu(); - | ^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:19:12 - | -LL | extern "thiscall" fn dm() {} - | ^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall-unwind ABI is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:20:12 - | -LL | extern "thiscall-unwind" fn dmu() {} - | ^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:25:12 - | -LL | extern "thiscall" fn m() {} - | ^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall-unwind ABI is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:26:12 - | -LL | extern "thiscall-unwind" fn mu() {} - | ^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:30:12 - | -LL | extern "thiscall" fn im() {} - | ^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall-unwind ABI is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:31:12 - | -LL | extern "thiscall-unwind" fn imu() {} - | ^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:34:18 - | -LL | type TA = extern "thiscall" fn(); - | ^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall-unwind ABI is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:35:19 - | -LL | type TAU = extern "thiscall-unwind" fn(); - | ^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:37:8 - | -LL | extern "thiscall" {} - | ^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error[E0658]: thiscall-unwind ABI is experimental and subject to change - --> $DIR/feature-gate-thiscall.rs:38:8 - | -LL | extern "thiscall-unwind" {} - | ^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable - -error: aborting due to 14 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/for/issue-20605.next.stderr index d55efedfcbe..0955efdbb73 100644 --- a/tests/ui/for/issue-20605.next.stderr +++ b/tests/ui/for/issue-20605.next.stderr @@ -34,12 +34,6 @@ error: the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIte LL | for item in *things { *item = 0 } | ^^^^^^^ -error[E0614]: type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be dereferenced - --> $DIR/issue-20605.rs:5:27 - | -LL | for item in *things { *item = 0 } - | ^^^^^ - error[E0277]: the size for values of type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be known at compilation time --> $DIR/issue-20605.rs:5:9 | @@ -66,6 +60,12 @@ LL | for item in *things { *item = 0 } note: required by a bound in `None` --> $SRC_DIR/core/src/option.rs:LL:COL +error[E0614]: type `<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item` cannot be dereferenced + --> $DIR/issue-20605.rs:5:27 + | +LL | for item in *things { *item = 0 } + | ^^^^^ + error: aborting due to 9 previous errors Some errors have detailed explanations: E0277, E0614. diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.rs b/tests/ui/generic-associated-types/issue-90014-tait2.rs index 34330ed8cba..7fb14eddc2c 100644 --- a/tests/ui/generic-associated-types/issue-90014-tait2.rs +++ b/tests/ui/generic-associated-types/issue-90014-tait2.rs @@ -1,27 +1,9 @@ //! This test checks that opaque type collection doesn't try to normalize the projection //! without respecting its binders (which would ICE). //! Unfortunately we don't even reach opaque type collection, as we ICE in typeck before that. -// known-bug: #109281 -// failure-status: 101 -// error-pattern:internal compiler error -// normalize-stderr-test "internal compiler error.*" -> "" -// normalize-stderr-test "DefId\([^)]*\)" -> "..." -// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" -// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" -// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" -// normalize-stderr-test "note: compiler flags.*\n\n" -> "" -// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" -// normalize-stderr-test "thread.*panicked.*:\n.*\n" -> "" -// normalize-stderr-test "stack backtrace:\n" -> "" -// normalize-stderr-test "\s\d{1,}: .*\n" -> "" -// normalize-stderr-test "\s at .*\n" -> "" -// normalize-stderr-test ".*note: Some details.*\n" -> "" -// normalize-stderr-test "\n\n[ ]*\n" -> "" -// normalize-stderr-test "compiler/.*: projection" -> "projection" -// normalize-stderr-test ".*omitted \d{1,} frame.*\n" -> "" -// normalize-stderr-test "error: [\s\n]*query stack" -> "error: query stack" -// normalize-stderr-test "[\n\s]*\nquery stack during panic:" -> "query stack during panic:" +//! See #109281 for the original report. // edition:2018 +// error-pattern: expected generic lifetime parameter, found `'a` #![feature(type_alias_impl_trait)] #![allow(incomplete_features)] diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.stderr b/tests/ui/generic-associated-types/issue-90014-tait2.stderr index 2538eb46dfa..d04788a919a 100644 --- a/tests/ui/generic-associated-types/issue-90014-tait2.stderr +++ b/tests/ui/generic-associated-types/issue-90014-tait2.stderr @@ -1,12 +1,5 @@ -error: - --> $DIR/issue-90014-tait2.rs:44:27 - | -LL | fn make_fut(&self) -> Box<dyn for<'a> Trait<'a, Thing = Fut<'a>>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^query stack during panic: -#0 [typeck] type-checking `<impl at $DIR/issue-90014-tait2.rs:43:1: 43:13>::make_fut` -#1 [type_of] computing type of `Fut::{opaque#0}` -#2 [check_mod_item_types] checking item types in top-level module -#3 [analysis] running analysis passes on this crate -end of query stack +error[E0792]: expected generic lifetime parameter, found `'a` + error: aborting due to previous error +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/issues/issue-100605.rs b/tests/ui/issues/issue-100605.rs deleted file mode 100644 index 917a45c15bb..00000000000 --- a/tests/ui/issues/issue-100605.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn takes_option(_arg: Option<&String>) {} - -fn main() { - takes_option(&None); //~ ERROR 4:18: 4:23: mismatched types [E0308] - - let x = String::from("x"); - let res = Some(x); - takes_option(&res); //~ ERROR 8:18: 8:22: mismatched types [E0308] -} diff --git a/tests/ui/lazy-type-alias/auxiliary/eager.rs b/tests/ui/lazy-type-alias/auxiliary/eager.rs new file mode 100644 index 00000000000..8793a1701ec --- /dev/null +++ b/tests/ui/lazy-type-alias/auxiliary/eager.rs @@ -0,0 +1,6 @@ +// This crate does *not* have lazy type aliases enabled. + +#![allow(type_alias_bounds)] + +// The `Copy` bound is ignored both locally and externally for backward compatibility. +pub type Alias<T: Copy> = Option<T>; diff --git a/tests/ui/lazy-type-alias/auxiliary/lazy.rs b/tests/ui/lazy-type-alias/auxiliary/lazy.rs new file mode 100644 index 00000000000..caa7999b4f7 --- /dev/null +++ b/tests/ui/lazy-type-alias/auxiliary/lazy.rs @@ -0,0 +1,4 @@ +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +pub type Alias<T: Copy> = Option<T>; diff --git a/tests/ui/lazy-type-alias/coerce-behind-lazy.current.stderr b/tests/ui/lazy-type-alias/coerce-behind-lazy.current.stderr new file mode 100644 index 00000000000..98b3921dec4 --- /dev/null +++ b/tests/ui/lazy-type-alias/coerce-behind-lazy.current.stderr @@ -0,0 +1,11 @@ +warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/coerce-behind-lazy.rs:5:12 + | +LL | #![feature(lazy_type_alias)] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/lazy-type-alias/coerce-behind-lazy.next.stderr b/tests/ui/lazy-type-alias/coerce-behind-lazy.next.stderr new file mode 100644 index 00000000000..98b3921dec4 --- /dev/null +++ b/tests/ui/lazy-type-alias/coerce-behind-lazy.next.stderr @@ -0,0 +1,11 @@ +warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/coerce-behind-lazy.rs:5:12 + | +LL | #![feature(lazy_type_alias)] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/lazy-type-alias/coerce-behind-lazy.rs b/tests/ui/lazy-type-alias/coerce-behind-lazy.rs new file mode 100644 index 00000000000..745eadb9625 --- /dev/null +++ b/tests/ui/lazy-type-alias/coerce-behind-lazy.rs @@ -0,0 +1,16 @@ +// check-pass +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +#![feature(lazy_type_alias)] +//~^ WARN the feature `lazy_type_alias` is incomplete + +use std::any::Any; + +type Coerce = Box<dyn Any>; + +fn test() -> Coerce { + Box::new(1) +} + +fn main() {} diff --git a/tests/ui/lazy-type-alias/extern-crate-has-eager-type-aliases.rs b/tests/ui/lazy-type-alias/extern-crate-has-eager-type-aliases.rs new file mode 100644 index 00000000000..07389961c4c --- /dev/null +++ b/tests/ui/lazy-type-alias/extern-crate-has-eager-type-aliases.rs @@ -0,0 +1,23 @@ +// This test serves as a regression test for issue #114468 and it also ensures that we consider +// type aliases from external crates that don't have `lazy_type_alias` enabled to be eager. + +// aux-crate:eager=eager.rs +// edition: 2021 +// check-pass + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +// This used to crash when we were computing the variances of `Struct` since we would convert +// `eager::Alias<T>` to a weak projection due to the presence of `#![feature(lazy_type_alias)]` in +// this (!) crate and subsequently attempt to obtain the variances of the type alias associated with +// the weak projection which would panic because we don't compute this information for eager type +// aliases at all. +struct Struct<T>(eager::Alias<T>); + +fn main() { + // We want to ignore (or rather “end up ignoring”) the bound `T: Copy` since `Alias` should be + // treated as an eager type alias not just inside the crate it is defined in but also in + // dependent crates (like this one). + let _: eager::Alias<String>; +} diff --git a/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_eager.stderr b/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_eager.stderr new file mode 100644 index 00000000000..9e0e2bfa872 --- /dev/null +++ b/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_eager.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/extern-crate-has-lazy-type-aliases.rs:15:12 + | +LL | let _: lazy::Alias<String>; + | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound on the type alias `Alias` + --> $DIR/auxiliary/lazy.rs:4:19 + | +LL | pub type Alias<T: Copy> = Option<T>; + | ^^^^ required by this bound + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_lazy.stderr b/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_lazy.stderr new file mode 100644 index 00000000000..9e0e2bfa872 --- /dev/null +++ b/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.locally_lazy.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/extern-crate-has-lazy-type-aliases.rs:15:12 + | +LL | let _: lazy::Alias<String>; + | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound on the type alias `Alias` + --> $DIR/auxiliary/lazy.rs:4:19 + | +LL | pub type Alias<T: Copy> = Option<T>; + | ^^^^ required by this bound + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.rs b/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.rs new file mode 100644 index 00000000000..31a19161b6c --- /dev/null +++ b/tests/ui/lazy-type-alias/extern-crate-has-lazy-type-aliases.rs @@ -0,0 +1,16 @@ +// revisions: locally_eager locally_lazy +// aux-crate:lazy=lazy.rs +// edition: 2021 + +// Test that we treat lazy type aliases from external crates as lazy independently of whether the +// local crate enables `lazy_type_alias` or not. + +#![cfg_attr( + locally_lazy, + feature(lazy_type_alias), + allow(incomplete_features) +)] + +fn main() { + let _: lazy::Alias<String>; //~ ERROR the trait bound `String: Copy` is not satisfied +} diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr index 4994e4dc444..01ec69a6110 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.stderr +++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr @@ -3,11 +3,6 @@ error[E0106]: missing lifetime specifier | LL | fn d<const C: S>() {} | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | fn d<'a, const C: S<'a>>() {} - | +++ ++++ error[E0770]: the type of const parameters must not depend on other generic parameters --> $DIR/unusual-rib-combinations.rs:29:22 diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 5d457ba0ec7..0d269e599dd 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -1,11 +1,30 @@ +warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:433:55 + | +LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + = note: `#[warn(improper_ctypes)]` on by default + +warning: `extern` block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:437:46 + | +LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + warning: `clash` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:14:13 | LL | fn clash(x: u8); - | ---------------- `clash` previously declared here + | --------------- `clash` previously declared here ... LL | fn clash(x: u64); - | ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn(u8)` found `unsafe extern "C" fn(u64)` @@ -18,12 +37,11 @@ LL | #![warn(clashing_extern_declarations)] warning: `extern_link_name` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:52:9 | -LL | / #[link_name = "extern_link_name"] -LL | | fn some_new_name(x: i16); - | |_____________________________- `extern_link_name` previously declared here +LL | #[link_name = "extern_link_name"] + | --------------------------------- `extern_link_name` previously declared here ... -LL | fn extern_link_name(x: u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration +LL | fn extern_link_name(x: u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn(i16)` found `unsafe extern "C" fn(u32)` @@ -31,13 +49,11 @@ LL | fn extern_link_name(x: u32); warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature --> $DIR/clashing-extern-fn.rs:55:9 | -LL | fn some_other_new_name(x: i16); - | ------------------------------- `some_other_new_name` previously declared here +LL | fn some_other_new_name(x: i16); + | ------------------------------ `some_other_new_name` previously declared here ... -LL | / #[link_name = "some_other_new_name"] -LL | | -LL | | fn some_other_extern_link_name(x: u32); - | |_______________________________________________^ this signature doesn't match the previous declaration +LL | #[link_name = "some_other_new_name"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn(i16)` found `unsafe extern "C" fn(u32)` @@ -45,14 +61,11 @@ LL | | fn some_other_extern_link_name(x: u32); warning: `other_both_names_different` redeclares `link_name_same` with a different signature --> $DIR/clashing-extern-fn.rs:59:9 | -LL | / #[link_name = "link_name_same"] -LL | | fn both_names_different(x: i16); - | |____________________________________- `link_name_same` previously declared here +LL | #[link_name = "link_name_same"] + | ------------------------------- `link_name_same` previously declared here ... -LL | / #[link_name = "link_name_same"] -LL | | -LL | | fn other_both_names_different(x: u32); - | |______________________________________________^ this signature doesn't match the previous declaration +LL | #[link_name = "link_name_same"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn(i16)` found `unsafe extern "C" fn(u32)` @@ -61,10 +74,10 @@ warning: `different_mod` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:72:9 | LL | fn different_mod(x: u8); - | ------------------------ `different_mod` previously declared here + | ----------------------- `different_mod` previously declared here ... LL | fn different_mod(x: u64); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn(u8)` found `unsafe extern "C" fn(u64)` @@ -73,10 +86,10 @@ warning: `variadic_decl` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:82:9 | LL | fn variadic_decl(x: u8, ...); - | ----------------------------- `variadic_decl` previously declared here + | ---------------------------- `variadic_decl` previously declared here ... LL | fn variadic_decl(x: u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn(u8, ...)` found `unsafe extern "C" fn(u8)` @@ -85,10 +98,10 @@ warning: `weigh_banana` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:142:13 | LL | fn weigh_banana(count: *const Banana) -> u64; - | --------------------------------------------- `weigh_banana` previously declared here + | -------------------------------------------- `weigh_banana` previously declared here ... LL | fn weigh_banana(count: *const Banana) -> u64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn(*const one::Banana) -> u64` found `unsafe extern "C" fn(*const three::Banana) -> u64` @@ -97,10 +110,10 @@ warning: `draw_point` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:171:13 | LL | fn draw_point(p: Point); - | ------------------------ `draw_point` previously declared here + | ----------------------- `draw_point` previously declared here ... LL | fn draw_point(p: Point); - | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn(sameish_members::a::Point)` found `unsafe extern "C" fn(sameish_members::b::Point)` @@ -109,10 +122,10 @@ warning: `origin` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:197:13 | LL | fn origin() -> Point3; - | ---------------------- `origin` previously declared here + | --------------------- `origin` previously declared here ... LL | fn origin() -> Point3; - | ^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> same_sized_members_clash::a::Point3` found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3` @@ -121,10 +134,10 @@ warning: `transparent_incorrect` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:220:13 | LL | fn transparent_incorrect() -> T; - | -------------------------------- `transparent_incorrect` previously declared here + | ------------------------------- `transparent_incorrect` previously declared here ... LL | fn transparent_incorrect() -> isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> T` found `unsafe extern "C" fn() -> isize` @@ -133,10 +146,10 @@ warning: `missing_return_type` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:259:13 | LL | fn missing_return_type() -> usize; - | ---------------------------------- `missing_return_type` previously declared here + | --------------------------------- `missing_return_type` previously declared here ... LL | fn missing_return_type(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> usize` found `unsafe extern "C" fn()` @@ -145,10 +158,10 @@ warning: `non_zero_usize` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:277:13 | LL | fn non_zero_usize() -> core::num::NonZeroUsize; - | ----------------------------------------------- `non_zero_usize` previously declared here + | ---------------------------------------------- `non_zero_usize` previously declared here ... LL | fn non_zero_usize() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> NonZeroUsize` found `unsafe extern "C" fn() -> usize` @@ -157,10 +170,10 @@ warning: `non_null_ptr` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:279:13 | LL | fn non_null_ptr() -> core::ptr::NonNull<usize>; - | ----------------------------------------------- `non_null_ptr` previously declared here + | ---------------------------------------------- `non_null_ptr` previously declared here ... LL | fn non_null_ptr() -> *const usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> NonNull<usize>` found `unsafe extern "C" fn() -> *const usize` @@ -169,10 +182,10 @@ warning: `option_non_zero_usize_incorrect` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:377:13 | LL | fn option_non_zero_usize_incorrect() -> usize; - | ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here + | --------------------------------------------- `option_non_zero_usize_incorrect` previously declared here ... LL | fn option_non_zero_usize_incorrect() -> isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> usize` found `unsafe extern "C" fn() -> isize` @@ -181,10 +194,10 @@ warning: `option_non_null_ptr_incorrect` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:379:13 | LL | fn option_non_null_ptr_incorrect() -> *const usize; - | --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here + | -------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here ... LL | fn option_non_null_ptr_incorrect() -> *const isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> *const usize` found `unsafe extern "C" fn() -> *const isize` @@ -193,10 +206,10 @@ warning: `hidden_niche_transparent_no_niche` redeclared with a different signatu --> $DIR/clashing-extern-fn.rs:433:13 | LL | fn hidden_niche_transparent_no_niche() -> usize; - | ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here + | ----------------------------------------------- `hidden_niche_transparent_no_niche` previously declared here ... LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> usize` found `unsafe extern "C" fn() -> Option<TransparentNoNiche>` @@ -205,32 +218,13 @@ warning: `hidden_niche_unsafe_cell` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:437:13 | LL | fn hidden_niche_unsafe_cell() -> usize; - | --------------------------------------- `hidden_niche_unsafe_cell` previously declared here + | -------------------------------------- `hidden_niche_unsafe_cell` previously declared here ... LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> usize` found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZeroUsize>>` -warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:433:55 - | -LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - = note: `#[warn(improper_ctypes)]` on by default - -warning: `extern` block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:437:46 - | -LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - warning: 19 warnings emitted diff --git a/tests/ui/lint/invalid-nan-comparison.stderr b/tests/ui/lint/invalid-nan-comparison.stderr index 054c06d38b3..f2d55c107ba 100644 --- a/tests/ui/lint/invalid-nan-comparison.stderr +++ b/tests/ui/lint/invalid-nan-comparison.stderr @@ -5,11 +5,6 @@ LL | const TEST: bool = 5f32 == f32::NAN; | ^^^^^^^^^^^^^^^^ | = note: `#[warn(invalid_nan_comparisons)]` on by default -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - const TEST: bool = 5f32 == f32::NAN; -LL + const TEST: bool = 5f32.is_nan(); - | warning: incorrect NaN comparison, NaN cannot be directly compared to itself --> $DIR/invalid-nan-comparison.rs:14:5 diff --git a/tests/ui/lint/issue-111359.stderr b/tests/ui/lint/issue-111359.stderr index 2296d8413d6..0aef5007a2b 100644 --- a/tests/ui/lint/issue-111359.stderr +++ b/tests/ui/lint/issue-111359.stderr @@ -1,26 +1,26 @@ -error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation +error: type could implement `Copy`; consider adding `impl Copy` --> $DIR/issue-111359.rs:7:5 | LL | pub struct BarPub; | ^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/issue-111359.rs:1:8 + --> $DIR/issue-111359.rs:2:8 | -LL | #[deny(missing_debug_implementations)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deny(missing_copy_implementations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: type could implement `Copy`; consider adding `impl Copy` +error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation --> $DIR/issue-111359.rs:7:5 | LL | pub struct BarPub; | ^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/issue-111359.rs:2:8 + --> $DIR/issue-111359.rs:1:8 | -LL | #[deny(missing_copy_implementations)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deny(missing_debug_implementations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/lint/issue-1866.stderr b/tests/ui/lint/issue-1866.stderr index d19a1349668..36d323825a4 100644 --- a/tests/ui/lint/issue-1866.stderr +++ b/tests/ui/lint/issue-1866.stderr @@ -2,10 +2,10 @@ warning: `rust_task_is_unwinding` redeclared with a different signature --> $DIR/issue-1866.rs:23:13 | LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool; - | ------------------------------------------------------------ `rust_task_is_unwinding` previously declared here + | ----------------------------------------------------------- `rust_task_is_unwinding` previously declared here ... LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn(*const usize) -> bool` found `unsafe extern "C" fn(*const bool) -> bool` diff --git a/tests/ui/lint/lint-attr-everywhere-late.stderr b/tests/ui/lint/lint-attr-everywhere-late.stderr index 9587556b0c1..7fe078068fe 100644 --- a/tests/ui/lint/lint-attr-everywhere-late.stderr +++ b/tests/ui/lint/lint-attr-everywhere-late.stderr @@ -34,12 +34,6 @@ note: the lint level is defined here LL | #![deny(missing_docs)] | ^^^^^^^^^^^^ -error: missing documentation for a function - --> $DIR/lint-attr-everywhere-late.rs:47:5 - | -LL | pub fn missing_inner() {} - | ^^^^^^^^^^^^^^^^^^^^^^ - error: missing documentation for an associated function --> $DIR/lint-attr-everywhere-late.rs:54:5 | @@ -142,52 +136,6 @@ note: the lint level is defined here LL | #[deny(missing_docs)] | ^^^^^^^^^^^^ -error: missing documentation for a variant - --> $DIR/lint-attr-everywhere-late.rs:112:5 - | -LL | Variant1, - | ^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/lint-attr-everywhere-late.rs:111:12 - | -LL | #[deny(missing_docs)] - | ^^^^^^^^^^^^ - -error: `clashing1` redeclared with a different signature - --> $DIR/lint-attr-everywhere-late.rs:123:5 - | -LL | fn clashing1(); - | --------------- `clashing1` previously declared here -... -LL | fn clashing1(_: i32); - | ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn()` - found `unsafe extern "C" fn(i32)` -note: the lint level is defined here - --> $DIR/lint-attr-everywhere-late.rs:122:13 - | -LL | #![deny(clashing_extern_declarations)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `clashing2` redeclared with a different signature - --> $DIR/lint-attr-everywhere-late.rs:128:5 - | -LL | fn clashing2(); - | --------------- `clashing2` previously declared here -... -LL | fn clashing2(_: i32); - | ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn()` - found `unsafe extern "C" fn(i32)` -note: the lint level is defined here - --> $DIR/lint-attr-everywhere-late.rs:127:12 - | -LL | #[deny(clashing_extern_declarations)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped --> $DIR/lint-attr-everywhere-late.rs:93:38 | @@ -230,6 +178,18 @@ note: the lint level is defined here LL | #[deny(overflowing_literals)] const ASSOC_CONST: u8 = 1000; | ^^^^^^^^^^^^^^^^^^^^ +error: missing documentation for a variant + --> $DIR/lint-attr-everywhere-late.rs:112:5 + | +LL | Variant1, + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:111:12 + | +LL | #[deny(missing_docs)] + | ^^^^^^^^^^^^ + error: variable `PARAM` should have a snake case name --> $DIR/lint-attr-everywhere-late.rs:131:37 | @@ -436,5 +396,45 @@ note: the lint level is defined here LL | TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::<i32>(&123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error: missing documentation for a function + --> $DIR/lint-attr-everywhere-late.rs:47:5 + | +LL | pub fn missing_inner() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: `clashing1` redeclared with a different signature + --> $DIR/lint-attr-everywhere-late.rs:123:5 + | +LL | fn clashing1(); + | -------------- `clashing1` previously declared here +... +LL | fn clashing1(_: i32); + | ^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn()` + found `unsafe extern "C" fn(i32)` +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:122:13 + | +LL | #![deny(clashing_extern_declarations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `clashing2` redeclared with a different signature + --> $DIR/lint-attr-everywhere-late.rs:128:5 + | +LL | fn clashing2(); + | -------------- `clashing2` previously declared here +... +LL | fn clashing2(_: i32); + | ^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn()` + found `unsafe extern "C" fn(i32)` +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:127:12 + | +LL | #[deny(clashing_extern_declarations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 32 previous errors diff --git a/tests/ui/lint/lint-missing-doc.stderr b/tests/ui/lint/lint-missing-doc.stderr index adcc21c44b2..4e9ee4f2769 100644 --- a/tests/ui/lint/lint-missing-doc.stderr +++ b/tests/ui/lint/lint-missing-doc.stderr @@ -113,24 +113,6 @@ LL | pub static BAR4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/lint-missing-doc.rs:174:5 - | -LL | pub fn undocumented1() {} - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function - --> $DIR/lint-missing-doc.rs:175:5 - | -LL | pub fn undocumented2() {} - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function - --> $DIR/lint-missing-doc.rs:181:9 - | -LL | pub fn also_undocumented1() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function --> $DIR/lint-missing-doc.rs:196:5 | LL | pub fn extern_fn_undocumented(f: f32) -> f32; @@ -154,5 +136,23 @@ error: missing documentation for a trait alias LL | pub trait T = Sync; | ^^^^^^^^^^^ +error: missing documentation for a function + --> $DIR/lint-missing-doc.rs:174:5 + | +LL | pub fn undocumented1() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a function + --> $DIR/lint-missing-doc.rs:175:5 + | +LL | pub fn undocumented2() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a function + --> $DIR/lint-missing-doc.rs:181:9 + | +LL | pub fn also_undocumented1() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 25 previous errors diff --git a/tests/ui/lint/lint-unconditional-drop-recursion.rs b/tests/ui/lint/lint-unconditional-drop-recursion.rs new file mode 100644 index 00000000000..348cd280139 --- /dev/null +++ b/tests/ui/lint/lint-unconditional-drop-recursion.rs @@ -0,0 +1,38 @@ +// Because drop recursion can only be detected after drop elaboration which +// happens for codegen: +// build-fail + +#![deny(unconditional_recursion)] +#![allow(dead_code)] + +pub struct RecursiveDrop; + +impl Drop for RecursiveDrop { + fn drop(&mut self) { //~ ERROR function cannot return without recursing + let _ = RecursiveDrop; + } +} + +#[derive(Default)] +struct NotRecursiveDrop1; + +impl Drop for NotRecursiveDrop1 { + fn drop(&mut self) { + // Before drop elaboration, the MIR can look like a recursive drop will + // occur. But it will not, since forget() prevents drop() from running. + let taken = std::mem::take(self); + std::mem::forget(taken); + } +} + +struct NotRecursiveDrop2; + +impl Drop for NotRecursiveDrop2 { + fn drop(&mut self) { + // Before drop elaboration, the MIR can look like a recursive drop will + // occur. But it will not, since this will panic. + std::panic::panic_any(NotRecursiveDrop2); + } +} + +fn main() {} diff --git a/tests/ui/lint/lint-unconditional-drop-recursion.stderr b/tests/ui/lint/lint-unconditional-drop-recursion.stderr new file mode 100644 index 00000000000..76f95481605 --- /dev/null +++ b/tests/ui/lint/lint-unconditional-drop-recursion.stderr @@ -0,0 +1,17 @@ +error: function cannot return without recursing + --> $DIR/lint-unconditional-drop-recursion.rs:11:5 + | +LL | fn drop(&mut self) { + | ^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | let _ = RecursiveDrop; + | - recursive call site + | + = help: a `loop` may express intention better if this is on purpose +note: the lint level is defined here + --> $DIR/lint-unconditional-drop-recursion.rs:5:9 + | +LL | #![deny(unconditional_recursion)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/lint/missing-copy-implementations-negative-copy.rs b/tests/ui/lint/missing-copy-implementations-negative-copy.rs new file mode 100644 index 00000000000..b29d2209fa9 --- /dev/null +++ b/tests/ui/lint/missing-copy-implementations-negative-copy.rs @@ -0,0 +1,15 @@ +// Regression test for issue #101980. +// Ensure that we don't suggest impl'ing `Copy` for a type if it already impl's `!Copy`. + +// check-pass + +#![feature(negative_impls)] +#![deny(missing_copy_implementations)] + +pub struct Struct { + pub field: i32, +} + +impl !Copy for Struct {} + +fn main() {} diff --git a/tests/ui/lint/missing-doc-private-macro.stderr b/tests/ui/lint/missing-doc-private-macro.stderr index 979b007d0ec..18c8ad2de6b 100644 --- a/tests/ui/lint/missing-doc-private-macro.stderr +++ b/tests/ui/lint/missing-doc-private-macro.stderr @@ -1,8 +1,8 @@ error: missing documentation for a macro - --> $DIR/missing-doc-private-macro.rs:31:5 + --> $DIR/missing-doc-private-macro.rs:37:1 | -LL | macro_rules! exported_to_top_level { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub macro top_level_pub_macro { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/missing-doc-private-macro.rs:5:9 @@ -11,10 +11,10 @@ LL | #![deny(missing_docs)] | ^^^^^^^^^^^^ error: missing documentation for a macro - --> $DIR/missing-doc-private-macro.rs:37:1 + --> $DIR/missing-doc-private-macro.rs:31:5 | -LL | pub macro top_level_pub_macro { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | macro_rules! exported_to_top_level { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/missing_debug_impls.rs b/tests/ui/missing_debug_impls.rs index dc4dacfc468..ccad861c037 100644 --- a/tests/ui/missing_debug_impls.rs +++ b/tests/ui/missing_debug_impls.rs @@ -35,4 +35,4 @@ struct PrivateStruct; enum PrivateEnum {} #[derive(Debug)] -struct GenericType<T>(T); +pub struct GenericType<T>(T); diff --git a/tests/ui/nll/guarantor-issue-46974.rs b/tests/ui/nll/guarantor-issue-46974.rs index 96af4bf5c36..93fdf7b460b 100644 --- a/tests/ui/nll/guarantor-issue-46974.rs +++ b/tests/ui/nll/guarantor-issue-46974.rs @@ -9,7 +9,6 @@ fn foo(s: &mut (i32,)) -> i32 { } fn bar(s: &Box<(i32,)>) -> &'static i32 { - // FIXME(#46983): error message should be better &s.0 //~ ERROR lifetime may not live long enough } diff --git a/tests/ui/nll/guarantor-issue-46974.stderr b/tests/ui/nll/guarantor-issue-46974.stderr index 7edc3dcc5cd..f09faf1630b 100644 --- a/tests/ui/nll/guarantor-issue-46974.stderr +++ b/tests/ui/nll/guarantor-issue-46974.stderr @@ -10,11 +10,10 @@ LL | *x | -- borrow later used here error: lifetime may not live long enough - --> $DIR/guarantor-issue-46974.rs:13:5 + --> $DIR/guarantor-issue-46974.rs:12:5 | LL | fn bar(s: &Box<(i32,)>) -> &'static i32 { | - let's call the lifetime of this reference `'1` -LL | // FIXME(#46983): error message should be better LL | &s.0 | ^^^^ returning this value requires that `'1` must outlive `'static` diff --git a/tests/ui/panic-handler/weak-lang-item-2.rs b/tests/ui/panic-handler/weak-lang-item-2.rs index a429d8fabc7..2cc5f23b45e 100644 --- a/tests/ui/panic-handler/weak-lang-item-2.rs +++ b/tests/ui/panic-handler/weak-lang-item-2.rs @@ -1,15 +1,15 @@ // run-pass // aux-build:weak-lang-items.rs -// ignore-emscripten no threads support // pretty-expanded FIXME #23616 extern crate weak_lang_items as other; -use std::thread; - fn main() { - let _ = thread::spawn(move|| { - other::foo() - }); + // The goal of the test is just to make sure other::foo() is referenced at link time. Since + // the function panics, to prevent it from running we gate it behind an always-false `if` that + // is not going to be optimized away. + if std::hint::black_box(false) { + other::foo(); + } } diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout index e476a8024fd..ac65ba07512 100644 --- a/tests/ui/proc-macro/meta-macro-hygiene.stdout +++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout @@ -18,7 +18,7 @@ Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro use core /* 0#1 */::prelude /* 0#1 */::rust_2018 /* 0#1 */::*; #[macro_use /* 0#1 */] extern crate core /* 0#1 */; -extern crate compiler_builtins /* 444 */ as _ /* 0#1 */; +extern crate compiler_builtins /* 445 */ as _ /* 0#1 */; // Don't load unnecessary hygiene information from std extern crate std /* 0#0 */; diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index 23a21004238..4031eb98a38 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -39,7 +39,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ use ::core /* 0#1 */::prelude /* 0#1 */::rust_2015 /* 0#1 */::*; #[macro_use /* 0#1 */] extern crate core /* 0#2 */; -extern crate compiler_builtins /* 444 */ as _ /* 0#2 */; +extern crate compiler_builtins /* 445 */ as _ /* 0#2 */; // Don't load unnecessary hygiene information from std extern crate std /* 0#0 */; diff --git a/tests/ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs b/tests/ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs new file mode 100644 index 00000000000..83349dd3350 --- /dev/null +++ b/tests/ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs @@ -0,0 +1,10 @@ +#![deny(unused_qualifications)] +// check-pass +fn bar() { + match Option::<Option<()>>::None { + Some(v) => {} + None => {} + } +} + +fn main() {} diff --git a/tests/ui/resolve/unresolved-segments-visibility.rs b/tests/ui/resolve/unresolved-segments-visibility.rs new file mode 100644 index 00000000000..c26171f75d2 --- /dev/null +++ b/tests/ui/resolve/unresolved-segments-visibility.rs @@ -0,0 +1,11 @@ +// Check that we do not ICE due to unresolved segments in visibility path. +#![crate_type = "lib"] + +extern crate alloc as b; + +mod foo { + mod bar { + pub(in b::string::String::newy) extern crate alloc as e; + //~^ ERROR failed to resolve: `String` is a struct, not a module [E0433] + } +} diff --git a/tests/ui/resolve/unresolved-segments-visibility.stderr b/tests/ui/resolve/unresolved-segments-visibility.stderr new file mode 100644 index 00000000000..0a11549cdbf --- /dev/null +++ b/tests/ui/resolve/unresolved-segments-visibility.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: `String` is a struct, not a module + --> $DIR/unresolved-segments-visibility.rs:8:27 + | +LL | pub(in b::string::String::newy) extern crate alloc as e; + | ^^^^^^ `String` is a struct, not a module + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/span/visibility-ty-params.rs b/tests/ui/span/visibility-ty-params.rs index d77febe0aa2..11c2cf44cb4 100644 --- a/tests/ui/span/visibility-ty-params.rs +++ b/tests/ui/span/visibility-ty-params.rs @@ -4,7 +4,7 @@ macro_rules! m { struct S<T>(T); m!{ S<u8> } //~ ERROR unexpected generic arguments in path - //~| ERROR expected module, found struct `S` + //~| ERROR failed to resolve: `S` is a struct, not a module [E0433] mod m { m!{ m<> } //~ ERROR unexpected generic arguments in path diff --git a/tests/ui/span/visibility-ty-params.stderr b/tests/ui/span/visibility-ty-params.stderr index 067893fd22d..97d05c4644e 100644 --- a/tests/ui/span/visibility-ty-params.stderr +++ b/tests/ui/span/visibility-ty-params.stderr @@ -4,11 +4,11 @@ error: unexpected generic arguments in path LL | m!{ S<u8> } | ^^^^ -error[E0577]: expected module, found struct `S` +error[E0433]: failed to resolve: `S` is a struct, not a module --> $DIR/visibility-ty-params.rs:6:5 | LL | m!{ S<u8> } - | ^^^^^ not a module + | ^ `S` is a struct, not a module error: unexpected generic arguments in path --> $DIR/visibility-ty-params.rs:10:10 @@ -18,4 +18,4 @@ LL | m!{ m<> } error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0577`. +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs b/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs index fd91d81cdf0..20f504928c7 100644 --- a/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs +++ b/tests/ui/traits/new-solver/lazy-nested-obligations-2.rs @@ -1,5 +1,5 @@ // compile-flags: -Ztrait-solver=next -// known-bug: #95863 +// check-pass pub trait With { type F; diff --git a/tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr b/tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr deleted file mode 100644 index d0a4cd661b3..00000000000 --- a/tests/ui/traits/new-solver/lazy-nested-obligations-2.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/lazy-nested-obligations-2.rs:15:23 - | -LL | let _: V<i32> = V(f); - | - ^ types differ - | | - | arguments to this struct are incorrect - | - = note: expected associated type `<i32 as With>::F` - found fn item `for<'a> fn(&'a str) {f}` - = help: consider constraining the associated type `<i32 as With>::F` to `for<'a> fn(&'a str) {f}` or calling a method that returns `<i32 as With>::F` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html -note: tuple struct defined here - --> $DIR/lazy-nested-obligations-2.rs:16:16 - | -LL | pub struct V<T: With>(<T as With>::F); - | ^ - -error[E0308]: mismatched types - --> $DIR/lazy-nested-obligations-2.rs:21:30 - | -LL | let _: E3<i32> = E3::Var(f); - | ------- ^ types differ - | | - | arguments to this enum variant are incorrect - | - = note: expected associated type `<i32 as With>::F` - found fn item `for<'a> fn(&'a str) {f}` - = help: consider constraining the associated type `<i32 as With>::F` to `for<'a> fn(&'a str) {f}` or calling a method that returns `<i32 as With>::F` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html -note: tuple variant defined here - --> $DIR/lazy-nested-obligations-2.rs:19:9 - | -LL | Var(<T as With>::F), - | ^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/new-solver/more-object-bound.stderr b/tests/ui/traits/new-solver/more-object-bound.stderr index 4554b8c7473..54965dee184 100644 --- a/tests/ui/traits/new-solver/more-object-bound.stderr +++ b/tests/ui/traits/new-solver/more-object-bound.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `dyn Trait<A = A, B = B>: Trait` is not satisfied - --> $DIR/more-object-bound.rs:12:17 + --> $DIR/more-object-bound.rs:12:5 | LL | foo::<A, B, dyn Trait<A = A, B = B>>(x) - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `dyn Trait<A = A, B = B>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `dyn Trait<A = A, B = B>` | note: required by a bound in `foo` --> $DIR/more-object-bound.rs:18:8 diff --git a/tests/ui/traits/new-solver/object-soundness-requires-generalization.rs b/tests/ui/traits/new-solver/object-soundness-requires-generalization.rs new file mode 100644 index 00000000000..d02dada72c9 --- /dev/null +++ b/tests/ui/traits/new-solver/object-soundness-requires-generalization.rs @@ -0,0 +1,20 @@ +// compile-flags: -Ztrait-solver=next +// ignore-test + +trait Trait { + type Gat<'lt>; +} +impl Trait for u8 { + type Gat<'lt> = u8; +} + +fn test<T: Trait, F: FnOnce(<T as Trait>::Gat<'_>) -> S + ?Sized, S>() {} + +fn main() { + // Proving `dyn FnOnce: FnOnce` requires making sure that all of the supertraits + // of the trait and associated type bounds hold. We check this in + // `predicates_for_object_candidate`, and eagerly replace projections using equality + // which may generalize a type and emit a nested AliasRelate goal. Make sure that + // we don't ICE in that case, and bubble that goal up to the caller. + test::<u8, dyn FnOnce(<u8 as Trait>::Gat<'_>) + 'static, _>(); +} diff --git a/tests/ui/type-alias-impl-trait/under-binder.rs b/tests/ui/type-alias-impl-trait/under-binder.rs new file mode 100644 index 00000000000..caf21d64027 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/under-binder.rs @@ -0,0 +1,9 @@ +#![feature(type_alias_impl_trait)] + +type Opaque<'a> = impl Sized + 'a; + +fn test(f: fn(u8)) -> fn(Opaque<'_>) { + f //~ ERROR E0792 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/under-binder.stderr b/tests/ui/type-alias-impl-trait/under-binder.stderr new file mode 100644 index 00000000000..82c4ec97335 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/under-binder.stderr @@ -0,0 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/under-binder.rs:6:5 + | +LL | type Opaque<'a> = impl Sized + 'a; + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | f + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type/option-ref-advice.rs b/tests/ui/type/option-ref-advice.rs new file mode 100644 index 00000000000..2dcee5a2eb9 --- /dev/null +++ b/tests/ui/type/option-ref-advice.rs @@ -0,0 +1,11 @@ +// Regression test for https://github.com/rust-lang/rust/issues/100605 + +fn takes_option(_arg: Option<&String>) {} + +fn main() { + takes_option(&None); //~ ERROR 6:18: 6:23: mismatched types [E0308] + + let x = String::from("x"); + let res = Some(x); + takes_option(&res); //~ ERROR 10:18: 10:22: mismatched types [E0308] +} diff --git a/tests/ui/issues/issue-100605.stderr b/tests/ui/type/option-ref-advice.stderr index 6f11f44755a..d4dbef3013f 100644 --- a/tests/ui/issues/issue-100605.stderr +++ b/tests/ui/type/option-ref-advice.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-100605.rs:4:18 + --> $DIR/option-ref-advice.rs:6:18 | LL | takes_option(&None); | ------------ ^^^^^ expected `Option<&String>`, found `&Option<_>` @@ -9,7 +9,7 @@ LL | takes_option(&None); = note: expected enum `Option<&String>` found reference `&Option<_>` note: function defined here - --> $DIR/issue-100605.rs:1:4 + --> $DIR/option-ref-advice.rs:3:4 | LL | fn takes_option(_arg: Option<&String>) {} | ^^^^^^^^^^^^ --------------------- @@ -20,7 +20,7 @@ LL + takes_option(None); | error[E0308]: mismatched types - --> $DIR/issue-100605.rs:8:18 + --> $DIR/option-ref-advice.rs:10:18 | LL | takes_option(&res); | ------------ ^^^^ expected `Option<&String>`, found `&Option<String>` @@ -30,7 +30,7 @@ LL | takes_option(&res); = note: expected enum `Option<&String>` found reference `&Option<String>` note: function defined here - --> $DIR/issue-100605.rs:1:4 + --> $DIR/option-ref-advice.rs:3:4 | LL | fn takes_option(_arg: Option<&String>) {} | ^^^^^^^^^^^^ --------------------- diff --git a/tests/ui/use/use-self-type.stderr b/tests/ui/use/use-self-type.stderr index 3da04a851f6..498df34fe32 100644 --- a/tests/ui/use/use-self-type.stderr +++ b/tests/ui/use/use-self-type.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions +error[E0433]: failed to resolve: `Self` cannot be used in imports --> $DIR/use-self-type.rs:7:16 | LL | pub(in Self::f) struct Z; - | ^^^^ `Self` is only available in impls, traits, and type definitions + | ^^^^ `Self` cannot be used in imports error[E0432]: unresolved import `Self` --> $DIR/use-self-type.rs:6:13 |
