mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
expand/resolve: Turn #[derive]
into a regular macro attribute
This commit is contained in:
parent
ae00b62ceb
commit
dbdbd30bf2
@ -3582,6 +3582,7 @@ dependencies = [
|
|||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_expand",
|
"rustc_expand",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
|
"rustc_lexer",
|
||||||
"rustc_parse",
|
"rustc_parse",
|
||||||
"rustc_parse_format",
|
"rustc_parse_format",
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
|
@ -15,6 +15,7 @@ rustc_attr = { path = "../rustc_attr" }
|
|||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_feature = { path = "../rustc_feature" }
|
rustc_feature = { path = "../rustc_feature" }
|
||||||
|
rustc_lexer = { path = "../rustc_lexer" }
|
||||||
rustc_parse = { path = "../rustc_parse" }
|
rustc_parse = { path = "../rustc_parse" }
|
||||||
rustc_target = { path = "../rustc_target" }
|
rustc_target = { path = "../rustc_target" }
|
||||||
rustc_session = { path = "../rustc_session" }
|
rustc_session = { path = "../rustc_session" }
|
||||||
|
132
compiler/rustc_builtin_macros/src/derive.rs
Normal file
132
compiler/rustc_builtin_macros/src/derive.rs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
use rustc_ast::{self as ast, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
|
||||||
|
use rustc_errors::{struct_span_err, Applicability};
|
||||||
|
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
|
||||||
|
use rustc_expand::config::StripUnconfigured;
|
||||||
|
use rustc_feature::AttributeTemplate;
|
||||||
|
use rustc_parse::validate_attr;
|
||||||
|
use rustc_session::Session;
|
||||||
|
use rustc_span::symbol::sym;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
crate struct Expander;
|
||||||
|
|
||||||
|
impl MultiItemModifier for Expander {
|
||||||
|
fn expand(
|
||||||
|
&self,
|
||||||
|
ecx: &mut ExtCtxt<'_>,
|
||||||
|
span: Span,
|
||||||
|
meta_item: &ast::MetaItem,
|
||||||
|
item: Annotatable,
|
||||||
|
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
|
||||||
|
let sess = ecx.sess;
|
||||||
|
if report_bad_target(sess, &item, span) {
|
||||||
|
// We don't want to pass inappropriate targets to derive macros to avoid
|
||||||
|
// follow up errors, all other errors below are recoverable.
|
||||||
|
return ExpandResult::Ready(vec![item]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let template =
|
||||||
|
AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() };
|
||||||
|
let attr = ecx.attribute(meta_item.clone());
|
||||||
|
validate_attr::check_builtin_attribute(&sess.parse_sess, &attr, sym::derive, template);
|
||||||
|
|
||||||
|
let derives: Vec<_> = attr
|
||||||
|
.meta_item_list()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|nested_meta| match nested_meta {
|
||||||
|
NestedMetaItem::MetaItem(meta) => Some(meta),
|
||||||
|
NestedMetaItem::Literal(lit) => {
|
||||||
|
// Reject `#[derive("Debug")]`.
|
||||||
|
report_unexpected_literal(sess, &lit);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|meta| {
|
||||||
|
// Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the paths.
|
||||||
|
report_path_args(sess, &meta);
|
||||||
|
meta.path
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// FIXME: Try to cache intermediate results to avoid collecting same paths multiple times.
|
||||||
|
match ecx.resolver.resolve_derives(ecx.current_expansion.id, derives, ecx.force_mode) {
|
||||||
|
Ok(()) => {
|
||||||
|
let mut visitor =
|
||||||
|
StripUnconfigured { sess, features: ecx.ecfg.features, modified: false };
|
||||||
|
let mut item = visitor.fully_configure(item);
|
||||||
|
if visitor.modified {
|
||||||
|
// Erase the tokens if cfg-stripping modified the item
|
||||||
|
// This will cause us to synthesize fake tokens
|
||||||
|
// when `nt_to_tokenstream` is called on this item.
|
||||||
|
match &mut item {
|
||||||
|
Annotatable::Item(item) => item,
|
||||||
|
Annotatable::Stmt(stmt) => match &mut stmt.kind {
|
||||||
|
StmtKind::Item(item) => item,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
.tokens = None;
|
||||||
|
}
|
||||||
|
ExpandResult::Ready(vec![item])
|
||||||
|
}
|
||||||
|
Err(Indeterminate) => ExpandResult::Retry(item),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
|
||||||
|
let item_kind = match item {
|
||||||
|
Annotatable::Item(item) => Some(&item.kind),
|
||||||
|
Annotatable::Stmt(stmt) => match &stmt.kind {
|
||||||
|
StmtKind::Item(item) => Some(&item.kind),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let bad_target =
|
||||||
|
!matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..)));
|
||||||
|
if bad_target {
|
||||||
|
struct_span_err!(
|
||||||
|
sess,
|
||||||
|
span,
|
||||||
|
E0774,
|
||||||
|
"`derive` may only be applied to structs, enums and unions",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
bad_target
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_unexpected_literal(sess: &Session, lit: &ast::Lit) {
|
||||||
|
let help_msg = match lit.token.kind {
|
||||||
|
token::Str if rustc_lexer::is_ident(&lit.token.symbol.as_str()) => {
|
||||||
|
format!("try using `#[derive({})]`", lit.token.symbol)
|
||||||
|
}
|
||||||
|
_ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(),
|
||||||
|
};
|
||||||
|
struct_span_err!(sess, lit.span, E0777, "expected path to a trait, found literal",)
|
||||||
|
.help(&help_msg)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
|
||||||
|
let report_error = |title, action| {
|
||||||
|
let span = meta.span.with_lo(meta.path.span.hi());
|
||||||
|
sess.struct_span_err(span, title)
|
||||||
|
.span_suggestion(span, action, String::new(), Applicability::MachineApplicable)
|
||||||
|
.emit();
|
||||||
|
};
|
||||||
|
match meta.kind {
|
||||||
|
MetaItemKind::Word => {}
|
||||||
|
MetaItemKind::List(..) => report_error(
|
||||||
|
"traits in `#[derive(...)]` don't accept arguments",
|
||||||
|
"remove the arguments",
|
||||||
|
),
|
||||||
|
MetaItemKind::NameValue(..) => {
|
||||||
|
report_error("traits in `#[derive(...)]` don't accept values", "remove the value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,7 @@ mod cfg_accessible;
|
|||||||
mod compile_error;
|
mod compile_error;
|
||||||
mod concat;
|
mod concat;
|
||||||
mod concat_idents;
|
mod concat_idents;
|
||||||
|
mod derive;
|
||||||
mod deriving;
|
mod deriving;
|
||||||
mod env;
|
mod env;
|
||||||
mod format;
|
mod format;
|
||||||
@ -88,6 +89,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
|||||||
register_attr! {
|
register_attr! {
|
||||||
bench: test::expand_bench,
|
bench: test::expand_bench,
|
||||||
cfg_accessible: cfg_accessible::Expander,
|
cfg_accessible: cfg_accessible::Expander,
|
||||||
|
derive: derive::Expander,
|
||||||
global_allocator: global_allocator::expand,
|
global_allocator: global_allocator::expand,
|
||||||
test: test::expand_test,
|
test: test::expand_test,
|
||||||
test_case: test::expand_test_case,
|
test_case: test::expand_test_case,
|
||||||
|
@ -141,7 +141,7 @@ impl Annotatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
|
crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
|
||||||
nt_to_tokenstream(&self.into_nonterminal(), sess, CanSynthesizeMissingTokens::No)
|
nt_to_tokenstream(&self.into_nonterminal(), sess, CanSynthesizeMissingTokens::Yes)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_item(self) -> P<ast::Item> {
|
pub fn expect_item(self) -> P<ast::Item> {
|
||||||
@ -234,25 +234,6 @@ impl Annotatable {
|
|||||||
_ => panic!("expected variant"),
|
_ => panic!("expected variant"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn derive_allowed(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
Annotatable::Stmt(ref stmt) => match stmt.kind {
|
|
||||||
ast::StmtKind::Item(ref item) => matches!(
|
|
||||||
item.kind,
|
|
||||||
ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..)
|
|
||||||
),
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
Annotatable::Item(ref item) => match item.kind {
|
|
||||||
ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Result of an expansion that may need to be retried.
|
/// Result of an expansion that may need to be retried.
|
||||||
@ -854,12 +835,6 @@ impl SyntaxExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Result of resolving a macro invocation.
|
|
||||||
pub enum InvocationRes {
|
|
||||||
Single(Lrc<SyntaxExtension>),
|
|
||||||
DeriveContainer(Vec<Lrc<SyntaxExtension>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Error type that denotes indeterminacy.
|
/// Error type that denotes indeterminacy.
|
||||||
pub struct Indeterminate;
|
pub struct Indeterminate;
|
||||||
|
|
||||||
@ -885,16 +860,29 @@ pub trait ResolverExpand {
|
|||||||
invoc: &Invocation,
|
invoc: &Invocation,
|
||||||
eager_expansion_root: ExpnId,
|
eager_expansion_root: ExpnId,
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> Result<InvocationRes, Indeterminate>;
|
) -> Result<Lrc<SyntaxExtension>, Indeterminate>;
|
||||||
|
|
||||||
fn check_unused_macros(&mut self);
|
fn check_unused_macros(&mut self);
|
||||||
|
|
||||||
/// Some parent node that is close enough to the given macro call.
|
/// Some parent node that is close enough to the given macro call.
|
||||||
fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId;
|
fn lint_node_id(&self, expn_id: ExpnId) -> NodeId;
|
||||||
|
|
||||||
// Resolver interfaces for specific built-in macros.
|
// Resolver interfaces for specific built-in macros.
|
||||||
/// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it?
|
/// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it?
|
||||||
fn has_derive_copy(&self, expn_id: ExpnId) -> bool;
|
fn has_derive_copy(&self, expn_id: ExpnId) -> bool;
|
||||||
|
/// Resolve paths inside the `#[derive(...)]` attribute with the given `ExpnId`.
|
||||||
|
fn resolve_derives(
|
||||||
|
&mut self,
|
||||||
|
expn_id: ExpnId,
|
||||||
|
derives: Vec<ast::Path>,
|
||||||
|
force: bool,
|
||||||
|
) -> Result<(), Indeterminate>;
|
||||||
|
/// Take resolutions for paths inside the `#[derive(...)]` attribute with the given `ExpnId`
|
||||||
|
/// back from resolver.
|
||||||
|
fn take_derive_resolutions(
|
||||||
|
&mut self,
|
||||||
|
expn_id: ExpnId,
|
||||||
|
) -> Option<Vec<(Lrc<SyntaxExtension>, ast::Path)>>;
|
||||||
/// Path resolution logic for `#[cfg_accessible(path)]`.
|
/// Path resolution logic for `#[cfg_accessible(path)]`.
|
||||||
fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate>;
|
fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate>;
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,26 @@
|
|||||||
use crate::base::*;
|
use crate::base::*;
|
||||||
use crate::config::StripUnconfigured;
|
use crate::config::StripUnconfigured;
|
||||||
use crate::configure;
|
use crate::configure;
|
||||||
use crate::hygiene::{ExpnData, ExpnKind, SyntaxContext};
|
use crate::hygiene::SyntaxContext;
|
||||||
use crate::mbe::macro_rules::annotate_err_with_kind;
|
use crate::mbe::macro_rules::annotate_err_with_kind;
|
||||||
use crate::module::{parse_external_mod, push_directory, Directory, DirectoryOwnership};
|
use crate::module::{parse_external_mod, push_directory, Directory, DirectoryOwnership};
|
||||||
use crate::placeholders::{placeholder, PlaceholderExpander};
|
use crate::placeholders::{placeholder, PlaceholderExpander};
|
||||||
use crate::proc_macro::collect_derives;
|
|
||||||
|
|
||||||
|
use rustc_ast as ast;
|
||||||
use rustc_ast::mut_visit::*;
|
use rustc_ast::mut_visit::*;
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token;
|
use rustc_ast::token;
|
||||||
use rustc_ast::tokenstream::TokenStream;
|
use rustc_ast::tokenstream::TokenStream;
|
||||||
use rustc_ast::visit::{self, AssocCtxt, Visitor};
|
use rustc_ast::visit::{self, AssocCtxt, Visitor};
|
||||||
use rustc_ast::{self as ast, AttrItem, AttrStyle, Block, LitKind, NodeId, PatKind, Path};
|
use rustc_ast::{AttrItem, AttrStyle, Block, ItemKind, LitKind, MacArgs};
|
||||||
use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind, Unsafe};
|
use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, NestedMetaItem};
|
||||||
|
use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
|
use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
|
||||||
use rustc_data_structures::map_in_place::MapInPlace;
|
use rustc_data_structures::map_in_place::MapInPlace;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_errors::{struct_span_err, Applicability, PResult};
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
use rustc_errors::{Applicability, PResult};
|
||||||
use rustc_feature::Features;
|
use rustc_feature::Features;
|
||||||
use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser};
|
use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser};
|
||||||
use rustc_parse::validate_attr;
|
use rustc_parse::validate_attr;
|
||||||
@ -302,20 +304,11 @@ pub enum InvocationKind {
|
|||||||
item: Annotatable,
|
item: Annotatable,
|
||||||
// Required for resolving derive helper attributes.
|
// Required for resolving derive helper attributes.
|
||||||
derives: Vec<Path>,
|
derives: Vec<Path>,
|
||||||
// We temporarily report errors for attribute macros placed after derives
|
|
||||||
after_derive: bool,
|
|
||||||
},
|
},
|
||||||
Derive {
|
Derive {
|
||||||
path: Path,
|
path: Path,
|
||||||
item: Annotatable,
|
item: Annotatable,
|
||||||
},
|
},
|
||||||
/// "Invocation" that contains all derives from an item,
|
|
||||||
/// broken into multiple `Derive` invocations when expanded.
|
|
||||||
/// FIXME: Find a way to remove it.
|
|
||||||
DeriveContainer {
|
|
||||||
derives: Vec<Path>,
|
|
||||||
item: Annotatable,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InvocationKind {
|
impl InvocationKind {
|
||||||
@ -328,7 +321,6 @@ impl InvocationKind {
|
|||||||
match self {
|
match self {
|
||||||
InvocationKind::Attr { item: Annotatable::StructField(field), .. }
|
InvocationKind::Attr { item: Annotatable::StructField(field), .. }
|
||||||
| InvocationKind::Derive { item: Annotatable::StructField(field), .. }
|
| InvocationKind::Derive { item: Annotatable::StructField(field), .. }
|
||||||
| InvocationKind::DeriveContainer { item: Annotatable::StructField(field), .. }
|
|
||||||
if field.ident.is_none() =>
|
if field.ident.is_none() =>
|
||||||
{
|
{
|
||||||
Some(field.vis.clone())
|
Some(field.vis.clone())
|
||||||
@ -344,7 +336,6 @@ impl Invocation {
|
|||||||
InvocationKind::Bang { span, .. } => *span,
|
InvocationKind::Bang { span, .. } => *span,
|
||||||
InvocationKind::Attr { attr, .. } => attr.span,
|
InvocationKind::Attr { attr, .. } => attr.span,
|
||||||
InvocationKind::Derive { path, .. } => path.span,
|
InvocationKind::Derive { path, .. } => path.span,
|
||||||
InvocationKind::DeriveContainer { item, .. } => item.span(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -446,7 +437,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
let mut undetermined_invocations = Vec::new();
|
let mut undetermined_invocations = Vec::new();
|
||||||
let (mut progress, mut force) = (false, !self.monotonic);
|
let (mut progress, mut force) = (false, !self.monotonic);
|
||||||
loop {
|
loop {
|
||||||
let (invoc, res) = if let Some(invoc) = invocations.pop() {
|
let (invoc, ext) = if let Some(invoc) = invocations.pop() {
|
||||||
invoc
|
invoc
|
||||||
} else {
|
} else {
|
||||||
self.resolve_imports();
|
self.resolve_imports();
|
||||||
@ -464,8 +455,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let res = match res {
|
let ext = match ext {
|
||||||
Some(res) => res,
|
Some(ext) => ext,
|
||||||
None => {
|
None => {
|
||||||
let eager_expansion_root = if self.monotonic {
|
let eager_expansion_root = if self.monotonic {
|
||||||
invoc.expansion_data.id
|
invoc.expansion_data.id
|
||||||
@ -477,7 +468,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
eager_expansion_root,
|
eager_expansion_root,
|
||||||
force,
|
force,
|
||||||
) {
|
) {
|
||||||
Ok(res) => res,
|
Ok(ext) => ext,
|
||||||
Err(Indeterminate) => {
|
Err(Indeterminate) => {
|
||||||
// Cannot resolve, will retry this invocation later.
|
// Cannot resolve, will retry this invocation later.
|
||||||
undetermined_invocations.push((invoc, None));
|
undetermined_invocations.push((invoc, None));
|
||||||
@ -491,86 +482,78 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
self.cx.current_expansion = invoc.expansion_data.clone();
|
self.cx.current_expansion = invoc.expansion_data.clone();
|
||||||
self.cx.force_mode = force;
|
self.cx.force_mode = force;
|
||||||
|
|
||||||
// FIXME(jseyfried): Refactor out the following logic
|
|
||||||
let fragment_kind = invoc.fragment_kind;
|
let fragment_kind = invoc.fragment_kind;
|
||||||
let (expanded_fragment, new_invocations) = match res {
|
let (expanded_fragment, new_invocations) = match self.expand_invoc(invoc, &ext.kind) {
|
||||||
InvocationRes::Single(ext) => match self.expand_invoc(invoc, &ext.kind) {
|
ExpandResult::Ready(fragment) => {
|
||||||
ExpandResult::Ready(fragment) => self.collect_invocations(fragment, &[]),
|
let derive_placeholders = self
|
||||||
ExpandResult::Retry(invoc) => {
|
.cx
|
||||||
if force {
|
.resolver
|
||||||
self.cx.span_bug(
|
.take_derive_resolutions(expn_id)
|
||||||
invoc.span(),
|
.map(|derives| {
|
||||||
"expansion entered force mode but is still stuck",
|
enum AnnotatableRef<'a> {
|
||||||
);
|
Item(&'a P<ast::Item>),
|
||||||
} else {
|
Stmt(&'a ast::Stmt),
|
||||||
// Cannot expand, will retry this invocation later.
|
|
||||||
undetermined_invocations
|
|
||||||
.push((invoc, Some(InvocationRes::Single(ext))));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
InvocationRes::DeriveContainer(_exts) => {
|
|
||||||
// FIXME: Consider using the derive resolutions (`_exts`) immediately,
|
|
||||||
// instead of enqueuing the derives to be resolved again later.
|
|
||||||
let (derives, mut item) = match invoc.kind {
|
|
||||||
InvocationKind::DeriveContainer { derives, item } => (derives, item),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let (item, derive_placeholders) = if !item.derive_allowed() {
|
|
||||||
self.error_derive_forbidden_on_non_adt(&derives, &item);
|
|
||||||
item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
|
|
||||||
(item, Vec::new())
|
|
||||||
} else {
|
|
||||||
let mut visitor = StripUnconfigured {
|
|
||||||
sess: self.cx.sess,
|
|
||||||
features: self.cx.ecfg.features,
|
|
||||||
modified: false,
|
|
||||||
};
|
|
||||||
let mut item = visitor.fully_configure(item);
|
|
||||||
item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
|
|
||||||
if visitor.modified && !derives.is_empty() {
|
|
||||||
// Erase the tokens if cfg-stripping modified the item
|
|
||||||
// This will cause us to synthesize fake tokens
|
|
||||||
// when `nt_to_tokenstream` is called on this item.
|
|
||||||
match &mut item {
|
|
||||||
Annotatable::Item(item) => item.tokens = None,
|
|
||||||
Annotatable::Stmt(stmt) => {
|
|
||||||
if let StmtKind::Item(item) = &mut stmt.kind {
|
|
||||||
item.tokens = None
|
|
||||||
} else {
|
|
||||||
panic!("Unexpected stmt {:?}", stmt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => panic!("Unexpected annotatable {:?}", item),
|
|
||||||
}
|
}
|
||||||
}
|
let item = match &fragment {
|
||||||
|
AstFragment::Items(items) => match &items[..] {
|
||||||
|
[item] => AnnotatableRef::Item(item),
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
AstFragment::Stmts(stmts) => match &stmts[..] {
|
||||||
|
[stmt] => AnnotatableRef::Stmt(stmt),
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
invocations.reserve(derives.len());
|
invocations.reserve(derives.len());
|
||||||
let derive_placeholders = derives
|
derives
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|path| {
|
.map(|(_exts, path)| {
|
||||||
let expn_id = ExpnId::fresh(None);
|
// FIXME: Consider using the derive resolutions (`_exts`)
|
||||||
invocations.push((
|
// instead of enqueuing the derives to be resolved again later.
|
||||||
Invocation {
|
let expn_id = ExpnId::fresh(None);
|
||||||
kind: InvocationKind::Derive { path, item: item.clone() },
|
invocations.push((
|
||||||
fragment_kind,
|
Invocation {
|
||||||
expansion_data: ExpansionData {
|
kind: InvocationKind::Derive {
|
||||||
id: expn_id,
|
path,
|
||||||
..self.cx.current_expansion.clone()
|
item: match item {
|
||||||
|
AnnotatableRef::Item(item) => {
|
||||||
|
Annotatable::Item(item.clone())
|
||||||
|
}
|
||||||
|
AnnotatableRef::Stmt(stmt) => {
|
||||||
|
Annotatable::Stmt(P(stmt.clone()))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fragment_kind,
|
||||||
|
expansion_data: ExpansionData {
|
||||||
|
id: expn_id,
|
||||||
|
..self.cx.current_expansion.clone()
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
None,
|
||||||
None,
|
));
|
||||||
));
|
NodeId::placeholder_from_expn_id(expn_id)
|
||||||
NodeId::placeholder_from_expn_id(expn_id)
|
})
|
||||||
})
|
.collect::<Vec<_>>()
|
||||||
.collect::<Vec<_>>();
|
})
|
||||||
(item, derive_placeholders)
|
.unwrap_or_default();
|
||||||
};
|
|
||||||
|
|
||||||
let fragment = fragment_kind.expect_from_annotatables(::std::iter::once(item));
|
|
||||||
self.collect_invocations(fragment, &derive_placeholders)
|
self.collect_invocations(fragment, &derive_placeholders)
|
||||||
}
|
}
|
||||||
|
ExpandResult::Retry(invoc) => {
|
||||||
|
if force {
|
||||||
|
self.cx.span_bug(
|
||||||
|
invoc.span(),
|
||||||
|
"expansion entered force mode but is still stuck",
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Cannot expand, will retry this invocation later.
|
||||||
|
undetermined_invocations.push((invoc, Some(ext)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
progress = true;
|
progress = true;
|
||||||
@ -596,29 +579,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
fragment_with_placeholders
|
fragment_with_placeholders
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) {
|
|
||||||
let attr = self.cx.sess.find_by_name(item.attrs(), sym::derive);
|
|
||||||
let span = attr.map_or(item.span(), |attr| attr.span);
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
self.cx.sess,
|
|
||||||
span,
|
|
||||||
E0774,
|
|
||||||
"`derive` may only be applied to structs, enums and unions",
|
|
||||||
);
|
|
||||||
if let Some(ast::Attribute { style: ast::AttrStyle::Inner, .. }) = attr {
|
|
||||||
let trait_list = derives.iter().map(|t| pprust::path_to_string(t)).collect::<Vec<_>>();
|
|
||||||
let suggestion = format!("#[derive({})]", trait_list.join(", "));
|
|
||||||
err.span_suggestion(
|
|
||||||
span,
|
|
||||||
"try an outer attribute",
|
|
||||||
suggestion,
|
|
||||||
// We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_imports(&mut self) {
|
fn resolve_imports(&mut self) {
|
||||||
if self.monotonic {
|
if self.monotonic {
|
||||||
self.cx.resolver.resolve_imports();
|
self.cx.resolver.resolve_imports();
|
||||||
@ -633,7 +593,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
mut fragment: AstFragment,
|
mut fragment: AstFragment,
|
||||||
extra_placeholders: &[NodeId],
|
extra_placeholders: &[NodeId],
|
||||||
) -> (AstFragment, Vec<(Invocation, Option<InvocationRes>)>) {
|
) -> (AstFragment, Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>) {
|
||||||
// Resolve `$crate`s in the fragment for pretty-printing.
|
// Resolve `$crate`s in the fragment for pretty-printing.
|
||||||
self.cx.resolver.resolve_dollar_crates();
|
self.cx.resolver.resolve_dollar_crates();
|
||||||
|
|
||||||
@ -733,7 +693,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
InvocationKind::Attr { attr, mut item, derives, after_derive } => match ext {
|
InvocationKind::Attr { attr, mut item, derives } => match ext {
|
||||||
SyntaxExtensionKind::Attr(expander) => {
|
SyntaxExtensionKind::Attr(expander) => {
|
||||||
self.gate_proc_macro_input(&item);
|
self.gate_proc_macro_input(&item);
|
||||||
self.gate_proc_macro_attr_item(span, &item);
|
self.gate_proc_macro_attr_item(span, &item);
|
||||||
@ -764,12 +724,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
ExpandResult::Retry(item) => {
|
ExpandResult::Retry(item) => {
|
||||||
// Reassemble the original invocation for retrying.
|
// Reassemble the original invocation for retrying.
|
||||||
return ExpandResult::Retry(Invocation {
|
return ExpandResult::Retry(Invocation {
|
||||||
kind: InvocationKind::Attr {
|
kind: InvocationKind::Attr { attr, item, derives },
|
||||||
attr,
|
|
||||||
item,
|
|
||||||
derives,
|
|
||||||
after_derive,
|
|
||||||
},
|
|
||||||
..invoc
|
..invoc
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -813,7 +768,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
InvocationKind::DeriveContainer { .. } => unreachable!(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1011,29 +965,13 @@ pub fn ensure_complete_parse<'a>(
|
|||||||
struct InvocationCollector<'a, 'b> {
|
struct InvocationCollector<'a, 'b> {
|
||||||
cx: &'a mut ExtCtxt<'b>,
|
cx: &'a mut ExtCtxt<'b>,
|
||||||
cfg: StripUnconfigured<'a>,
|
cfg: StripUnconfigured<'a>,
|
||||||
invocations: Vec<(Invocation, Option<InvocationRes>)>,
|
invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>,
|
||||||
monotonic: bool,
|
monotonic: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> InvocationCollector<'a, 'b> {
|
impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||||
fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
|
fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
|
||||||
// Expansion data for all the collected invocations is set upon their resolution,
|
let expn_id = ExpnId::fresh(None);
|
||||||
// with exception of the derive container case which is not resolved and can get
|
|
||||||
// its expansion data immediately.
|
|
||||||
let expn_data = match &kind {
|
|
||||||
InvocationKind::DeriveContainer { item, .. } => {
|
|
||||||
let mut expn_data = ExpnData::default(
|
|
||||||
ExpnKind::Macro(MacroKind::Attr, sym::derive),
|
|
||||||
item.span(),
|
|
||||||
self.cx.sess.parse_sess.edition,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
expn_data.parent = self.cx.current_expansion.id;
|
|
||||||
Some(expn_data)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
let expn_id = ExpnId::fresh(expn_data);
|
|
||||||
let vis = kind.placeholder_visibility();
|
let vis = kind.placeholder_visibility();
|
||||||
self.invocations.push((
|
self.invocations.push((
|
||||||
Invocation {
|
Invocation {
|
||||||
@ -1061,64 +999,44 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||||||
|
|
||||||
fn collect_attr(
|
fn collect_attr(
|
||||||
&mut self,
|
&mut self,
|
||||||
(attr, derives, after_derive): (Option<ast::Attribute>, Vec<Path>, bool),
|
(attr, derives): (ast::Attribute, Vec<Path>),
|
||||||
item: Annotatable,
|
item: Annotatable,
|
||||||
kind: AstFragmentKind,
|
kind: AstFragmentKind,
|
||||||
) -> AstFragment {
|
) -> AstFragment {
|
||||||
self.collect(
|
self.collect(kind, InvocationKind::Attr { attr, item, derives })
|
||||||
kind,
|
|
||||||
match attr {
|
|
||||||
Some(attr) => InvocationKind::Attr { attr, item, derives, after_derive },
|
|
||||||
None => InvocationKind::DeriveContainer { derives, item },
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_attr_invoc(
|
/// If `item` is an attribute invocation, remove the attribute and return it together with
|
||||||
&self,
|
/// derives following it. We have to collect the derives in order to resolve legacy derive
|
||||||
attrs: &mut Vec<ast::Attribute>,
|
/// helpers (helpers written before derives that introduce them).
|
||||||
after_derive: &mut bool,
|
fn take_first_attr(&mut self, item: &mut impl HasAttrs) -> Option<(ast::Attribute, Vec<Path>)> {
|
||||||
) -> Option<ast::Attribute> {
|
let mut attr = None;
|
||||||
attrs
|
|
||||||
.iter()
|
|
||||||
.position(|a| {
|
|
||||||
if a.has_name(sym::derive) {
|
|
||||||
*after_derive = true;
|
|
||||||
}
|
|
||||||
!self.cx.sess.is_attr_known(a) && !is_builtin_attr(a)
|
|
||||||
})
|
|
||||||
.map(|i| attrs.remove(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
|
item.visit_attrs(|attrs| {
|
||||||
fn take_first_attr(
|
attr = attrs
|
||||||
&mut self,
|
.iter()
|
||||||
item: &mut impl HasAttrs,
|
.position(|a| !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a))
|
||||||
) -> Option<(Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)> {
|
.map(|attr_pos| {
|
||||||
let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false);
|
let attr = attrs.remove(attr_pos);
|
||||||
|
let following_derives = attrs[attr_pos..]
|
||||||
|
.iter()
|
||||||
|
.filter(|a| a.has_name(sym::derive))
|
||||||
|
.flat_map(|a| a.meta_item_list().unwrap_or_default())
|
||||||
|
.filter_map(|nested_meta| match nested_meta {
|
||||||
|
NestedMetaItem::MetaItem(ast::MetaItem {
|
||||||
|
kind: MetaItemKind::Word,
|
||||||
|
path,
|
||||||
|
..
|
||||||
|
}) => Some(path),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
item.visit_attrs(|mut attrs| {
|
(attr, following_derives)
|
||||||
attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
|
})
|
||||||
traits = collect_derives(&mut self.cx, &mut attrs);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if attr.is_some() || !traits.is_empty() { Some((attr, traits, after_derive)) } else { None }
|
attr
|
||||||
}
|
|
||||||
|
|
||||||
/// Alternative to `take_first_attr()` that ignores `#[derive]` so invocations fallthrough
|
|
||||||
/// to the unused-attributes lint (making it an error on statements and expressions
|
|
||||||
/// is a breaking change)
|
|
||||||
fn take_first_attr_no_derive(
|
|
||||||
&mut self,
|
|
||||||
nonitem: &mut impl HasAttrs,
|
|
||||||
) -> Option<(Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)> {
|
|
||||||
let (mut attr, mut after_derive) = (None, false);
|
|
||||||
|
|
||||||
nonitem.visit_attrs(|mut attrs| {
|
|
||||||
attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
|
|
||||||
});
|
|
||||||
|
|
||||||
attr.map(|attr| (Some(attr), Vec::new(), after_derive))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
|
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
|
||||||
@ -1132,17 +1050,6 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||||||
for attr in attrs.iter() {
|
for attr in attrs.iter() {
|
||||||
rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
|
rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
|
||||||
validate_attr::check_meta(&self.cx.sess.parse_sess, attr);
|
validate_attr::check_meta(&self.cx.sess.parse_sess, attr);
|
||||||
|
|
||||||
// macros are expanded before any lint passes so this warning has to be hardcoded
|
|
||||||
if attr.has_name(sym::derive) {
|
|
||||||
self.cx
|
|
||||||
.parse_sess()
|
|
||||||
.span_diagnostic
|
|
||||||
.struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations")
|
|
||||||
.note("this may become a hard error in a future release")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
if attr.doc_str().is_some() {
|
if attr.doc_str().is_some() {
|
||||||
self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
|
self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
|
||||||
&UNUSED_DOC_COMMENTS,
|
&UNUSED_DOC_COMMENTS,
|
||||||
@ -1162,12 +1069,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||||||
visit_clobber(expr.deref_mut(), |mut expr| {
|
visit_clobber(expr.deref_mut(), |mut expr| {
|
||||||
self.cfg.configure_expr_kind(&mut expr.kind);
|
self.cfg.configure_expr_kind(&mut expr.kind);
|
||||||
|
|
||||||
if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
|
if let Some(attr) = self.take_first_attr(&mut expr) {
|
||||||
// Collect the invoc regardless of whether or not attributes are permitted here
|
// Collect the invoc regardless of whether or not attributes are permitted here
|
||||||
// expansion will eat the attribute so it won't error later.
|
// expansion will eat the attribute so it won't error later.
|
||||||
if let Some(attr) = attr.0.as_ref() {
|
self.cfg.maybe_emit_expr_attr_err(&attr.0);
|
||||||
self.cfg.maybe_emit_expr_attr_err(attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AstFragmentKind::Expr requires the macro to emit an expression.
|
// AstFragmentKind::Expr requires the macro to emit an expression.
|
||||||
return self
|
return self
|
||||||
@ -1263,10 +1168,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||||||
expr.filter_map(|mut expr| {
|
expr.filter_map(|mut expr| {
|
||||||
self.cfg.configure_expr_kind(&mut expr.kind);
|
self.cfg.configure_expr_kind(&mut expr.kind);
|
||||||
|
|
||||||
if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
|
if let Some(attr) = self.take_first_attr(&mut expr) {
|
||||||
if let Some(attr) = attr.0.as_ref() {
|
self.cfg.maybe_emit_expr_attr_err(&attr.0);
|
||||||
self.cfg.maybe_emit_expr_attr_err(attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
.collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr)
|
.collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr)
|
||||||
@ -1308,15 +1211,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||||||
|
|
||||||
// we'll expand attributes on expressions separately
|
// we'll expand attributes on expressions separately
|
||||||
if !stmt.is_expr() {
|
if !stmt.is_expr() {
|
||||||
let attr = if stmt.is_item() {
|
if let Some(attr) = self.take_first_attr(&mut stmt) {
|
||||||
self.take_first_attr(&mut stmt)
|
|
||||||
} else {
|
|
||||||
// Ignore derives on non-item statements for backwards compatibility.
|
|
||||||
// This will result in a unused attribute warning
|
|
||||||
self.take_first_attr_no_derive(&mut stmt)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(attr) = attr {
|
|
||||||
return self
|
return self
|
||||||
.collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts)
|
.collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts)
|
||||||
.make_stmts();
|
.make_stmts();
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
use crate::base::{self, *};
|
use crate::base::{self, *};
|
||||||
use crate::proc_macro_server;
|
use crate::proc_macro_server;
|
||||||
|
|
||||||
|
use rustc_ast as ast;
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token;
|
use rustc_ast::token;
|
||||||
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
|
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
|
||||||
use rustc_ast::{self as ast, *};
|
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::{struct_span_err, Applicability, ErrorReported};
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_lexer::is_ident;
|
|
||||||
use rustc_parse::nt_to_tokenstream;
|
use rustc_parse::nt_to_tokenstream;
|
||||||
use rustc_parse::parser::ForceCollect;
|
use rustc_parse::parser::ForceCollect;
|
||||||
use rustc_span::symbol::sym;
|
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
|
||||||
const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
|
const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
|
||||||
@ -142,91 +140,3 @@ impl MultiItemModifier for ProcMacroDerive {
|
|||||||
ExpandResult::Ready(items)
|
ExpandResult::Ready(items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
|
|
||||||
let mut result = Vec::new();
|
|
||||||
attrs.retain(|attr| {
|
|
||||||
if !attr.has_name(sym::derive) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1) First let's ensure that it's a meta item.
|
|
||||||
let nmis = match attr.meta_item_list() {
|
|
||||||
None => {
|
|
||||||
cx.struct_span_err(attr.span, "malformed `derive` attribute input")
|
|
||||||
.span_suggestion(
|
|
||||||
attr.span,
|
|
||||||
"missing traits to be derived",
|
|
||||||
"#[derive(Trait1, Trait2, ...)]".to_owned(),
|
|
||||||
Applicability::HasPlaceholders,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Some(x) => x,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut error_reported_filter_map = false;
|
|
||||||
let mut error_reported_map = false;
|
|
||||||
let traits = nmis
|
|
||||||
.into_iter()
|
|
||||||
// 2) Moreover, let's ensure we have a path and not `#[derive("foo")]`.
|
|
||||||
.filter_map(|nmi| match nmi {
|
|
||||||
NestedMetaItem::Literal(lit) => {
|
|
||||||
error_reported_filter_map = true;
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
cx.sess,
|
|
||||||
lit.span,
|
|
||||||
E0777,
|
|
||||||
"expected path to a trait, found literal",
|
|
||||||
);
|
|
||||||
let token = lit.token.to_string();
|
|
||||||
if token.starts_with('"')
|
|
||||||
&& token.len() > 2
|
|
||||||
&& is_ident(&token[1..token.len() - 1])
|
|
||||||
{
|
|
||||||
err.help(&format!("try using `#[derive({})]`", &token[1..token.len() - 1]));
|
|
||||||
} else {
|
|
||||||
err.help("for example, write `#[derive(Debug)]` for `Debug`");
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
None
|
|
||||||
}
|
|
||||||
NestedMetaItem::MetaItem(mi) => Some(mi),
|
|
||||||
})
|
|
||||||
// 3) Finally, we only accept `#[derive($path_0, $path_1, ..)]`
|
|
||||||
// but not e.g. `#[derive($path_0 = "value", $path_1(abc))]`.
|
|
||||||
// In this case we can still at least determine that the user
|
|
||||||
// wanted this trait to be derived, so let's keep it.
|
|
||||||
.map(|mi| {
|
|
||||||
let mut traits_dont_accept = |title, action| {
|
|
||||||
error_reported_map = true;
|
|
||||||
let sp = mi.span.with_lo(mi.path.span.hi());
|
|
||||||
cx.struct_span_err(sp, title)
|
|
||||||
.span_suggestion(
|
|
||||||
sp,
|
|
||||||
action,
|
|
||||||
String::new(),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
};
|
|
||||||
match &mi.kind {
|
|
||||||
MetaItemKind::List(..) => traits_dont_accept(
|
|
||||||
"traits in `#[derive(...)]` don't accept arguments",
|
|
||||||
"remove the arguments",
|
|
||||||
),
|
|
||||||
MetaItemKind::NameValue(..) => traits_dont_accept(
|
|
||||||
"traits in `#[derive(...)]` don't accept values",
|
|
||||||
"remove the value",
|
|
||||||
),
|
|
||||||
MetaItemKind::Word => {}
|
|
||||||
}
|
|
||||||
mi.path
|
|
||||||
});
|
|
||||||
|
|
||||||
result.extend(traits);
|
|
||||||
!error_reported_filter_map && !error_reported_map
|
|
||||||
});
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
@ -188,7 +188,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||||||
ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")),
|
ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")),
|
||||||
|
|
||||||
// Macros:
|
// Macros:
|
||||||
ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")),
|
|
||||||
ungated!(automatically_derived, Normal, template!(Word)),
|
ungated!(automatically_derived, Normal, template!(Word)),
|
||||||
// FIXME(#14407)
|
// FIXME(#14407)
|
||||||
ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")),
|
ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")),
|
||||||
|
@ -636,6 +636,9 @@ pub trait LintContext: Sized {
|
|||||||
db.span_label(span, "ABI should be specified here");
|
db.span_label(span, "ABI should be specified here");
|
||||||
db.help(&format!("the default ABI is {}", default_abi.name()));
|
db.help(&format!("the default ABI is {}", default_abi.name()));
|
||||||
}
|
}
|
||||||
|
BuiltinLintDiagnostics::LegacyDeriveHelpers(span) => {
|
||||||
|
db.span_label(span, "the attribute is introduced here");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Rewrap `db`, and pass control to the user.
|
// Rewrap `db`, and pass control to the user.
|
||||||
decorate(LintDiagnosticBuilder::new(db));
|
decorate(LintDiagnosticBuilder::new(db));
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
// ignore-tidy-filelength
|
// ignore-tidy-filelength
|
||||||
|
|
||||||
//! Some lints that are built in to the compiler.
|
//! Some lints that are built in to the compiler.
|
||||||
//!
|
//!
|
||||||
//! These are the built-in lints that are emitted direct in the main
|
//! These are the built-in lints that are emitted direct in the main
|
||||||
//! compiler code, rather than using their own custom pass. Those
|
//! compiler code, rather than using their own custom pass. Those
|
||||||
//! lints are all available in `rustc_lint::builtin`.
|
//! lints are all available in `rustc_lint::builtin`.
|
||||||
|
|
||||||
// ignore-tidy-filelength
|
|
||||||
|
|
||||||
use crate::{declare_lint, declare_lint_pass};
|
use crate::{declare_lint, declare_lint_pass};
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
@ -2922,6 +2921,52 @@ declare_lint! {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `legacy_derive_helpers` lint detects derive helper attributes
|
||||||
|
/// that are used before they are introduced.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust,ignore (needs extern crate)
|
||||||
|
/// #[serde(rename_all = "camelCase")]
|
||||||
|
/// #[derive(Deserialize)]
|
||||||
|
/// struct S { /* fields */ }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// produces:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// warning: derive helper attribute is used before it is introduced
|
||||||
|
/// --> $DIR/legacy-derive-helpers.rs:1:3
|
||||||
|
/// |
|
||||||
|
/// 1 | #[serde(rename_all = "camelCase")]
|
||||||
|
/// | ^^^^^
|
||||||
|
/// ...
|
||||||
|
/// 2 | #[derive(Deserialize)]
|
||||||
|
/// | ----------- the attribute is introduced here
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Attributes like this work for historical reasons, but attribute expansion works in
|
||||||
|
/// left-to-right order in general, so, to resolve `#[serde]`, compiler has to try to "look
|
||||||
|
/// into the future" at not yet expanded part of the item , but such attempts are not always
|
||||||
|
/// reliable.
|
||||||
|
///
|
||||||
|
/// To fix the warning place the helper attribute after its corresponding derive.
|
||||||
|
/// ```rust,ignore (needs extern crate)
|
||||||
|
/// #[derive(Deserialize)]
|
||||||
|
/// #[serde(rename_all = "camelCase")]
|
||||||
|
/// struct S { /* fields */ }
|
||||||
|
/// ```
|
||||||
|
pub LEGACY_DERIVE_HELPERS,
|
||||||
|
Warn,
|
||||||
|
"detects derive helper attributes that are used before they are introduced",
|
||||||
|
@future_incompatible = FutureIncompatibleInfo {
|
||||||
|
reference: "issue #79202 <https://github.com/rust-lang/rust/issues/79202>",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint_pass! {
|
declare_lint_pass! {
|
||||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||||
/// that are used by other parts of the compiler.
|
/// that are used by other parts of the compiler.
|
||||||
@ -3012,6 +3057,7 @@ declare_lint_pass! {
|
|||||||
MISSING_ABI,
|
MISSING_ABI,
|
||||||
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
||||||
DISJOINT_CAPTURE_DROP_REORDER,
|
DISJOINT_CAPTURE_DROP_REORDER,
|
||||||
|
LEGACY_DERIVE_HELPERS,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,6 +256,7 @@ pub enum BuiltinLintDiagnostics {
|
|||||||
MissingAbi(Span, Abi),
|
MissingAbi(Span, Abi),
|
||||||
UnusedDocComment(Span),
|
UnusedDocComment(Span),
|
||||||
PatternsInFnsWithoutBody(Span, Ident),
|
PatternsInFnsWithoutBody(Span, Ident),
|
||||||
|
LegacyDeriveHelpers(Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lints that are buffered up early on in the `Session` before the
|
/// Lints that are buffered up early on in the `Session` before the
|
||||||
|
@ -306,13 +306,11 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool {
|
pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool {
|
||||||
// One of the attributes may either itself be a macro, or apply derive macros (`derive`),
|
// One of the attributes may either itself be a macro,
|
||||||
// or expand to macro attributes (`cfg_attr`).
|
// or expand to macro attributes (`cfg_attr`).
|
||||||
attrs.iter().any(|attr| {
|
attrs.iter().any(|attr| {
|
||||||
attr.ident().map_or(true, |ident| {
|
attr.ident().map_or(true, |ident| {
|
||||||
ident.name == sym::derive
|
ident.name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(ident.name)
|
||||||
|| ident.name == sym::cfg_attr
|
|
||||||
|| !rustc_feature::is_builtin_attr_name(ident.name)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -967,6 +967,8 @@ pub struct Resolver<'a> {
|
|||||||
output_macro_rules_scopes: FxHashMap<ExpnId, MacroRulesScopeRef<'a>>,
|
output_macro_rules_scopes: FxHashMap<ExpnId, MacroRulesScopeRef<'a>>,
|
||||||
/// Helper attributes that are in scope for the given expansion.
|
/// Helper attributes that are in scope for the given expansion.
|
||||||
helper_attrs: FxHashMap<ExpnId, Vec<Ident>>,
|
helper_attrs: FxHashMap<ExpnId, Vec<Ident>>,
|
||||||
|
/// Resolutions for paths inside the `#[derive(...)]` attribute with the given `ExpnId`.
|
||||||
|
derive_resolutions: FxHashMap<ExpnId, Vec<(Lrc<SyntaxExtension>, ast::Path)>>,
|
||||||
|
|
||||||
/// Avoid duplicated errors for "name already defined".
|
/// Avoid duplicated errors for "name already defined".
|
||||||
name_already_seen: FxHashMap<Symbol, Span>,
|
name_already_seen: FxHashMap<Symbol, Span>,
|
||||||
@ -1295,6 +1297,7 @@ impl<'a> Resolver<'a> {
|
|||||||
invocation_parent_scopes: Default::default(),
|
invocation_parent_scopes: Default::default(),
|
||||||
output_macro_rules_scopes: Default::default(),
|
output_macro_rules_scopes: Default::default(),
|
||||||
helper_attrs: Default::default(),
|
helper_attrs: Default::default(),
|
||||||
|
derive_resolutions: Default::default(),
|
||||||
local_macro_def_scopes: FxHashMap::default(),
|
local_macro_def_scopes: FxHashMap::default(),
|
||||||
name_already_seen: FxHashMap::default(),
|
name_already_seen: FxHashMap::default(),
|
||||||
potentially_unused_imports: Vec::new(),
|
potentially_unused_imports: Vec::new(),
|
||||||
|
@ -14,8 +14,7 @@ use rustc_data_structures::fx::FxHashSet;
|
|||||||
use rustc_data_structures::ptr_key::PtrKey;
|
use rustc_data_structures::ptr_key::PtrKey;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::struct_span_err;
|
use rustc_errors::struct_span_err;
|
||||||
use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand};
|
use rustc_expand::base::{Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
|
||||||
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
|
|
||||||
use rustc_expand::compile_declarative_macro;
|
use rustc_expand::compile_declarative_macro;
|
||||||
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
|
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
|
||||||
use rustc_feature::is_builtin_attr_name;
|
use rustc_feature::is_builtin_attr_name;
|
||||||
@ -24,7 +23,8 @@ use rustc_hir::def_id;
|
|||||||
use rustc_hir::PrimTy;
|
use rustc_hir::PrimTy;
|
||||||
use rustc_middle::middle::stability;
|
use rustc_middle::middle::stability;
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS};
|
use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNUSED_MACROS};
|
||||||
|
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
@ -227,7 +227,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
|||||||
invoc: &Invocation,
|
invoc: &Invocation,
|
||||||
eager_expansion_root: ExpnId,
|
eager_expansion_root: ExpnId,
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> Result<InvocationRes, Indeterminate> {
|
) -> Result<Lrc<SyntaxExtension>, Indeterminate> {
|
||||||
let invoc_id = invoc.expansion_data.id;
|
let invoc_id = invoc.expansion_data.id;
|
||||||
let parent_scope = match self.invocation_parent_scopes.get(&invoc_id) {
|
let parent_scope = match self.invocation_parent_scopes.get(&invoc_id) {
|
||||||
Some(parent_scope) => *parent_scope,
|
Some(parent_scope) => *parent_scope,
|
||||||
@ -244,65 +244,15 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (path, kind, inner_attr, derives, after_derive) = match invoc.kind {
|
let (path, kind, inner_attr, derives) = match invoc.kind {
|
||||||
InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => (
|
InvocationKind::Attr { ref attr, ref derives, .. } => (
|
||||||
&attr.get_normal_item().path,
|
&attr.get_normal_item().path,
|
||||||
MacroKind::Attr,
|
MacroKind::Attr,
|
||||||
attr.style == ast::AttrStyle::Inner,
|
attr.style == ast::AttrStyle::Inner,
|
||||||
self.arenas.alloc_ast_paths(derives),
|
self.arenas.alloc_ast_paths(derives),
|
||||||
after_derive,
|
|
||||||
),
|
),
|
||||||
InvocationKind::Bang { ref mac, .. } => {
|
InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, false, &[][..]),
|
||||||
(&mac.path, MacroKind::Bang, false, &[][..], false)
|
InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, false, &[][..]),
|
||||||
}
|
|
||||||
InvocationKind::Derive { ref path, .. } => {
|
|
||||||
(path, MacroKind::Derive, false, &[][..], false)
|
|
||||||
}
|
|
||||||
InvocationKind::DeriveContainer { ref derives, .. } => {
|
|
||||||
// Block expansion of the container until we resolve all derives in it.
|
|
||||||
// This is required for two reasons:
|
|
||||||
// - Derive helper attributes are in scope for the item to which the `#[derive]`
|
|
||||||
// is applied, so they have to be produced by the container's expansion rather
|
|
||||||
// than by individual derives.
|
|
||||||
// - Derives in the container need to know whether one of them is a built-in `Copy`.
|
|
||||||
// FIXME: Try to avoid repeated resolutions for derives here and in expansion.
|
|
||||||
let mut exts = Vec::new();
|
|
||||||
let mut helper_attrs = Vec::new();
|
|
||||||
for path in derives {
|
|
||||||
exts.push(
|
|
||||||
match self.resolve_macro_path(
|
|
||||||
path,
|
|
||||||
Some(MacroKind::Derive),
|
|
||||||
&parent_scope,
|
|
||||||
true,
|
|
||||||
force,
|
|
||||||
) {
|
|
||||||
Ok((Some(ext), _)) => {
|
|
||||||
let span = path
|
|
||||||
.segments
|
|
||||||
.last()
|
|
||||||
.unwrap()
|
|
||||||
.ident
|
|
||||||
.span
|
|
||||||
.normalize_to_macros_2_0();
|
|
||||||
helper_attrs.extend(
|
|
||||||
ext.helper_attrs.iter().map(|name| Ident::new(*name, span)),
|
|
||||||
);
|
|
||||||
if ext.builtin_name == Some(sym::Copy) {
|
|
||||||
self.containers_deriving_copy.insert(invoc_id);
|
|
||||||
}
|
|
||||||
ext
|
|
||||||
}
|
|
||||||
Ok(_) | Err(Determinacy::Determined) => {
|
|
||||||
self.dummy_ext(MacroKind::Derive)
|
|
||||||
}
|
|
||||||
Err(Determinacy::Undetermined) => return Err(Indeterminate),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
self.helper_attrs.insert(invoc_id, helper_attrs);
|
|
||||||
return Ok(InvocationRes::DeriveContainer(exts));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Derives are not included when `invocations` are collected, so we have to add them here.
|
// Derives are not included when `invocations` are collected, so we have to add them here.
|
||||||
@ -328,14 +278,11 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
|||||||
));
|
));
|
||||||
|
|
||||||
if let Res::Def(_, _) = res {
|
if let Res::Def(_, _) = res {
|
||||||
if after_derive {
|
|
||||||
self.session.span_err(span, "macro attributes must be placed before `#[derive]`");
|
|
||||||
}
|
|
||||||
let normal_module_def_id = self.macro_def_scope(invoc_id).nearest_parent_mod;
|
let normal_module_def_id = self.macro_def_scope(invoc_id).nearest_parent_mod;
|
||||||
self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id);
|
self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(InvocationRes::Single(ext))
|
Ok(ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_unused_macros(&mut self) {
|
fn check_unused_macros(&mut self) {
|
||||||
@ -344,7 +291,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId {
|
fn lint_node_id(&self, expn_id: ExpnId) -> NodeId {
|
||||||
// FIXME - make this more precise. This currently returns the NodeId of the
|
// FIXME - make this more precise. This currently returns the NodeId of the
|
||||||
// nearest closing item - we should try to return the closest parent of the ExpnId
|
// nearest closing item - we should try to return the closest parent of the ExpnId
|
||||||
self.invocation_parents
|
self.invocation_parents
|
||||||
@ -356,6 +303,63 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
|||||||
self.containers_deriving_copy.contains(&expn_id)
|
self.containers_deriving_copy.contains(&expn_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_derives(
|
||||||
|
&mut self,
|
||||||
|
expn_id: ExpnId,
|
||||||
|
derives: Vec<ast::Path>,
|
||||||
|
force: bool,
|
||||||
|
) -> Result<(), Indeterminate> {
|
||||||
|
// Block expansion of the container until we resolve all derives in it.
|
||||||
|
// This is required for two reasons:
|
||||||
|
// - Derive helper attributes are in scope for the item to which the `#[derive]`
|
||||||
|
// is applied, so they have to be produced by the container's expansion rather
|
||||||
|
// than by individual derives.
|
||||||
|
// - Derives in the container need to know whether one of them is a built-in `Copy`.
|
||||||
|
// FIXME: Try to cache intermediate results to avoid resolving same derives multiple times.
|
||||||
|
let parent_scope = self.invocation_parent_scopes[&expn_id];
|
||||||
|
let mut exts = Vec::new();
|
||||||
|
let mut helper_attrs = Vec::new();
|
||||||
|
let mut has_derive_copy = false;
|
||||||
|
for path in derives {
|
||||||
|
exts.push((
|
||||||
|
match self.resolve_macro_path(
|
||||||
|
&path,
|
||||||
|
Some(MacroKind::Derive),
|
||||||
|
&parent_scope,
|
||||||
|
true,
|
||||||
|
force,
|
||||||
|
) {
|
||||||
|
Ok((Some(ext), _)) => {
|
||||||
|
let span =
|
||||||
|
path.segments.last().unwrap().ident.span.normalize_to_macros_2_0();
|
||||||
|
helper_attrs
|
||||||
|
.extend(ext.helper_attrs.iter().map(|name| Ident::new(*name, span)));
|
||||||
|
has_derive_copy |= ext.builtin_name == Some(sym::Copy);
|
||||||
|
ext
|
||||||
|
}
|
||||||
|
Ok(_) | Err(Determinacy::Determined) => self.dummy_ext(MacroKind::Derive),
|
||||||
|
Err(Determinacy::Undetermined) => return Err(Indeterminate),
|
||||||
|
},
|
||||||
|
path,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
self.derive_resolutions.insert(expn_id, exts);
|
||||||
|
self.helper_attrs.insert(expn_id, helper_attrs);
|
||||||
|
// Mark this derive as having `Copy` either if it has `Copy` itself or if its parent derive
|
||||||
|
// has `Copy`, to support cases like `#[derive(Clone, Copy)] #[derive(Debug)]`.
|
||||||
|
if has_derive_copy || self.has_derive_copy(parent_scope.expansion) {
|
||||||
|
self.containers_deriving_copy.insert(expn_id);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_derive_resolutions(
|
||||||
|
&mut self,
|
||||||
|
expn_id: ExpnId,
|
||||||
|
) -> Option<Vec<(Lrc<SyntaxExtension>, ast::Path)>> {
|
||||||
|
self.derive_resolutions.remove(&expn_id)
|
||||||
|
}
|
||||||
|
|
||||||
// The function that implements the resolution logic of `#[cfg_accessible(path)]`.
|
// The function that implements the resolution logic of `#[cfg_accessible(path)]`.
|
||||||
// Returns true if the path can certainly be resolved in one of three namespaces,
|
// Returns true if the path can certainly be resolved in one of three namespaces,
|
||||||
// returns false if the path certainly cannot be resolved in any of the three namespaces.
|
// returns false if the path certainly cannot be resolved in any of the three namespaces.
|
||||||
@ -818,6 +822,8 @@ impl<'a> Resolver<'a> {
|
|||||||
let is_builtin = |res| {
|
let is_builtin = |res| {
|
||||||
matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..)))
|
matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..)))
|
||||||
};
|
};
|
||||||
|
let derive_helper =
|
||||||
|
Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
|
||||||
let derive_helper_compat =
|
let derive_helper_compat =
|
||||||
Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
|
Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
|
||||||
|
|
||||||
@ -826,7 +832,7 @@ impl<'a> Resolver<'a> {
|
|||||||
} else if is_builtin(innermost_res) || is_builtin(res) {
|
} else if is_builtin(innermost_res) || is_builtin(res) {
|
||||||
Some(AmbiguityKind::BuiltinAttr)
|
Some(AmbiguityKind::BuiltinAttr)
|
||||||
} else if innermost_res == derive_helper_compat
|
} else if innermost_res == derive_helper_compat
|
||||||
|| res == derive_helper_compat
|
|| res == derive_helper_compat && innermost_res != derive_helper
|
||||||
{
|
{
|
||||||
Some(AmbiguityKind::DeriveHelper)
|
Some(AmbiguityKind::DeriveHelper)
|
||||||
} else if innermost_flags.contains(Flags::MACRO_RULES)
|
} else if innermost_flags.contains(Flags::MACRO_RULES)
|
||||||
@ -992,6 +998,15 @@ impl<'a> Resolver<'a> {
|
|||||||
let res = binding.res();
|
let res = binding.res();
|
||||||
let seg = Segment::from_ident(ident);
|
let seg = Segment::from_ident(ident);
|
||||||
check_consistency(self, &[seg], ident.span, kind, initial_res, res);
|
check_consistency(self, &[seg], ident.span, kind, initial_res, res);
|
||||||
|
if res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat) {
|
||||||
|
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||||
|
LEGACY_DERIVE_HELPERS,
|
||||||
|
self.lint_node_id(parent_scope.expansion),
|
||||||
|
ident.span,
|
||||||
|
"derive helper attribute is used before it is introduced",
|
||||||
|
BuiltinLintDiagnostics::LegacyDeriveHelpers(binding.span),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(..) => {
|
Err(..) => {
|
||||||
let expected = kind.descr_expected();
|
let expected = kind.descr_expected();
|
||||||
@ -1078,7 +1093,7 @@ impl<'a> Resolver<'a> {
|
|||||||
crate fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) {
|
crate fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) {
|
||||||
// Reserve some names that are not quite covered by the general check
|
// Reserve some names that are not quite covered by the general check
|
||||||
// performed on `Resolver::builtin_attrs`.
|
// performed on `Resolver::builtin_attrs`.
|
||||||
if ident.name == sym::cfg || ident.name == sym::cfg_attr || ident.name == sym::derive {
|
if ident.name == sym::cfg || ident.name == sym::cfg_attr {
|
||||||
let macro_kind = self.get_macro(res).map(|ext| ext.macro_kind());
|
let macro_kind = self.get_macro(res).map(|ext| ext.macro_kind());
|
||||||
if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
|
if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
|
||||||
self.session.span_err(
|
self.session.span_err(
|
||||||
|
@ -1324,6 +1324,14 @@ pub(crate) mod builtin {
|
|||||||
(false) => {{ /* compiler built-in */ }};
|
(false) => {{ /* compiler built-in */ }};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attribute macro used to apply derive macros.
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
pub macro derive($item:item) {
|
||||||
|
/* compiler built-in */
|
||||||
|
}
|
||||||
|
|
||||||
/// Attribute macro applied to a function to turn it into a unit test.
|
/// Attribute macro applied to a function to turn it into a unit test.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[allow_internal_unstable(test, rustc_attrs)]
|
#[allow_internal_unstable(test, rustc_attrs)]
|
||||||
|
@ -69,6 +69,11 @@ pub use crate::macros::builtin::{
|
|||||||
bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
|
bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use crate::macros::builtin::derive;
|
||||||
|
|
||||||
#[unstable(
|
#[unstable(
|
||||||
feature = "cfg_accessible",
|
feature = "cfg_accessible",
|
||||||
issue = "64797",
|
issue = "64797",
|
||||||
|
@ -54,6 +54,11 @@ pub use core::prelude::v1::{
|
|||||||
bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
|
bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub use core::prelude::v1::derive;
|
||||||
|
|
||||||
#[unstable(
|
#[unstable(
|
||||||
feature = "cfg_accessible",
|
feature = "cfg_accessible",
|
||||||
issue = "64797",
|
issue = "64797",
|
||||||
|
@ -96,8 +96,8 @@ pub struct Deprecation {
|
|||||||
pub note: Option<String>,
|
pub note: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum Visibility {
|
pub enum Visibility {
|
||||||
Public,
|
Public,
|
||||||
/// For the most part items are private by default. The exceptions are associated items of
|
/// For the most part items are private by default. The exceptions are associated items of
|
||||||
@ -112,8 +112,8 @@ pub enum Visibility {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum GenericArgs {
|
pub enum GenericArgs {
|
||||||
/// <'a, 32, B: Copy, C = u32>
|
/// <'a, 32, B: Copy, C = u32>
|
||||||
AngleBracketed { args: Vec<GenericArg>, bindings: Vec<TypeBinding> },
|
AngleBracketed { args: Vec<GenericArg>, bindings: Vec<TypeBinding> },
|
||||||
@ -121,8 +121,8 @@ pub enum GenericArgs {
|
|||||||
Parenthesized { inputs: Vec<Type>, output: Option<Type> },
|
Parenthesized { inputs: Vec<Type>, output: Option<Type> },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum GenericArg {
|
pub enum GenericArg {
|
||||||
Lifetime(String),
|
Lifetime(String),
|
||||||
Type(Type),
|
Type(Type),
|
||||||
@ -144,8 +144,8 @@ pub struct TypeBinding {
|
|||||||
pub binding: TypeBindingKind,
|
pub binding: TypeBindingKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum TypeBindingKind {
|
pub enum TypeBindingKind {
|
||||||
Equality(Type),
|
Equality(Type),
|
||||||
Constraint(Vec<GenericBound>),
|
Constraint(Vec<GenericBound>),
|
||||||
@ -154,8 +154,8 @@ pub enum TypeBindingKind {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub struct Id(pub String);
|
pub struct Id(pub String);
|
||||||
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ItemKind {
|
pub enum ItemKind {
|
||||||
Module,
|
Module,
|
||||||
ExternCrate,
|
ExternCrate,
|
||||||
@ -184,8 +184,8 @@ pub enum ItemKind {
|
|||||||
Keyword,
|
Keyword,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde(untagged)]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(untagged)]
|
||||||
pub enum ItemEnum {
|
pub enum ItemEnum {
|
||||||
ModuleItem(Module),
|
ModuleItem(Module),
|
||||||
ExternCrateItem {
|
ExternCrateItem {
|
||||||
@ -264,17 +264,17 @@ pub struct Enum {
|
|||||||
pub impls: Vec<Id>,
|
pub impls: Vec<Id>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[serde(tag = "variant_kind", content = "variant_inner")]
|
#[serde(tag = "variant_kind", content = "variant_inner")]
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub enum Variant {
|
pub enum Variant {
|
||||||
Plain,
|
Plain,
|
||||||
Tuple(Vec<Type>),
|
Tuple(Vec<Type>),
|
||||||
Struct(Vec<Id>),
|
Struct(Vec<Id>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum StructType {
|
pub enum StructType {
|
||||||
Plain,
|
Plain,
|
||||||
Tuple,
|
Tuple,
|
||||||
@ -310,24 +310,24 @@ pub struct GenericParamDef {
|
|||||||
pub kind: GenericParamDefKind,
|
pub kind: GenericParamDefKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum GenericParamDefKind {
|
pub enum GenericParamDefKind {
|
||||||
Lifetime,
|
Lifetime,
|
||||||
Type { bounds: Vec<GenericBound>, default: Option<Type> },
|
Type { bounds: Vec<GenericBound>, default: Option<Type> },
|
||||||
Const(Type),
|
Const(Type),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum WherePredicate {
|
pub enum WherePredicate {
|
||||||
BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
|
BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
|
||||||
RegionPredicate { lifetime: String, bounds: Vec<GenericBound> },
|
RegionPredicate { lifetime: String, bounds: Vec<GenericBound> },
|
||||||
EqPredicate { lhs: Type, rhs: Type },
|
EqPredicate { lhs: Type, rhs: Type },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum GenericBound {
|
pub enum GenericBound {
|
||||||
TraitBound {
|
TraitBound {
|
||||||
#[serde(rename = "trait")]
|
#[serde(rename = "trait")]
|
||||||
@ -339,17 +339,17 @@ pub enum GenericBound {
|
|||||||
Outlives(String),
|
Outlives(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum TraitBoundModifier {
|
pub enum TraitBoundModifier {
|
||||||
None,
|
None,
|
||||||
Maybe,
|
Maybe,
|
||||||
MaybeConst,
|
MaybeConst,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[serde(tag = "kind", content = "inner")]
|
#[serde(tag = "kind", content = "inner")]
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
/// Structs, enums, and traits
|
/// Structs, enums, and traits
|
||||||
ResolvedPath {
|
ResolvedPath {
|
||||||
@ -448,8 +448,8 @@ pub struct Impl {
|
|||||||
pub blanket_impl: Option<Type>,
|
pub blanket_impl: Option<Type>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct Import {
|
pub struct Import {
|
||||||
/// The full path being imported.
|
/// The full path being imported.
|
||||||
pub span: String,
|
pub span: String,
|
||||||
@ -468,8 +468,8 @@ pub struct ProcMacro {
|
|||||||
pub helpers: Vec<String>,
|
pub helpers: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum MacroKind {
|
pub enum MacroKind {
|
||||||
/// A bang macro `foo!()`.
|
/// A bang macro `foo!()`.
|
||||||
Bang,
|
Bang,
|
||||||
|
@ -75,3 +75,8 @@ auto trait Freeze {}
|
|||||||
macro_rules! Copy {
|
macro_rules! Copy {
|
||||||
() => {};
|
() => {};
|
||||||
}
|
}
|
||||||
|
#[macro_export]
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
macro_rules! derive {
|
||||||
|
() => {};
|
||||||
|
}
|
||||||
|
6
src/test/ui/derives/derive-deadlock.rs
Normal file
6
src/test/ui/derives/derive-deadlock.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
use std as derive;
|
||||||
|
|
||||||
|
#[derive(Default)] //~ ERROR cannot determine resolution for the attribute macro `derive`
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
fn main() {}
|
10
src/test/ui/derives/derive-deadlock.stderr
Normal file
10
src/test/ui/derives/derive-deadlock.stderr
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
error: cannot determine resolution for the attribute macro `derive`
|
||||||
|
--> $DIR/derive-deadlock.rs:3:3
|
||||||
|
|
|
||||||
|
LL | #[derive(Default)]
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: import resolution is stuck, try simplifying macro imports
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
10
src/test/ui/derives/derive-multiple-with-packed.rs
Normal file
10
src/test/ui/derives/derive-multiple-with-packed.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[derive(Debug)] // OK, even if `Copy` is in the different `#[derive]`
|
||||||
|
#[repr(packed)]
|
||||||
|
struct CacheRecordHeader {
|
||||||
|
field: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -1,6 +1,8 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
#![deny(unused)]
|
#![deny(unused)]
|
||||||
|
|
||||||
#[derive()] //~ ERROR unused attribute
|
#[derive()] // OK
|
||||||
struct _Bar;
|
struct _Bar;
|
||||||
|
|
||||||
pub fn main() {}
|
pub fn main() {}
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
error: unused attribute
|
|
||||||
--> $DIR/deriving-meta-empty-trait-list.rs:3:1
|
|
||||||
|
|
|
||||||
LL | #[derive()]
|
|
||||||
| ^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
note: the lint level is defined here
|
|
||||||
--> $DIR/deriving-meta-empty-trait-list.rs:1:9
|
|
||||||
|
|
|
||||||
LL | #![deny(unused)]
|
|
||||||
| ^^^^^^
|
|
||||||
= note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]`
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
|||||||
#![derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions
|
#![derive(Copy)] //~ ERROR cannot determine resolution for the attribute macro `derive`
|
||||||
//~| ERROR cannot determine resolution for the derive macro `Copy`
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
error[E0774]: `derive` may only be applied to structs, enums and unions
|
error: cannot determine resolution for the attribute macro `derive`
|
||||||
--> $DIR/issue-36617.rs:1:1
|
--> $DIR/issue-36617.rs:1:4
|
||||||
|
|
|
|
||||||
LL | #![derive(Copy)]
|
LL | #![derive(Copy)]
|
||||||
| ^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Copy)]`
|
| ^^^^^^
|
||||||
|
|
||||||
error: cannot determine resolution for the derive macro `Copy`
|
|
||||||
--> $DIR/issue-36617.rs:1:11
|
|
||||||
|
|
|
||||||
LL | #![derive(Copy)]
|
|
||||||
| ^^^^
|
|
||||||
|
|
|
|
||||||
= note: import resolution is stuck, try simplifying macro imports
|
= note: import resolution is stuck, try simplifying macro imports
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0774`.
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
mod derive {
|
mod derive {
|
||||||
mod inner { #![derive(Debug)] }
|
mod inner { #![derive(Debug)] }
|
||||||
//~^ ERROR `derive` may only be applied to structs, enums and unions
|
//~^ ERROR `derive` may only be applied to structs, enums and unions
|
||||||
|
//~| ERROR inner macro attributes are unstable
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
//~^ ERROR `derive` may only be applied to structs, enums and unions
|
//~^ ERROR `derive` may only be applied to structs, enums and unions
|
||||||
|
@ -4,30 +4,40 @@ error[E0774]: `derive` may only be applied to structs, enums and unions
|
|||||||
LL | #[derive(Debug)]
|
LL | #[derive(Debug)]
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0658]: inner macro attributes are unstable
|
||||||
|
--> $DIR/issue-43106-gating-of-derive.rs:7:20
|
||||||
|
|
|
||||||
|
LL | mod inner { #![derive(Debug)] }
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
|
||||||
|
= help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0774]: `derive` may only be applied to structs, enums and unions
|
error[E0774]: `derive` may only be applied to structs, enums and unions
|
||||||
--> $DIR/issue-43106-gating-of-derive.rs:7:17
|
--> $DIR/issue-43106-gating-of-derive.rs:7:17
|
||||||
|
|
|
|
||||||
LL | mod inner { #![derive(Debug)] }
|
LL | mod inner { #![derive(Debug)] }
|
||||||
| ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]`
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0774]: `derive` may only be applied to structs, enums and unions
|
error[E0774]: `derive` may only be applied to structs, enums and unions
|
||||||
--> $DIR/issue-43106-gating-of-derive.rs:10:5
|
--> $DIR/issue-43106-gating-of-derive.rs:11:5
|
||||||
|
|
|
|
||||||
LL | #[derive(Debug)]
|
LL | #[derive(Debug)]
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0774]: `derive` may only be applied to structs, enums and unions
|
error[E0774]: `derive` may only be applied to structs, enums and unions
|
||||||
--> $DIR/issue-43106-gating-of-derive.rs:23:5
|
--> $DIR/issue-43106-gating-of-derive.rs:24:5
|
||||||
|
|
|
|
||||||
LL | #[derive(Debug)]
|
LL | #[derive(Debug)]
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0774]: `derive` may only be applied to structs, enums and unions
|
error[E0774]: `derive` may only be applied to structs, enums and unions
|
||||||
--> $DIR/issue-43106-gating-of-derive.rs:27:5
|
--> $DIR/issue-43106-gating-of-derive.rs:28:5
|
||||||
|
|
|
|
||||||
LL | #[derive(Debug)]
|
LL | #[derive(Debug)]
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0774`.
|
Some errors have detailed explanations: E0658, E0774.
|
||||||
|
For more information about an error, try `rustc --explain E0658`.
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
fn foo<#[derive(Debug)] T>() {
|
fn foo<#[derive(Debug)] T>() { //~ ERROR expected non-macro attribute, found attribute macro
|
||||||
//~^ ERROR `derive` may only be applied to structs, enums and unions
|
|
||||||
match 0 {
|
match 0 {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)] //~ ERROR expected non-macro attribute, found attribute macro
|
||||||
//~^ ERROR `derive` may only be applied to structs, enums and unions
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {}
|
||||||
}
|
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
error[E0774]: `derive` may only be applied to structs, enums and unions
|
error: expected non-macro attribute, found attribute macro `derive`
|
||||||
--> $DIR/issue-49934-errors.rs:1:8
|
--> $DIR/issue-49934-errors.rs:1:10
|
||||||
|
|
|
|
||||||
LL | fn foo<#[derive(Debug)] T>() {
|
LL | fn foo<#[derive(Debug)] T>() {
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^ not a non-macro attribute
|
||||||
|
|
||||||
error[E0774]: `derive` may only be applied to structs, enums and unions
|
error: expected non-macro attribute, found attribute macro `derive`
|
||||||
--> $DIR/issue-49934-errors.rs:4:9
|
--> $DIR/issue-49934-errors.rs:3:11
|
||||||
|
|
|
|
||||||
LL | #[derive(Debug)]
|
LL | #[derive(Debug)]
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^ not a non-macro attribute
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0774`.
|
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
// check-pass
|
|
||||||
|
|
||||||
#![feature(stmt_expr_attributes)]
|
#![feature(stmt_expr_attributes)]
|
||||||
#![warn(unused_attributes)] //~ NOTE the lint level is defined here
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// fold_stmt (Item)
|
// fold_stmt (Item)
|
||||||
@ -10,26 +7,24 @@ fn main() {
|
|||||||
struct Foo;
|
struct Foo;
|
||||||
|
|
||||||
// fold_stmt (Mac)
|
// fold_stmt (Mac)
|
||||||
#[derive(Debug)]
|
#[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions
|
||||||
//~^ WARN `#[derive]` does nothing on macro invocations
|
|
||||||
//~| NOTE this may become a hard error in a future release
|
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
|
|
||||||
// fold_stmt (Semi)
|
// fold_stmt (Semi)
|
||||||
#[derive(Debug)] //~ WARN unused attribute
|
#[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions
|
||||||
"Hello, world!";
|
"Hello, world!";
|
||||||
|
|
||||||
// fold_stmt (Local)
|
// fold_stmt (Local)
|
||||||
#[derive(Debug)] //~ WARN unused attribute
|
#[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions
|
||||||
let _ = "Hello, world!";
|
let _ = "Hello, world!";
|
||||||
|
|
||||||
// visit_expr
|
// visit_expr
|
||||||
let _ = #[derive(Debug)] "Hello, world!";
|
let _ = #[derive(Debug)] "Hello, world!";
|
||||||
//~^ WARN unused attribute
|
//~^ ERROR `derive` may only be applied to structs, enums and unions
|
||||||
|
|
||||||
let _ = [
|
let _ = [
|
||||||
// filter_map_expr
|
// filter_map_expr
|
||||||
#[derive(Debug)] //~ WARN unused attribute
|
#[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions
|
||||||
"Hello, world!"
|
"Hello, world!",
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,33 @@
|
|||||||
warning: `#[derive]` does nothing on macro invocations
|
error[E0774]: `derive` may only be applied to structs, enums and unions
|
||||||
--> $DIR/issue-49934.rs:13:5
|
--> $DIR/issue-49934.rs:10:5
|
||||||
|
|
|
||||||
LL | #[derive(Debug)]
|
|
||||||
| ^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: this may become a hard error in a future release
|
|
||||||
|
|
||||||
warning: unused attribute
|
|
||||||
--> $DIR/issue-49934.rs:19:5
|
|
||||||
|
|
|
||||||
LL | #[derive(Debug)]
|
|
||||||
| ^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
note: the lint level is defined here
|
|
||||||
--> $DIR/issue-49934.rs:4:9
|
|
||||||
|
|
|
||||||
LL | #![warn(unused_attributes)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
warning: unused attribute
|
|
||||||
--> $DIR/issue-49934.rs:23:5
|
|
||||||
|
|
|
|
||||||
LL | #[derive(Debug)]
|
LL | #[derive(Debug)]
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
warning: unused attribute
|
error[E0774]: `derive` may only be applied to structs, enums and unions
|
||||||
--> $DIR/issue-49934.rs:27:13
|
--> $DIR/issue-49934.rs:14:5
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug)]
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0774]: `derive` may only be applied to structs, enums and unions
|
||||||
|
--> $DIR/issue-49934.rs:18:5
|
||||||
|
|
|
||||||
|
LL | #[derive(Debug)]
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0774]: `derive` may only be applied to structs, enums and unions
|
||||||
|
--> $DIR/issue-49934.rs:22:13
|
||||||
|
|
|
|
||||||
LL | let _ = #[derive(Debug)] "Hello, world!";
|
LL | let _ = #[derive(Debug)] "Hello, world!";
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
warning: unused attribute
|
error[E0774]: `derive` may only be applied to structs, enums and unions
|
||||||
--> $DIR/issue-49934.rs:32:9
|
--> $DIR/issue-49934.rs:27:9
|
||||||
|
|
|
|
||||||
LL | #[derive(Debug)]
|
LL | #[derive(Debug)]
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
warning: 5 warnings emitted
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0774`.
|
||||||
|
@ -1,3 +1,15 @@
|
|||||||
|
error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
|
||||||
|
--> $DIR/builtin-std-paths-fail.rs:2:11
|
||||||
|
|
|
||||||
|
LL | core::RustcDecodable,
|
||||||
|
| ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
|
||||||
|
--> $DIR/builtin-std-paths-fail.rs:4:11
|
||||||
|
|
|
||||||
|
LL | core::RustcDecodable,
|
||||||
|
| ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
|
||||||
|
|
||||||
error[E0433]: failed to resolve: could not find `bench` in `core`
|
error[E0433]: failed to resolve: could not find `bench` in `core`
|
||||||
--> $DIR/builtin-std-paths-fail.rs:7:9
|
--> $DIR/builtin-std-paths-fail.rs:7:9
|
||||||
|
|
|
|
||||||
@ -22,18 +34,6 @@ error[E0433]: failed to resolve: could not find `test` in `core`
|
|||||||
LL | #[core::test]
|
LL | #[core::test]
|
||||||
| ^^^^ could not find `test` in `core`
|
| ^^^^ could not find `test` in `core`
|
||||||
|
|
||||||
error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
|
|
||||||
--> $DIR/builtin-std-paths-fail.rs:2:11
|
|
||||||
|
|
|
||||||
LL | core::RustcDecodable,
|
|
||||||
| ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
|
|
||||||
|
|
||||||
error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
|
|
||||||
--> $DIR/builtin-std-paths-fail.rs:4:11
|
|
||||||
|
|
|
||||||
LL | core::RustcDecodable,
|
|
||||||
| ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
|
|
||||||
|
|
||||||
error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
|
error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
|
||||||
--> $DIR/builtin-std-paths-fail.rs:4:11
|
--> $DIR/builtin-std-paths-fail.rs:4:11
|
||||||
|
|
|
|
||||||
@ -46,6 +46,18 @@ error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
|
|||||||
LL | core::RustcDecodable,
|
LL | core::RustcDecodable,
|
||||||
| ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
|
| ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
|
||||||
|
--> $DIR/builtin-std-paths-fail.rs:14:10
|
||||||
|
|
|
||||||
|
LL | std::RustcDecodable,
|
||||||
|
| ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
|
||||||
|
--> $DIR/builtin-std-paths-fail.rs:16:10
|
||||||
|
|
|
||||||
|
LL | std::RustcDecodable,
|
||||||
|
| ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
|
||||||
|
|
||||||
error[E0433]: failed to resolve: could not find `bench` in `std`
|
error[E0433]: failed to resolve: could not find `bench` in `std`
|
||||||
--> $DIR/builtin-std-paths-fail.rs:19:8
|
--> $DIR/builtin-std-paths-fail.rs:19:8
|
||||||
|
|
|
|
||||||
@ -70,18 +82,6 @@ error[E0433]: failed to resolve: could not find `test` in `std`
|
|||||||
LL | #[std::test]
|
LL | #[std::test]
|
||||||
| ^^^^ could not find `test` in `std`
|
| ^^^^ could not find `test` in `std`
|
||||||
|
|
||||||
error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
|
|
||||||
--> $DIR/builtin-std-paths-fail.rs:14:10
|
|
||||||
|
|
|
||||||
LL | std::RustcDecodable,
|
|
||||||
| ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
|
|
||||||
|
|
||||||
error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
|
|
||||||
--> $DIR/builtin-std-paths-fail.rs:16:10
|
|
||||||
|
|
|
||||||
LL | std::RustcDecodable,
|
|
||||||
| ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
|
|
||||||
|
|
||||||
error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
|
error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
|
||||||
--> $DIR/builtin-std-paths-fail.rs:16:10
|
--> $DIR/builtin-std-paths-fail.rs:16:10
|
||||||
|
|
|
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
||||||
struct CLI {
|
struct CLI {
|
||||||
#[derive(parse())]
|
#[derive(parse())] //~ ERROR expected non-macro attribute, found attribute macro
|
||||||
//~^ ERROR traits in `#[derive(...)]` don't accept arguments
|
|
||||||
//~| ERROR cannot find derive macro `parse` in this scope
|
|
||||||
path: (),
|
path: (),
|
||||||
//~^ ERROR `derive` may only be applied to structs, enums and unions
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,8 @@
|
|||||||
error: traits in `#[derive(...)]` don't accept arguments
|
error: expected non-macro attribute, found attribute macro `derive`
|
||||||
--> $DIR/issue-69341-malformed-derive-inert.rs:4:19
|
--> $DIR/issue-69341-malformed-derive-inert.rs:4:7
|
||||||
|
|
|
|
||||||
LL | #[derive(parse())]
|
LL | #[derive(parse())]
|
||||||
| ^^ help: remove the arguments
|
| ^^^^^^ not a non-macro attribute
|
||||||
|
|
||||||
error[E0774]: `derive` may only be applied to structs, enums and unions
|
error: aborting due to previous error
|
||||||
--> $DIR/issue-69341-malformed-derive-inert.rs:7:5
|
|
||||||
|
|
|
||||||
LL | path: (),
|
|
||||||
| ^^^^^^^^
|
|
||||||
|
|
||||||
error: cannot find derive macro `parse` in this scope
|
|
||||||
--> $DIR/issue-69341-malformed-derive-inert.rs:4:14
|
|
||||||
|
|
|
||||||
LL | #[derive(parse())]
|
|
||||||
| ^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0774`.
|
|
||||||
|
@ -14,7 +14,7 @@ error: malformed `derive` attribute input
|
|||||||
--> $DIR/malformed-derive-entry.rs:11:1
|
--> $DIR/malformed-derive-entry.rs:11:1
|
||||||
|
|
|
|
||||||
LL | #[derive]
|
LL | #[derive]
|
||||||
| ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]`
|
| ^^^^^^^^^ help: must be of the form: `#[derive(Trait1, Trait2, ...)]`
|
||||||
|
|
||||||
error[E0277]: the trait bound `Test1: Clone` is not satisfied
|
error[E0277]: the trait bound `Test1: Clone` is not satisfied
|
||||||
--> $DIR/malformed-derive-entry.rs:1:10
|
--> $DIR/malformed-derive-entry.rs:1:10
|
||||||
|
@ -18,13 +18,13 @@ error: malformed `derive` attribute input
|
|||||||
--> $DIR/malformed-special-attrs.rs:7:1
|
--> $DIR/malformed-special-attrs.rs:7:1
|
||||||
|
|
|
|
||||||
LL | #[derive]
|
LL | #[derive]
|
||||||
| ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]`
|
| ^^^^^^^^^ help: must be of the form: `#[derive(Trait1, Trait2, ...)]`
|
||||||
|
|
||||||
error: malformed `derive` attribute input
|
error: malformed `derive` attribute input
|
||||||
--> $DIR/malformed-special-attrs.rs:10:1
|
--> $DIR/malformed-special-attrs.rs:10:1
|
||||||
|
|
|
|
||||||
LL | #[derive = ""]
|
LL | #[derive = ""]
|
||||||
| ^^^^^^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]`
|
| ^^^^^^^^^^^^^^ help: must be of the form: `#[derive(Trait1, Trait2, ...)]`
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
28
src/test/ui/proc-macro/attribute-after-derive.rs
Normal file
28
src/test/ui/proc-macro/attribute-after-derive.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Macro attributes are allowed after `#[derive]` and
|
||||||
|
// `#[derive]` fully configures the item for following attributes.
|
||||||
|
|
||||||
|
// check-pass
|
||||||
|
// compile-flags: -Z span-debug
|
||||||
|
// aux-build: test-macros.rs
|
||||||
|
|
||||||
|
#![no_std] // Don't load unnecessary hygiene information from std
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate test_macros;
|
||||||
|
|
||||||
|
#[print_attr]
|
||||||
|
#[derive(Print)]
|
||||||
|
struct AttributeDerive {
|
||||||
|
#[cfg(FALSE)]
|
||||||
|
field: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Print)]
|
||||||
|
#[print_attr]
|
||||||
|
struct DeriveAttribute {
|
||||||
|
#[cfg(FALSE)]
|
||||||
|
field: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
148
src/test/ui/proc-macro/attribute-after-derive.stdout
Normal file
148
src/test/ui/proc-macro/attribute-after-derive.stdout
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
PRINT-ATTR INPUT (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(FALSE)] field : u8, }
|
||||||
|
PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||||
|
Punct {
|
||||||
|
ch: '#',
|
||||||
|
spacing: Alone,
|
||||||
|
span: $DIR/attribute-after-derive.rs:15:1: 15:2 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Bracket,
|
||||||
|
stream: TokenStream [
|
||||||
|
Ident {
|
||||||
|
ident: "derive",
|
||||||
|
span: $DIR/attribute-after-derive.rs:15:3: 15:9 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Parenthesis,
|
||||||
|
stream: TokenStream [
|
||||||
|
Ident {
|
||||||
|
ident: "Print",
|
||||||
|
span: $DIR/attribute-after-derive.rs:15:10: 15:15 (#0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: $DIR/attribute-after-derive.rs:15:9: 15:16 (#0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: $DIR/attribute-after-derive.rs:15:2: 15:17 (#0),
|
||||||
|
},
|
||||||
|
Ident {
|
||||||
|
ident: "struct",
|
||||||
|
span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0),
|
||||||
|
},
|
||||||
|
Ident {
|
||||||
|
ident: "AttributeDerive",
|
||||||
|
span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Brace,
|
||||||
|
stream: TokenStream [
|
||||||
|
Punct {
|
||||||
|
ch: '#',
|
||||||
|
spacing: Alone,
|
||||||
|
span: $DIR/attribute-after-derive.rs:17:5: 17:6 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Bracket,
|
||||||
|
stream: TokenStream [
|
||||||
|
Ident {
|
||||||
|
ident: "cfg",
|
||||||
|
span: $DIR/attribute-after-derive.rs:17:7: 17:10 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Parenthesis,
|
||||||
|
stream: TokenStream [
|
||||||
|
Ident {
|
||||||
|
ident: "FALSE",
|
||||||
|
span: $DIR/attribute-after-derive.rs:17:11: 17:16 (#0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: $DIR/attribute-after-derive.rs:17:10: 17:17 (#0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: $DIR/attribute-after-derive.rs:17:6: 17:18 (#0),
|
||||||
|
},
|
||||||
|
Ident {
|
||||||
|
ident: "field",
|
||||||
|
span: $DIR/attribute-after-derive.rs:18:5: 18:10 (#0),
|
||||||
|
},
|
||||||
|
Punct {
|
||||||
|
ch: ':',
|
||||||
|
spacing: Alone,
|
||||||
|
span: $DIR/attribute-after-derive.rs:18:10: 18:11 (#0),
|
||||||
|
},
|
||||||
|
Ident {
|
||||||
|
ident: "u8",
|
||||||
|
span: $DIR/attribute-after-derive.rs:18:12: 18:14 (#0),
|
||||||
|
},
|
||||||
|
Punct {
|
||||||
|
ch: ',',
|
||||||
|
spacing: Alone,
|
||||||
|
span: $DIR/attribute-after-derive.rs:18:14: 18:15 (#0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive { }
|
||||||
|
PRINT-DERIVE INPUT (DEBUG): TokenStream [
|
||||||
|
Ident {
|
||||||
|
ident: "struct",
|
||||||
|
span: $DIR/attribute-after-derive.rs:16:1: 19:2 (#0),
|
||||||
|
},
|
||||||
|
Ident {
|
||||||
|
ident: "AttributeDerive",
|
||||||
|
span: $DIR/attribute-after-derive.rs:16:1: 19:2 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Brace,
|
||||||
|
stream: TokenStream [],
|
||||||
|
span: $DIR/attribute-after-derive.rs:16:1: 19:2 (#0),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { }
|
||||||
|
PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||||
|
Ident {
|
||||||
|
ident: "struct",
|
||||||
|
span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
|
||||||
|
},
|
||||||
|
Ident {
|
||||||
|
ident: "DeriveAttribute",
|
||||||
|
span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Brace,
|
||||||
|
stream: TokenStream [],
|
||||||
|
span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute { }
|
||||||
|
PRINT-DERIVE INPUT (DEBUG): TokenStream [
|
||||||
|
Punct {
|
||||||
|
ch: '#',
|
||||||
|
spacing: Alone,
|
||||||
|
span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Bracket,
|
||||||
|
stream: TokenStream [
|
||||||
|
Ident {
|
||||||
|
ident: "print_attr",
|
||||||
|
span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
|
||||||
|
},
|
||||||
|
Ident {
|
||||||
|
ident: "struct",
|
||||||
|
span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
|
||||||
|
},
|
||||||
|
Ident {
|
||||||
|
ident: "DeriveAttribute",
|
||||||
|
span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
delimiter: Brace,
|
||||||
|
stream: TokenStream [],
|
||||||
|
span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0),
|
||||||
|
},
|
||||||
|
]
|
@ -1,14 +0,0 @@
|
|||||||
// aux-build:test-macros.rs
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate test_macros;
|
|
||||||
|
|
||||||
#[identity_attr] // OK
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct Before;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
#[identity_attr] //~ ERROR macro attributes must be placed before `#[derive]`
|
|
||||||
struct After;
|
|
||||||
|
|
||||||
fn main() {}
|
|
@ -1,8 +0,0 @@
|
|||||||
error: macro attributes must be placed before `#[derive]`
|
|
||||||
--> $DIR/attribute-order-restricted.rs:11:1
|
|
||||||
|
|
|
||||||
LL | #[identity_attr]
|
|
||||||
| ^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
@ -17,6 +17,8 @@ macro_rules! gen_helper_use {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[empty_helper] //~ ERROR `empty_helper` is ambiguous
|
#[empty_helper] //~ ERROR `empty_helper` is ambiguous
|
||||||
|
//~| WARN derive helper attribute is used before it is introduced
|
||||||
|
//~| WARN this was previously accepted
|
||||||
#[derive(Empty)]
|
#[derive(Empty)]
|
||||||
struct S {
|
struct S {
|
||||||
#[empty_helper] // OK, no ambiguity, derive helpers have highest priority
|
#[empty_helper] // OK, no ambiguity, derive helpers have highest priority
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
error: cannot use a derive helper attribute through an import
|
error: cannot use a derive helper attribute through an import
|
||||||
--> $DIR/derive-helper-shadowing.rs:40:15
|
--> $DIR/derive-helper-shadowing.rs:42:15
|
||||||
|
|
|
|
||||||
LL | #[renamed]
|
LL | #[renamed]
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
|
|
||||||
note: the derive helper attribute imported here
|
note: the derive helper attribute imported here
|
||||||
--> $DIR/derive-helper-shadowing.rs:39:17
|
--> $DIR/derive-helper-shadowing.rs:41:17
|
||||||
|
|
|
|
||||||
LL | use empty_helper as renamed;
|
LL | use empty_helper as renamed;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: cannot find attribute `empty_helper` in this scope
|
error: cannot find attribute `empty_helper` in this scope
|
||||||
--> $DIR/derive-helper-shadowing.rs:36:22
|
--> $DIR/derive-helper-shadowing.rs:38:22
|
||||||
|
|
|
|
||||||
LL | #[derive(GenHelperUse)]
|
LL | #[derive(GenHelperUse)]
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
@ -30,13 +30,13 @@ LL | gen_helper_use!();
|
|||||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error[E0659]: `empty_helper` is ambiguous (name vs any other name during import resolution)
|
error[E0659]: `empty_helper` is ambiguous (name vs any other name during import resolution)
|
||||||
--> $DIR/derive-helper-shadowing.rs:24:13
|
--> $DIR/derive-helper-shadowing.rs:26:13
|
||||||
|
|
|
|
||||||
LL | use empty_helper;
|
LL | use empty_helper;
|
||||||
| ^^^^^^^^^^^^ ambiguous name
|
| ^^^^^^^^^^^^ ambiguous name
|
||||||
|
|
|
|
||||||
note: `empty_helper` could refer to the derive helper attribute defined here
|
note: `empty_helper` could refer to the derive helper attribute defined here
|
||||||
--> $DIR/derive-helper-shadowing.rs:20:10
|
--> $DIR/derive-helper-shadowing.rs:22:10
|
||||||
|
|
|
|
||||||
LL | #[derive(Empty)]
|
LL | #[derive(Empty)]
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
@ -54,7 +54,7 @@ LL | #[empty_helper]
|
|||||||
| ^^^^^^^^^^^^ ambiguous name
|
| ^^^^^^^^^^^^ ambiguous name
|
||||||
|
|
|
|
||||||
note: `empty_helper` could refer to the derive helper attribute defined here
|
note: `empty_helper` could refer to the derive helper attribute defined here
|
||||||
--> $DIR/derive-helper-shadowing.rs:20:10
|
--> $DIR/derive-helper-shadowing.rs:22:10
|
||||||
|
|
|
|
||||||
LL | #[derive(Empty)]
|
LL | #[derive(Empty)]
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
@ -65,6 +65,19 @@ LL | use test_macros::empty_attr as empty_helper;
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= help: use `crate::empty_helper` to refer to this attribute macro unambiguously
|
= help: use `crate::empty_helper` to refer to this attribute macro unambiguously
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
warning: derive helper attribute is used before it is introduced
|
||||||
|
--> $DIR/derive-helper-shadowing.rs:19:3
|
||||||
|
|
|
||||||
|
LL | #[empty_helper]
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | #[derive(Empty)]
|
||||||
|
| ----- the attribute is introduced here
|
||||||
|
|
|
||||||
|
= note: `#[warn(legacy_derive_helpers)]` on by default
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors; 1 warning emitted
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0659`.
|
For more information about this error, try `rustc --explain E0659`.
|
||||||
|
12
src/test/ui/proc-macro/derive-helper-vs-legacy.rs
Normal file
12
src/test/ui/proc-macro/derive-helper-vs-legacy.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// check-pass
|
||||||
|
// aux-build:test-macros.rs
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate test_macros;
|
||||||
|
|
||||||
|
#[derive(Empty)]
|
||||||
|
#[empty_helper] // OK, this is both derive helper and legacy derive helper
|
||||||
|
#[derive(Empty)]
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
fn main() {}
|
11
src/test/ui/proc-macro/derive-multiple-with-packed.rs
Normal file
11
src/test/ui/proc-macro/derive-multiple-with-packed.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[derive(Debug)] // OK, even if `Copy` is in the different `#[derive]`
|
||||||
|
#[derive(PartialEq)] // OK too
|
||||||
|
#[repr(packed)]
|
||||||
|
struct CacheRecordHeader {
|
||||||
|
field: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -4,8 +4,10 @@
|
|||||||
extern crate test_macros;
|
extern crate test_macros;
|
||||||
use test_macros::empty_attr as empty_helper;
|
use test_macros::empty_attr as empty_helper;
|
||||||
|
|
||||||
#[derive(Empty)]
|
|
||||||
#[empty_helper] //~ ERROR `empty_helper` is ambiguous
|
#[empty_helper] //~ ERROR `empty_helper` is ambiguous
|
||||||
|
//~| WARN derive helper attribute is used before it is introduced
|
||||||
|
//~| WARN this was previously accepted
|
||||||
|
#[derive(Empty)]
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
|
error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
|
||||||
--> $DIR/helper-attr-blocked-by-import-ambig.rs:8:3
|
--> $DIR/helper-attr-blocked-by-import-ambig.rs:7:3
|
||||||
|
|
|
|
||||||
LL | #[empty_helper]
|
LL | #[empty_helper]
|
||||||
| ^^^^^^^^^^^^ ambiguous name
|
| ^^^^^^^^^^^^ ambiguous name
|
||||||
|
|
|
|
||||||
note: `empty_helper` could refer to the derive helper attribute defined here
|
note: `empty_helper` could refer to the derive helper attribute defined here
|
||||||
--> $DIR/helper-attr-blocked-by-import-ambig.rs:7:10
|
--> $DIR/helper-attr-blocked-by-import-ambig.rs:10:10
|
||||||
|
|
|
|
||||||
LL | #[derive(Empty)]
|
LL | #[derive(Empty)]
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
@ -16,6 +16,19 @@ LL | use test_macros::empty_attr as empty_helper;
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= help: use `crate::empty_helper` to refer to this attribute macro unambiguously
|
= help: use `crate::empty_helper` to refer to this attribute macro unambiguously
|
||||||
|
|
||||||
error: aborting due to previous error
|
warning: derive helper attribute is used before it is introduced
|
||||||
|
--> $DIR/helper-attr-blocked-by-import-ambig.rs:7:3
|
||||||
|
|
|
||||||
|
LL | #[empty_helper]
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | #[derive(Empty)]
|
||||||
|
| ----- the attribute is introduced here
|
||||||
|
|
|
||||||
|
= note: `#[warn(legacy_derive_helpers)]` on by default
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
|
||||||
|
|
||||||
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0659`.
|
For more information about this error, try `rustc --explain E0659`.
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate test_macros;
|
extern crate test_macros;
|
||||||
|
|
||||||
#[print_helper(a)]
|
#[print_helper(a)] //~ WARN derive helper attribute is used before it is introduced
|
||||||
|
//~| WARN this was previously accepted
|
||||||
#[cfg_attr(not(FALSE), allow(dead_code))]
|
#[cfg_attr(not(FALSE), allow(dead_code))]
|
||||||
#[print_attr]
|
#[print_attr]
|
||||||
#[derive(Print)]
|
#[derive(Print)]
|
||||||
|
15
src/test/ui/proc-macro/issue-75930-derive-cfg.stderr
Normal file
15
src/test/ui/proc-macro/issue-75930-derive-cfg.stderr
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
warning: derive helper attribute is used before it is introduced
|
||||||
|
--> $DIR/issue-75930-derive-cfg.rs:16:3
|
||||||
|
|
|
||||||
|
LL | #[print_helper(a)]
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
...
|
||||||
|
LL | #[derive(Print)]
|
||||||
|
| ----- the attribute is introduced here
|
||||||
|
|
|
||||||
|
= note: `#[warn(legacy_derive_helpers)]` on by default
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -4,10 +4,18 @@
|
|||||||
extern crate derive_b;
|
extern crate derive_b;
|
||||||
|
|
||||||
#[B] //~ ERROR `B` is ambiguous
|
#[B] //~ ERROR `B` is ambiguous
|
||||||
|
//~| WARN derive helper attribute is used before it is introduced
|
||||||
|
//~| WARN this was previously accepted
|
||||||
#[C] //~ ERROR cannot find attribute `C` in this scope
|
#[C] //~ ERROR cannot find attribute `C` in this scope
|
||||||
#[B(D)] //~ ERROR `B` is ambiguous
|
#[B(D)] //~ ERROR `B` is ambiguous
|
||||||
|
//~| WARN derive helper attribute is used before it is introduced
|
||||||
|
//~| WARN this was previously accepted
|
||||||
#[B(E = "foo")] //~ ERROR `B` is ambiguous
|
#[B(E = "foo")] //~ ERROR `B` is ambiguous
|
||||||
|
//~| WARN derive helper attribute is used before it is introduced
|
||||||
|
//~| WARN this was previously accepted
|
||||||
#[B(arbitrary tokens)] //~ ERROR `B` is ambiguous
|
#[B(arbitrary tokens)] //~ ERROR `B` is ambiguous
|
||||||
|
//~| WARN derive helper attribute is used before it is introduced
|
||||||
|
//~| WARN this was previously accepted
|
||||||
#[derive(B)]
|
#[derive(B)]
|
||||||
struct B;
|
struct B;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: cannot find attribute `C` in this scope
|
error: cannot find attribute `C` in this scope
|
||||||
--> $DIR/proc-macro-attributes.rs:7:3
|
--> $DIR/proc-macro-attributes.rs:9:3
|
||||||
|
|
|
|
||||||
LL | #[C]
|
LL | #[C]
|
||||||
| ^ help: a derive helper attribute with a similar name exists: `B`
|
| ^ help: a derive helper attribute with a similar name exists: `B`
|
||||||
@ -11,41 +11,7 @@ LL | #[B]
|
|||||||
| ^ ambiguous name
|
| ^ ambiguous name
|
||||||
|
|
|
|
||||||
note: `B` could refer to the derive helper attribute defined here
|
note: `B` could refer to the derive helper attribute defined here
|
||||||
--> $DIR/proc-macro-attributes.rs:11:10
|
--> $DIR/proc-macro-attributes.rs:19:10
|
||||||
|
|
|
||||||
LL | #[derive(B)]
|
|
||||||
| ^
|
|
||||||
note: `B` could also refer to the derive macro imported here
|
|
||||||
--> $DIR/proc-macro-attributes.rs:3:1
|
|
||||||
|
|
|
||||||
LL | #[macro_use]
|
|
||||||
| ^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
|
|
||||||
--> $DIR/proc-macro-attributes.rs:8:3
|
|
||||||
|
|
|
||||||
LL | #[B(D)]
|
|
||||||
| ^ ambiguous name
|
|
||||||
|
|
|
||||||
note: `B` could refer to the derive helper attribute defined here
|
|
||||||
--> $DIR/proc-macro-attributes.rs:11:10
|
|
||||||
|
|
|
||||||
LL | #[derive(B)]
|
|
||||||
| ^
|
|
||||||
note: `B` could also refer to the derive macro imported here
|
|
||||||
--> $DIR/proc-macro-attributes.rs:3:1
|
|
||||||
|
|
|
||||||
LL | #[macro_use]
|
|
||||||
| ^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
|
|
||||||
--> $DIR/proc-macro-attributes.rs:9:3
|
|
||||||
|
|
|
||||||
LL | #[B(E = "foo")]
|
|
||||||
| ^ ambiguous name
|
|
||||||
|
|
|
||||||
note: `B` could refer to the derive helper attribute defined here
|
|
||||||
--> $DIR/proc-macro-attributes.rs:11:10
|
|
||||||
|
|
|
|
||||||
LL | #[derive(B)]
|
LL | #[derive(B)]
|
||||||
| ^
|
| ^
|
||||||
@ -58,11 +24,11 @@ LL | #[macro_use]
|
|||||||
error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
|
error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
|
||||||
--> $DIR/proc-macro-attributes.rs:10:3
|
--> $DIR/proc-macro-attributes.rs:10:3
|
||||||
|
|
|
|
||||||
LL | #[B(arbitrary tokens)]
|
LL | #[B(D)]
|
||||||
| ^ ambiguous name
|
| ^ ambiguous name
|
||||||
|
|
|
|
||||||
note: `B` could refer to the derive helper attribute defined here
|
note: `B` could refer to the derive helper attribute defined here
|
||||||
--> $DIR/proc-macro-attributes.rs:11:10
|
--> $DIR/proc-macro-attributes.rs:19:10
|
||||||
|
|
|
|
||||||
LL | #[derive(B)]
|
LL | #[derive(B)]
|
||||||
| ^
|
| ^
|
||||||
@ -72,6 +38,89 @@ note: `B` could also refer to the derive macro imported here
|
|||||||
LL | #[macro_use]
|
LL | #[macro_use]
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
|
||||||
|
--> $DIR/proc-macro-attributes.rs:13:3
|
||||||
|
|
|
||||||
|
LL | #[B(E = "foo")]
|
||||||
|
| ^ ambiguous name
|
||||||
|
|
|
||||||
|
note: `B` could refer to the derive helper attribute defined here
|
||||||
|
--> $DIR/proc-macro-attributes.rs:19:10
|
||||||
|
|
|
||||||
|
LL | #[derive(B)]
|
||||||
|
| ^
|
||||||
|
note: `B` could also refer to the derive macro imported here
|
||||||
|
--> $DIR/proc-macro-attributes.rs:3:1
|
||||||
|
|
|
||||||
|
LL | #[macro_use]
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
|
||||||
|
--> $DIR/proc-macro-attributes.rs:16:3
|
||||||
|
|
|
||||||
|
LL | #[B(arbitrary tokens)]
|
||||||
|
| ^ ambiguous name
|
||||||
|
|
|
||||||
|
note: `B` could refer to the derive helper attribute defined here
|
||||||
|
--> $DIR/proc-macro-attributes.rs:19:10
|
||||||
|
|
|
||||||
|
LL | #[derive(B)]
|
||||||
|
| ^
|
||||||
|
note: `B` could also refer to the derive macro imported here
|
||||||
|
--> $DIR/proc-macro-attributes.rs:3:1
|
||||||
|
|
|
||||||
|
LL | #[macro_use]
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
warning: derive helper attribute is used before it is introduced
|
||||||
|
--> $DIR/proc-macro-attributes.rs:6:3
|
||||||
|
|
|
||||||
|
LL | #[B]
|
||||||
|
| ^
|
||||||
|
...
|
||||||
|
LL | #[derive(B)]
|
||||||
|
| - the attribute is introduced here
|
||||||
|
|
|
||||||
|
= note: `#[warn(legacy_derive_helpers)]` on by default
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
|
||||||
|
|
||||||
|
warning: derive helper attribute is used before it is introduced
|
||||||
|
--> $DIR/proc-macro-attributes.rs:10:3
|
||||||
|
|
|
||||||
|
LL | #[B(D)]
|
||||||
|
| ^
|
||||||
|
...
|
||||||
|
LL | #[derive(B)]
|
||||||
|
| - the attribute is introduced here
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
|
||||||
|
|
||||||
|
warning: derive helper attribute is used before it is introduced
|
||||||
|
--> $DIR/proc-macro-attributes.rs:13:3
|
||||||
|
|
|
||||||
|
LL | #[B(E = "foo")]
|
||||||
|
| ^
|
||||||
|
...
|
||||||
|
LL | #[derive(B)]
|
||||||
|
| - the attribute is introduced here
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
|
||||||
|
|
||||||
|
warning: derive helper attribute is used before it is introduced
|
||||||
|
--> $DIR/proc-macro-attributes.rs:16:3
|
||||||
|
|
|
||||||
|
LL | #[B(arbitrary tokens)]
|
||||||
|
| ^
|
||||||
|
...
|
||||||
|
LL | #[derive(B)]
|
||||||
|
| - the attribute is introduced here
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors; 4 warnings emitted
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0659`.
|
For more information about this error, try `rustc --explain E0659`.
|
||||||
|
@ -17,9 +17,3 @@ pub fn cfg_attr(_: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
//~^ ERROR name `cfg_attr` is reserved in attribute namespace
|
//~^ ERROR name `cfg_attr` is reserved in attribute namespace
|
||||||
input
|
input
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn derive(_: TokenStream, input: TokenStream) -> TokenStream {
|
|
||||||
//~^ ERROR name `derive` is reserved in attribute namespace
|
|
||||||
input
|
|
||||||
}
|
|
||||||
|
@ -10,11 +10,5 @@ error: name `cfg_attr` is reserved in attribute namespace
|
|||||||
LL | pub fn cfg_attr(_: TokenStream, input: TokenStream) -> TokenStream {
|
LL | pub fn cfg_attr(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: name `derive` is reserved in attribute namespace
|
error: aborting due to 2 previous errors
|
||||||
--> $DIR/reserved-macro-names.rs:22:8
|
|
||||||
|
|
|
||||||
LL | pub fn derive(_: TokenStream, input: TokenStream) -> TokenStream {
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
|
||||||
|
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
#![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
|
#![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
|
||||||
//~^ ERROR `derive` may only be applied to structs, enums and unions
|
//~^ ERROR cannot determine resolution for the attribute macro `derive`
|
||||||
//~| ERROR cannot determine resolution for the derive macro `Debug`
|
|
||||||
//~| ERROR cannot determine resolution for the derive macro `PartialEq`
|
|
||||||
//~| ERROR cannot determine resolution for the derive macro `Eq`
|
|
||||||
struct DerivedOn;
|
struct DerivedOn;
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -1,33 +1,10 @@
|
|||||||
error[E0774]: `derive` may only be applied to structs, enums and unions
|
error: cannot determine resolution for the attribute macro `derive`
|
||||||
--> $DIR/issue-43927-non-ADT-derive.rs:3:1
|
--> $DIR/issue-43927-non-ADT-derive.rs:1:4
|
||||||
|
|
|
|
||||||
LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
|
LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug, PartialEq, Eq)]`
|
| ^^^^^^
|
||||||
|
|
||||||
error: cannot determine resolution for the derive macro `Debug`
|
|
||||||
--> $DIR/issue-43927-non-ADT-derive.rs:3:11
|
|
||||||
|
|
|
||||||
LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
|
|
||||||
| ^^^^^
|
|
||||||
|
|
|
|
||||||
= note: import resolution is stuck, try simplifying macro imports
|
= note: import resolution is stuck, try simplifying macro imports
|
||||||
|
|
||||||
error: cannot determine resolution for the derive macro `PartialEq`
|
error: aborting due to previous error
|
||||||
--> $DIR/issue-43927-non-ADT-derive.rs:3:18
|
|
||||||
|
|
|
||||||
LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
|
|
||||||
| ^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: import resolution is stuck, try simplifying macro imports
|
|
||||||
|
|
||||||
error: cannot determine resolution for the derive macro `Eq`
|
|
||||||
--> $DIR/issue-43927-non-ADT-derive.rs:3:29
|
|
||||||
|
|
|
||||||
LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute!
|
|
||||||
| ^^
|
|
||||||
|
|
|
||||||
= note: import resolution is stuck, try simplifying macro imports
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0774`.
|
|
||||||
|
@ -9,5 +9,5 @@ macro_rules! foo { () => () }
|
|||||||
fn main() {
|
fn main() {
|
||||||
foo::<T>!(); //~ ERROR generic arguments in macro path
|
foo::<T>!(); //~ ERROR generic arguments in macro path
|
||||||
foo::<>!(); //~ ERROR generic arguments in macro path
|
foo::<>!(); //~ ERROR generic arguments in macro path
|
||||||
m!(Default<>); //~ ERROR generic arguments in macro path
|
m!(Default<>); //~ ERROR unexpected generic arguments in path
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ error: generic arguments in macro path
|
|||||||
LL | foo::<>!();
|
LL | foo::<>!();
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: generic arguments in macro path
|
error: unexpected generic arguments in path
|
||||||
--> $DIR/macro-ty-params.rs:12:15
|
--> $DIR/macro-ty-params.rs:12:15
|
||||||
|
|
|
|
||||||
LL | m!(Default<>);
|
LL | m!(Default<>);
|
||||||
|
Loading…
Reference in New Issue
Block a user