Parse, feature-gate, and validate the #[marker] attribute

This commit is contained in:
Scott McMurray 2018-08-25 00:54:41 -07:00
parent 62c6e4e145
commit 6149a83c0b
6 changed files with 97 additions and 2 deletions

View File

@ -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 {}
```
"##,
} }

View File

@ -32,6 +32,7 @@ enum Target {
Statement, Statement,
Closure, Closure,
Static, Static,
Trait,
Other, Other,
} }
@ -45,6 +46,7 @@ impl Target {
hir::ItemKind::Const(..) => Target::Const, hir::ItemKind::Const(..) => Target::Const,
hir::ItemKind::ForeignMod(..) => Target::ForeignMod, hir::ItemKind::ForeignMod(..) => Target::ForeignMod,
hir::ItemKind::Static(..) => Target::Static, hir::ItemKind::Static(..) => Target::Static,
hir::ItemKind::Trait(..) => Target::Trait,
_ => Target::Other, _ => Target::Other,
} }
} }
@ -70,6 +72,8 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
self.check_inline(attr, &item.span, target) self.check_inline(attr, &item.span, target)
} else if attr.check_name("non_exhaustive") { } else if attr.check_name("non_exhaustive") {
self.check_non_exhaustive(attr, item, target) 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. /// Check if the `#[repr]` attributes on `item` are valid.
fn check_repr(&self, item: &hir::Item, target: Target) { fn check_repr(&self, item: &hir::Item, target: Target) {
// Extract the names of all repr hints, e.g., [foo, bar, align] for: // Extract the names of all repr hints, e.g., [foo, bar, align] for:

View File

@ -735,8 +735,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::
err.emit(); 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_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); let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, is_auto, is_marker, def_path_hash);
tcx.alloc_trait_def(def) tcx.alloc_trait_def(def)

View File

@ -355,6 +355,9 @@ declare_features! (
// Allows overlapping impls of marker traits // Allows overlapping impls of marker traits
(active, overlapping_marker_traits, "1.18.0", Some(29864), None), (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 // rustc internal
(active, abi_thiscall, "1.19.0", None, None), (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", "non exhaustive is an experimental feature",
cfg_fn!(non_exhaustive))), 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", CrateLevel, Gated(Stability::Unstable,
"plugin", "plugin",
"compiler plugins are experimental \ "compiler plugins are experimental \

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T: Display> ExplicitMarker for T {}
impl<T: Debug> ExplicitMarker for T {}
fn main() {}

View File

@ -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`.