about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-03-30 12:34:37 +0000
committerbors <bors@rust-lang.org>2023-03-30 12:34:37 +0000
commit02ea92fecbda16ce4bf4c8e295d46d5eb765ff0a (patch)
tree6c750ce3d2780664a8c798bdc27391ae7a3d961b
parentfc8c5139fad70696f99d27e2ca1f59e4672fd017 (diff)
parent33b6012827b5d5a31c746177582017248acb339b (diff)
downloadrust-02ea92fecbda16ce4bf4c8e295d46d5eb765ff0a.tar.gz
rust-02ea92fecbda16ce4bf4c8e295d46d5eb765ff0a.zip
Auto merge of #14445 - Veykril:adt-flags, r=Veykril
internal: Introduce StructFlags
-rw-r--r--crates/hir-def/src/adt.rs61
-rw-r--r--crates/hir-def/src/attr.rs9
-rw-r--r--crates/hir-ty/src/autoderef.rs14
-rw-r--r--crates/hir-ty/src/diagnostics/match_check.rs2
-rw-r--r--crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs8
-rw-r--r--crates/hir-ty/src/lang_items.rs18
-rw-r--r--crates/hir-ty/src/layout/adt.rs2
-rw-r--r--crates/hir-ty/src/method_resolution.rs33
8 files changed, 91 insertions, 56 deletions
diff --git a/crates/hir-def/src/adt.rs b/crates/hir-def/src/adt.rs
index b336f59ffee..7a5025aa6a5 100644
--- a/crates/hir-def/src/adt.rs
+++ b/crates/hir-def/src/adt.rs
@@ -3,6 +3,7 @@
 use std::sync::Arc;
 
 use base_db::CrateId;
+use bitflags::bitflags;
 use cfg::CfgOptions;
 use either::Either;
 
@@ -20,6 +21,7 @@ use crate::{
     builtin_type::{BuiltinInt, BuiltinUint},
     db::DefDatabase,
     item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
+    lang_item::LangItem,
     layout::{Align, ReprFlags, ReprOptions},
     nameres::diagnostics::DefDiagnostic,
     src::HasChildSource,
@@ -39,8 +41,26 @@ pub struct StructData {
     pub variant_data: Arc<VariantData>,
     pub repr: Option<ReprOptions>,
     pub visibility: RawVisibility,
-    pub rustc_has_incoherent_inherent_impls: bool,
-    pub fundamental: bool,
+    pub flags: StructFlags,
+}
+
+bitflags! {
+    pub struct StructFlags: u8 {
+        const NO_FLAGS         = 0;
+        /// Indicates whether the struct is `PhantomData`.
+        const IS_PHANTOM_DATA  = 1 << 2;
+        /// Indicates whether the struct has a `#[fundamental]` attribute.
+        const IS_FUNDAMENTAL   = 1 << 3;
+        // FIXME: should this be a flag?
+        /// Indicates whether the struct has a `#[rustc_has_incoherent_inherent_impls]` attribute.
+        const IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL      = 1 << 4;
+        /// Indicates whether this struct is `Box`.
+        const IS_BOX           = 1 << 5;
+        /// Indicates whether this struct is `ManuallyDrop`.
+        const IS_MANUALLY_DROP = 1 << 6;
+        /// Indicates whether this struct is `UnsafeCell`.
+        const IS_UNSAFE_CELL   = 1 << 6;
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -174,10 +194,25 @@ impl StructData {
         let item_tree = loc.id.item_tree(db);
         let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
         let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
+
         let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
-        let rustc_has_incoherent_inherent_impls =
-            attrs.by_key("rustc_has_incoherent_inherent_impls").exists();
-        let fundamental = attrs.by_key("fundamental").exists();
+
+        let mut flags = StructFlags::NO_FLAGS;
+        if attrs.by_key("rustc_has_incoherent_inherent_impls").exists() {
+            flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL;
+        }
+        if attrs.by_key("fundamental").exists() {
+            flags |= StructFlags::IS_FUNDAMENTAL;
+        }
+        if let Some(lang) = attrs.lang_item() {
+            match lang {
+                LangItem::PhantomData => flags |= StructFlags::IS_PHANTOM_DATA,
+                LangItem::OwnedBox => flags |= StructFlags::IS_BOX,
+                LangItem::ManuallyDrop => flags |= StructFlags::IS_MANUALLY_DROP,
+                LangItem::UnsafeCell => flags |= StructFlags::IS_UNSAFE_CELL,
+                _ => (),
+            }
+        }
 
         let strukt = &item_tree[loc.id.value];
         let (variant_data, diagnostics) = lower_fields(
@@ -196,8 +231,7 @@ impl StructData {
                 variant_data: Arc::new(variant_data),
                 repr,
                 visibility: item_tree[strukt.visibility].clone(),
-                rustc_has_incoherent_inherent_impls,
-                fundamental,
+                flags,
             }),
             diagnostics.into(),
         )
@@ -218,9 +252,13 @@ impl StructData {
         let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
 
         let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
-        let rustc_has_incoherent_inherent_impls =
-            attrs.by_key("rustc_has_incoherent_inherent_impls").exists();
-        let fundamental = attrs.by_key("fundamental").exists();
+        let mut flags = StructFlags::NO_FLAGS;
+        if attrs.by_key("rustc_has_incoherent_inherent_impls").exists() {
+            flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL;
+        }
+        if attrs.by_key("fundamental").exists() {
+            flags |= StructFlags::IS_FUNDAMENTAL;
+        }
 
         let union = &item_tree[loc.id.value];
         let (variant_data, diagnostics) = lower_fields(
@@ -239,8 +277,7 @@ impl StructData {
                 variant_data: Arc::new(variant_data),
                 repr,
                 visibility: item_tree[union.visibility].clone(),
-                rustc_has_incoherent_inherent_impls,
-                fundamental,
+                flags,
             }),
             diagnostics.into(),
         )
diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs
index e4d3636ce5e..860df1b68b2 100644
--- a/crates/hir-def/src/attr.rs
+++ b/crates/hir-def/src/attr.rs
@@ -20,6 +20,7 @@ use syntax::{
 use crate::{
     db::DefDatabase,
     item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeNode},
+    lang_item::LangItem,
     nameres::{ModuleOrigin, ModuleSource},
     src::{HasChildSource, HasSource},
     AdtId, AttrDefId, EnumId, GenericParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroId,
@@ -177,13 +178,13 @@ impl Attrs {
 
         Arc::new(res)
     }
+}
 
+impl Attrs {
     pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
         AttrQuery { attrs: self, key }
     }
-}
 
-impl Attrs {
     pub fn cfg(&self) -> Option<CfgExpr> {
         let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse);
         let first = cfgs.next()?;
@@ -206,6 +207,10 @@ impl Attrs {
         self.by_key("lang").string_value()
     }
 
+    pub fn lang_item(&self) -> Option<LangItem> {
+        self.by_key("lang").string_value().and_then(|it| LangItem::from_str(it))
+    }
+
     pub fn docs(&self) -> Option<Documentation> {
         let docs = self.by_key("doc").attrs().filter_map(|attr| attr.string_value());
         let indent = doc_indent(self);
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index c749bf570c3..e23ae750dd5 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -4,10 +4,7 @@
 //! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs).
 
 use chalk_ir::cast::Cast;
-use hir_def::{
-    lang_item::{LangItem, LangItemTarget},
-    AdtId,
-};
+use hir_def::lang_item::LangItem;
 use hir_expand::name::name;
 use limit::Limit;
 
@@ -90,13 +87,8 @@ pub(crate) fn builtin_deref<'ty>(
         TyKind::Ref(.., ty) => Some(ty),
         // FIXME: Maybe accept this but diagnose if its not explicit?
         TyKind::Raw(.., ty) if explicit => Some(ty),
-        &TyKind::Adt(chalk_ir::AdtId(AdtId::StructId(strukt)), ref substs) => {
-            if Some(strukt)
-                == table
-                    .db
-                    .lang_item(table.trait_env.krate, LangItem::OwnedBox)
-                    .and_then(LangItemTarget::as_struct)
-            {
+        &TyKind::Adt(chalk_ir::AdtId(adt), ref substs) => {
+            if crate::lang_items::is_box(table.db, adt) {
                 substs.at(Interner, 0).ty(Interner)
             } else {
                 None
diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs
index 859a37804ae..fe1cda71dd5 100644
--- a/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/crates/hir-ty/src/diagnostics/match_check.rs
@@ -379,7 +379,7 @@ impl HirDisplay for Pat {
             }
             PatKind::Deref { subpattern } => {
                 match self.ty.kind(Interner) {
-                    TyKind::Adt(adt, _) if is_box(adt.0, f.db) => write!(f, "box ")?,
+                    TyKind::Adt(adt, _) if is_box(f.db, adt.0) => write!(f, "box ")?,
                     &TyKind::Ref(mutbl, ..) => {
                         write!(f, "&{}", if mutbl == Mutability::Mut { "mut " } else { "" })?
                     }
diff --git a/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
index d130827a77e..b103fdc709d 100644
--- a/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
@@ -384,7 +384,7 @@ impl Constructor {
                 TyKind::Tuple(arity, ..) => arity,
                 TyKind::Ref(..) => 1,
                 TyKind::Adt(adt, ..) => {
-                    if is_box(adt.0, pcx.cx.db) {
+                    if is_box(pcx.cx.db, adt.0) {
                         // The only legal patterns of type `Box` (outside `std`) are `_` and box
                         // patterns. If we're here we can assume this is a box pattern.
                         1
@@ -800,7 +800,7 @@ impl<'p> Fields<'p> {
                 }
                 TyKind::Ref(.., rty) => Fields::wildcards_from_tys(cx, once(rty.clone())),
                 &TyKind::Adt(AdtId(adt), ref substs) => {
-                    if is_box(adt, cx.db) {
+                    if is_box(cx.db, adt) {
                         // The only legal patterns of type `Box` (outside `std`) are `_` and box
                         // patterns. If we're here we can assume this is a box pattern.
                         let subst_ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone();
@@ -905,7 +905,7 @@ impl<'p> DeconstructedPat<'p> {
                         }
                         fields = Fields::from_iter(cx, wilds)
                     }
-                    TyKind::Adt(adt, substs) if is_box(adt.0, cx.db) => {
+                    TyKind::Adt(adt, substs) if is_box(cx.db, adt.0) => {
                         // The only legal patterns of type `Box` (outside `std`) are `_` and box
                         // patterns. If we're here we can assume this is a box pattern.
                         // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_,
@@ -992,7 +992,7 @@ impl<'p> DeconstructedPat<'p> {
                         })
                         .collect(),
                 },
-                TyKind::Adt(adt, _) if is_box(adt.0, cx.db) => {
+                TyKind::Adt(adt, _) if is_box(cx.db, adt.0) => {
                     // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
                     // of `std`). So this branch is only reachable when the feature is enabled and
                     // the pattern is a box pattern.
diff --git a/crates/hir-ty/src/lang_items.rs b/crates/hir-ty/src/lang_items.rs
index 28e5f6df063..b0ad4fc946a 100644
--- a/crates/hir-ty/src/lang_items.rs
+++ b/crates/hir-ty/src/lang_items.rs
@@ -1,22 +1,18 @@
 //! Functions to detect special lang items
 
-use hir_def::{lang_item::LangItem, AdtId, HasModule};
+use hir_def::{adt::StructFlags, lang_item::LangItem, AdtId};
 use hir_expand::name::Name;
 
 use crate::db::HirDatabase;
 
-pub fn is_box(adt: AdtId, db: &dyn HirDatabase) -> bool {
-    let krate = adt.module(db.upcast()).krate();
-    let box_adt =
-        db.lang_item(krate, LangItem::OwnedBox).and_then(|it| it.as_struct()).map(AdtId::from);
-    Some(adt) == box_adt
+pub fn is_box(db: &dyn HirDatabase, adt: AdtId) -> bool {
+    let AdtId::StructId(id) = adt else { return false };
+    db.struct_data(id).flags.contains(StructFlags::IS_UNSAFE_CELL)
 }
 
-pub fn is_unsafe_cell(adt: AdtId, db: &dyn HirDatabase) -> bool {
-    let krate = adt.module(db.upcast()).krate();
-    let box_adt =
-        db.lang_item(krate, LangItem::UnsafeCell).and_then(|it| it.as_struct()).map(AdtId::from);
-    Some(adt) == box_adt
+pub fn is_unsafe_cell(db: &dyn HirDatabase, adt: AdtId) -> bool {
+    let AdtId::StructId(id) = adt else { return false };
+    db.struct_data(id).flags.contains(StructFlags::IS_UNSAFE_CELL)
 }
 
 pub fn lang_items_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, LangItem)> {
diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs
index b22d0fe8ded..18199f327d1 100644
--- a/crates/hir-ty/src/layout/adt.rs
+++ b/crates/hir-ty/src/layout/adt.rs
@@ -71,7 +71,7 @@ pub fn layout_of_adt_query(
             &repr,
             &variants,
             is_enum,
-            is_unsafe_cell(def, db),
+            is_unsafe_cell(db, def),
             layout_scalar_valid_range(db, def),
             |min, max| Integer::repr_discr(&dl, &repr, min, max).unwrap_or((Integer::I8, false)),
             variants.iter_enumerated().filter_map(|(id, _)| {
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index e08c44f0a04..d253b4cc03e 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -7,8 +7,9 @@ use std::{ops::ControlFlow, sync::Arc};
 use base_db::{CrateId, Edition};
 use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause};
 use hir_def::{
-    data::ImplData, item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId, ConstId,
-    FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId, TraitId,
+    adt::StructFlags, data::ImplData, item_scope::ItemScope, nameres::DefMap, AssocItemId, BlockId,
+    ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ModuleId,
+    TraitId,
 };
 use hir_expand::name::Name;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -405,12 +406,14 @@ pub fn def_crates(
     match ty.kind(Interner) {
         &TyKind::Adt(AdtId(def_id), _) => {
             let rustc_has_incoherent_inherent_impls = match def_id {
-                hir_def::AdtId::StructId(id) => {
-                    db.struct_data(id).rustc_has_incoherent_inherent_impls
-                }
-                hir_def::AdtId::UnionId(id) => {
-                    db.union_data(id).rustc_has_incoherent_inherent_impls
-                }
+                hir_def::AdtId::StructId(id) => db
+                    .struct_data(id)
+                    .flags
+                    .contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL),
+                hir_def::AdtId::UnionId(id) => db
+                    .union_data(id)
+                    .flags
+                    .contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL),
                 hir_def::AdtId::EnumId(id) => db.enum_data(id).rustc_has_incoherent_inherent_impls,
             };
             Some(if rustc_has_incoherent_inherent_impls {
@@ -808,12 +811,14 @@ fn is_inherent_impl_coherent(
             | TyKind::Scalar(_) => true,
 
             &TyKind::Adt(AdtId(adt), _) => match adt {
-                hir_def::AdtId::StructId(it) => {
-                    db.struct_data(it).rustc_has_incoherent_inherent_impls
-                }
-                hir_def::AdtId::UnionId(it) => {
-                    db.union_data(it).rustc_has_incoherent_inherent_impls
-                }
+                hir_def::AdtId::StructId(id) => db
+                    .struct_data(id)
+                    .flags
+                    .contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL),
+                hir_def::AdtId::UnionId(id) => db
+                    .union_data(id)
+                    .flags
+                    .contains(StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL),
                 hir_def::AdtId::EnumId(it) => db.enum_data(it).rustc_has_incoherent_inherent_impls,
             },
             TyKind::Dyn(it) => it.principal().map_or(false, |trait_ref| {