Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,18 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowIncoherentImplParser {
const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl;
}

pub(crate) struct AllowIncoherentTraitImplParser;
impl<S: Stage> NoArgsAttributeParser<S> for AllowIncoherentTraitImplParser {
const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_trait_impl];
const ON_DUPLICATE: OnDuplicate<S> = 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<S: Stage> NoArgsAttributeParser<S> for FundamentalParser {
const PATH: &[Symbol] = &[sym::fundamental];
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -231,6 +231,7 @@ attribute_parsers!(
Single<TypeLengthLimitParser>,
Single<WindowsSubsystemParser>,
Single<WithoutArgs<AllowIncoherentImplParser>>,
Single<WithoutArgs<AllowIncoherentTraitImplParser>>,
Single<WithoutArgs<AllowInternalUnsafeParser>>,
Single<WithoutArgs<AsPtrParser>>,
Single<WithoutArgs<AutomaticallyDerivedParser>>,
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ impl AttributeKind {
Align { .. } => No,
AllowConstFnUnstable(..) => No,
AllowIncoherentImpl(..) => No,
AllowIncoherentTraitImpl(..) => No,
AllowInternalUnsafe(..) => Yes,
AllowInternalUnstable(..) => Yes,
AsPtr(..) => Yes,
Expand Down
30 changes: 29 additions & 1 deletion compiler/rustc_hir_analysis/src/coherence/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@

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::{
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
};
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,
};
Expand All @@ -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));
}
}
},
}

Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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]`
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Loading