about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs5
-rw-r--r--compiler/rustc_hir/src/lang_items.rs2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs28
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs9
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls.rs56
6 files changed, 84 insertions, 17 deletions
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index e588385cfca..1d0fb31cd5e 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -644,6 +644,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing,
         "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
     ),
+    rustc_attr!(
+        rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), ErrorFollowing,
+        "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \
+         the given type by annotating all impl items with #[rustc_allow_incoherent_impl]."
+    ),
     BuiltinAttribute {
         name: sym::rustc_diagnostic_item,
         type_: Normal,
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index b3c22d4ec21..9e5d7818924 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -327,8 +327,6 @@ language_item_table! {
     Range,                   sym::Range,               range_struct,               Target::Struct,         GenericRequirement::None;
     RangeToInclusive,        sym::RangeToInclusive,    range_to_inclusive_struct,  Target::Struct,         GenericRequirement::None;
     RangeTo,                 sym::RangeTo,             range_to_struct,            Target::Struct,         GenericRequirement::None;
-
-    CStr,                    sym::CStr,                c_str,                      Target::Struct,         GenericRequirement::None;
 }
 
 pub enum GenericRequirement {
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index a9444972130..aa933043195 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -124,6 +124,9 @@ impl CheckAttrVisitor<'_> {
                 sym::rustc_allow_incoherent_impl => {
                     self.check_allow_incoherent_impl(&attr, span, target)
                 }
+                sym::rustc_has_incoherent_inherent_impls => {
+                    self.check_has_incoherent_inherent_impls(&attr, span, target)
+                }
                 sym::rustc_const_unstable
                 | sym::rustc_const_stable
                 | sym::unstable
@@ -1095,7 +1098,6 @@ impl CheckAttrVisitor<'_> {
         }
     }
 
-    /// Warns against some misuses of `#[pass_by_value]`
     fn check_allow_incoherent_impl(&self, attr: &Attribute, span: Span, target: Target) -> bool {
         match target {
             Target::Method(MethodKind::Inherent) => true,
@@ -1113,6 +1115,30 @@ impl CheckAttrVisitor<'_> {
         }
     }
 
+    fn check_has_incoherent_inherent_impls(
+        &self,
+        attr: &Attribute,
+        span: Span,
+        target: Target,
+    ) -> bool {
+        match target {
+            Target::Trait | Target::Struct | Target::Enum | Target::Union | Target::ForeignTy => {
+                true
+            }
+            _ => {
+                self.tcx
+                    .sess
+                    .struct_span_err(
+                        attr.span,
+                        "`rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.",
+                    )
+                    .span_label(span, "only adts, extern types and traits are supported")
+                    .emit();
+                false
+            }
+        }
+    }
+
     /// Warns against some misuses of `#[must_use]`
     fn check_must_use(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
         let node = self.tcx.hir().get(hir_id);
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index c1299c94c4b..fab2cf1504e 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1187,6 +1187,7 @@ symbols! {
         rustc_error,
         rustc_evaluate_where_clauses,
         rustc_expected_cgu_reuse,
+        rustc_has_incoherent_inherent_impls,
         rustc_if_this_changed,
         rustc_inherit_overflow_checks,
         rustc_insignificant_dtor,
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index e04cc42b6d7..3a36686613b 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -27,6 +27,7 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::lev_distance::{
     find_best_match_for_name_with_substrings, lev_distance_with_substrings,
 };
+use rustc_span::symbol::sym;
 use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
 use rustc_trait_selection::autoderef::{self, Autoderef};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -642,16 +643,22 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
                 self.assemble_inherent_candidates_from_object(generalized_self_ty);
                 self.assemble_inherent_impl_candidates_for_type(p.def_id());
+                if self.tcx.has_attr(p.def_id(), sym::rustc_has_incoherent_inherent_impls) {
+                    self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
+                }
             }
             ty::Adt(def, _) => {
                 let def_id = def.did();
                 self.assemble_inherent_impl_candidates_for_type(def_id);
-                if Some(def_id) == self.tcx.lang_items().c_str() {
+                if self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls) {
                     self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
                 }
             }
             ty::Foreign(did) => {
                 self.assemble_inherent_impl_candidates_for_type(did);
+                if self.tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
+                    self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty);
+                }
             }
             ty::Param(p) => {
                 self.assemble_inherent_candidates_from_param(p);
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index 5ad0c4ac52d..359828effa6 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -55,18 +55,13 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
         let self_ty = self.tcx.type_of(item.def_id);
         match *self_ty.kind() {
             ty::Adt(def, _) => {
-                let def_id = def.did();
-                if !def_id.is_local() && Some(def_id) == self.tcx.lang_items().c_str() {
-                    self.check_primitive_impl(item.def_id, self_ty, items, ty.span)
-                } else {
-                    self.check_def_id(item, def_id);
-                }
+                self.check_def_id(item, self_ty, def.did());
             }
             ty::Foreign(did) => {
-                self.check_def_id(item, did);
+                self.check_def_id(item, self_ty, did);
             }
             ty::Dynamic(data, ..) if data.principal_def_id().is_some() => {
-                self.check_def_id(item, data.principal_def_id().unwrap());
+                self.check_def_id(item, self_ty, data.principal_def_id().unwrap());
             }
             ty::Dynamic(..) => {
                 struct_span_err!(
@@ -124,14 +119,52 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> {
     fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
 }
 
+const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible";
+const INTO_DEFINING_CRATE: &str =
+    "consider moving this inherent impl into the crate defining the type if possible";
+const ADD_ATTR: &str =
+    "alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
+
 impl<'tcx> InherentCollect<'tcx> {
-    fn check_def_id(&mut self, item: &hir::Item<'_>, def_id: DefId) {
+    fn check_def_id(&mut self, item: &hir::Item<'_>, self_ty: Ty<'tcx>, def_id: DefId) {
+        let impl_def_id = item.def_id;
         if let Some(def_id) = def_id.as_local() {
             // Add the implementation to the mapping from implementation to base
             // type def ID, if there is a base type for this implementation and
             // the implementation does not have any associated traits.
             let vec = self.impls_map.inherent_impls.entry(def_id).or_default();
-            vec.push(item.def_id.to_def_id());
+            vec.push(impl_def_id.to_def_id());
+            return;
+        }
+
+        if self.tcx.features().rustc_attrs
+            && self.tcx.has_attr(def_id, sym::rustc_has_incoherent_inherent_impls)
+        {
+            let hir::ItemKind::Impl(hir::Impl { items, .. }) = item.kind else {
+                bug!("expected `impl` item: {:?}", item);
+            };
+
+            for item in items {
+                if !self.tcx.has_attr(item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+                {
+                    struct_span_err!(
+                        self.tcx.sess,
+                        item.span,
+                        E0390,
+                        "cannot define inherent `impl` for a type outside of crate where the type is defined",
+                    )
+                    .help(INTO_DEFINING_CRATE)
+                    .span_help(item.span, ADD_ATTR)
+                    .emit();
+                    return;
+                }
+            }
+
+            if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsPlaceholders) {
+                self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
+            } else {
+                bug!("unexpected self type: {:?}", self_ty);
+            }
         } else {
             struct_span_err!(
                 self.tcx.sess,
@@ -153,9 +186,6 @@ impl<'tcx> InherentCollect<'tcx> {
         items: &[hir::ImplItemRef],
         span: Span,
     ) {
-        const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible";
-        const ADD_ATTR: &str =
-            "alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
         if !self.tcx.hir().rustc_coherence_is_core() {
             if self.tcx.features().rustc_attrs {
                 for item in items {