Auto merge of #58899 - petrochenkov:derval2, r=estebank
Do not accidentally treat multi-segment meta-items as single-segment Fixes https://github.com/rust-lang/rust/issues/55168 and many other regressions from https://github.com/rust-lang/rust/pull/50030 Basically, attributes like `#[any::prefix::foo]` were commonly interpreted as `#[foo]` due to `name()` successfully returning the last segment (this applies to nested things as well `#[attr(any::prefix::foo)]`).
This commit is contained in:
commit
7cf074a1e6
53 changed files with 571 additions and 517 deletions
|
@ -166,7 +166,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
|
|||
// ```
|
||||
let hints: Vec<_> = item.attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.name() == "repr")
|
||||
.filter(|attr| attr.check_name("repr"))
|
||||
.filter_map(|attr| attr.meta_item_list())
|
||||
.flatten()
|
||||
.collect();
|
||||
|
@ -177,7 +177,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
|
|||
let mut is_transparent = false;
|
||||
|
||||
for hint in &hints {
|
||||
let name = if let Some(name) = hint.name() {
|
||||
let name = if let Some(name) = hint.ident_str() {
|
||||
name
|
||||
} else {
|
||||
// Invalid repr hint like repr(42). We don't check for unrecognized hints here
|
||||
|
@ -185,7 +185,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
|
|||
continue;
|
||||
};
|
||||
|
||||
let (article, allowed_targets) = match &*name.as_str() {
|
||||
let (article, allowed_targets) = match name {
|
||||
"C" | "align" => {
|
||||
is_c |= name == "C";
|
||||
if target != Target::Struct &&
|
||||
|
@ -233,7 +233,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
|
|||
_ => continue,
|
||||
};
|
||||
self.emit_repr_error(
|
||||
hint.span,
|
||||
hint.span(),
|
||||
item.span,
|
||||
&format!("attribute should be applied to {}", allowed_targets),
|
||||
&format!("not {} {}", article, allowed_targets),
|
||||
|
@ -242,7 +242,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
|
|||
|
||||
// Just point at all repr hints if there are any incompatibilities.
|
||||
// This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
|
||||
let hint_spans = hints.iter().map(|hint| hint.span);
|
||||
let hint_spans = hints.iter().map(|hint| hint.span());
|
||||
|
||||
// Error on repr(transparent, <anything else>).
|
||||
if is_transparent && hints.len() > 1 {
|
||||
|
@ -313,7 +313,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
|
|||
|
||||
fn check_used(&self, item: &hir::Item, target: Target) {
|
||||
for attr in &item.attrs {
|
||||
if attr.name() == "used" && target != Target::Static {
|
||||
if attr.check_name("used") && target != Target::Static {
|
||||
self.tcx.sess
|
||||
.span_err(attr.span, "attribute must be applied to a `static` variable");
|
||||
}
|
||||
|
|
|
@ -197,7 +197,8 @@ impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
|
|||
let filtered: SmallVec<[&ast::Attribute; 8]> = self
|
||||
.iter()
|
||||
.filter(|attr| {
|
||||
!attr.is_sugared_doc && !hcx.is_ignored_attr(attr.name())
|
||||
!attr.is_sugared_doc &&
|
||||
!attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name))
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -224,7 +225,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute {
|
|||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
// Make sure that these have been filtered out.
|
||||
debug_assert!(!hcx.is_ignored_attr(self.name()));
|
||||
debug_assert!(!self.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name)));
|
||||
debug_assert!(!self.is_sugared_doc);
|
||||
|
||||
let ast::Attribute {
|
||||
|
@ -359,15 +360,13 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>(
|
|||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for_spanned!(::syntax::ast::NestedMetaItemKind);
|
||||
|
||||
impl_stable_hash_for!(enum ::syntax::ast::NestedMetaItemKind {
|
||||
impl_stable_hash_for!(enum ::syntax::ast::NestedMetaItem {
|
||||
MetaItem(meta_item),
|
||||
Literal(lit)
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct ::syntax::ast::MetaItem {
|
||||
ident,
|
||||
path,
|
||||
node,
|
||||
span
|
||||
});
|
||||
|
|
|
@ -194,7 +194,7 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
struct_span_err!(sess, span, E0452, "malformed lint attribute")
|
||||
};
|
||||
for attr in attrs {
|
||||
let level = match Level::from_str(&attr.name().as_str()) {
|
||||
let level = match attr.ident_str().and_then(|name| Level::from_str(name)) {
|
||||
None => continue,
|
||||
Some(lvl) => lvl,
|
||||
};
|
||||
|
@ -221,7 +221,7 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
match item.node {
|
||||
ast::MetaItemKind::Word => {} // actual lint names handled later
|
||||
ast::MetaItemKind::NameValue(ref name_value) => {
|
||||
if item.ident == "reason" {
|
||||
if item.path == "reason" {
|
||||
// found reason, reslice meta list to exclude it
|
||||
metas = &metas[0..metas.len()-1];
|
||||
// FIXME (#55112): issue unused-attributes lint if we thereby
|
||||
|
@ -255,13 +255,13 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
}
|
||||
|
||||
for li in metas {
|
||||
let word = match li.word() {
|
||||
Some(word) => word,
|
||||
None => {
|
||||
let mut err = bad_attr(li.span);
|
||||
let meta_item = match li.meta_item() {
|
||||
Some(meta_item) if meta_item.is_word() => meta_item,
|
||||
_ => {
|
||||
let mut err = bad_attr(li.span());
|
||||
if let Some(item) = li.meta_item() {
|
||||
if let ast::MetaItemKind::NameValue(_) = item.node {
|
||||
if item.ident == "reason" {
|
||||
if item.path == "reason" {
|
||||
err.help("reason in lint attribute must come last");
|
||||
}
|
||||
}
|
||||
|
@ -270,26 +270,27 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
continue;
|
||||
}
|
||||
};
|
||||
let tool_name = if let Some(lint_tool) = word.is_scoped() {
|
||||
if !attr::is_known_lint_tool(lint_tool) {
|
||||
let tool_name = if meta_item.path.segments.len() > 1 {
|
||||
let tool_ident = meta_item.path.segments[0].ident;
|
||||
if !attr::is_known_lint_tool(tool_ident) {
|
||||
span_err!(
|
||||
sess,
|
||||
lint_tool.span,
|
||||
tool_ident.span,
|
||||
E0710,
|
||||
"an unknown tool name found in scoped lint: `{}`",
|
||||
word.ident
|
||||
meta_item.path
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
Some(lint_tool.as_str())
|
||||
Some(tool_ident.as_str())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let name = word.name();
|
||||
let name = meta_item.path.segments.last().expect("empty lint name").ident.name;
|
||||
match store.check_lint_name(&name.as_str(), tool_name) {
|
||||
CheckLintNameResult::Ok(ids) => {
|
||||
let src = LintSource::Node(name, li.span, reason);
|
||||
let src = LintSource::Node(name, li.span(), reason);
|
||||
for id in ids {
|
||||
specs.insert(*id, (level, src));
|
||||
}
|
||||
|
@ -300,7 +301,7 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
Ok(ids) => {
|
||||
let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
|
||||
let src = LintSource::Node(
|
||||
Symbol::intern(complete_name), li.span, reason
|
||||
Symbol::intern(complete_name), li.span(), reason
|
||||
);
|
||||
for id in ids {
|
||||
specs.insert(*id, (level, src));
|
||||
|
@ -322,18 +323,18 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
lint,
|
||||
lvl,
|
||||
src,
|
||||
Some(li.span.into()),
|
||||
Some(li.span().into()),
|
||||
&msg,
|
||||
);
|
||||
err.span_suggestion(
|
||||
li.span,
|
||||
li.span(),
|
||||
"change it to",
|
||||
new_lint_name.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
).emit();
|
||||
|
||||
let src = LintSource::Node(
|
||||
Symbol::intern(&new_lint_name), li.span, reason
|
||||
Symbol::intern(&new_lint_name), li.span(), reason
|
||||
);
|
||||
for id in ids {
|
||||
specs.insert(*id, (level, src));
|
||||
|
@ -360,11 +361,11 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
lint,
|
||||
level,
|
||||
src,
|
||||
Some(li.span.into()),
|
||||
Some(li.span().into()),
|
||||
&msg);
|
||||
if let Some(new_name) = renamed {
|
||||
err.span_suggestion(
|
||||
li.span,
|
||||
li.span(),
|
||||
"use the new name",
|
||||
new_name,
|
||||
Applicability::MachineApplicable
|
||||
|
@ -383,12 +384,12 @@ impl<'a> LintLevelsBuilder<'a> {
|
|||
lint,
|
||||
level,
|
||||
src,
|
||||
Some(li.span.into()),
|
||||
Some(li.span().into()),
|
||||
&msg);
|
||||
|
||||
if let Some(suggestion) = suggestion {
|
||||
db.span_suggestion(
|
||||
li.span,
|
||||
li.span(),
|
||||
"did you mean",
|
||||
suggestion.to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
|
|
|
@ -724,7 +724,7 @@ pub fn struct_lint_level<'a>(sess: &'a Session,
|
|||
pub fn maybe_lint_level_root(tcx: TyCtxt<'_, '_, '_>, id: hir::HirId) -> bool {
|
||||
let attrs = tcx.hir().attrs_by_hir_id(id);
|
||||
for attr in attrs {
|
||||
if Level::from_str(&attr.name().as_str()).is_some() {
|
||||
if attr.ident_str().and_then(Level::from_str).is_some() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,9 +65,9 @@ impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> {
|
|||
for meta in metas {
|
||||
if let Some(mi) = meta.meta_item() {
|
||||
// Find the `feature = ".."` meta-item.
|
||||
match (&*mi.name().as_str(), mi.value_str()) {
|
||||
("feature", val) => feature = val,
|
||||
("since", val) => since = val,
|
||||
match (mi.ident_str(), mi.value_str()) {
|
||||
(Some("feature"), val) => feature = val,
|
||||
(Some("since"), val) => since = val,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,11 +194,12 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
|
|||
} else {
|
||||
// Emit errors for non-staged-api crates.
|
||||
for attr in attrs {
|
||||
let tag = attr.name();
|
||||
if tag == "unstable" || tag == "stable" || tag == "rustc_deprecated" {
|
||||
attr::mark_used(attr);
|
||||
self.tcx.sess.span_err(attr.span(), "stability attributes may not be used \
|
||||
outside of the standard library");
|
||||
if let Some(tag) = attr.ident_str() {
|
||||
if tag == "unstable" || tag == "stable" || tag == "rustc_deprecated" {
|
||||
attr::mark_used(attr);
|
||||
self.tcx.sess.span_err(attr.span, "stability attributes may not be used \
|
||||
outside of the standard library");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1839,7 +1839,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
|
|||
|
||||
match &mut parser.parse_meta_item() {
|
||||
Ok(meta_item) if parser.token == token::Eof => {
|
||||
if meta_item.ident.segments.len() != 1 {
|
||||
if meta_item.path.segments.len() != 1 {
|
||||
error!("argument key must be an identifier");
|
||||
}
|
||||
match &meta_item.node {
|
||||
|
@ -1850,7 +1850,8 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
|
|||
error!("argument value must be a string");
|
||||
}
|
||||
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
|
||||
return (meta_item.name(), meta_item.value_str());
|
||||
let ident = meta_item.ident().expect("multi-segment cfg key");
|
||||
return (ident.name, meta_item.value_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
|||
{
|
||||
if let Some(items) = item.meta_item_list() {
|
||||
if let Ok(subcommand) =
|
||||
Self::parse(tcx, trait_def_id, &items, item.span, false)
|
||||
Self::parse(tcx, trait_def_id, &items, item.span(), false)
|
||||
{
|
||||
subcommands.push(subcommand);
|
||||
} else {
|
||||
|
@ -118,7 +118,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
|||
}
|
||||
|
||||
// nothing found
|
||||
parse_error(tcx, item.span,
|
||||
parse_error(tcx, item.span(),
|
||||
"this attribute must have a valid value",
|
||||
"expected value here",
|
||||
Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#));
|
||||
|
@ -177,10 +177,12 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
|||
for command in self.subcommands.iter().chain(Some(self)).rev() {
|
||||
if let Some(ref condition) = command.condition {
|
||||
if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| {
|
||||
options.contains(&(
|
||||
c.name().as_str().to_string(),
|
||||
c.value_str().map(|s| s.as_str().to_string())
|
||||
))
|
||||
c.ident_str().map_or(false, |name| {
|
||||
options.contains(&(
|
||||
name.to_string(),
|
||||
c.value_str().map(|s| s.as_str().to_string())
|
||||
))
|
||||
})
|
||||
}) {
|
||||
debug!("evaluate: skipping {:?} due to condition", command);
|
||||
continue
|
||||
|
|
|
@ -683,7 +683,7 @@ impl RustcDefaultCalls {
|
|||
|
||||
let mut cfgs = sess.parse_sess.config.iter().filter_map(|&(name, ref value)| {
|
||||
let gated_cfg = GatedCfg::gate(&ast::MetaItem {
|
||||
ident: ast::Path::from_ident(ast::Ident::with_empty_ctxt(name)),
|
||||
path: ast::Path::from_ident(ast::Ident::with_empty_ctxt(name)),
|
||||
node: ast::MetaItemKind::Word,
|
||||
span: DUMMY_SP,
|
||||
});
|
||||
|
|
|
@ -99,12 +99,12 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
|
|||
fn argument(&self, attr: &ast::Attribute) -> Option<ast::Name> {
|
||||
let mut value = None;
|
||||
for list_item in attr.meta_item_list().unwrap_or_default() {
|
||||
match list_item.word() {
|
||||
Some(word) if value.is_none() =>
|
||||
value = Some(word.name()),
|
||||
match list_item.ident() {
|
||||
Some(ident) if list_item.is_word() && value.is_none() =>
|
||||
value = Some(ident.name),
|
||||
_ =>
|
||||
// FIXME better-encapsulate meta_item (don't directly access `node`)
|
||||
span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node),
|
||||
span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item),
|
||||
}
|
||||
}
|
||||
value
|
||||
|
|
|
@ -153,7 +153,7 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
|
|||
return value;
|
||||
} else {
|
||||
self.tcx.sess.span_fatal(
|
||||
item.span,
|
||||
item.span(),
|
||||
&format!("associated value expected for `{}`", name));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -430,13 +430,13 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
|
|||
if DepNode::has_label_string(label) {
|
||||
if out.contains(label) {
|
||||
self.tcx.sess.span_fatal(
|
||||
item.span,
|
||||
item.span(),
|
||||
&format!("dep-node label `{}` is repeated", label));
|
||||
}
|
||||
out.insert(label.to_string());
|
||||
} else {
|
||||
self.tcx.sess.span_fatal(
|
||||
item.span,
|
||||
item.span(),
|
||||
&format!("dep-node label `{}` not recognized", label));
|
||||
}
|
||||
}
|
||||
|
@ -576,13 +576,13 @@ fn expect_associated_value(tcx: TyCtxt<'_, '_, '_>, item: &NestedMetaItem) -> as
|
|||
if let Some(value) = item.value_str() {
|
||||
value
|
||||
} else {
|
||||
let msg = if let Some(name) = item.name() {
|
||||
let msg = if let Some(name) = item.ident_str() {
|
||||
format!("associated value expected for `{}`", name)
|
||||
} else {
|
||||
"expected an associated value".to_string()
|
||||
};
|
||||
|
||||
tcx.sess.span_fatal(item.span, &msg);
|
||||
tcx.sess.span_fatal(item.span(), &msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -760,7 +760,7 @@ impl LintPass for DeprecatedAttr {
|
|||
impl EarlyLintPass for DeprecatedAttr {
|
||||
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
|
||||
for &&(n, _, _, ref g) in &self.depr_attrs {
|
||||
if attr.name() == n {
|
||||
if attr.ident_str() == Some(n) {
|
||||
if let &AttributeGate::Gated(Stability::Deprecated(link, suggestion),
|
||||
ref name,
|
||||
ref reason,
|
||||
|
@ -831,7 +831,7 @@ impl UnusedDocComment {
|
|||
|
||||
let span = sugared_span.take().unwrap_or_else(|| attr.span);
|
||||
|
||||
if attr.name() == "doc" {
|
||||
if attr.check_name("doc") {
|
||||
let mut err = cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, "unused doc comment");
|
||||
|
||||
err.span_label(
|
||||
|
|
|
@ -267,19 +267,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
|
|||
}
|
||||
}
|
||||
|
||||
let name = attr.name();
|
||||
let name = attr.ident_str();
|
||||
if !attr::is_used(attr) {
|
||||
debug!("Emitting warning for: {:?}", attr);
|
||||
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
|
||||
// Is it a builtin attribute that must be used at the crate level?
|
||||
let known_crate = BUILTIN_ATTRIBUTES.iter()
|
||||
.find(|&&(builtin, ty, ..)| name == builtin && ty == AttributeType::CrateLevel)
|
||||
.find(|&&(builtin, ty, ..)| {
|
||||
name == Some(builtin) && ty == AttributeType::CrateLevel
|
||||
})
|
||||
.is_some();
|
||||
|
||||
// Has a plugin registered this attribute as one that must be used at
|
||||
// the crate level?
|
||||
let plugin_crate = plugin_attributes.iter()
|
||||
.find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t)
|
||||
.find(|&&(ref x, t)| name == Some(x) && AttributeType::CrateLevel == t)
|
||||
.is_some();
|
||||
if known_crate || plugin_crate {
|
||||
let msg = match attr.style {
|
||||
|
|
|
@ -76,7 +76,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> {
|
|||
k => {
|
||||
struct_span_err!(self.tcx.sess, m.span, E0458,
|
||||
"unknown kind: `{}`", k)
|
||||
.span_label(item.span, "unknown kind").emit();
|
||||
.span_label(item.span(), "unknown kind").emit();
|
||||
cstore::NativeUnknown
|
||||
}
|
||||
};
|
||||
|
|
|
@ -146,7 +146,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitD
|
|||
} else {
|
||||
sess.span_err(
|
||||
item.span,
|
||||
&format!("{} attribute requires a path", item.ident));
|
||||
&format!("{} attribute requires a path", item.path));
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,9 +53,7 @@ impl<'a, 'tcx> VarianceTest<'a, 'tcx> {
|
|||
// The `..` are the names of fields to dump.
|
||||
let meta_items = attr.meta_item_list().unwrap_or_default();
|
||||
for meta_item in meta_items {
|
||||
let name = meta_item.word().map(|mi| mi.name().as_str());
|
||||
let name = name.as_ref().map(|s| &s[..]).unwrap_or("");
|
||||
|
||||
let name = meta_item.ident_str().unwrap_or("");
|
||||
match name {
|
||||
"abi" => {
|
||||
self.tcx
|
||||
|
@ -88,7 +86,7 @@ impl<'a, 'tcx> VarianceTest<'a, 'tcx> {
|
|||
|
||||
_ => {
|
||||
self.tcx.sess.span_err(
|
||||
meta_item.span,
|
||||
meta_item.span(),
|
||||
&format!("unrecognized field name `{}`", name),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -56,10 +56,10 @@ pub fn load_plugins(sess: &Session,
|
|||
|
||||
for plugin in plugins {
|
||||
// plugins must have a name and can't be key = value
|
||||
match plugin.name() {
|
||||
match plugin.ident_str() {
|
||||
Some(name) if !plugin.is_value_str() => {
|
||||
let args = plugin.meta_item_list().map(ToOwned::to_owned);
|
||||
loader.load_plugin(plugin.span, &name.as_str(), args.unwrap_or_default());
|
||||
loader.load_plugin(plugin.span(), name, args.unwrap_or_default());
|
||||
},
|
||||
_ => call_malformed_plugin_attribute(sess, attr.span),
|
||||
}
|
||||
|
|
|
@ -463,10 +463,9 @@ impl<'a> Resolver<'a> {
|
|||
if let Some(attr) = attr::find_by_name(&item.attrs, "proc_macro_derive") {
|
||||
if let Some(trait_attr) =
|
||||
attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
|
||||
if let Some(ident) = trait_attr.name().map(Ident::with_empty_ctxt) {
|
||||
let sp = trait_attr.span;
|
||||
if let Some(ident) = trait_attr.ident() {
|
||||
let def = Def::Macro(def.def_id(), MacroKind::ProcMacroStub);
|
||||
self.define(parent, ident, MacroNS, (def, vis, sp, expansion));
|
||||
self.define(parent, ident, MacroNS, (def, vis, ident.span, expansion));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -812,14 +811,14 @@ impl<'a> Resolver<'a> {
|
|||
break;
|
||||
}
|
||||
MetaItemKind::List(nested_metas) => for nested_meta in nested_metas {
|
||||
match nested_meta.word() {
|
||||
Some(word) => single_imports.push((word.name(), word.span)),
|
||||
None => ill_formed(nested_meta.span),
|
||||
match nested_meta.ident() {
|
||||
Some(ident) if nested_meta.is_word() => single_imports.push(ident),
|
||||
_ => ill_formed(nested_meta.span()),
|
||||
}
|
||||
}
|
||||
MetaItemKind::NameValue(..) => ill_formed(meta.span),
|
||||
}
|
||||
None => ill_formed(attr.span()),
|
||||
None => ill_formed(attr.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -850,23 +849,23 @@ impl<'a> Resolver<'a> {
|
|||
self.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing);
|
||||
});
|
||||
} else {
|
||||
for (name, span) in single_imports.iter().cloned() {
|
||||
let ident = Ident::with_empty_ctxt(name);
|
||||
for ident in single_imports.iter().cloned() {
|
||||
let result = self.resolve_ident_in_module(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
MacroNS,
|
||||
None,
|
||||
false,
|
||||
span,
|
||||
ident.span,
|
||||
);
|
||||
if let Ok(binding) = result {
|
||||
let directive = macro_use_directive(span);
|
||||
let directive = macro_use_directive(ident.span);
|
||||
self.potentially_unused_imports.push(directive);
|
||||
let imported_binding = self.import(binding, directive);
|
||||
self.legacy_import_macro(name, imported_binding, span, allow_shadowing);
|
||||
self.legacy_import_macro(ident.name, imported_binding,
|
||||
ident.span, allow_shadowing);
|
||||
} else {
|
||||
span_err!(self.session, span, E0469, "imported macro not found");
|
||||
span_err!(self.session, ident.span, E0469, "imported macro not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2326,7 +2326,7 @@ fn from_target_feature(
|
|||
if !item.check_name("enable") {
|
||||
let msg = "#[target_feature(..)] only accepts sub-keys of `enable` \
|
||||
currently";
|
||||
tcx.sess.span_err(item.span, &msg);
|
||||
tcx.sess.span_err(item.span(), &msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2336,7 +2336,7 @@ fn from_target_feature(
|
|||
None => {
|
||||
let msg = "#[target_feature] attribute must be of the form \
|
||||
#[target_feature(enable = \"..\")]";
|
||||
tcx.sess.span_err(item.span, &msg);
|
||||
tcx.sess.span_err(item.span(), &msg);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
@ -2352,7 +2352,7 @@ fn from_target_feature(
|
|||
this target",
|
||||
feature
|
||||
);
|
||||
let mut err = tcx.sess.struct_span_err(item.span, &msg);
|
||||
let mut err = tcx.sess.struct_span_err(item.span(), &msg);
|
||||
|
||||
if feature.starts_with("+") {
|
||||
let valid = whitelist.contains_key(&feature[1..]);
|
||||
|
@ -2387,7 +2387,7 @@ fn from_target_feature(
|
|||
feature_gate::emit_feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
feature_gate.as_ref().unwrap(),
|
||||
item.span,
|
||||
item.span(),
|
||||
feature_gate::GateIssue::Language,
|
||||
&format!("the target feature `{}` is currently unstable", feature),
|
||||
);
|
||||
|
@ -2549,7 +2549,7 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
|
|||
} else {
|
||||
span_err!(
|
||||
tcx.sess.diagnostic(),
|
||||
items[0].span,
|
||||
items[0].span(),
|
||||
E0535,
|
||||
"invalid argument"
|
||||
);
|
||||
|
@ -2583,7 +2583,7 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen
|
|||
} else if list_contains_name(&items[..], "speed") {
|
||||
OptimizeAttr::Speed
|
||||
} else {
|
||||
err(items[0].span, "invalid argument");
|
||||
err(items[0].span(), "invalid argument");
|
||||
OptimizeAttr::None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::fmt::{self, Write};
|
|||
use std::ops;
|
||||
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind, LitKind};
|
||||
use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, LitKind};
|
||||
use syntax::parse::ParseSess;
|
||||
use syntax::feature_gate::Features;
|
||||
|
||||
|
@ -41,9 +41,9 @@ pub struct InvalidCfgError {
|
|||
impl Cfg {
|
||||
/// Parses a `NestedMetaItem` into a `Cfg`.
|
||||
fn parse_nested(nested_cfg: &NestedMetaItem) -> Result<Cfg, InvalidCfgError> {
|
||||
match nested_cfg.node {
|
||||
NestedMetaItemKind::MetaItem(ref cfg) => Cfg::parse(cfg),
|
||||
NestedMetaItemKind::Literal(ref lit) => Err(InvalidCfgError {
|
||||
match nested_cfg {
|
||||
NestedMetaItem::MetaItem(ref cfg) => Cfg::parse(cfg),
|
||||
NestedMetaItem::Literal(ref lit) => Err(InvalidCfgError {
|
||||
msg: "unexpected literal",
|
||||
span: lit.span,
|
||||
}),
|
||||
|
@ -58,7 +58,13 @@ impl Cfg {
|
|||
/// If the content is not properly formatted, it will return an error indicating what and where
|
||||
/// the error is.
|
||||
pub fn parse(cfg: &MetaItem) -> Result<Cfg, InvalidCfgError> {
|
||||
let name = cfg.name();
|
||||
let name = match cfg.ident() {
|
||||
Some(ident) => ident.name,
|
||||
None => return Err(InvalidCfgError {
|
||||
msg: "expected a single identifier",
|
||||
span: cfg.span
|
||||
}),
|
||||
};
|
||||
match cfg.node {
|
||||
MetaItemKind::Word => Ok(Cfg::Cfg(name, None)),
|
||||
MetaItemKind::NameValue(ref lit) => match lit.node {
|
||||
|
@ -424,7 +430,7 @@ mod test {
|
|||
|
||||
fn dummy_meta_item_word(name: &str) -> MetaItem {
|
||||
MetaItem {
|
||||
ident: Path::from_ident(Ident::from_str(name)),
|
||||
path: Path::from_ident(Ident::from_str(name)),
|
||||
node: MetaItemKind::Word,
|
||||
span: DUMMY_SP,
|
||||
}
|
||||
|
@ -433,12 +439,12 @@ mod test {
|
|||
macro_rules! dummy_meta_item_list {
|
||||
($name:ident, [$($list:ident),* $(,)?]) => {
|
||||
MetaItem {
|
||||
ident: Path::from_ident(Ident::from_str(stringify!($name))),
|
||||
path: Path::from_ident(Ident::from_str(stringify!($name))),
|
||||
node: MetaItemKind::List(vec![
|
||||
$(
|
||||
dummy_spanned(NestedMetaItemKind::MetaItem(
|
||||
NestedMetaItem::MetaItem(
|
||||
dummy_meta_item_word(stringify!($list)),
|
||||
)),
|
||||
),
|
||||
)*
|
||||
]),
|
||||
span: DUMMY_SP,
|
||||
|
@ -447,10 +453,10 @@ mod test {
|
|||
|
||||
($name:ident, [$($list:expr),* $(,)?]) => {
|
||||
MetaItem {
|
||||
ident: Path::from_ident(Ident::from_str(stringify!($name))),
|
||||
path: Path::from_ident(Ident::from_str(stringify!($name))),
|
||||
node: MetaItemKind::List(vec![
|
||||
$(
|
||||
dummy_spanned(NestedMetaItemKind::MetaItem($list)),
|
||||
NestedMetaItem::MetaItem($list),
|
||||
)*
|
||||
]),
|
||||
span: DUMMY_SP,
|
||||
|
@ -587,7 +593,7 @@ mod test {
|
|||
assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all")));
|
||||
|
||||
let mi = MetaItem {
|
||||
ident: Path::from_ident(Ident::from_str("all")),
|
||||
path: Path::from_ident(Ident::from_str("all")),
|
||||
node: MetaItemKind::NameValue(dummy_spanned(LitKind::Str(
|
||||
Symbol::intern("done"),
|
||||
StrStyle::Cooked,
|
||||
|
@ -622,7 +628,7 @@ mod test {
|
|||
fn test_parse_err() {
|
||||
with_globals(|| {
|
||||
let mi = MetaItem {
|
||||
ident: Path::from_ident(Ident::from_str("foo")),
|
||||
path: Path::from_ident(Ident::from_str("foo")),
|
||||
node: MetaItemKind::NameValue(dummy_spanned(LitKind::Bool(false))),
|
||||
span: DUMMY_SP,
|
||||
};
|
||||
|
|
|
@ -492,7 +492,7 @@ impl Item {
|
|||
|
||||
pub fn is_non_exhaustive(&self) -> bool {
|
||||
self.attrs.other_attrs.iter()
|
||||
.any(|a| a.name().as_str() == "non_exhaustive")
|
||||
.any(|a| a.check_name("non_exhaustive"))
|
||||
}
|
||||
|
||||
/// Returns a documentation-level item type from the item.
|
||||
|
@ -777,15 +777,15 @@ pub struct Attributes {
|
|||
impl Attributes {
|
||||
/// Extracts the content from an attribute `#[doc(cfg(content))]`.
|
||||
fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
|
||||
use syntax::ast::NestedMetaItemKind::MetaItem;
|
||||
use syntax::ast::NestedMetaItem::MetaItem;
|
||||
|
||||
if let ast::MetaItemKind::List(ref nmis) = mi.node {
|
||||
if nmis.len() == 1 {
|
||||
if let MetaItem(ref cfg_mi) = nmis[0].node {
|
||||
if let MetaItem(ref cfg_mi) = nmis[0] {
|
||||
if cfg_mi.check_name("cfg") {
|
||||
if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.node {
|
||||
if cfg_nmis.len() == 1 {
|
||||
if let MetaItem(ref content_mi) = cfg_nmis[0].node {
|
||||
if let MetaItem(ref content_mi) = cfg_nmis[0] {
|
||||
return Some(content_mi);
|
||||
}
|
||||
}
|
||||
|
@ -3683,7 +3683,7 @@ impl Clean<Vec<Item>> for doctree::ExternCrate {
|
|||
fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
|
||||
|
||||
let please_inline = self.vis.node.is_pub() && self.attrs.iter().any(|a| {
|
||||
a.name() == "doc" && match a.meta_item_list() {
|
||||
a.check_name("doc") && match a.meta_item_list() {
|
||||
Some(l) => attr::list_contains_name(&l, "inline"),
|
||||
None => false,
|
||||
}
|
||||
|
@ -3722,7 +3722,7 @@ impl Clean<Vec<Item>> for doctree::Import {
|
|||
// #[doc(no_inline)] attribute is present.
|
||||
// Don't inline doc(hidden) imports so they can be stripped at a later stage.
|
||||
let mut denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| {
|
||||
a.name() == "doc" && match a.meta_item_list() {
|
||||
a.check_name("doc") && match a.meta_item_list() {
|
||||
Some(l) => attr::list_contains_name(&l, "no_inline") ||
|
||||
attr::list_contains_name(&l, "hidden"),
|
||||
None => false,
|
||||
|
|
|
@ -521,8 +521,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
|||
for attr in krate.module.as_ref().unwrap().attrs.lists("doc") {
|
||||
let diag = ctxt.sess().diagnostic();
|
||||
|
||||
let name = attr.name().map(|s| s.as_str());
|
||||
let name = name.as_ref().map(|s| &s[..]);
|
||||
let name = attr.ident_str();
|
||||
if attr.is_word() {
|
||||
if name == Some("no_default_passes") {
|
||||
report_deprecated_attr("no_default_passes", diag);
|
||||
|
|
|
@ -562,8 +562,7 @@ pub fn run(mut krate: clean::Crate,
|
|||
// going to emit HTML
|
||||
if let Some(attrs) = krate.module.as_ref().map(|m| &m.attrs) {
|
||||
for attr in attrs.lists("doc") {
|
||||
let name = attr.name().map(|s| s.as_str());
|
||||
match (name.as_ref().map(|s| &s[..]), attr.value_str()) {
|
||||
match (attr.ident_str(), attr.value_str()) {
|
||||
(Some("html_favicon_url"), Some(s)) => {
|
||||
scx.layout.favicon = s.to_string();
|
||||
}
|
||||
|
@ -3714,19 +3713,19 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
|
|||
}
|
||||
|
||||
fn render_attribute(attr: &ast::MetaItem) -> Option<String> {
|
||||
let name = attr.name();
|
||||
let path = attr.path.to_string();
|
||||
|
||||
if attr.is_word() {
|
||||
Some(name.to_string())
|
||||
Some(path)
|
||||
} else if let Some(v) = attr.value_str() {
|
||||
Some(format!("{} = {:?}", name, v.as_str()))
|
||||
Some(format!("{} = {:?}", path, v.as_str()))
|
||||
} else if let Some(values) = attr.meta_item_list() {
|
||||
let display: Vec<_> = values.iter().filter_map(|attr| {
|
||||
attr.meta_item().and_then(|mi| render_attribute(mi))
|
||||
}).collect();
|
||||
|
||||
if display.len() > 0 {
|
||||
Some(format!("{}({})", name, display.join(", ")))
|
||||
Some(format!("{}({})", path, display.join(", ")))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -3750,8 +3749,7 @@ fn render_attributes(w: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt::Resul
|
|||
let mut attrs = String::new();
|
||||
|
||||
for attr in &it.attrs.other_attrs {
|
||||
let name = attr.name();
|
||||
if !ATTRIBUTE_WHITELIST.contains(&&*name.as_str()) {
|
||||
if !attr.ident_str().map_or(false, |name| ATTRIBUTE_WHITELIST.contains(&name)) {
|
||||
continue;
|
||||
}
|
||||
if let Some(s) = render_attribute(&attr.meta().unwrap()) {
|
||||
|
|
|
@ -178,9 +178,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
Some(kind) => {
|
||||
let name = if kind == MacroKind::Derive {
|
||||
item.attrs.lists("proc_macro_derive")
|
||||
.filter_map(|mi| mi.name())
|
||||
.filter_map(|mi| mi.ident())
|
||||
.next()
|
||||
.expect("proc-macro derives require a name")
|
||||
.name
|
||||
} else {
|
||||
name
|
||||
};
|
||||
|
@ -193,8 +194,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
|
||||
if let Some(list) = mi.meta_item_list() {
|
||||
for inner_mi in list {
|
||||
if let Some(name) = inner_mi.name() {
|
||||
helpers.push(name);
|
||||
if let Some(ident) = inner_mi.ident() {
|
||||
helpers.push(ident.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -443,14 +443,11 @@ pub struct Crate {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
/// A spanned compile-time attribute list item.
|
||||
pub type NestedMetaItem = Spanned<NestedMetaItemKind>;
|
||||
|
||||
/// Possible values inside of compile-time attribute lists.
|
||||
///
|
||||
/// E.g., the '..' in `#[name(..)]`.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub enum NestedMetaItemKind {
|
||||
pub enum NestedMetaItem {
|
||||
/// A full MetaItem, for recursive meta items.
|
||||
MetaItem(MetaItem),
|
||||
/// A literal.
|
||||
|
@ -464,7 +461,7 @@ pub enum NestedMetaItemKind {
|
|||
/// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`.
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct MetaItem {
|
||||
pub ident: Path,
|
||||
pub path: Path,
|
||||
pub node: MetaItemKind,
|
||||
pub span: Span,
|
||||
}
|
||||
|
@ -2207,7 +2204,7 @@ pub struct Item {
|
|||
impl Item {
|
||||
/// Return the span that encompasses the attributes.
|
||||
pub fn span_with_attributes(&self) -> Span {
|
||||
self.attrs.iter().fold(self.span, |acc, attr| acc.to(attr.span()))
|
||||
self.attrs.iter().fold(self.span, |acc, attr| acc.to(attr.span))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Parsing and validation of builtin attributes
|
||||
|
||||
use crate::ast::{self, Attribute, MetaItem, Name, NestedMetaItemKind};
|
||||
use crate::ast::{self, Attribute, MetaItem, NestedMetaItem};
|
||||
use crate::feature_gate::{Features, GatedCfg};
|
||||
use crate::parse::ParseSess;
|
||||
|
||||
|
@ -10,8 +10,8 @@ use syntax_pos::{symbol::Symbol, Span};
|
|||
use super::{mark_used, MetaItemKind};
|
||||
|
||||
enum AttrError {
|
||||
MultipleItem(Name),
|
||||
UnknownMetaItem(Name, &'static [&'static str]),
|
||||
MultipleItem(String),
|
||||
UnknownMetaItem(String, &'static [&'static str]),
|
||||
MissingSince,
|
||||
MissingFeature,
|
||||
MultipleStabilityLevels,
|
||||
|
@ -155,10 +155,7 @@ pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool {
|
|||
attrs.iter().any(|item| {
|
||||
item.check_name("feature") &&
|
||||
item.meta_item_list().map(|list| {
|
||||
list.iter().any(|mi| {
|
||||
mi.word().map(|w| w.name() == feature_name)
|
||||
.unwrap_or(false)
|
||||
})
|
||||
list.iter().any(|mi| mi.is_word() && mi.check_name(feature_name))
|
||||
}).unwrap_or(false)
|
||||
})
|
||||
}
|
||||
|
@ -206,7 +203,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
|
|||
let meta = meta.as_ref().unwrap();
|
||||
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
|
||||
if item.is_some() {
|
||||
handle_errors(sess, meta.span, AttrError::MultipleItem(meta.name()));
|
||||
handle_errors(sess, meta.span, AttrError::MultipleItem(meta.path.to_string()));
|
||||
return false
|
||||
}
|
||||
if let Some(v) = meta.value_str() {
|
||||
|
@ -225,9 +222,9 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
|
|||
)+
|
||||
for meta in metas {
|
||||
if let Some(mi) = meta.meta_item() {
|
||||
match &*mi.name().as_str() {
|
||||
match mi.ident_str() {
|
||||
$(
|
||||
stringify!($name)
|
||||
Some(stringify!($name))
|
||||
=> if !get(mi, &mut $name) { continue 'outer },
|
||||
)+
|
||||
_ => {
|
||||
|
@ -235,7 +232,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
|
|||
handle_errors(
|
||||
sess,
|
||||
mi.span,
|
||||
AttrError::UnknownMetaItem(mi.name(), expected),
|
||||
AttrError::UnknownMetaItem(mi.path.to_string(), expected),
|
||||
);
|
||||
continue 'outer
|
||||
}
|
||||
|
@ -243,7 +240,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
|
|||
} else {
|
||||
handle_errors(
|
||||
sess,
|
||||
meta.span,
|
||||
meta.span(),
|
||||
AttrError::UnsupportedLiteral(
|
||||
"unsupported literal",
|
||||
false,
|
||||
|
@ -255,7 +252,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
|
|||
}
|
||||
}
|
||||
|
||||
match &*meta.name().as_str() {
|
||||
match meta.ident_str().expect("not a stability level") {
|
||||
"rustc_deprecated" => {
|
||||
if rustc_depr.is_some() {
|
||||
span_err!(diagnostic, item_sp, E0540,
|
||||
|
@ -274,11 +271,11 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
|
|||
})
|
||||
}
|
||||
(None, _) => {
|
||||
handle_errors(sess, attr.span(), AttrError::MissingSince);
|
||||
handle_errors(sess, attr.span, AttrError::MissingSince);
|
||||
continue
|
||||
}
|
||||
_ => {
|
||||
span_err!(diagnostic, attr.span(), E0543, "missing 'reason'");
|
||||
span_err!(diagnostic, attr.span, E0543, "missing 'reason'");
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -294,13 +291,13 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
|
|||
if let Some(feature) = feature {
|
||||
rustc_const_unstable = Some(feature);
|
||||
} else {
|
||||
span_err!(diagnostic, attr.span(), E0629, "missing 'feature'");
|
||||
span_err!(diagnostic, attr.span, E0629, "missing 'feature'");
|
||||
continue
|
||||
}
|
||||
}
|
||||
"unstable" => {
|
||||
if stab.is_some() {
|
||||
handle_errors(sess, attr.span(), AttrError::MultipleStabilityLevels);
|
||||
handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -309,16 +306,16 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
|
|||
let mut issue = None;
|
||||
for meta in metas {
|
||||
if let Some(mi) = meta.meta_item() {
|
||||
match &*mi.name().as_str() {
|
||||
"feature" => if !get(mi, &mut feature) { continue 'outer },
|
||||
"reason" => if !get(mi, &mut reason) { continue 'outer },
|
||||
"issue" => if !get(mi, &mut issue) { continue 'outer },
|
||||
match mi.ident_str() {
|
||||
Some("feature") => if !get(mi, &mut feature) { continue 'outer },
|
||||
Some("reason") => if !get(mi, &mut reason) { continue 'outer },
|
||||
Some("issue") => if !get(mi, &mut issue) { continue 'outer },
|
||||
_ => {
|
||||
handle_errors(
|
||||
sess,
|
||||
meta.span,
|
||||
meta.span(),
|
||||
AttrError::UnknownMetaItem(
|
||||
mi.name(),
|
||||
mi.path.to_string(),
|
||||
&["feature", "reason", "issue"]
|
||||
),
|
||||
);
|
||||
|
@ -328,7 +325,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
|
|||
} else {
|
||||
handle_errors(
|
||||
sess,
|
||||
meta.span,
|
||||
meta.span(),
|
||||
AttrError::UnsupportedLiteral(
|
||||
"unsupported literal",
|
||||
false,
|
||||
|
@ -347,7 +344,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
|
|||
if let Ok(issue) = issue.as_str().parse() {
|
||||
issue
|
||||
} else {
|
||||
span_err!(diagnostic, attr.span(), E0545,
|
||||
span_err!(diagnostic, attr.span, E0545,
|
||||
"incorrect 'issue'");
|
||||
continue
|
||||
}
|
||||
|
@ -360,42 +357,44 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
|
|||
})
|
||||
}
|
||||
(None, _, _) => {
|
||||
handle_errors(sess, attr.span(), AttrError::MissingFeature);
|
||||
handle_errors(sess, attr.span, AttrError::MissingFeature);
|
||||
continue
|
||||
}
|
||||
_ => {
|
||||
span_err!(diagnostic, attr.span(), E0547, "missing 'issue'");
|
||||
span_err!(diagnostic, attr.span, E0547, "missing 'issue'");
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
"stable" => {
|
||||
if stab.is_some() {
|
||||
handle_errors(sess, attr.span(), AttrError::MultipleStabilityLevels);
|
||||
handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
|
||||
break
|
||||
}
|
||||
|
||||
let mut feature = None;
|
||||
let mut since = None;
|
||||
for meta in metas {
|
||||
match &meta.node {
|
||||
NestedMetaItemKind::MetaItem(mi) => {
|
||||
match &*mi.name().as_str() {
|
||||
"feature" => if !get(mi, &mut feature) { continue 'outer },
|
||||
"since" => if !get(mi, &mut since) { continue 'outer },
|
||||
match meta {
|
||||
NestedMetaItem::MetaItem(mi) => {
|
||||
match mi.ident_str() {
|
||||
Some("feature") =>
|
||||
if !get(mi, &mut feature) { continue 'outer },
|
||||
Some("since") =>
|
||||
if !get(mi, &mut since) { continue 'outer },
|
||||
_ => {
|
||||
handle_errors(
|
||||
sess,
|
||||
meta.span,
|
||||
meta.span(),
|
||||
AttrError::UnknownMetaItem(
|
||||
mi.name(), &["since", "note"],
|
||||
mi.path.to_string(), &["since", "note"],
|
||||
),
|
||||
);
|
||||
continue 'outer
|
||||
}
|
||||
}
|
||||
},
|
||||
NestedMetaItemKind::Literal(lit) => {
|
||||
NestedMetaItem::Literal(lit) => {
|
||||
handle_errors(
|
||||
sess,
|
||||
lit.span,
|
||||
|
@ -422,11 +421,11 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
|
|||
})
|
||||
}
|
||||
(None, _) => {
|
||||
handle_errors(sess, attr.span(), AttrError::MissingFeature);
|
||||
handle_errors(sess, attr.span, AttrError::MissingFeature);
|
||||
continue
|
||||
}
|
||||
_ => {
|
||||
handle_errors(sess, attr.span(), AttrError::MissingSince);
|
||||
handle_errors(sess, attr.span, AttrError::MissingSince);
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -483,8 +482,8 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
|
|||
gated_cfg.check_and_emit(sess, feats);
|
||||
}
|
||||
let error = |span, msg| { sess.span_diagnostic.span_err(span, msg); true };
|
||||
if cfg.ident.segments.len() != 1 {
|
||||
return error(cfg.ident.span, "`cfg` predicate key must be an identifier");
|
||||
if cfg.path.segments.len() != 1 {
|
||||
return error(cfg.path.span, "`cfg` predicate key must be an identifier");
|
||||
}
|
||||
match &cfg.node {
|
||||
MetaItemKind::List(..) => {
|
||||
|
@ -502,7 +501,8 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
|
|||
true
|
||||
}
|
||||
MetaItemKind::NameValue(..) | MetaItemKind::Word => {
|
||||
sess.config.contains(&(cfg.name(), cfg.value_str()))
|
||||
let ident = cfg.ident().expect("multi-segment cfg predicate");
|
||||
sess.config.contains(&(ident.name, cfg.value_str()))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -520,7 +520,7 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
|
|||
if !mi.is_meta_item() {
|
||||
handle_errors(
|
||||
sess,
|
||||
mi.span,
|
||||
mi.span(),
|
||||
AttrError::UnsupportedLiteral(
|
||||
"unsupported literal",
|
||||
false
|
||||
|
@ -532,14 +532,14 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
|
|||
|
||||
// The unwraps below may look dangerous, but we've already asserted
|
||||
// that they won't fail with the loop above.
|
||||
match &*cfg.name().as_str() {
|
||||
"any" => mis.iter().any(|mi| {
|
||||
match cfg.ident_str() {
|
||||
Some("any") => mis.iter().any(|mi| {
|
||||
eval_condition(mi.meta_item().unwrap(), sess, eval)
|
||||
}),
|
||||
"all" => mis.iter().all(|mi| {
|
||||
Some("all") => mis.iter().all(|mi| {
|
||||
eval_condition(mi.meta_item().unwrap(), sess, eval)
|
||||
}),
|
||||
"not" => {
|
||||
Some("not") => {
|
||||
if mis.len() != 1 {
|
||||
span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern");
|
||||
return false;
|
||||
|
@ -547,8 +547,9 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
|
|||
|
||||
!eval_condition(mis[0].meta_item().unwrap(), sess, eval)
|
||||
},
|
||||
p => {
|
||||
span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p);
|
||||
_ => {
|
||||
span_err!(sess.span_diagnostic, cfg.span, E0537,
|
||||
"invalid predicate `{}`", cfg.path);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -602,7 +603,9 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess,
|
|||
MetaItemKind::List(list) => {
|
||||
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
|
||||
if item.is_some() {
|
||||
handle_errors(sess, meta.span, AttrError::MultipleItem(meta.name()));
|
||||
handle_errors(
|
||||
sess, meta.span, AttrError::MultipleItem(meta.path.to_string())
|
||||
);
|
||||
return false
|
||||
}
|
||||
if let Some(v) = meta.value_str() {
|
||||
|
@ -630,22 +633,23 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess,
|
|||
let mut since = None;
|
||||
let mut note = None;
|
||||
for meta in list {
|
||||
match &meta.node {
|
||||
NestedMetaItemKind::MetaItem(mi) => {
|
||||
match &*mi.name().as_str() {
|
||||
"since" => if !get(mi, &mut since) { continue 'outer },
|
||||
"note" => if !get(mi, &mut note) { continue 'outer },
|
||||
match meta {
|
||||
NestedMetaItem::MetaItem(mi) => {
|
||||
match mi.ident_str() {
|
||||
Some("since") => if !get(mi, &mut since) { continue 'outer },
|
||||
Some("note") => if !get(mi, &mut note) { continue 'outer },
|
||||
_ => {
|
||||
handle_errors(
|
||||
sess,
|
||||
meta.span,
|
||||
AttrError::UnknownMetaItem(mi.name(), &["since", "note"]),
|
||||
meta.span(),
|
||||
AttrError::UnknownMetaItem(mi.path.to_string(),
|
||||
&["since", "note"]),
|
||||
);
|
||||
continue 'outer
|
||||
}
|
||||
}
|
||||
}
|
||||
NestedMetaItemKind::Literal(lit) => {
|
||||
NestedMetaItem::Literal(lit) => {
|
||||
handle_errors(
|
||||
sess,
|
||||
lit.span,
|
||||
|
@ -714,7 +718,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
|
|||
if !item.is_meta_item() {
|
||||
handle_errors(
|
||||
sess,
|
||||
item.span,
|
||||
item.span(),
|
||||
AttrError::UnsupportedLiteral(
|
||||
"meta item in `repr` must be an identifier",
|
||||
false,
|
||||
|
@ -724,19 +728,13 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
|
|||
}
|
||||
|
||||
let mut recognised = false;
|
||||
if let Some(mi) = item.word() {
|
||||
let word = &*mi.name().as_str();
|
||||
let hint = match word {
|
||||
"C" => Some(ReprC),
|
||||
"packed" => Some(ReprPacked(1)),
|
||||
"simd" => Some(ReprSimd),
|
||||
"transparent" => Some(ReprTransparent),
|
||||
_ => match int_type_of_word(word) {
|
||||
Some(ity) => Some(ReprInt(ity)),
|
||||
None => {
|
||||
None
|
||||
}
|
||||
}
|
||||
if item.is_word() {
|
||||
let hint = match item.ident_str() {
|
||||
Some("C") => Some(ReprC),
|
||||
Some("packed") => Some(ReprPacked(1)),
|
||||
Some("simd") => Some(ReprSimd),
|
||||
Some("transparent") => Some(ReprTransparent),
|
||||
name => name.and_then(|name| int_type_of_word(name)).map(ReprInt),
|
||||
};
|
||||
|
||||
if let Some(h) = hint {
|
||||
|
@ -777,20 +775,20 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
|
|||
};
|
||||
}
|
||||
if let Some(literal_error) = literal_error {
|
||||
span_err!(diagnostic, item.span, E0589,
|
||||
span_err!(diagnostic, item.span(), E0589,
|
||||
"invalid `repr(align)` attribute: {}", literal_error);
|
||||
}
|
||||
} else {
|
||||
if let Some(meta_item) = item.meta_item() {
|
||||
if meta_item.name() == "align" {
|
||||
if meta_item.check_name("align") {
|
||||
if let MetaItemKind::NameValue(ref value) = meta_item.node {
|
||||
recognised = true;
|
||||
let mut err = struct_span_err!(diagnostic, item.span, E0693,
|
||||
let mut err = struct_span_err!(diagnostic, item.span(), E0693,
|
||||
"incorrect `repr(align)` attribute format");
|
||||
match value.node {
|
||||
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
|
||||
err.span_suggestion(
|
||||
item.span,
|
||||
item.span(),
|
||||
"use parentheses instead",
|
||||
format!("align({})", int),
|
||||
Applicability::MachineApplicable
|
||||
|
@ -798,7 +796,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
|
|||
}
|
||||
ast::LitKind::Str(s, _) => {
|
||||
err.span_suggestion(
|
||||
item.span,
|
||||
item.span(),
|
||||
"use parentheses instead",
|
||||
format!("align({})", s),
|
||||
Applicability::MachineApplicable
|
||||
|
@ -813,7 +811,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
|
|||
}
|
||||
if !recognised {
|
||||
// Not a word we recognize
|
||||
span_err!(diagnostic, item.span, E0552,
|
||||
span_err!(diagnostic, item.span(), E0552,
|
||||
"unrecognized representation hint");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ pub use StabilityLevel::*;
|
|||
|
||||
use crate::ast;
|
||||
use crate::ast::{AttrId, Attribute, AttrStyle, Name, Ident, Path, PathSegment};
|
||||
use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
|
||||
use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
|
||||
use crate::ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind, GenericParam};
|
||||
use crate::mut_visit::visit_clobber;
|
||||
use crate::source_map::{BytePos, Spanned, respan, dummy_spanned};
|
||||
|
@ -64,36 +64,33 @@ pub fn is_known_lint_tool(m_item: Ident) -> bool {
|
|||
}
|
||||
|
||||
impl NestedMetaItem {
|
||||
/// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem.
|
||||
/// Returns the MetaItem if self is a NestedMetaItem::MetaItem.
|
||||
pub fn meta_item(&self) -> Option<&MetaItem> {
|
||||
match self.node {
|
||||
NestedMetaItemKind::MetaItem(ref item) => Some(item),
|
||||
match *self {
|
||||
NestedMetaItem::MetaItem(ref item) => Some(item),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Lit if self is a NestedMetaItemKind::Literal.
|
||||
/// Returns the Lit if self is a NestedMetaItem::Literal.
|
||||
pub fn literal(&self) -> Option<&Lit> {
|
||||
match self.node {
|
||||
NestedMetaItemKind::Literal(ref lit) => Some(lit),
|
||||
match *self {
|
||||
NestedMetaItem::Literal(ref lit) => Some(lit),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Span for `self`.
|
||||
pub fn span(&self) -> Span {
|
||||
self.span
|
||||
}
|
||||
|
||||
/// Returns `true` if this list item is a MetaItem with a name of `name`.
|
||||
pub fn check_name(&self, name: &str) -> bool {
|
||||
self.meta_item().map_or(false, |meta_item| meta_item.check_name(name))
|
||||
}
|
||||
|
||||
/// Returns the name of the meta item, e.g., `foo` in `#[foo]`,
|
||||
/// `#[foo="bar"]` and `#[foo(bar)]`, if self is a MetaItem
|
||||
pub fn name(&self) -> Option<Name> {
|
||||
self.meta_item().and_then(|meta_item| Some(meta_item.name()))
|
||||
/// For a single-segment meta-item returns its name, otherwise returns `None`.
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
self.meta_item().and_then(|meta_item| meta_item.ident())
|
||||
}
|
||||
pub fn ident_str(&self) -> Option<&str> {
|
||||
self.ident().map(|name| name.as_str().get())
|
||||
}
|
||||
|
||||
/// Gets the string value if self is a MetaItem and the MetaItem is a
|
||||
|
@ -108,25 +105,14 @@ impl NestedMetaItem {
|
|||
|meta_item| meta_item.meta_item_list().and_then(
|
||||
|meta_item_list| {
|
||||
if meta_item_list.len() == 1 {
|
||||
let nested_item = &meta_item_list[0];
|
||||
if nested_item.is_literal() {
|
||||
Some((meta_item.name(), nested_item.literal().unwrap()))
|
||||
} else {
|
||||
None
|
||||
if let Some(ident) = meta_item.ident() {
|
||||
if let Some(lit) = meta_item_list[0].literal() {
|
||||
return Some((ident.name, lit));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
None
|
||||
}}))
|
||||
}
|
||||
|
||||
/// Returns a MetaItem if self is a MetaItem with Kind Word.
|
||||
pub fn word(&self) -> Option<&MetaItem> {
|
||||
self.meta_item().and_then(|meta_item| if meta_item.is_word() {
|
||||
Some(meta_item)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
None
|
||||
}))
|
||||
}
|
||||
|
||||
/// Gets a list of inner meta items from a list MetaItem type.
|
||||
|
@ -146,7 +132,7 @@ impl NestedMetaItem {
|
|||
|
||||
/// Returns `true` if self is a MetaItem and the meta item is a word.
|
||||
pub fn is_word(&self) -> bool {
|
||||
self.word().is_some()
|
||||
self.meta_item().map_or(false, |meta_item| meta_item.is_word())
|
||||
}
|
||||
|
||||
/// Returns `true` if self is a MetaItem and the meta item is a ValueString.
|
||||
|
@ -160,10 +146,6 @@ impl NestedMetaItem {
|
|||
}
|
||||
}
|
||||
|
||||
fn name_from_path(path: &Path) -> Name {
|
||||
path.segments.last().expect("empty path in attribute").ident.name
|
||||
}
|
||||
|
||||
impl Attribute {
|
||||
/// Returns `true` if the attribute's path matches the argument. If it matches, then the
|
||||
/// attribute is marked as used.
|
||||
|
@ -177,10 +159,16 @@ impl Attribute {
|
|||
matches
|
||||
}
|
||||
|
||||
/// Returns the **last** segment of the name of this attribute.
|
||||
/// e.g., `foo` for `#[foo]`, `skip` for `#[rustfmt::skip]`.
|
||||
pub fn name(&self) -> Name {
|
||||
name_from_path(&self.path)
|
||||
/// For a single-segment attribute returns its name, otherwise returns `None`.
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
if self.path.segments.len() == 1 {
|
||||
Some(self.path.segments[0].ident)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn ident_str(&self) -> Option<&str> {
|
||||
self.ident().map(|name| name.as_str().get())
|
||||
}
|
||||
|
||||
pub fn value_str(&self) -> Option<Symbol> {
|
||||
|
@ -195,11 +183,7 @@ impl Attribute {
|
|||
}
|
||||
|
||||
pub fn is_word(&self) -> bool {
|
||||
self.path.segments.len() == 1 && self.tokens.is_empty()
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
self.span
|
||||
self.tokens.is_empty()
|
||||
}
|
||||
|
||||
pub fn is_meta_item_list(&self) -> bool {
|
||||
|
@ -213,8 +197,16 @@ impl Attribute {
|
|||
}
|
||||
|
||||
impl MetaItem {
|
||||
pub fn name(&self) -> Name {
|
||||
name_from_path(&self.ident)
|
||||
/// For a single-segment meta-item returns its name, otherwise returns `None`.
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
if self.path.segments.len() == 1 {
|
||||
Some(self.path.segments[0].ident)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn ident_str(&self) -> Option<&str> {
|
||||
self.ident().map(|name| name.as_str().get())
|
||||
}
|
||||
|
||||
// #[attribute(name = "value")]
|
||||
|
@ -252,10 +244,8 @@ impl MetaItem {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span { self.span }
|
||||
|
||||
pub fn check_name(&self, name: &str) -> bool {
|
||||
self.name() == name
|
||||
self.path == name
|
||||
}
|
||||
|
||||
pub fn is_value_str(&self) -> bool {
|
||||
|
@ -265,14 +255,6 @@ impl MetaItem {
|
|||
pub fn is_meta_item_list(&self) -> bool {
|
||||
self.meta_item_list().is_some()
|
||||
}
|
||||
|
||||
pub fn is_scoped(&self) -> Option<Ident> {
|
||||
if self.ident.segments.len() > 1 {
|
||||
Some(self.ident.segments[0].ident)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Attribute {
|
||||
|
@ -280,7 +262,7 @@ impl Attribute {
|
|||
pub fn meta(&self) -> Option<MetaItem> {
|
||||
let mut tokens = self.tokens.trees().peekable();
|
||||
Some(MetaItem {
|
||||
ident: self.path.clone(),
|
||||
path: self.path.clone(),
|
||||
node: if let Some(node) = MetaItemKind::from_tokens(&mut tokens) {
|
||||
if tokens.peek().is_some() {
|
||||
return None;
|
||||
|
@ -326,7 +308,7 @@ impl Attribute {
|
|||
|
||||
pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> {
|
||||
Ok(MetaItem {
|
||||
ident: self.path.clone(),
|
||||
path: self.path.clone(),
|
||||
node: self.parse(sess, |parser| parser.parse_meta_item_kind())?,
|
||||
span: self.span,
|
||||
})
|
||||
|
@ -364,19 +346,19 @@ pub fn mk_name_value_item_str(ident: Ident, value: Spanned<Symbol>) -> MetaItem
|
|||
}
|
||||
|
||||
pub fn mk_name_value_item(span: Span, ident: Ident, value: ast::Lit) -> MetaItem {
|
||||
MetaItem { ident: Path::from_ident(ident), span, node: MetaItemKind::NameValue(value) }
|
||||
MetaItem { path: Path::from_ident(ident), span, node: MetaItemKind::NameValue(value) }
|
||||
}
|
||||
|
||||
pub fn mk_list_item(span: Span, ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem {
|
||||
MetaItem { ident: Path::from_ident(ident), span, node: MetaItemKind::List(items) }
|
||||
MetaItem { path: Path::from_ident(ident), span, node: MetaItemKind::List(items) }
|
||||
}
|
||||
|
||||
pub fn mk_word_item(ident: Ident) -> MetaItem {
|
||||
MetaItem { ident: Path::from_ident(ident), span: ident.span, node: MetaItemKind::Word }
|
||||
MetaItem { path: Path::from_ident(ident), span: ident.span, node: MetaItemKind::Word }
|
||||
}
|
||||
|
||||
pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
|
||||
respan(ident.span, NestedMetaItemKind::MetaItem(mk_word_item(ident)))
|
||||
NestedMetaItem::MetaItem(mk_word_item(ident))
|
||||
}
|
||||
|
||||
pub fn mk_attr_id() -> AttrId {
|
||||
|
@ -400,7 +382,7 @@ pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: MetaItem) -> Attribute
|
|||
Attribute {
|
||||
id,
|
||||
style: ast::AttrStyle::Inner,
|
||||
path: item.ident,
|
||||
path: item.path,
|
||||
tokens: item.node.tokens(item.span),
|
||||
is_sugared_doc: false,
|
||||
span: sp,
|
||||
|
@ -417,7 +399,7 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute
|
|||
Attribute {
|
||||
id,
|
||||
style: ast::AttrStyle::Outer,
|
||||
path: item.ident,
|
||||
path: item.path,
|
||||
tokens: item.node.tokens(item.span),
|
||||
is_sugared_doc: false,
|
||||
span: sp,
|
||||
|
@ -468,7 +450,7 @@ impl MetaItem {
|
|||
fn tokens(&self) -> TokenStream {
|
||||
let mut idents = vec![];
|
||||
let mut last_pos = BytePos(0 as u32);
|
||||
for (i, segment) in self.ident.segments.iter().enumerate() {
|
||||
for (i, segment) in self.path.segments.iter().enumerate() {
|
||||
let is_first = i == 0;
|
||||
if !is_first {
|
||||
let mod_sep_span = Span::new(last_pos,
|
||||
|
@ -488,7 +470,7 @@ impl MetaItem {
|
|||
where I: Iterator<Item = TokenTree>,
|
||||
{
|
||||
// FIXME: Share code with `parse_path`.
|
||||
let ident = match tokens.next() {
|
||||
let path = match tokens.next() {
|
||||
Some(TokenTree::Token(span, token @ Token::Ident(..))) |
|
||||
Some(TokenTree::Token(span, token @ Token::ModSep)) => 'arm: {
|
||||
let mut segments = if let Token::Ident(ident, _) = token {
|
||||
|
@ -529,11 +511,11 @@ impl MetaItem {
|
|||
let node = MetaItemKind::from_tokens(tokens)?;
|
||||
let hi = match node {
|
||||
MetaItemKind::NameValue(ref lit) => lit.span.hi(),
|
||||
MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(ident.span.hi()),
|
||||
_ => ident.span.hi(),
|
||||
MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
|
||||
_ => path.span.hi(),
|
||||
};
|
||||
let span = ident.span.with_hi(hi);
|
||||
Some(MetaItem { ident, node, span })
|
||||
let span = path.span.with_hi(hi);
|
||||
Some(MetaItem { path, node, span })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -552,7 +534,7 @@ impl MetaItemKind {
|
|||
if i > 0 {
|
||||
tokens.push(TokenTree::Token(span, Token::Comma).into());
|
||||
}
|
||||
item.node.tokens().append_to_tree_and_joint_vec(&mut tokens);
|
||||
item.tokens().append_to_tree_and_joint_vec(&mut tokens);
|
||||
}
|
||||
TokenTree::Delimited(
|
||||
DelimSpan::from_single(span),
|
||||
|
@ -586,8 +568,8 @@ impl MetaItemKind {
|
|||
let mut tokens = delimited.into_trees().peekable();
|
||||
let mut result = Vec::new();
|
||||
while let Some(..) = tokens.peek() {
|
||||
let item = NestedMetaItemKind::from_tokens(&mut tokens)?;
|
||||
result.push(respan(item.span(), item));
|
||||
let item = NestedMetaItem::from_tokens(&mut tokens)?;
|
||||
result.push(item);
|
||||
match tokens.next() {
|
||||
None | Some(TokenTree::Token(_, Token::Comma)) => {}
|
||||
_ => return None,
|
||||
|
@ -597,32 +579,32 @@ impl MetaItemKind {
|
|||
}
|
||||
}
|
||||
|
||||
impl NestedMetaItemKind {
|
||||
fn span(&self) -> Span {
|
||||
impl NestedMetaItem {
|
||||
pub fn span(&self) -> Span {
|
||||
match *self {
|
||||
NestedMetaItemKind::MetaItem(ref item) => item.span,
|
||||
NestedMetaItemKind::Literal(ref lit) => lit.span,
|
||||
NestedMetaItem::MetaItem(ref item) => item.span,
|
||||
NestedMetaItem::Literal(ref lit) => lit.span,
|
||||
}
|
||||
}
|
||||
|
||||
fn tokens(&self) -> TokenStream {
|
||||
match *self {
|
||||
NestedMetaItemKind::MetaItem(ref item) => item.tokens(),
|
||||
NestedMetaItemKind::Literal(ref lit) => lit.tokens(),
|
||||
NestedMetaItem::MetaItem(ref item) => item.tokens(),
|
||||
NestedMetaItem::Literal(ref lit) => lit.tokens(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItemKind>
|
||||
fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
|
||||
where I: Iterator<Item = TokenTree>,
|
||||
{
|
||||
if let Some(TokenTree::Token(span, token)) = tokens.peek().cloned() {
|
||||
if let Some(node) = LitKind::from_token(token) {
|
||||
tokens.next();
|
||||
return Some(NestedMetaItemKind::Literal(respan(span, node)));
|
||||
return Some(NestedMetaItem::Literal(respan(span, node)));
|
||||
}
|
||||
}
|
||||
|
||||
MetaItem::from_tokens(tokens).map(NestedMetaItemKind::MetaItem)
|
||||
MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -181,13 +181,13 @@ impl<'a> StripUnconfigured<'a> {
|
|||
if nested_meta_items.is_empty() {
|
||||
return error(meta_item.span, "`cfg` predicate is not specified", "");
|
||||
} else if nested_meta_items.len() > 1 {
|
||||
return error(nested_meta_items.last().unwrap().span,
|
||||
return error(nested_meta_items.last().unwrap().span(),
|
||||
"multiple `cfg` predicates are specified", "");
|
||||
}
|
||||
|
||||
match nested_meta_items[0].meta_item() {
|
||||
Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features),
|
||||
None => error(nested_meta_items[0].span,
|
||||
None => error(nested_meta_items[0].span(),
|
||||
"`cfg` predicate key cannot be a literal", ""),
|
||||
}
|
||||
})
|
||||
|
|
|
@ -601,7 +601,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
res
|
||||
}
|
||||
ProcMacroDerive(..) | BuiltinDerive(..) => {
|
||||
self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path));
|
||||
self.cx.span_err(attr.span, &format!("`{}` is a derive macro", attr.path));
|
||||
self.cx.trace_macros_diag();
|
||||
invoc.fragment_kind.dummy(attr.span)
|
||||
}
|
||||
|
@ -822,7 +822,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
|
||||
ProcMacroDerive(..) | BuiltinDerive(..) => {
|
||||
self.cx.span_err(path.span, &format!("`{}` is a derive mode", path));
|
||||
self.cx.span_err(path.span, &format!("`{}` is a derive macro", path));
|
||||
self.cx.trace_macros_diag();
|
||||
kind.dummy(span)
|
||||
}
|
||||
|
@ -929,7 +929,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
invoc.expansion_data.mark.set_expn_info(expn_info);
|
||||
let span = span.with_ctxt(self.cx.backtrace());
|
||||
let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this
|
||||
ident: Path::from_ident(keywords::Invalid.ident()),
|
||||
path: Path::from_ident(keywords::Invalid.ident()),
|
||||
span: DUMMY_SP,
|
||||
node: ast::MetaItemKind::Word,
|
||||
};
|
||||
|
@ -1520,23 +1520,23 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||
self.cx.source_map().new_source_file(filename.into(), src);
|
||||
|
||||
let include_info = vec![
|
||||
dummy_spanned(ast::NestedMetaItemKind::MetaItem(
|
||||
ast::NestedMetaItem::MetaItem(
|
||||
attr::mk_name_value_item_str(
|
||||
Ident::from_str("file"),
|
||||
dummy_spanned(file),
|
||||
),
|
||||
)),
|
||||
dummy_spanned(ast::NestedMetaItemKind::MetaItem(
|
||||
),
|
||||
ast::NestedMetaItem::MetaItem(
|
||||
attr::mk_name_value_item_str(
|
||||
Ident::from_str("contents"),
|
||||
dummy_spanned(src_interned),
|
||||
),
|
||||
)),
|
||||
),
|
||||
];
|
||||
|
||||
let include_ident = Ident::from_str("include");
|
||||
let item = attr::mk_list_item(DUMMY_SP, include_ident, include_info);
|
||||
items.push(dummy_spanned(ast::NestedMetaItemKind::MetaItem(item)));
|
||||
items.push(ast::NestedMetaItem::MetaItem(item));
|
||||
}
|
||||
Err(e) => {
|
||||
let lit = it
|
||||
|
@ -1569,7 +1569,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||
}
|
||||
} else {
|
||||
let mut err = self.cx.struct_span_err(
|
||||
it.span,
|
||||
it.span(),
|
||||
&format!("expected path to external documentation"),
|
||||
);
|
||||
|
||||
|
@ -1590,7 +1590,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||
};
|
||||
|
||||
err.span_suggestion(
|
||||
it.span,
|
||||
it.span(),
|
||||
"provide a file path with `=`",
|
||||
format!("include = \"{}\"", path),
|
||||
applicability,
|
||||
|
|
|
@ -380,9 +380,14 @@ pub fn compile(
|
|||
.map(|attr| attr
|
||||
.meta_item_list()
|
||||
.map(|list| list.iter()
|
||||
.map(|it| it.name().unwrap_or_else(|| sess.span_diagnostic.span_bug(
|
||||
it.span, "allow internal unstable expects feature names",
|
||||
)))
|
||||
.filter_map(|it| {
|
||||
let name = it.ident().map(|ident| ident.name);
|
||||
if name.is_none() {
|
||||
sess.span_diagnostic.span_err(it.span(),
|
||||
"allow internal unstable expects feature names")
|
||||
}
|
||||
name
|
||||
})
|
||||
.collect::<Vec<Symbol>>().into()
|
||||
)
|
||||
.unwrap_or_else(|| {
|
||||
|
|
|
@ -1289,9 +1289,8 @@ pub struct GatedCfg {
|
|||
|
||||
impl GatedCfg {
|
||||
pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
|
||||
let name = cfg.name().as_str();
|
||||
GATED_CFGS.iter()
|
||||
.position(|info| info.0 == name)
|
||||
.position(|info| cfg.check_name(info.0))
|
||||
.map(|idx| {
|
||||
GatedCfg {
|
||||
span: cfg.span,
|
||||
|
@ -1342,16 +1341,16 @@ macro_rules! gate_feature {
|
|||
impl<'a> Context<'a> {
|
||||
fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
|
||||
debug!("check_attribute(attr = {:?})", attr);
|
||||
let name = attr.name().as_str();
|
||||
let name = attr.ident_str();
|
||||
for &(n, ty, _template, ref gateage) in BUILTIN_ATTRIBUTES {
|
||||
if name == n {
|
||||
if name == Some(n) {
|
||||
if let Gated(_, name, desc, ref has_feature) = *gateage {
|
||||
if !attr.span.allows_unstable(name) {
|
||||
gate_feature_fn!(
|
||||
self, has_feature, attr.span, name, desc, GateStrength::Hard
|
||||
);
|
||||
}
|
||||
} else if name == "doc" {
|
||||
} else if n == "doc" {
|
||||
if let Some(content) = attr.meta_item_list() {
|
||||
if content.iter().any(|c| c.check_name("include")) {
|
||||
gate_feature!(self, external_doc, attr.span,
|
||||
|
@ -1374,7 +1373,7 @@ impl<'a> Context<'a> {
|
|||
}
|
||||
}
|
||||
if !attr::is_known(attr) {
|
||||
if name.starts_with("rustc_") {
|
||||
if name.map_or(false, |name| name.starts_with("rustc_")) {
|
||||
let msg = "unless otherwise specified, attributes with the prefix `rustc_` \
|
||||
are reserved for internal compiler diagnostics";
|
||||
gate_feature!(self, rustc_attrs, attr.span, msg);
|
||||
|
@ -2055,15 +2054,14 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
|
|||
};
|
||||
|
||||
for mi in list {
|
||||
let name = if let Some(word) = mi.word() {
|
||||
word.name()
|
||||
} else {
|
||||
continue
|
||||
let name = match mi.ident_str() {
|
||||
Some(name) if mi.is_word() => name,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
if incomplete_features.iter().any(|f| *f == name.as_str()) {
|
||||
if incomplete_features.iter().any(|f| *f == name) {
|
||||
span_handler.struct_span_warn(
|
||||
mi.span,
|
||||
mi.span(),
|
||||
&format!(
|
||||
"the feature `{}` is incomplete and may cause the compiler to crash",
|
||||
name
|
||||
|
@ -2101,18 +2099,19 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
|
|||
};
|
||||
|
||||
for mi in list {
|
||||
let name = if let Some(word) = mi.word() {
|
||||
word.name()
|
||||
} else {
|
||||
span_err!(span_handler, mi.span, E0556,
|
||||
"malformed feature, expected just one word");
|
||||
continue
|
||||
let name = match mi.ident() {
|
||||
Some(ident) if mi.is_word() => ident.name,
|
||||
_ => {
|
||||
span_err!(span_handler, mi.span(), E0556,
|
||||
"malformed feature, expected just one word");
|
||||
continue
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(edition) = edition_enabled_features.get(&name) {
|
||||
struct_span_warn!(
|
||||
span_handler,
|
||||
mi.span,
|
||||
mi.span(),
|
||||
E0705,
|
||||
"the feature `{}` is included in the Rust {} edition",
|
||||
name,
|
||||
|
@ -2129,32 +2128,32 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
|
|||
if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
|
||||
if let Some(allowed) = allow_features.as_ref() {
|
||||
if allowed.iter().find(|f| *f == name.as_str()).is_none() {
|
||||
span_err!(span_handler, mi.span, E0725,
|
||||
span_err!(span_handler, mi.span(), E0725,
|
||||
"the feature `{}` is not in the list of allowed features",
|
||||
name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
set(&mut features, mi.span);
|
||||
features.declared_lang_features.push((name, mi.span, None));
|
||||
set(&mut features, mi.span());
|
||||
features.declared_lang_features.push((name, mi.span(), None));
|
||||
continue
|
||||
}
|
||||
|
||||
let removed = REMOVED_FEATURES.iter().find(|f| name == f.0);
|
||||
let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0);
|
||||
if let Some((.., reason)) = removed.or(stable_removed) {
|
||||
feature_removed(span_handler, mi.span, *reason);
|
||||
feature_removed(span_handler, mi.span(), *reason);
|
||||
continue
|
||||
}
|
||||
|
||||
if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) {
|
||||
let since = Some(Symbol::intern(since));
|
||||
features.declared_lang_features.push((name, mi.span, since));
|
||||
features.declared_lang_features.push((name, mi.span(), since));
|
||||
continue
|
||||
}
|
||||
|
||||
features.declared_lib_features.push((name, mi.span));
|
||||
features.declared_lib_features.push((name, mi.span()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -539,16 +539,14 @@ pub fn noop_visit_macro_def<T: MutVisitor>(macro_def: &mut MacroDef, vis: &mut T
|
|||
}
|
||||
|
||||
pub fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T) {
|
||||
let Spanned { node, span } = li;
|
||||
match node {
|
||||
NestedMetaItemKind::MetaItem(mi) => vis.visit_meta_item(mi),
|
||||
NestedMetaItemKind::Literal(_lit) => {}
|
||||
match li {
|
||||
NestedMetaItem::MetaItem(mi) => vis.visit_meta_item(mi),
|
||||
NestedMetaItem::Literal(_lit) => {}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) {
|
||||
let MetaItem { ident: _, node, span } = mi;
|
||||
let MetaItem { path: _, node, span } = mi;
|
||||
match node {
|
||||
MetaItemKind::Word => {}
|
||||
MetaItemKind::List(mis) => visit_vec(mis, |mi| vis.visit_meta_list_item(mi)),
|
||||
|
@ -1340,4 +1338,3 @@ mod tests {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::attr;
|
||||
use crate::ast;
|
||||
use crate::source_map::respan;
|
||||
use crate::parse::{SeqSep, PResult};
|
||||
use crate::parse::token::{self, Nonterminal, DelimToken};
|
||||
use crate::parse::parser::{Parser, TokenType, PathStyle};
|
||||
|
@ -149,7 +148,7 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
Ok(if let Some(meta) = meta {
|
||||
self.bump();
|
||||
(meta.ident, meta.node.tokens(meta.span))
|
||||
(meta.path, meta.node.tokens(meta.span))
|
||||
} else {
|
||||
let path = self.parse_path(PathStyle::Mod)?;
|
||||
let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) ||
|
||||
|
@ -250,10 +249,10 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
let lo = self.span;
|
||||
let ident = self.parse_path(PathStyle::Mod)?;
|
||||
let path = self.parse_path(PathStyle::Mod)?;
|
||||
let node = self.parse_meta_item_kind()?;
|
||||
let span = lo.to(self.prev_span);
|
||||
Ok(ast::MetaItem { ident, node, span })
|
||||
Ok(ast::MetaItem { path, node, span })
|
||||
}
|
||||
|
||||
crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
|
||||
|
@ -268,18 +267,16 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;
|
||||
fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
|
||||
let lo = self.span;
|
||||
|
||||
match self.parse_unsuffixed_lit() {
|
||||
Ok(lit) => {
|
||||
return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::Literal(lit)))
|
||||
return Ok(ast::NestedMetaItem::Literal(lit))
|
||||
}
|
||||
Err(ref mut err) => self.diagnostic().cancel(err)
|
||||
}
|
||||
|
||||
match self.parse_meta_item() {
|
||||
Ok(mi) => {
|
||||
return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::MetaItem(mi)))
|
||||
return Ok(ast::NestedMetaItem::MetaItem(mi))
|
||||
}
|
||||
Err(ref mut err) => self.diagnostic().cancel(err)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::ast::{self, Ident};
|
||||
use crate::source_map::{SourceMap, FilePathMapping};
|
||||
use crate::parse::{token, ParseSess};
|
||||
use crate::symbol::{Symbol, keywords};
|
||||
use crate::symbol::Symbol;
|
||||
|
||||
use errors::{Applicability, FatalError, Diagnostic, DiagnosticBuilder};
|
||||
use syntax_pos::{BytePos, CharPos, Pos, Span, NO_EXPANSION};
|
||||
|
@ -1249,15 +1249,11 @@ impl<'a> StringReader<'a> {
|
|||
// FIXME: perform NFKC normalization here. (Issue #2253)
|
||||
let ident = self.mk_ident(string);
|
||||
|
||||
if is_raw_ident && (ident.is_path_segment_keyword() ||
|
||||
ident.name == keywords::Underscore.name()) {
|
||||
self.fatal_span_(raw_start, self.pos,
|
||||
&format!("`r#{}` is not currently supported.", ident.name)
|
||||
).raise();
|
||||
}
|
||||
|
||||
if is_raw_ident {
|
||||
let span = self.mk_sp(raw_start, self.pos);
|
||||
if !ident.can_be_raw() {
|
||||
self.err_span(span, &format!("`{}` cannot be a raw identifier", ident));
|
||||
}
|
||||
self.sess.raw_identifier_spans.borrow_mut().push(span);
|
||||
}
|
||||
|
||||
|
|
|
@ -895,9 +895,7 @@ impl<'a> Parser<'a> {
|
|||
&format!("expected identifier, found {}",
|
||||
self.this_token_descr()));
|
||||
if let token::Ident(ident, false) = &self.token {
|
||||
if ident.is_reserved() && !ident.is_path_segment_keyword() &&
|
||||
ident.name != keywords::Underscore.name()
|
||||
{
|
||||
if ident.is_raw_guess() {
|
||||
err.span_suggestion(
|
||||
self.span,
|
||||
"you can escape reserved keywords to use them as identifiers",
|
||||
|
@ -2335,7 +2333,7 @@ impl<'a> Parser<'a> {
|
|||
let meta_ident = match self.token {
|
||||
token::Interpolated(ref nt) => match **nt {
|
||||
token::NtMeta(ref meta) => match meta.node {
|
||||
ast::MetaItemKind::Word => Some(meta.ident.clone()),
|
||||
ast::MetaItemKind::Word => Some(meta.path.clone()),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
|
|
|
@ -768,11 +768,11 @@ pub trait PrintState<'a> {
|
|||
}
|
||||
|
||||
fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) -> io::Result<()> {
|
||||
match item.node {
|
||||
ast::NestedMetaItemKind::MetaItem(ref mi) => {
|
||||
match item {
|
||||
ast::NestedMetaItem::MetaItem(ref mi) => {
|
||||
self.print_meta_item(mi)
|
||||
},
|
||||
ast::NestedMetaItemKind::Literal(ref lit) => {
|
||||
ast::NestedMetaItem::Literal(ref lit) => {
|
||||
self.print_literal(lit)
|
||||
}
|
||||
}
|
||||
|
@ -781,15 +781,15 @@ pub trait PrintState<'a> {
|
|||
fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> {
|
||||
self.ibox(INDENT_UNIT)?;
|
||||
match item.node {
|
||||
ast::MetaItemKind::Word => self.print_attribute_path(&item.ident)?,
|
||||
ast::MetaItemKind::Word => self.print_attribute_path(&item.path)?,
|
||||
ast::MetaItemKind::NameValue(ref value) => {
|
||||
self.print_attribute_path(&item.ident)?;
|
||||
self.print_attribute_path(&item.path)?;
|
||||
self.writer().space()?;
|
||||
self.word_space("=")?;
|
||||
self.print_literal(value)?;
|
||||
}
|
||||
ast::MetaItemKind::List(ref items) => {
|
||||
self.print_attribute_path(&item.ident)?;
|
||||
self.print_attribute_path(&item.path)?;
|
||||
self.popen()?;
|
||||
self.commasep(Consistent,
|
||||
&items[..],
|
||||
|
|
|
@ -435,9 +435,12 @@ fn get_test_runner(sd: &errors::Handler, krate: &ast::Crate) -> Option<ast::Path
|
|||
let test_attr = attr::find_by_name(&krate.attrs, "test_runner")?;
|
||||
test_attr.meta_item_list().map(|meta_list| {
|
||||
if meta_list.len() != 1 {
|
||||
sd.span_fatal(test_attr.span(),
|
||||
sd.span_fatal(test_attr.span,
|
||||
"#![test_runner(..)] accepts exactly 1 argument").raise()
|
||||
}
|
||||
meta_list[0].word().as_ref().unwrap().ident.clone()
|
||||
match meta_list[0].meta_item() {
|
||||
Some(meta_item) if meta_item.is_word() => meta_item.path.clone(),
|
||||
_ => sd.span_fatal(test_attr.span, "`test_runner` argument must be a path").raise()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -17,9 +17,11 @@ struct MarkAttrs<'a>(&'a [ast::Name]);
|
|||
|
||||
impl<'a> Visitor<'a> for MarkAttrs<'a> {
|
||||
fn visit_attribute(&mut self, attr: &Attribute) {
|
||||
if self.0.contains(&attr.name()) {
|
||||
mark_used(attr);
|
||||
mark_known(attr);
|
||||
if let Some(ident) = attr.ident() {
|
||||
if self.0.contains(&ident.name) {
|
||||
mark_used(attr);
|
||||
mark_known(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -463,12 +463,9 @@ impl<'a> TraitDef<'a> {
|
|||
let mut attrs = newitem.attrs.clone();
|
||||
attrs.extend(item.attrs
|
||||
.iter()
|
||||
.filter(|a| {
|
||||
match &*a.name().as_str() {
|
||||
"allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
.filter(|a| a.ident_str().map_or(false, |name| {
|
||||
["allow", "warn", "deny", "forbid", "stable", "unstable"].contains(&name)
|
||||
}))
|
||||
.cloned());
|
||||
push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() })))
|
||||
}
|
||||
|
|
|
@ -109,52 +109,67 @@ impl<'a> CollectProcMacros<'a> {
|
|||
None => return,
|
||||
};
|
||||
if list.len() != 1 && list.len() != 2 {
|
||||
self.handler.span_err(attr.span(),
|
||||
self.handler.span_err(attr.span,
|
||||
"attribute must have either one or two arguments");
|
||||
return
|
||||
}
|
||||
let trait_attr = &list[0];
|
||||
let attributes_attr = list.get(1);
|
||||
let trait_name = match trait_attr.name() {
|
||||
Some(name) => name,
|
||||
let trait_attr = match list[0].meta_item() {
|
||||
Some(meta_item) => meta_item,
|
||||
_ => {
|
||||
self.handler.span_err(trait_attr.span(), "not a meta item");
|
||||
self.handler.span_err(list[0].span(), "not a meta item");
|
||||
return
|
||||
}
|
||||
};
|
||||
if !trait_attr.is_word() {
|
||||
self.handler.span_err(trait_attr.span(), "must only be one word");
|
||||
}
|
||||
|
||||
if deriving::is_builtin_trait(trait_name) {
|
||||
self.handler.span_err(trait_attr.span(),
|
||||
"cannot override a built-in #[derive] mode");
|
||||
let trait_ident = match trait_attr.ident() {
|
||||
Some(trait_ident) if trait_attr.is_word() => trait_ident,
|
||||
_ => {
|
||||
self.handler.span_err(trait_attr.span, "must only be one word");
|
||||
return
|
||||
}
|
||||
};
|
||||
|
||||
if !trait_ident.can_be_raw() {
|
||||
self.handler.span_err(trait_attr.span,
|
||||
&format!("`{}` cannot be a name of derive macro", trait_ident));
|
||||
}
|
||||
if deriving::is_builtin_trait(trait_ident.name) {
|
||||
self.handler.span_err(trait_attr.span,
|
||||
"cannot override a built-in derive macro");
|
||||
}
|
||||
|
||||
let attributes_attr = list.get(1);
|
||||
let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
|
||||
if !attr.check_name("attributes") {
|
||||
self.handler.span_err(attr.span(), "second argument must be `attributes`")
|
||||
}
|
||||
attr.meta_item_list().unwrap_or_else(|| {
|
||||
self.handler.span_err(attr.span(),
|
||||
"attribute must be of form: \
|
||||
`attributes(foo, bar)`");
|
||||
"attribute must be of form: `attributes(foo, bar)`");
|
||||
&[]
|
||||
}).into_iter().filter_map(|attr| {
|
||||
let name = match attr.name() {
|
||||
Some(name) => name,
|
||||
let attr = match attr.meta_item() {
|
||||
Some(meta_item) => meta_item,
|
||||
_ => {
|
||||
self.handler.span_err(attr.span(), "not a meta item");
|
||||
return None;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
if !attr.is_word() {
|
||||
self.handler.span_err(attr.span(), "must only be one word");
|
||||
return None;
|
||||
let ident = match attr.ident() {
|
||||
Some(ident) if attr.is_word() => ident,
|
||||
_ => {
|
||||
self.handler.span_err(attr.span, "must only be one word");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
if !ident.can_be_raw() {
|
||||
self.handler.span_err(
|
||||
attr.span,
|
||||
&format!("`{}` cannot be a name of derive helper attribute", ident),
|
||||
);
|
||||
}
|
||||
|
||||
Some(name)
|
||||
Some(ident.name)
|
||||
}).collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
|
@ -163,7 +178,7 @@ impl<'a> CollectProcMacros<'a> {
|
|||
if self.in_root && item.vis.node.is_pub() {
|
||||
self.derives.push(ProcMacroDerive {
|
||||
span: item.span,
|
||||
trait_name,
|
||||
trait_name: trait_ident.name,
|
||||
function_name: item.ident,
|
||||
attrs: proc_attrs,
|
||||
});
|
||||
|
@ -247,8 +262,8 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
|
|||
to the same function", attr.path, prev_attr.path)
|
||||
};
|
||||
|
||||
self.handler.struct_span_err(attr.span(), &msg)
|
||||
.span_note(prev_attr.span(), "Previous attribute here")
|
||||
self.handler.struct_span_err(attr.span, &msg)
|
||||
.span_note(prev_attr.span, "Previous attribute here")
|
||||
.emit();
|
||||
|
||||
return;
|
||||
|
@ -273,7 +288,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
|
|||
let msg = format!("the `#[{}]` attribute may only be used on bare functions",
|
||||
attr.path);
|
||||
|
||||
self.handler.span_err(attr.span(), &msg);
|
||||
self.handler.span_err(attr.span, &msg);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -285,7 +300,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
|
|||
let msg = format!("the `#[{}]` attribute is only usable with crates of the \
|
||||
`proc-macro` crate type", attr.path);
|
||||
|
||||
self.handler.span_err(attr.span(), &msg);
|
||||
self.handler.span_err(attr.span, &msg);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -340,12 +340,8 @@ impl Ident {
|
|||
if !Self::is_valid(string) {
|
||||
panic!("`{:?}` is not a valid identifier", string)
|
||||
}
|
||||
if is_raw {
|
||||
let normalized_sym = Symbol::intern(string);
|
||||
if normalized_sym == keywords::Underscore.name() ||
|
||||
ast::Ident::with_empty_ctxt(normalized_sym).is_path_segment_keyword() {
|
||||
panic!("`{:?}` is not a valid raw identifier", string)
|
||||
}
|
||||
if is_raw && !ast::Ident::from_str(string).can_be_raw() {
|
||||
panic!("`{}` cannot be a raw identifier", string);
|
||||
}
|
||||
Ident { sym, is_raw, span }
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
|
|||
.and_then(|mi| mi.value_str());
|
||||
if list.len() != 1 || msg.is_none() {
|
||||
sd.struct_span_warn(
|
||||
attr.span(),
|
||||
attr.span,
|
||||
"argument must be of the form: \
|
||||
`expected = \"error message\"`"
|
||||
).note("Errors in this attribute were erroneously \
|
||||
|
|
|
@ -484,11 +484,16 @@ impl Ident {
|
|||
self.name == keywords::DollarCrate.name()
|
||||
}
|
||||
|
||||
// We see this identifier in a normal identifier position, like variable name or a type.
|
||||
// How was it written originally? Did it use the raw form? Let's try to guess.
|
||||
pub fn is_raw_guess(self) -> bool {
|
||||
/// This identifier can be a raw identifier.
|
||||
pub fn can_be_raw(self) -> bool {
|
||||
self.name != keywords::Invalid.name() && self.name != keywords::Underscore.name() &&
|
||||
self.is_reserved() && !self.is_path_segment_keyword()
|
||||
!self.is_path_segment_keyword()
|
||||
}
|
||||
|
||||
/// We see this identifier in a normal identifier position, like variable name or a type.
|
||||
/// How was it written originally? Did it use the raw form? Let's try to guess.
|
||||
pub fn is_raw_guess(self) -> bool {
|
||||
self.can_be_raw() && self.is_reserved()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
fn self_test(r#self: u32) {
|
||||
//~^ ERROR `r#self` is not currently supported.
|
||||
fn main() {
|
||||
let r#self;
|
||||
//~^ ERROR `self` cannot be a raw identifier
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error: `r#self` is not currently supported.
|
||||
--> $DIR/raw-literal-self.rs:1:14
|
||||
error: `self` cannot be a raw identifier
|
||||
--> $DIR/raw-literal-self.rs:2:9
|
||||
|
|
||||
LL | fn self_test(r#self: u32) {
|
||||
| ^^^^^^
|
||||
LL | let r#self;
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
fn underscore_test(r#_: u32) {
|
||||
//~^ ERROR `r#_` is not currently supported.
|
||||
fn main() {
|
||||
let r#_;
|
||||
//~^ ERROR `_` cannot be a raw identifier
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error: `r#_` is not currently supported.
|
||||
--> $DIR/raw-literal-underscore.rs:1:20
|
||||
error: `_` cannot be a raw identifier
|
||||
--> $DIR/raw-literal-underscore.rs:2:9
|
||||
|
|
||||
LL | fn underscore_test(r#_: u32) {
|
||||
| ^^^
|
||||
LL | let r#_;
|
||||
| ^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -4,53 +4,73 @@
|
|||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::*;
|
||||
|
||||
#[proc_macro_derive]
|
||||
//~^ ERROR: attribute must be of the form
|
||||
pub fn foo1(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
pub fn foo1(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive = "foo"]
|
||||
#[proc_macro_derive = ""]
|
||||
//~^ ERROR: attribute must be of the form
|
||||
pub fn foo2(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
pub fn foo2(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(
|
||||
a = "b"
|
||||
)]
|
||||
//~^^ ERROR: must only be one word
|
||||
pub fn foo3(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[proc_macro_derive(b, c, d)]
|
||||
#[proc_macro_derive(d3, a, b)]
|
||||
//~^ ERROR: attribute must have either one or two arguments
|
||||
pub fn foo4(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
pub fn foo3(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(d(e))]
|
||||
//~^ ERROR: must only be one word
|
||||
pub fn foo5(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[proc_macro_derive(f, attributes(g = "h"))]
|
||||
//~^ ERROR: must only be one word
|
||||
pub fn foo6(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[proc_macro_derive(i, attributes(j(k)))]
|
||||
//~^ ERROR: must only be one word
|
||||
pub fn foo7(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
|
||||
#[proc_macro_derive(l, attributes(m), n)]
|
||||
#[proc_macro_derive(d4, attributes(a), b)]
|
||||
//~^ ERROR: attribute must have either one or two arguments
|
||||
pub fn foo8(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
input
|
||||
}
|
||||
pub fn foo4(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive("a")]
|
||||
//~^ ERROR: not a meta item
|
||||
pub fn foo5(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(d6 = "")]
|
||||
//~^ ERROR: must only be one word
|
||||
pub fn foo6(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(m::d7)]
|
||||
//~^ ERROR: must only be one word
|
||||
pub fn foo7(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(d8(a))]
|
||||
//~^ ERROR: must only be one word
|
||||
pub fn foo8(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(self)]
|
||||
//~^ ERROR: `self` cannot be a name of derive macro
|
||||
pub fn foo9(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(PartialEq)]
|
||||
//~^ ERROR: cannot override a built-in derive macro
|
||||
pub fn foo10(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(d11, a)]
|
||||
//~^ ERROR: second argument must be `attributes`
|
||||
//~| ERROR: attribute must be of form: `attributes(foo, bar)`
|
||||
pub fn foo11(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(d12, attributes)]
|
||||
//~^ ERROR: attribute must be of form: `attributes(foo, bar)`
|
||||
pub fn foo12(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(d13, attributes("a"))]
|
||||
//~^ ERROR: not a meta item
|
||||
pub fn foo13(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(d14, attributes(a = ""))]
|
||||
//~^ ERROR: must only be one word
|
||||
pub fn foo14(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(d15, attributes(m::a))]
|
||||
//~^ ERROR: must only be one word
|
||||
pub fn foo15(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(d16, attributes(a(b)))]
|
||||
//~^ ERROR: must only be one word
|
||||
pub fn foo16(input: TokenStream) -> TokenStream { input }
|
||||
|
||||
#[proc_macro_derive(d17, attributes(self))]
|
||||
//~^ ERROR: `self` cannot be a name of derive helper attribute
|
||||
pub fn foo17(input: TokenStream) -> TokenStream { input }
|
||||
|
|
|
@ -1,50 +1,110 @@
|
|||
error: must only be one word
|
||||
--> $DIR/attribute.rs:21:5
|
||||
error: attribute must have either one or two arguments
|
||||
--> $DIR/attribute.rs:17:1
|
||||
|
|
||||
LL | a = "b"
|
||||
| ^^^^^^^
|
||||
LL | #[proc_macro_derive(d3, a, b)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: attribute must have either one or two arguments
|
||||
--> $DIR/attribute.rs:28:1
|
||||
--> $DIR/attribute.rs:21:1
|
||||
|
|
||||
LL | #[proc_macro_derive(b, c, d)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[proc_macro_derive(d4, attributes(a), b)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: not a meta item
|
||||
--> $DIR/attribute.rs:25:21
|
||||
|
|
||||
LL | #[proc_macro_derive("a")]
|
||||
| ^^^
|
||||
|
||||
error: must only be one word
|
||||
--> $DIR/attribute.rs:34:21
|
||||
--> $DIR/attribute.rs:29:21
|
||||
|
|
||||
LL | #[proc_macro_derive(d(e))]
|
||||
LL | #[proc_macro_derive(d6 = "")]
|
||||
| ^^^^^^^
|
||||
|
||||
error: must only be one word
|
||||
--> $DIR/attribute.rs:33:21
|
||||
|
|
||||
LL | #[proc_macro_derive(m::d7)]
|
||||
| ^^^^^
|
||||
|
||||
error: must only be one word
|
||||
--> $DIR/attribute.rs:37:21
|
||||
|
|
||||
LL | #[proc_macro_derive(d8(a))]
|
||||
| ^^^^^
|
||||
|
||||
error: `self` cannot be a name of derive macro
|
||||
--> $DIR/attribute.rs:41:21
|
||||
|
|
||||
LL | #[proc_macro_derive(self)]
|
||||
| ^^^^
|
||||
|
||||
error: must only be one word
|
||||
--> $DIR/attribute.rs:40:35
|
||||
error: cannot override a built-in derive macro
|
||||
--> $DIR/attribute.rs:45:21
|
||||
|
|
||||
LL | #[proc_macro_derive(f, attributes(g = "h"))]
|
||||
| ^^^^^^^
|
||||
LL | #[proc_macro_derive(PartialEq)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: second argument must be `attributes`
|
||||
--> $DIR/attribute.rs:49:26
|
||||
|
|
||||
LL | #[proc_macro_derive(d11, a)]
|
||||
| ^
|
||||
|
||||
error: attribute must be of form: `attributes(foo, bar)`
|
||||
--> $DIR/attribute.rs:49:26
|
||||
|
|
||||
LL | #[proc_macro_derive(d11, a)]
|
||||
| ^
|
||||
|
||||
error: attribute must be of form: `attributes(foo, bar)`
|
||||
--> $DIR/attribute.rs:54:26
|
||||
|
|
||||
LL | #[proc_macro_derive(d12, attributes)]
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: not a meta item
|
||||
--> $DIR/attribute.rs:58:37
|
||||
|
|
||||
LL | #[proc_macro_derive(d13, attributes("a"))]
|
||||
| ^^^
|
||||
|
||||
error: must only be one word
|
||||
--> $DIR/attribute.rs:46:35
|
||||
--> $DIR/attribute.rs:62:37
|
||||
|
|
||||
LL | #[proc_macro_derive(i, attributes(j(k)))]
|
||||
| ^^^^
|
||||
LL | #[proc_macro_derive(d14, attributes(a = ""))]
|
||||
| ^^^^^^
|
||||
|
||||
error: attribute must have either one or two arguments
|
||||
--> $DIR/attribute.rs:52:1
|
||||
error: must only be one word
|
||||
--> $DIR/attribute.rs:66:37
|
||||
|
|
||||
LL | #[proc_macro_derive(l, attributes(m), n)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[proc_macro_derive(d15, attributes(m::a))]
|
||||
| ^^^^
|
||||
|
||||
error: must only be one word
|
||||
--> $DIR/attribute.rs:70:37
|
||||
|
|
||||
LL | #[proc_macro_derive(d16, attributes(a(b)))]
|
||||
| ^^^^
|
||||
|
||||
error: `self` cannot be a name of derive helper attribute
|
||||
--> $DIR/attribute.rs:74:37
|
||||
|
|
||||
LL | #[proc_macro_derive(d17, attributes(self))]
|
||||
| ^^^^
|
||||
|
||||
error: attribute must be of the form `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
|
||||
--> $DIR/attribute.rs:8:1
|
||||
--> $DIR/attribute.rs:9:1
|
||||
|
|
||||
LL | #[proc_macro_derive]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: attribute must be of the form `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
|
||||
--> $DIR/attribute.rs:14:1
|
||||
--> $DIR/attribute.rs:13:1
|
||||
|
|
||||
LL | #[proc_macro_derive = "foo"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[proc_macro_derive = ""]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: aborting due to 18 previous errors
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ error: proc macro panicked
|
|||
LL | invalid_raw_ident!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: message: `"self"` is not a valid raw identifier
|
||||
= help: message: `self` cannot be a raw identifier
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro_derive(PartialEq)]
|
||||
//~^ ERROR: cannot override a built-in #[derive] mode
|
||||
pub fn foo(input: TokenStream) -> TokenStream {
|
||||
input
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
error: cannot override a built-in #[derive] mode
|
||||
--> $DIR/shadow-builtin.rs:10:21
|
||||
|
|
||||
LL | #[proc_macro_derive(PartialEq)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Add table
Reference in a new issue