syntax_ext: Reuse built-in attribute template checking for macro attributes
This commit is contained in:
parent
433024147a
commit
76b1ffaf6c
9 changed files with 132 additions and 113 deletions
|
@ -36,10 +36,10 @@ use syntax::tokenstream::{TokenTree, TokenStream};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
use syntax::ast::Expr;
|
use syntax::ast::Expr;
|
||||||
use syntax::attr::{self, HasAttrs};
|
use syntax::attr::{self, HasAttrs, AttributeTemplate};
|
||||||
use syntax::source_map::Spanned;
|
use syntax::source_map::Spanned;
|
||||||
use syntax::edition::Edition;
|
use syntax::edition::Edition;
|
||||||
use syntax::feature_gate::{AttributeGate, AttributeTemplate, AttributeType};
|
use syntax::feature_gate::{AttributeGate, AttributeType};
|
||||||
use syntax::feature_gate::{Stability, deprecated_attributes};
|
use syntax::feature_gate::{Stability, deprecated_attributes};
|
||||||
use syntax_pos::{BytePos, Span, SyntaxContext};
|
use syntax_pos::{BytePos, Span, SyntaxContext};
|
||||||
use syntax::symbol::{Symbol, kw, sym};
|
use syntax::symbol::{Symbol, kw, sym};
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
//! Parsing and validation of builtin attributes
|
//! Parsing and validation of builtin attributes
|
||||||
|
|
||||||
use crate::ast::{self, Attribute, MetaItem, NestedMetaItem};
|
use crate::ast::{self, Attribute, MetaItem, NestedMetaItem};
|
||||||
|
use crate::early_buffered_lints::BufferedEarlyLintId;
|
||||||
|
use crate::ext::base::ExtCtxt;
|
||||||
|
use crate::ext::build::AstBuilder;
|
||||||
use crate::feature_gate::{Features, GatedCfg};
|
use crate::feature_gate::{Features, GatedCfg};
|
||||||
use crate::parse::ParseSess;
|
use crate::parse::ParseSess;
|
||||||
|
|
||||||
|
@ -19,6 +22,27 @@ enum AttrError {
|
||||||
UnsupportedLiteral(&'static str, /* is_bytestr */ bool),
|
UnsupportedLiteral(&'static str, /* is_bytestr */ bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A template that the attribute input must match.
|
||||||
|
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct AttributeTemplate {
|
||||||
|
crate word: bool,
|
||||||
|
crate list: Option<&'static str>,
|
||||||
|
crate name_value_str: Option<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AttributeTemplate {
|
||||||
|
/// Checks that the given meta-item is compatible with this template.
|
||||||
|
fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool {
|
||||||
|
match meta_item_kind {
|
||||||
|
ast::MetaItemKind::Word => self.word,
|
||||||
|
ast::MetaItemKind::List(..) => self.list.is_some(),
|
||||||
|
ast::MetaItemKind::NameValue(lit) if lit.node.is_str() => self.name_value_str.is_some(),
|
||||||
|
ast::MetaItemKind::NameValue(..) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
|
fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
|
||||||
let diag = &sess.span_diagnostic;
|
let diag = &sess.span_diagnostic;
|
||||||
match error {
|
match error {
|
||||||
|
@ -901,3 +925,75 @@ pub fn find_transparency(
|
||||||
let fallback = if is_legacy { Transparency::SemiTransparent } else { Transparency::Opaque };
|
let fallback = if is_legacy { Transparency::SemiTransparent } else { Transparency::Opaque };
|
||||||
(transparency.map_or(fallback, |t| t.0), error)
|
(transparency.map_or(fallback, |t| t.0), error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
|
||||||
|
// All the built-in macro attributes are "words" at the moment.
|
||||||
|
let template = AttributeTemplate { word: true, list: None, name_value_str: None };
|
||||||
|
let attr = ecx.attribute(meta_item.span, meta_item.clone());
|
||||||
|
check_builtin_attribute(ecx.parse_sess, &attr, name, template);
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn check_builtin_attribute(
|
||||||
|
sess: &ParseSess, attr: &ast::Attribute, name: Symbol, template: AttributeTemplate
|
||||||
|
) {
|
||||||
|
// Some special attributes like `cfg` must be checked
|
||||||
|
// before the generic check, so we skip them here.
|
||||||
|
let should_skip = |name| name == sym::cfg;
|
||||||
|
// Some of previously accepted forms were used in practice,
|
||||||
|
// report them as warnings for now.
|
||||||
|
let should_warn = |name| name == sym::doc || name == sym::ignore ||
|
||||||
|
name == sym::inline || name == sym::link;
|
||||||
|
|
||||||
|
match attr.parse_meta(sess) {
|
||||||
|
Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) {
|
||||||
|
let error_msg = format!("malformed `{}` attribute input", name);
|
||||||
|
let mut msg = "attribute must be of the form ".to_owned();
|
||||||
|
let mut suggestions = vec![];
|
||||||
|
let mut first = true;
|
||||||
|
if template.word {
|
||||||
|
first = false;
|
||||||
|
let code = format!("#[{}]", name);
|
||||||
|
msg.push_str(&format!("`{}`", &code));
|
||||||
|
suggestions.push(code);
|
||||||
|
}
|
||||||
|
if let Some(descr) = template.list {
|
||||||
|
if !first {
|
||||||
|
msg.push_str(" or ");
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
let code = format!("#[{}({})]", name, descr);
|
||||||
|
msg.push_str(&format!("`{}`", &code));
|
||||||
|
suggestions.push(code);
|
||||||
|
}
|
||||||
|
if let Some(descr) = template.name_value_str {
|
||||||
|
if !first {
|
||||||
|
msg.push_str(" or ");
|
||||||
|
}
|
||||||
|
let code = format!("#[{} = \"{}\"]", name, descr);
|
||||||
|
msg.push_str(&format!("`{}`", &code));
|
||||||
|
suggestions.push(code);
|
||||||
|
}
|
||||||
|
if should_warn(name) {
|
||||||
|
sess.buffer_lint(
|
||||||
|
BufferedEarlyLintId::IllFormedAttributeInput,
|
||||||
|
meta.span,
|
||||||
|
ast::CRATE_NODE_ID,
|
||||||
|
&msg,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
sess.span_diagnostic.struct_span_err(meta.span, &error_msg)
|
||||||
|
.span_suggestions(
|
||||||
|
meta.span,
|
||||||
|
if suggestions.len() == 1 {
|
||||||
|
"must be of the form"
|
||||||
|
} else {
|
||||||
|
"the following are the possible correct uses"
|
||||||
|
},
|
||||||
|
suggestions.into_iter(),
|
||||||
|
Applicability::HasPlaceholders,
|
||||||
|
).emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(mut err) => err.emit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -19,8 +19,7 @@ use crate::ast::{
|
||||||
self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
|
self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
|
||||||
PatKind, RangeEnd,
|
PatKind, RangeEnd,
|
||||||
};
|
};
|
||||||
use crate::attr;
|
use crate::attr::{self, check_builtin_attribute, AttributeTemplate};
|
||||||
use crate::early_buffered_lints::BufferedEarlyLintId;
|
|
||||||
use crate::source_map::Spanned;
|
use crate::source_map::Spanned;
|
||||||
use crate::edition::{ALL_EDITIONS, Edition};
|
use crate::edition::{ALL_EDITIONS, Edition};
|
||||||
use crate::visit::{self, FnKind, Visitor};
|
use crate::visit::{self, FnKind, Visitor};
|
||||||
|
@ -906,27 +905,6 @@ pub enum AttributeGate {
|
||||||
Ungated,
|
Ungated,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A template that the attribute input must match.
|
|
||||||
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct AttributeTemplate {
|
|
||||||
word: bool,
|
|
||||||
list: Option<&'static str>,
|
|
||||||
name_value_str: Option<&'static str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AttributeTemplate {
|
|
||||||
/// Checks that the given meta-item is compatible with this template.
|
|
||||||
fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool {
|
|
||||||
match meta_item_kind {
|
|
||||||
ast::MetaItemKind::Word => self.word,
|
|
||||||
ast::MetaItemKind::List(..) => self.list.is_some(),
|
|
||||||
ast::MetaItemKind::NameValue(lit) if lit.node.is_str() => self.name_value_str.is_some(),
|
|
||||||
ast::MetaItemKind::NameValue(..) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A convenience macro for constructing attribute templates.
|
/// A convenience macro for constructing attribute templates.
|
||||||
/// E.g., `template!(Word, List: "description")` means that the attribute
|
/// E.g., `template!(Word, List: "description")` means that the attribute
|
||||||
/// supports forms `#[attr]` and `#[attr(description)]`.
|
/// supports forms `#[attr]` and `#[attr(description)]`.
|
||||||
|
@ -1901,70 +1879,6 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||||
Abi::System => {}
|
Abi::System => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_builtin_attribute(&mut self, attr: &ast::Attribute, name: Symbol,
|
|
||||||
template: AttributeTemplate) {
|
|
||||||
// Some special attributes like `cfg` must be checked
|
|
||||||
// before the generic check, so we skip them here.
|
|
||||||
let should_skip = |name| name == sym::cfg;
|
|
||||||
// Some of previously accepted forms were used in practice,
|
|
||||||
// report them as warnings for now.
|
|
||||||
let should_warn = |name| name == sym::doc || name == sym::ignore ||
|
|
||||||
name == sym::inline || name == sym::link;
|
|
||||||
|
|
||||||
match attr.parse_meta(self.context.parse_sess) {
|
|
||||||
Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) {
|
|
||||||
let error_msg = format!("malformed `{}` attribute input", name);
|
|
||||||
let mut msg = "attribute must be of the form ".to_owned();
|
|
||||||
let mut suggestions = vec![];
|
|
||||||
let mut first = true;
|
|
||||||
if template.word {
|
|
||||||
first = false;
|
|
||||||
let code = format!("#[{}]", name);
|
|
||||||
msg.push_str(&format!("`{}`", &code));
|
|
||||||
suggestions.push(code);
|
|
||||||
}
|
|
||||||
if let Some(descr) = template.list {
|
|
||||||
if !first {
|
|
||||||
msg.push_str(" or ");
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
let code = format!("#[{}({})]", name, descr);
|
|
||||||
msg.push_str(&format!("`{}`", &code));
|
|
||||||
suggestions.push(code);
|
|
||||||
}
|
|
||||||
if let Some(descr) = template.name_value_str {
|
|
||||||
if !first {
|
|
||||||
msg.push_str(" or ");
|
|
||||||
}
|
|
||||||
let code = format!("#[{} = \"{}\"]", name, descr);
|
|
||||||
msg.push_str(&format!("`{}`", &code));
|
|
||||||
suggestions.push(code);
|
|
||||||
}
|
|
||||||
if should_warn(name) {
|
|
||||||
self.context.parse_sess.buffer_lint(
|
|
||||||
BufferedEarlyLintId::IllFormedAttributeInput,
|
|
||||||
meta.span,
|
|
||||||
ast::CRATE_NODE_ID,
|
|
||||||
&msg,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
self.context.parse_sess.span_diagnostic.struct_span_err(meta.span, &error_msg)
|
|
||||||
.span_suggestions(
|
|
||||||
meta.span,
|
|
||||||
if suggestions.len() == 1 {
|
|
||||||
"must be of the form"
|
|
||||||
} else {
|
|
||||||
"the following are the possible correct uses"
|
|
||||||
},
|
|
||||||
suggestions.into_iter(),
|
|
||||||
Applicability::HasPlaceholders,
|
|
||||||
).emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(mut err) => err.emit(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
|
@ -2005,7 +1919,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
match attr_info {
|
match attr_info {
|
||||||
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
|
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
|
||||||
Some(&(name, _, template, _)) if name != sym::rustc_dummy =>
|
Some(&(name, _, template, _)) if name != sym::rustc_dummy =>
|
||||||
self.check_builtin_attribute(attr, name, template),
|
check_builtin_attribute(self.context.parse_sess, attr, name, template),
|
||||||
_ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() {
|
_ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() {
|
||||||
if token == token::Eq {
|
if token == token::Eq {
|
||||||
// All key-value attributes are restricted to meta-item syntax.
|
// All key-value attributes are restricted to meta-item syntax.
|
||||||
|
|
|
@ -1,31 +1,22 @@
|
||||||
use errors::Applicability;
|
|
||||||
use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident, Item};
|
|
||||||
use syntax::ast::{ItemKind, Mutability, Ty, TyKind, Unsafety, VisibilityKind};
|
use syntax::ast::{ItemKind, Mutability, Ty, TyKind, Unsafety, VisibilityKind};
|
||||||
use syntax::source_map::respan;
|
use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident, Item};
|
||||||
|
use syntax::attr::check_builtin_macro_attribute;
|
||||||
use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS};
|
use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS};
|
||||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||||
use syntax::ext::build::AstBuilder;
|
use syntax::ext::build::AstBuilder;
|
||||||
use syntax::ext::hygiene::SyntaxContext;
|
use syntax::ext::hygiene::SyntaxContext;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
|
use syntax::source_map::respan;
|
||||||
use syntax::symbol::{kw, sym};
|
use syntax::symbol::{kw, sym};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
|
||||||
pub fn expand(
|
pub fn expand(
|
||||||
ecx: &mut ExtCtxt<'_>,
|
ecx: &mut ExtCtxt<'_>,
|
||||||
span: Span,
|
_span: Span,
|
||||||
meta_item: &ast::MetaItem,
|
meta_item: &ast::MetaItem,
|
||||||
item: Annotatable,
|
item: Annotatable,
|
||||||
) -> Vec<Annotatable> {
|
) -> Vec<Annotatable> {
|
||||||
if !meta_item.is_word() {
|
check_builtin_macro_attribute(ecx, meta_item, sym::global_allocator);
|
||||||
let msg = format!("malformed `{}` attribute input", meta_item.path);
|
|
||||||
ecx.parse_sess.span_diagnostic.struct_span_err(span, &msg)
|
|
||||||
.span_suggestion(
|
|
||||||
span,
|
|
||||||
"must be of the form",
|
|
||||||
format!("`#[{}]`", meta_item.path),
|
|
||||||
Applicability::MachineApplicable
|
|
||||||
).emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
let not_static = |item: Annotatable| {
|
let not_static = |item: Annotatable| {
|
||||||
ecx.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
|
ecx.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
|
||||||
|
|
|
@ -1,31 +1,34 @@
|
||||||
/// The expansion from a test function to the appropriate test struct for libtest
|
/// The expansion from a test function to the appropriate test struct for libtest
|
||||||
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
|
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
|
||||||
|
|
||||||
|
use syntax::ast;
|
||||||
|
use syntax::attr::{self, check_builtin_macro_attribute};
|
||||||
use syntax::ext::base::*;
|
use syntax::ext::base::*;
|
||||||
use syntax::ext::build::AstBuilder;
|
use syntax::ext::build::AstBuilder;
|
||||||
use syntax::ext::hygiene::SyntaxContext;
|
use syntax::ext::hygiene::SyntaxContext;
|
||||||
use syntax::attr;
|
|
||||||
use syntax::ast;
|
|
||||||
use syntax::print::pprust;
|
use syntax::print::pprust;
|
||||||
use syntax::symbol::{Symbol, sym};
|
use syntax::symbol::{Symbol, sym};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
pub fn expand_test(
|
pub fn expand_test(
|
||||||
cx: &mut ExtCtxt<'_>,
|
cx: &mut ExtCtxt<'_>,
|
||||||
attr_sp: Span,
|
attr_sp: Span,
|
||||||
_meta_item: &ast::MetaItem,
|
meta_item: &ast::MetaItem,
|
||||||
item: Annotatable,
|
item: Annotatable,
|
||||||
) -> Vec<Annotatable> {
|
) -> Vec<Annotatable> {
|
||||||
|
check_builtin_macro_attribute(cx, meta_item, sym::test);
|
||||||
expand_test_or_bench(cx, attr_sp, item, false)
|
expand_test_or_bench(cx, attr_sp, item, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand_bench(
|
pub fn expand_bench(
|
||||||
cx: &mut ExtCtxt<'_>,
|
cx: &mut ExtCtxt<'_>,
|
||||||
attr_sp: Span,
|
attr_sp: Span,
|
||||||
_meta_item: &ast::MetaItem,
|
meta_item: &ast::MetaItem,
|
||||||
item: Annotatable,
|
item: Annotatable,
|
||||||
) -> Vec<Annotatable> {
|
) -> Vec<Annotatable> {
|
||||||
|
check_builtin_macro_attribute(cx, meta_item, sym::bench);
|
||||||
expand_test_or_bench(cx, attr_sp, item, true)
|
expand_test_or_bench(cx, attr_sp, item, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,11 @@
|
||||||
// We mark item with an inert attribute "rustc_test_marker" which the test generation
|
// We mark item with an inert attribute "rustc_test_marker" which the test generation
|
||||||
// logic will pick up on.
|
// logic will pick up on.
|
||||||
|
|
||||||
|
use syntax::ast;
|
||||||
|
use syntax::attr::check_builtin_macro_attribute;
|
||||||
use syntax::ext::base::*;
|
use syntax::ext::base::*;
|
||||||
use syntax::ext::build::AstBuilder;
|
use syntax::ext::build::AstBuilder;
|
||||||
use syntax::ext::hygiene::SyntaxContext;
|
use syntax::ext::hygiene::SyntaxContext;
|
||||||
use syntax::ast;
|
|
||||||
use syntax::source_map::respan;
|
use syntax::source_map::respan;
|
||||||
use syntax::symbol::sym;
|
use syntax::symbol::sym;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
@ -20,9 +21,11 @@ use syntax_pos::Span;
|
||||||
pub fn expand(
|
pub fn expand(
|
||||||
ecx: &mut ExtCtxt<'_>,
|
ecx: &mut ExtCtxt<'_>,
|
||||||
attr_sp: Span,
|
attr_sp: Span,
|
||||||
_meta_item: &ast::MetaItem,
|
meta_item: &ast::MetaItem,
|
||||||
anno_item: Annotatable
|
anno_item: Annotatable
|
||||||
) -> Vec<Annotatable> {
|
) -> Vec<Annotatable> {
|
||||||
|
check_builtin_macro_attribute(ecx, meta_item, sym::test_case);
|
||||||
|
|
||||||
if !ecx.ecfg.should_test { return vec![]; }
|
if !ecx.ecfg.should_test { return vec![]; }
|
||||||
|
|
||||||
let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id));
|
let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id));
|
||||||
|
|
|
@ -2,7 +2,7 @@ error: malformed `global_allocator` attribute input
|
||||||
--> $DIR/allocator-args.rs:10:1
|
--> $DIR/allocator-args.rs:10:1
|
||||||
|
|
|
|
||||||
LL | #[global_allocator(malloc)]
|
LL | #[global_allocator(malloc)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: ``#[global_allocator]``
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[global_allocator]`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
|
error: malformed `bench` attribute input
|
||||||
|
--> $DIR/issue-43106-gating-of-bench.rs:15:1
|
||||||
|
|
|
||||||
|
LL | #![bench = "4100"]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[bench]`
|
||||||
|
|
||||||
error[E0601]: `main` function not found in crate `issue_43106_gating_of_bench`
|
error[E0601]: `main` function not found in crate `issue_43106_gating_of_bench`
|
||||||
|
|
|
|
||||||
= note: consider adding a `main` function to `$DIR/issue-43106-gating-of-bench.rs`
|
= note: consider adding a `main` function to `$DIR/issue-43106-gating-of-bench.rs`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0601`.
|
For more information about this error, try `rustc --explain E0601`.
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
|
error: malformed `test` attribute input
|
||||||
|
--> $DIR/issue-43106-gating-of-test.rs:10:1
|
||||||
|
|
|
||||||
|
LL | #![test = "4200"]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[test]`
|
||||||
|
|
||||||
error[E0601]: `main` function not found in crate `issue_43106_gating_of_test`
|
error[E0601]: `main` function not found in crate `issue_43106_gating_of_test`
|
||||||
|
|
|
|
||||||
= note: consider adding a `main` function to `$DIR/issue-43106-gating-of-test.rs`
|
= note: consider adding a `main` function to `$DIR/issue-43106-gating-of-test.rs`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0601`.
|
For more information about this error, try `rustc --explain E0601`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue