1
Fork 0

Merge attrs, better validation

This commit is contained in:
Michael Goulet 2023-06-16 23:45:01 +00:00
parent 91e5c3f2e5
commit ca68cf0d46
16 changed files with 140 additions and 73 deletions

View file

@ -705,14 +705,13 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
"#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
),
rustc_attr!(
rustc_deny_explicit_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true,
rustc_deny_explicit_impl,
AttributeType::Normal,
template!(List: "implement_via_object = (true|false)"),
ErrorFollowing,
@only_local: true,
"#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls"
),
rustc_attr!(
rustc_do_not_implement_via_object, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true,
"#[rustc_do_not_implement_via_object] marks a trait so that `dyn Trait` does not \
implement `Trait` (without requiring `Sized` as a supertrait)"
),
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 \

View file

@ -985,8 +985,50 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
no_dups.then_some(list)
});
let do_not_implement_via_object = tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object);
let deny_explicit_impl = tcx.has_attr(def_id, sym::rustc_deny_explicit_impl);
let mut deny_explicit_impl = false;
let mut implement_via_object = true;
if let Some(attr) = tcx.get_attr(def_id, sym::rustc_deny_explicit_impl) {
deny_explicit_impl = true;
let mut seen_attr = false;
for meta in attr.meta_item_list().iter().flatten() {
if let Some(meta) = meta.meta_item()
&& meta.name_or_empty() == sym::implement_via_object
&& let Some(lit) = meta.name_value_literal()
{
if seen_attr {
tcx.sess.span_err(
meta.span,
"duplicated `implement_via_object` meta item",
);
}
seen_attr = true;
match lit.symbol {
kw::True => {
implement_via_object = true;
}
kw::False => {
implement_via_object = false;
}
_ => {
tcx.sess.span_err(
meta.span,
format!("unknown literal passed to `implement_via_object` attribute: {}", lit.symbol),
);
}
}
} else {
tcx.sess.span_err(
meta.span(),
format!("unknown meta item passed to `rustc_deny_explicit_impl` {:?}", meta),
);
}
}
if !seen_attr {
tcx.sess.span_err(attr.span, "missing `implement_via_object` meta item");
}
}
ty::TraitDef {
def_id: def_id.to_def_id(),

View file

@ -53,12 +53,14 @@ pub struct TraitDef {
/// must be implemented.
pub must_implement_one_of: Option<Box<[Ident]>>,
/// Whether a type's built-in `dyn Trait: Trait` implementation is explicitly
/// denied. This only applies to built-in trait, and is marked via
/// `#[rustc_do_not_implement_via_object]`.
pub do_not_implement_via_object: bool,
/// Whether to add a builtin `dyn Trait: Trait` implementation.
/// This is enabled for all traits except ones marked with
/// `#[rustc_deny_explicit_impl(implement_via_object = false)]`.
pub implement_via_object: bool,
/// Whether a trait is fully built-in, and any implementation is disallowed.
/// This only applies to built-in traits, and is marked via
/// `#[rustc_deny_explicit_impl(implement_via_object = ...)]`.
pub deny_explicit_impl: bool,
}

View file

@ -102,9 +102,6 @@ passes_const_impl_const_trait =
const `impl`s must be for traits marked with `#[const_trait]`
.note = this trait must be annotated with `#[const_trait]`
passes_const_trait =
attribute should be applied to a trait
passes_continue_labeled_block =
`continue` pointing to a labeled block
.label = labeled blocks cannot be `continue`'d

View file

@ -110,9 +110,6 @@ impl CheckAttrVisitor<'_> {
sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target),
sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
sym::marker => self.check_marker(hir_id, attr, span, target),
sym::rustc_must_implement_one_of => {
self.check_rustc_must_implement_one_of(attr, span, target)
}
sym::target_feature => self.check_target_feature(hir_id, attr, span, target),
sym::thread_local => self.check_thread_local(attr, span, target),
sym::track_caller => {
@ -159,12 +156,14 @@ impl CheckAttrVisitor<'_> {
| sym::rustc_dirty
| sym::rustc_if_this_changed
| sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr),
sym::rustc_coinductive => self.check_rustc_coinductive(&attr, span, target),
sym::rustc_coinductive
| sym::rustc_must_implement_one_of
| sym::rustc_deny_explicit_impl
| sym::const_trait => self.check_must_be_applied_to_trait(&attr, span, target),
sym::cmse_nonsecure_entry => {
self.check_cmse_nonsecure_entry(hir_id, attr, span, target)
}
sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target),
sym::const_trait => self.check_const_trait(attr, span, target),
sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
sym::must_use => self.check_must_use(hir_id, &attr, target),
sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target),
@ -567,25 +566,6 @@ impl CheckAttrVisitor<'_> {
}
}
/// Checks if the `#[rustc_must_implement_one_of]` attribute on a `target` is valid. Returns `true` if valid.
fn check_rustc_must_implement_one_of(
&self,
attr: &Attribute,
span: Span,
target: Target,
) -> bool {
match target {
Target::Trait => true,
_ => {
self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait {
attr_span: attr.span,
defn_span: span,
});
false
}
}
}
/// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid.
fn check_target_feature(
&self,
@ -1591,8 +1571,8 @@ impl CheckAttrVisitor<'_> {
}
}
/// Checks if the `#[rustc_coinductive]` attribute is applied to a trait.
fn check_rustc_coinductive(&self, attr: &Attribute, span: Span, target: Target) -> bool {
/// Checks if the attribute is applied to a trait.
fn check_must_be_applied_to_trait(&self, attr: &Attribute, span: Span, target: Target) -> bool {
match target {
Target::Trait => true,
_ => {
@ -1986,17 +1966,6 @@ impl CheckAttrVisitor<'_> {
}
}
/// `#[const_trait]` only applies to traits.
fn check_const_trait(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
match target {
Target::Trait => true,
_ => {
self.tcx.sess.emit_err(errors::ConstTrait { attr_span: attr.span });
false
}
}
}
fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
match target {
Target::Expression => {

View file

@ -610,13 +610,6 @@ pub struct RustcStdInternalSymbol {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_const_trait)]
pub struct ConstTrait {
#[primary_span]
pub attr_span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_link_ordinal)]
pub struct LinkOrdinal {

View file

@ -817,6 +817,7 @@ symbols! {
impl_trait_in_bindings,
impl_trait_in_fn_trait_return,
impl_trait_projections,
implement_via_object,
implied_by,
import,
import_name_type,
@ -1270,7 +1271,6 @@ symbols! {
rustc_diagnostic_macros,
rustc_dirty,
rustc_do_not_const_check,
rustc_do_not_implement_via_object,
rustc_doc_primitive,
rustc_dummy,
rustc_dump_env_program_clauses,

View file

@ -1586,6 +1586,10 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
let tcx = selcx.tcx();
if !tcx.trait_def(obligation.predicate.trait_def_id(tcx)).implement_via_object {
return;
}
let self_ty = obligation.predicate.self_ty();
let object_ty = selcx.infcx.shallow_resolve(self_ty);
let data = match object_ty.kind() {

View file

@ -554,6 +554,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
"assemble_candidates_from_object_ty",
);
if !self.tcx().trait_def(obligation.predicate.def_id()).implement_via_object {
return;
}
self.infcx.probe(|_snapshot| {
if obligation.has_non_region_late_bound() {
return;