diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index ee5895a6efd0f..ef27fd60dce10 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -139,6 +139,18 @@ impl NoArgsAttributeParser for AllowIncoherentImplParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl; } +pub(crate) struct AllowIncoherentTraitImplParser; +impl NoArgsAttributeParser for AllowIncoherentTraitImplParser { + const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_trait_impl]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::AssocConst), + Allow(Target::AssocTy), + ]); + const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentTraitImpl; +} + pub(crate) struct FundamentalParser; impl NoArgsAttributeParser for FundamentalParser { const PATH: &[Symbol] = &[sym::fundamental]; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b85bb6c6c89d4..d4bf295d5181f 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -76,10 +76,10 @@ use crate::attributes::stability::{ }; use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser}; use crate::attributes::traits::{ - AllowIncoherentImplParser, CoinductiveParser, DenyExplicitImplParser, - DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, ParenSugarParser, - PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser, - UnsafeSpecializationMarkerParser, + AllowIncoherentImplParser, AllowIncoherentTraitImplParser, CoinductiveParser, + DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, + ParenSugarParser, PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, + TypeConstParser, UnsafeSpecializationMarkerParser, }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; @@ -231,6 +231,7 @@ attribute_parsers!( Single, Single, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index a7e8515e415f0..5a476e981ed73 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1308,6 +1308,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No, "`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl." ), + rustc_attr!( + rustc_allow_incoherent_trait_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No, + "`#[rustc_allow_incoherent_trait_impl]` has to be added to all impl items of an incoherent trait impl." + ), rustc_attr!( rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No, "`#![rustc_preserve_ub_checks]` prevents the designated crate from evaluating whether UB checks are enabled when optimizing MIR", @@ -1335,6 +1339,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ "`#[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]`." ), + rustc_attr!( + rustc_has_incoherent_trait_impls, AttributeType::Normal, template!(Word), + ErrorFollowing, EncodeCrossCrate::Yes, + "`#[rustc_has_incoherent_trait_impls]` allows the addition of incoherent trait impls for \ + the given trait by annotating all impl items with `#[rustc_allow_incoherent_trait_impl]`." + ), BuiltinAttribute { name: sym::rustc_diagnostic_item, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index f418c391ece7a..44fcf454ff42d 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -694,6 +694,9 @@ pub enum AttributeKind { /// Represents `#[rustc_allow_incoherent_impl]`. AllowIncoherentImpl(Span), + /// Represents `#[rustc_allow_incoherent_trait_impl]`. + AllowIncoherentTraitImpl(Span), + /// Represents `#[allow_internal_unsafe]`. AllowInternalUnsafe(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 57d2d6c5875ed..3505fff8eb5b9 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -21,6 +21,7 @@ impl AttributeKind { Align { .. } => No, AllowConstFnUnstable(..) => No, AllowIncoherentImpl(..) => No, + AllowIncoherentTraitImpl(..) => No, AllowInternalUnsafe(..) => Yes, AllowInternalUnstable(..) => Yes, AsPtr(..) => Yes, diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index f1e138dbcb97a..25c9106ce6db9 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -3,6 +3,8 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorGuaranteed; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION; use rustc_middle::ty::{ @@ -10,6 +12,7 @@ use rustc_middle::ty::{ }; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::sym; use rustc_trait_selection::traits::{ self, IsFirstInputType, OrphanCheckErr, OrphanCheckMode, UncoveredTyParams, }; @@ -36,7 +39,32 @@ pub(crate) fn orphan_check_impl( bug!("orphanck: shouldn't've gotten non-local input tys in compat mode") } }, - Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)), + Err(err) => { + // The orphan check failed fully, see if we may tolerate it ... + if tcx.has_attr(trait_ref.def_id, sym::rustc_has_incoherent_trait_impls) { + // `#[rustc_has_incoherent_trait_impls]` was specified, + // meaning we tolerate a violation here; now ensure that all + // associated methods, types, and constants have the + // `#[rustc_allow_incoherent_trait_impl]` attribute. + let items = tcx.associated_item_def_ids(impl_def_id); + for item in items { + if !find_attr!( + tcx.get_all_attrs(*item), + AttributeKind::AllowIncoherentTraitImpl(_) + ) { + // Missing `#[rustc_allow_incoherent_trait_impl]`. + return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)); + } + + // Item is fine, continue. + } + // All items are fine, let's tolerate. + } else { + // We do not tolerate orphan violations, usually the default + // except for some standard library hacks. + return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)); + } + } }, } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 94996c0adb470..a17d036876b76 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -248,6 +248,10 @@ passes_has_incoherent_inherent_impl = `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits .label = only adts, extern types and traits are supported +passes_has_incoherent_trait_impl = + `rustc_has_incoherent_trait_impls` attribute should be applied to traits + .label = only traits are supported + passes_ignored_derived_impls = `{$name}` has {$trait_list_len -> [one] a derived impl diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2370a7d1dd5c6..8df4b326bd7e7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -246,6 +246,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::UnsafeSpecializationMarker(..) | AttributeKind::ParenSugar(..) | AttributeKind::AllowIncoherentImpl(..) + | AttributeKind::AllowIncoherentTraitImpl(..) | AttributeKind::Confusables { .. } | AttributeKind::TypeConst{..} // `#[doc]` is actually a lot more than just doc comments, so is checked below @@ -326,6 +327,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::rustc_has_incoherent_inherent_impls, ..] => { self.check_has_incoherent_inherent_impls(attr, span, target) } + [sym::rustc_has_incoherent_trait_impls, ..] => { + self.check_has_incoherent_trait_impls(attr, span, target) + } [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } @@ -1169,6 +1173,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + /// Checks if `#[rustc_has_incoherent_trait_impls]` is applied to a trait. + fn check_has_incoherent_trait_impls(&self, attr: &Attribute, span: Span, target: Target) { + match target { + Target::Trait => {} + _ => { + self.tcx + .dcx() + .emit_err(errors::HasIncoherentTraitImpl { attr_span: attr.span(), span }); + } + } + } + fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute]) { if find_attr!(attrs, AttributeKind::FfiConst(_)) { // `#[ffi_const]` functions cannot be `#[ffi_pure]` diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index af5cb29b83d04..b193b6f6ec49b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -196,6 +196,15 @@ pub(crate) struct HasIncoherentInherentImpl { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_has_incoherent_trait_impl)] +pub(crate) struct HasIncoherentTraitImpl { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(passes_both_ffi_const_and_pure, code = E0757)] pub(crate) struct BothFfiConstAndPure { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 72709753b1dff..69439a45e57f8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1912,6 +1912,7 @@ symbols! { rustc_allocator_zeroed_variant, rustc_allow_const_fn_unstable, rustc_allow_incoherent_impl, + rustc_allow_incoherent_trait_impl, rustc_allowed_through_unstable_modules, rustc_as_ptr, rustc_attrs, @@ -1951,6 +1952,7 @@ symbols! { rustc_expected_cgu_reuse, rustc_force_inline, rustc_has_incoherent_inherent_impls, + rustc_has_incoherent_trait_impls, rustc_hidden_type_of_opaques, rustc_if_this_changed, rustc_inherit_overflow_checks,