about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2024-04-27 12:33:04 +0200
committerLukas Wirth <lukastw97@gmail.com>2024-04-27 13:15:36 +0200
commitd37c4b70d2441f7dad1277de716a3a208a67e00e (patch)
tree5acf7357f206fa2001a930d3517e9368c44daba5
parent2b6f198a5e42547017ff9472077cec57059fe7b8 (diff)
downloadrust-d37c4b70d2441f7dad1277de716a3a208a67e00e.tar.gz
rust-d37c4b70d2441f7dad1277de716a3a208a67e00e.zip
fix: Fix attributes on generic parameters colliding in item tree
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs98
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs47
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs111
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs44
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs93
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs1
11 files changed, 250 insertions, 212 deletions
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 e3d750d33ca..1b77de575cf 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -698,24 +698,22 @@ impl<'a> AssocItemCollector<'a> {
         match item {
             AssocItem::Function(id) => {
                 let item = &item_tree[id];
-
                 let def =
                     FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
                 self.items.push((item.name.clone(), def.into()));
             }
-            AssocItem::Const(id) => {
-                let item = &item_tree[id];
-                let Some(name) = item.name.clone() else { return };
-                let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
-                self.items.push((name, def.into()));
-            }
             AssocItem::TypeAlias(id) => {
                 let item = &item_tree[id];
-
                 let def =
                     TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
                 self.items.push((item.name.clone(), def.into()));
             }
+            AssocItem::Const(id) => {
+                let item = &item_tree[id];
+                let Some(name) = item.name.clone() else { return };
+                let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
+                self.items.push((name, def.into()));
+            }
             AssocItem::MacroCall(call) => {
                 let file_id = self.expander.current_file_id();
                 let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call];
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index bf728a71079..4e57845a694 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -1177,6 +1177,8 @@ pub mod fmt {
 //- /main.rs crate:main deps:alloc,std
 #![no_std]
 
+extern crate alloc;
+
 $0
 
 //- /std.rs crate:std deps:alloc
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index acc60e1d9e4..7a701a48bf7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -20,7 +20,7 @@ use triomphe::Arc;
 use crate::{
     db::DefDatabase,
     expander::Expander,
-    item_tree::{GenericsItemTreeNode, ItemTree},
+    item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
     lower::LowerCtx,
     nameres::{DefMap, MacroSubNs},
     type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
@@ -456,56 +456,67 @@ impl GenericParams {
         let cfg_options = &cfg_options[krate].cfg_options;
 
         // Returns the generic parameters that are enabled under the current `#[cfg]` options
-        let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| {
-            let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
-
-            // In the common case, no parameters will by disabled by `#[cfg]` attributes.
-            // Therefore, make a first pass to check if all parameters are enabled and, if so,
-            // clone the `Interned<GenericParams>` instead of recreating an identical copy.
-            let all_type_or_consts_enabled =
-                params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into()));
-            let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into()));
-
-            if all_type_or_consts_enabled && all_lifetimes_enabled {
-                params.clone()
-            } else {
-                Interned::new(GenericParams {
-                    type_or_consts: all_type_or_consts_enabled
-                        .then(|| params.type_or_consts.clone())
-                        .unwrap_or_else(|| {
-                            params
-                                .type_or_consts
-                                .iter()
-                                .filter(|(idx, _)| enabled((*idx).into()))
-                                .map(|(_, param)| param.clone())
-                                .collect()
-                        }),
-                    lifetimes: all_lifetimes_enabled
-                        .then(|| params.lifetimes.clone())
-                        .unwrap_or_else(|| {
-                            params
-                                .lifetimes
-                                .iter()
-                                .filter(|(idx, _)| enabled((*idx).into()))
-                                .map(|(_, param)| param.clone())
-                                .collect()
-                        }),
-                    where_predicates: params.where_predicates.clone(),
-                })
-            }
-        };
+        let enabled_params =
+            |params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
+                let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
+                let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
+                let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
+
+                // In the common case, no parameters will by disabled by `#[cfg]` attributes.
+                // Therefore, make a first pass to check if all parameters are enabled and, if so,
+                // clone the `Interned<GenericParams>` instead of recreating an identical copy.
+                let all_type_or_consts_enabled =
+                    params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx)));
+                let all_lifetimes_enabled =
+                    params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx)));
+
+                if all_type_or_consts_enabled && all_lifetimes_enabled {
+                    params.clone()
+                } else {
+                    Interned::new(GenericParams {
+                        type_or_consts: all_type_or_consts_enabled
+                            .then(|| params.type_or_consts.clone())
+                            .unwrap_or_else(|| {
+                                params
+                                    .type_or_consts
+                                    .iter()
+                                    .filter(|&(idx, _)| enabled(attr_owner_ct(idx)))
+                                    .map(|(_, param)| param.clone())
+                                    .collect()
+                            }),
+                        lifetimes: all_lifetimes_enabled
+                            .then(|| params.lifetimes.clone())
+                            .unwrap_or_else(|| {
+                                params
+                                    .lifetimes
+                                    .iter()
+                                    .filter(|&(idx, _)| enabled(attr_owner_lt(idx)))
+                                    .map(|(_, param)| param.clone())
+                                    .collect()
+                            }),
+                        where_predicates: params.where_predicates.clone(),
+                    })
+                }
+            };
         fn id_to_generics<Id: GenericsItemTreeNode>(
             db: &dyn DefDatabase,
             id: impl for<'db> Lookup<
                 Database<'db> = dyn DefDatabase + 'db,
                 Data = impl ItemTreeLoc<Id = Id>,
             >,
-            enabled_params: impl Fn(&Interned<GenericParams>, &ItemTree) -> Interned<GenericParams>,
-        ) -> Interned<GenericParams> {
+            enabled_params: impl Fn(
+                &Interned<GenericParams>,
+                &ItemTree,
+                GenericModItem,
+            ) -> Interned<GenericParams>,
+        ) -> Interned<GenericParams>
+        where
+            FileItemTreeId<Id>: Into<GenericModItem>,
+        {
             let id = id.lookup(db).item_tree_id();
             let tree = id.item_tree(db);
             let item = &tree[id.value];
-            enabled_params(item.generic_params(), &tree)
+            enabled_params(item.generic_params(), &tree, id.value.into())
         }
 
         match def {
@@ -514,7 +525,8 @@ impl GenericParams {
                 let tree = loc.id.item_tree(db);
                 let item = &tree[loc.id.value];
 
-                let enabled_params = enabled_params(&item.explicit_generic_params, &tree);
+                let enabled_params =
+                    enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into());
 
                 let module = loc.container.module(db);
                 let func_data = db.function_data(id);
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 4bf4bc768f0..226a457c90a 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
@@ -57,11 +57,11 @@ use triomphe::Arc;
 use crate::{
     attr::Attrs,
     db::DefDatabase,
-    generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
+    generics::GenericParams,
     path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
     type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
     visibility::{RawVisibility, VisibilityExplicitness},
-    BlockId, Lookup,
+    BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
 };
 
 #[derive(Copy, Clone, Eq, PartialEq)]
@@ -293,8 +293,8 @@ pub enum AttrOwner {
     Variant(FileItemTreeId<Variant>),
     Field(Idx<Field>),
     Param(Idx<Param>),
-    TypeOrConstParamData(Idx<TypeOrConstParamData>),
-    LifetimeParamData(Idx<LifetimeParamData>),
+    TypeOrConstParamData(GenericModItem, LocalTypeOrConstParamId),
+    LifetimeParamData(GenericModItem, LocalLifetimeParamId),
 }
 
 macro_rules! from_attrs {
@@ -314,8 +314,6 @@ from_attrs!(
     Variant(FileItemTreeId<Variant>),
     Field(Idx<Field>),
     Param(Idx<Param>),
-    TypeOrConstParamData(Idx<TypeOrConstParamData>),
-    LifetimeParamData(Idx<LifetimeParamData>),
 );
 
 /// Trait implemented by all nodes in the item tree.
@@ -465,12 +463,49 @@ macro_rules! mod_items {
             )+
         }
 
+        #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+        pub enum GenericModItem {
+            $(
+                $(
+                    #[cfg_attr(FALSE, $generic_params)]
+                    $typ(FileItemTreeId<$typ>),
+                )?
+            )+
+        }
+
+        impl From<GenericModItem> for ModItem {
+            fn from(id: GenericModItem) -> ModItem {
+                match id {
+                    $(
+                        $(
+                            #[cfg_attr(FALSE, $generic_params)]
+                            GenericModItem::$typ(id) => ModItem::$typ(id),
+                        )?
+                    )+
+                }
+            }
+        }
+
+        impl From<GenericModItem> for AttrOwner {
+            fn from(t: GenericModItem) -> AttrOwner {
+                AttrOwner::ModItem(t.into())
+            }
+        }
+
         $(
             impl From<FileItemTreeId<$typ>> for ModItem {
                 fn from(id: FileItemTreeId<$typ>) -> ModItem {
                     ModItem::$typ(id)
                 }
             }
+            $(
+                #[cfg_attr(FALSE, $generic_params)]
+                impl From<FileItemTreeId<$typ>> for GenericModItem {
+                    fn from(id: FileItemTreeId<$typ>) -> GenericModItem {
+                        GenericModItem::$typ(id)
+                    }
+                }
+            )?
         )+
 
         $(
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 4b5ef56d782..6aa5a63d628 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
@@ -4,6 +4,7 @@ use std::collections::hash_map::Entry;
 
 use hir_expand::{mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId};
 use la_arena::Arena;
+use rustc_hash::FxHashMap;
 use span::{AstIdMap, SyntaxContextId};
 use syntax::{
     ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
@@ -16,11 +17,11 @@ use crate::{
     generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
     item_tree::{
         AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldAstId,
-        Fields, FileItemTreeId, FnFlags, Function, GenericArgs, Idx, IdxRange, Impl, ImportAlias,
-        Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod,
-        ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path, Range, RawAttrs,
-        RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union,
-        Use, UseTree, UseTreeKind, Variant,
+        Fields, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, IdxRange,
+        Impl, ImportAlias, Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall,
+        MacroRules, Mod, ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path,
+        Range, RawAttrs, RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias,
+        TypeAlias, Union, Use, UseTree, UseTreeKind, Variant,
     },
     path::AssociatedTypeBinding,
     type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef},
@@ -36,6 +37,8 @@ pub(super) struct Ctx<'a> {
     db: &'a dyn DefDatabase,
     tree: ItemTree,
     source_ast_id_map: Arc<AstIdMap>,
+    generic_param_attr_buffer:
+        FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>,
     body_ctx: crate::lower::LowerCtx<'a>,
 }
 
@@ -44,6 +47,7 @@ impl<'a> Ctx<'a> {
         Self {
             db,
             tree: ItemTree::default(),
+            generic_param_attr_buffer: FxHashMap::default(),
             source_ast_id_map: db.ast_id_map(file),
             body_ctx: crate::lower::LowerCtx::new(db, file),
         }
@@ -56,6 +60,7 @@ impl<'a> Ctx<'a> {
     pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
         self.tree.top_level =
             item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
+        assert!(self.generic_param_attr_buffer.is_empty());
         self.tree
     }
 
@@ -89,6 +94,7 @@ impl<'a> Ctx<'a> {
             }
         }
 
+        assert!(self.generic_param_attr_buffer.is_empty());
         self.tree
     }
 
@@ -117,6 +123,7 @@ impl<'a> Ctx<'a> {
             }
         }
 
+        assert!(self.generic_param_attr_buffer.is_empty());
         self.tree
     }
 
@@ -185,10 +192,12 @@ impl<'a> Ctx<'a> {
         let visibility = self.lower_visibility(strukt);
         let name = strukt.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(strukt);
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
         let fields = self.lower_fields(&strukt.kind());
+        let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
         let res = Struct { name, visibility, generic_params, fields, ast_id };
-        Some(id(self.data().structs.alloc(res)))
+        let id = id(self.data().structs.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields {
@@ -252,28 +261,32 @@ impl<'a> Ctx<'a> {
         let visibility = self.lower_visibility(union);
         let name = union.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(union);
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
         let fields = match union.record_field_list() {
             Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
             None => Fields::Record(IdxRange::new(self.next_field_idx()..self.next_field_idx())),
         };
+        let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
         let res = Union { name, visibility, generic_params, fields, ast_id };
-        Some(id(self.data().unions.alloc(res)))
+        let id = id(self.data().unions.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> {
         let visibility = self.lower_visibility(enum_);
         let name = enum_.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(enum_);
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
         let variants = match &enum_.variant_list() {
             Some(variant_list) => self.lower_variants(variant_list),
             None => {
                 FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
             }
         };
+        let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
         let res = Enum { name, visibility, generic_params, variants, ast_id };
-        Some(id(self.data().enums.alloc(res)))
+        let id = id(self.data().enums.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_variants(&mut self, variants: &ast::VariantList) -> Range<FileItemTreeId<Variant>> {
@@ -414,7 +427,9 @@ impl<'a> Ctx<'a> {
             flags,
         };
 
-        Some(id(self.data().functions.alloc(res)))
+        let id = id(self.data().functions.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_type_alias(
@@ -428,7 +443,9 @@ impl<'a> Ctx<'a> {
         let ast_id = self.source_ast_id_map.ast_id(type_alias);
         let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias);
         let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id };
-        Some(id(self.data().type_aliases.alloc(res)))
+        let id = id(self.data().type_aliases.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
@@ -475,8 +492,6 @@ impl<'a> Ctx<'a> {
         let name = trait_def.name()?.as_name();
         let visibility = self.lower_visibility(trait_def);
         let ast_id = self.source_ast_id_map.ast_id(trait_def);
-        let generic_params =
-            self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
         let is_auto = trait_def.auto_token().is_some();
         let is_unsafe = trait_def.unsafe_token().is_some();
 
@@ -487,8 +502,12 @@ impl<'a> Ctx<'a> {
             .filter_map(|item_node| self.lower_assoc_item(&item_node))
             .collect();
 
+        let generic_params =
+            self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
         let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id };
-        Some(id(self.data().traits.alloc(def)))
+        let id = id(self.data().traits.alloc(def));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_trait_alias(
@@ -504,19 +523,18 @@ impl<'a> Ctx<'a> {
         );
 
         let alias = TraitAlias { name, visibility, generic_params, ast_id };
-        Some(id(self.data().trait_aliases.alloc(alias)))
+        let id = id(self.data().trait_aliases.alloc(alias));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
         let ast_id = self.source_ast_id_map.ast_id(impl_def);
-        // Note that trait impls don't get implicit `Self` unlike traits, because here they are a
-        // type alias rather than a type parameter, so this is handled by the resolver.
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
         // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
         // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
         // equals itself.
-        let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
         let self_ty = self.lower_type_ref(&impl_def.self_ty()?);
+        let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
         let is_negative = impl_def.excl_token().is_some();
         let is_unsafe = impl_def.unsafe_token().is_some();
 
@@ -527,9 +545,14 @@ impl<'a> Ctx<'a> {
             .flat_map(|it| it.assoc_items())
             .filter_map(|item| self.lower_assoc_item(&item))
             .collect();
+        // Note that trait impls don't get implicit `Self` unlike traits, because here they are a
+        // type alias rather than a type parameter, so this is handled by the resolver.
+        let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
         let res =
             Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id };
-        Some(id(self.data().impls.alloc(res)))
+        let id = id(self.data().impls.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
@@ -616,11 +639,30 @@ impl<'a> Ctx<'a> {
         id(self.data().extern_blocks.alloc(res))
     }
 
+    fn write_generic_params_attributes(&mut self, parent: GenericModItem) {
+        self.generic_param_attr_buffer.drain().for_each(|(idx, attrs)| {
+            self.tree.attrs.insert(
+                match idx {
+                    Either::Left(id) => AttrOwner::TypeOrConstParamData(parent, id),
+                    Either::Right(id) => AttrOwner::LifetimeParamData(parent, id),
+                },
+                attrs,
+            );
+        })
+    }
+
     fn lower_generic_params(
         &mut self,
         has_implicit_self: HasImplicitSelf,
         node: &dyn ast::HasGenericParams,
     ) -> Interned<GenericParams> {
+        debug_assert!(self.generic_param_attr_buffer.is_empty(),);
+        let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
+                               param| {
+            let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.span_map());
+            debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
+        };
+
         let mut generics = GenericParamsCollector::default();
 
         if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
@@ -635,28 +677,13 @@ impl<'a> Ctx<'a> {
             );
             // add super traits as bounds on Self
             // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
-            let self_param = TypeRef::Path(name![Self].into());
-            generics.fill_bounds(&self.body_ctx, bounds, Either::Left(self_param));
+            generics.fill_bounds(
+                &self.body_ctx,
+                bounds,
+                Either::Left(TypeRef::Path(name![Self].into())),
+            );
         }
 
-        let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
-                               param| {
-            let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.span_map());
-            // This is identical to the body of `Ctx::add_attrs()` but we can't call that here
-            // because it requires `&mut self` and the call to `generics.fill()` below also
-            // references `self`.
-            match self.tree.attrs.entry(match item {
-                Either::Right(id) => id.into(),
-                Either::Left(id) => id.into(),
-            }) {
-                Entry::Occupied(mut entry) => {
-                    *entry.get_mut() = entry.get().merge(attrs);
-                }
-                Entry::Vacant(entry) => {
-                    entry.insert(attrs);
-                }
-            }
-        };
         generics.fill(&self.body_ctx, node, add_param_attrs);
 
         Interned::new(generics.finish())
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 cef2a3fb866..2803678a330 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
@@ -8,8 +8,8 @@ use crate::{
     generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
     item_tree::{
         AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldAstId, Fields,
-        FileItemTreeId, FnFlags, Function, GenericParams, Impl, Interned, ItemTree, Macro2,
-        MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs,
+        FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl, Interned, ItemTree,
+        Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs,
         RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, TypeRef, Union,
         Use, UseTree, UseTreeKind, Variant,
     },
@@ -276,7 +276,7 @@ impl Printer<'_> {
                     w!(self, "extern \"{}\" ", abi);
                 }
                 w!(self, "fn {}", name.display(self.db.upcast()));
-                self.print_generic_params(explicit_generic_params);
+                self.print_generic_params(explicit_generic_params, it.into());
                 w!(self, "(");
                 if !params.is_empty() {
                     self.indented(|this| {
@@ -316,7 +316,7 @@ impl Printer<'_> {
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "struct {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 self.print_fields_and_where_clause(fields, generic_params);
                 if matches!(fields, Fields::Record(_)) {
                     wln!(self);
@@ -329,7 +329,7 @@ impl Printer<'_> {
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "union {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 self.print_fields_and_where_clause(fields, generic_params);
                 if matches!(fields, Fields::Record(_)) {
                     wln!(self);
@@ -342,7 +342,7 @@ impl Printer<'_> {
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "enum {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
                     for variant in FileItemTreeId::range_iter(variants.clone()) {
@@ -394,7 +394,7 @@ impl Printer<'_> {
                     w!(self, "auto ");
                 }
                 w!(self, "trait {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
                     for item in &**items {
@@ -408,7 +408,7 @@ impl Printer<'_> {
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "trait {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 w!(self, " = ");
                 self.print_where_clause(generic_params);
                 w!(self, ";");
@@ -429,7 +429,7 @@ impl Printer<'_> {
                     w!(self, "unsafe");
                 }
                 w!(self, "impl");
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 w!(self, " ");
                 if *is_negative {
                     w!(self, "!");
@@ -453,7 +453,7 @@ impl Printer<'_> {
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "type {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 if !bounds.is_empty() {
                     w!(self, ": ");
                     self.print_type_bounds(bounds);
@@ -525,7 +525,7 @@ impl Printer<'_> {
         print_path(self.db, path, self).unwrap();
     }
 
-    fn print_generic_params(&mut self, params: &GenericParams) {
+    fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
         if params.is_empty() {
             return;
         }
@@ -537,7 +537,7 @@ impl Printer<'_> {
                 w!(self, ", ");
             }
             first = false;
-            self.print_attrs_of(idx, " ");
+            self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " ");
             w!(self, "{}", lt.name.display(self.db.upcast()));
         }
         for (idx, x) in params.type_or_consts.iter() {
@@ -545,7 +545,7 @@ impl Printer<'_> {
                 w!(self, ", ");
             }
             first = false;
-            self.print_attrs_of(idx, " ");
+            self.print_attrs_of(AttrOwner::TypeOrConstParamData(parent, idx), " ");
             match x {
                 TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
                     Some(name) => w!(self, "{}", name.display(self.db.upcast())),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
index 48da876ac15..79bab11998b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
@@ -427,10 +427,18 @@ fn generics_with_attributes() {
     check(
         r#"
 struct S<#[cfg(never)] T>;
+struct S<A, B, #[cfg(never)] C>;
+struct S<A, #[cfg(never)] B, C>;
         "#,
         expect![[r#"
             // AstId: 1
             pub(self) struct S<#[cfg(never)] T>;
+
+            // AstId: 2
+            pub(self) struct S<A, B, #[cfg(never)] C>;
+
+            // AstId: 3
+            pub(self) struct S<A, #[cfg(never)] B, C>;
         "#]],
     )
 }
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 0a6cd0fe9ed..a3b6a65238f 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
@@ -5,7 +5,7 @@
 
 use std::{cmp::Ordering, iter, mem, ops::Not};
 
-use base_db::{CrateId, Dependency, FileId};
+use base_db::{CrateId, CrateOrigin, Dependency, FileId, LangCrateOrigin};
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
 use hir_expand::{
@@ -279,7 +279,8 @@ impl DefCollector<'_> {
     fn seed_with_top_level(&mut self) {
         let _p = tracing::span!(tracing::Level::INFO, "seed_with_top_level").entered();
 
-        let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
+        let crate_graph = self.db.crate_graph();
+        let file_id = crate_graph[self.def_map.krate].root_file_id;
         let item_tree = self.db.file_item_tree(file_id.into());
         let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
         let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap();
@@ -318,8 +319,43 @@ impl DefCollector<'_> {
                         self.is_proc_macro = true;
                     }
                 }
-                () if *attr_name == hir_expand::name![no_core] => crate_data.no_core = true,
-                () if *attr_name == hir_expand::name![no_std] => crate_data.no_std = true,
+                () if *attr_name == hir_expand::name![no_core] => {
+                    if let Some((core, _)) =
+                        crate_data.extern_prelude.iter().find(|(_, (root, _))| {
+                            matches!(
+                                crate_graph[root.krate].origin,
+                                CrateOrigin::Lang(LangCrateOrigin::Core)
+                            )
+                        })
+                    {
+                        crate_data.extern_prelude.remove(&core.clone());
+                    }
+
+                    crate_data.no_core = true
+                }
+                () if *attr_name == hir_expand::name![no_std] => {
+                    if let Some((alloc, _)) =
+                        crate_data.extern_prelude.iter().find(|(_, (root, _))| {
+                            matches!(
+                                crate_graph[root.krate].origin,
+                                CrateOrigin::Lang(LangCrateOrigin::Alloc)
+                            )
+                        })
+                    {
+                        crate_data.extern_prelude.remove(&alloc.clone());
+                    }
+                    if let Some((std, _)) =
+                        crate_data.extern_prelude.iter().find(|(_, (root, _))| {
+                            matches!(
+                                crate_graph[root.krate].origin,
+                                CrateOrigin::Lang(LangCrateOrigin::Std)
+                            )
+                        })
+                    {
+                        crate_data.extern_prelude.remove(&std.clone());
+                    }
+                    crate_data.no_std = true
+                }
                 () if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") => {
                     crate_data.rustc_coherence_is_core = true;
                 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 4d0516ead67..7423c9ed327 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -1056,23 +1056,7 @@ impl<'a> TyLoweringContext<'a> {
         let clause = match bound.as_ref() {
             TypeBound::Path(path, TraitBoundModifier::None) => {
                 trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty));
-                trait_ref
-                    .clone()
-                    .filter(|tr| {
-                        // ignore `T: Drop` or `T: Destruct` bounds.
-                        // - `T: ~const Drop` has a special meaning in Rust 1.61 that we don't implement.
-                        //   (So ideally, we'd only ignore `~const Drop` here)
-                        // - `Destruct` impls are built-in in 1.62 (current nightly as of 08-04-2022), so until
-                        //   the builtin impls are supported by Chalk, we ignore them here.
-                        if let Some(lang) = self.db.lang_attr(tr.hir_trait_id().into()) {
-                            if matches!(lang, LangItem::Drop | LangItem::Destruct) {
-                                return false;
-                            }
-                        }
-                        true
-                    })
-                    .map(WhereClause::Implemented)
-                    .map(crate::wrap_empty_binders)
+                trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
             }
             TypeBound::Path(path, TraitBoundModifier::Maybe) => {
                 let sized_trait = self
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 43fe14126e0..69c7a815488 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
@@ -1600,85 +1600,6 @@ fn f(s: S) {
 }
 
 #[test]
-fn rust_161_option_clone() {
-    check_types(
-        r#"
-//- minicore: option, drop
-
-fn test(o: &Option<i32>) {
-    o.my_clone();
-  //^^^^^^^^^^^^ Option<i32>
-}
-
-pub trait MyClone: Sized {
-    fn my_clone(&self) -> Self;
-}
-
-impl<T> const MyClone for Option<T>
-where
-    T: ~const MyClone + ~const Drop + ~const Destruct,
-{
-    fn my_clone(&self) -> Self {
-        match self {
-            Some(x) => Some(x.my_clone()),
-            None => None,
-        }
-    }
-}
-
-impl const MyClone for i32 {
-    fn my_clone(&self) -> Self {
-        *self
-    }
-}
-
-pub trait Destruct {}
-
-impl<T: ?Sized> const Destruct for T {}
-"#,
-    );
-}
-
-#[test]
-fn rust_162_option_clone() {
-    check_types(
-        r#"
-//- minicore: option, drop
-
-fn test(o: &Option<i32>) {
-    o.my_clone();
-  //^^^^^^^^^^^^ Option<i32>
-}
-
-pub trait MyClone: Sized {
-    fn my_clone(&self) -> Self;
-}
-
-impl<T> const MyClone for Option<T>
-where
-    T: ~const MyClone + ~const Destruct,
-{
-    fn my_clone(&self) -> Self {
-        match self {
-            Some(x) => Some(x.my_clone()),
-            None => None,
-        }
-    }
-}
-
-impl const MyClone for i32 {
-    fn my_clone(&self) -> Self {
-        *self
-    }
-}
-
-#[lang = "destruct"]
-pub trait Destruct {}
-"#,
-    );
-}
-
-#[test]
 fn tuple_struct_pattern_with_unmatched_args_crash() {
     check_infer(
         r#"
@@ -2040,3 +1961,17 @@ fn main() {
 "#,
     )
 }
+
+#[test]
+fn cfg_first_trait_param_16141() {
+    check_no_mismatches(
+        r#"
+//- minicore: sized, coerce_unsized
+trait Bar {
+    fn bar(&self) {}
+}
+
+impl<#[cfg(feature = "a-feature")] A> Bar for (){}
+"#,
+    )
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index eb2c6095012..4bc3e121ac1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -238,6 +238,7 @@ fn infer_for_loop() {
 //- minicore: iterator
 //- /main.rs crate:main deps:alloc
 #![no_std]
+extern crate alloc;
 use alloc::collections::Vec;
 
 fn test() {