From 6149a83c0bae2976328ec9e433eb0803048c3a1d Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 25 Aug 2018 00:54:41 -0700 Subject: [PATCH] Parse, feature-gate, and validate the #[marker] attribute --- src/librustc/diagnostics.rs | 28 ++++++++++++++++++ src/librustc/hir/check_attr.rs | 29 +++++++++++++++++++ src/librustc_typeck/collect.rs | 3 +- src/libsyntax/feature_gate.rs | 9 ++++++ .../feature-gate-marker_trait_attr.rs | 19 ++++++++++++ .../feature-gate-marker_trait_attr.stderr | 11 +++++++ 6 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs create mode 100644 src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 3318bbd8c87..c82e2111b77 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2116,6 +2116,34 @@ struct Foo; ``` "##, +E0713: r##" +This error indicates that a `#[marker]` attribute was incorrectly placed +on something other than a trait. + +Examples of erroneous code: + +```compile_fail,E0713 +# #![feature(marker_trait_attr)] + +#[marker] +struct Foo { } +``` +"##, + +E0714: r##" +This error indicates that a `#[marker]` attribute had a value. The +`#[marker]` should be empty. + +Examples of erroneous code: + +```compile_fail,E0714 +# #![feature(marker_trait_attr)] + +#[marker(anything)] +trait Foo {} +``` +"##, + } diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 298ef67923a..57fc561a2f4 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -32,6 +32,7 @@ enum Target { Statement, Closure, Static, + Trait, Other, } @@ -45,6 +46,7 @@ impl Target { hir::ItemKind::Const(..) => Target::Const, hir::ItemKind::ForeignMod(..) => Target::ForeignMod, hir::ItemKind::Static(..) => Target::Static, + hir::ItemKind::Trait(..) => Target::Trait, _ => Target::Other, } } @@ -70,6 +72,8 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { self.check_inline(attr, &item.span, target) } else if attr.check_name("non_exhaustive") { self.check_non_exhaustive(attr, item, target) + } else if attr.check_name("marker") { + self.check_marker(attr, item, target) } } @@ -114,6 +118,31 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { } } + /// Check if the `#[marker]` attribute on an `item` is valid. + fn check_marker(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) { + match target { + Target::Trait => { /* Valid */ }, + _ => { + struct_span_err!(self.tcx.sess, + attr.span, + E0713, + "attribute can only be applied to a trait") + .span_label(item.span, "not a trait") + .emit(); + return; + } + } + + if attr.meta_item_list().is_some() || attr.value_str().is_some() { + struct_span_err!(self.tcx.sess, + attr.span, + E0714, + "attribute should be empty") + .span_label(item.span, "not empty") + .emit(); + } + } + /// Check if the `#[repr]` attributes on `item` are valid. fn check_repr(&self, item: &hir::Item, target: Target) { // Extract the names of all repr hints, e.g., [foo, bar, align] for: diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 5892296102c..507ed594789 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -735,8 +735,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty:: err.emit(); } - let is_marker = false; // FIXME (scottmcm) - + let is_marker = tcx.has_attr(def_id, "marker"); let def_path_hash = tcx.def_path_hash(def_id); let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, is_auto, is_marker, def_path_hash); tcx.alloc_trait_def(def) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7266d807d3b..8f7f9cac447 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -355,6 +355,9 @@ declare_features! ( // Allows overlapping impls of marker traits (active, overlapping_marker_traits, "1.18.0", Some(29864), None), + // Trait attribute to allow overlapping impls + (active, marker_trait_attr, "1.30.0", Some(29864), None), + // rustc internal (active, abi_thiscall, "1.19.0", None, None), @@ -805,6 +808,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "non exhaustive is an experimental feature", cfg_fn!(non_exhaustive))), + // RFC #1268 + ("marker", Normal, Gated(Stability::Unstable, + "marker_trait_attr", + "marker traits is an experimental feature", + cfg_fn!(marker_trait_attr))), + ("plugin", CrateLevel, Gated(Stability::Unstable, "plugin", "compiler plugins are experimental \ diff --git a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs new file mode 100644 index 00000000000..508ffe3845b --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs @@ -0,0 +1,19 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt::{Debug, Display}; + +#[marker] trait ExplicitMarker {} +//~^ ERROR marker traits is an experimental feature (see issue #29864) + +impl ExplicitMarker for T {} +impl ExplicitMarker for T {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr new file mode 100644 index 00000000000..4023a04000a --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr @@ -0,0 +1,11 @@ +error[E0658]: marker traits is an experimental feature (see issue #29864) + --> $DIR/feature-gate-marker_trait_attr.rs:13:1 + | +LL | #[marker] trait ExplicitMarker {} + | ^^^^^^^^^ + | + = help: add #![feature(marker_trait_attr)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`.