Parse, feature-gate, and validate the #[marker] attribute
This commit is contained in:
parent
62c6e4e145
commit
6149a83c0b
@ -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 {}
|
||||||
|
```
|
||||||
|
"##,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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)
|
||||||
|
@ -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 \
|
||||||
|
19
src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs
Normal file
19
src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs
Normal 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() {}
|
@ -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`.
|
Loading…
x
Reference in New Issue
Block a user