Auto merge of #144689 - JonathanBrouwer:share_parse_path, r=jdonszelmann
Rewrite the new attribute argument parser Fixes https://github.com/rust-lang/rust/issues/143940 This rewrites the parser, should improve performance and maintainability. This can be reviewed commit by commit
This commit is contained in:
commit
f5703d5dd3
51 changed files with 670 additions and 524 deletions
|
|
@ -3459,7 +3459,6 @@ dependencies = [
|
|||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_macros",
|
||||
"rustc_parse",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
|
|
@ -3490,6 +3489,7 @@ dependencies = [
|
|||
"rustc_hir",
|
||||
"rustc_lexer",
|
||||
"rustc_macros",
|
||||
"rustc_parse",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"thin-vec",
|
||||
|
|
@ -4355,7 +4355,6 @@ dependencies = [
|
|||
"rustc-literal-escaper",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ rustc_errors = { path = "../rustc_errors" }
|
|||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
|
|
|
|||
|
|
@ -25,10 +25,10 @@ use rustc_abi::{CanonAbi, ExternAbi, InterruptKind};
|
|||
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::{self, State};
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_feature::Features;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::builtin::{
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
|||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
thin-vec = "0.2.12"
|
||||
|
|
|
|||
|
|
@ -170,3 +170,22 @@ attr_parsing_unused_multiple =
|
|||
|
||||
-attr_parsing_previously_accepted =
|
||||
this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
attr_parsing_meta_bad_delim = wrong meta list delimiters
|
||||
attr_parsing_meta_bad_delim_suggestion = the delimiters should be `(` and `)`
|
||||
|
||||
attr_parsing_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
|
||||
.label = usage of unsafe attribute
|
||||
attr_parsing_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
|
||||
|
||||
attr_parsing_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
|
||||
.label = this is not an unsafe attribute
|
||||
.suggestion = remove the `unsafe(...)`
|
||||
.note = extraneous unsafe is not allowed in attributes
|
||||
|
||||
attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr}
|
||||
.remove_neg_sugg = negative numbers are not literals, try removing the `-` sign
|
||||
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
|
||||
|
||||
attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
|
||||
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
|
|
@ -49,27 +51,44 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
target_node_id: NodeId,
|
||||
features: Option<&'sess Features>,
|
||||
) -> Option<Attribute> {
|
||||
let mut p = Self {
|
||||
features,
|
||||
tools: Vec::new(),
|
||||
parse_only: Some(sym),
|
||||
let mut parsed = Self::parse_limited_all(
|
||||
sess,
|
||||
stage: Early { emit_errors: ShouldEmit::Nothing },
|
||||
};
|
||||
let mut parsed = p.parse_attribute_list(
|
||||
attrs,
|
||||
Some(sym),
|
||||
Target::Crate, // Does not matter, we're not going to emit errors anyways
|
||||
target_span,
|
||||
target_node_id,
|
||||
features,
|
||||
ShouldEmit::Nothing,
|
||||
);
|
||||
assert!(parsed.len() <= 1);
|
||||
parsed.pop()
|
||||
}
|
||||
|
||||
pub fn parse_limited_all(
|
||||
sess: &'sess Session,
|
||||
attrs: &[ast::Attribute],
|
||||
parse_only: Option<Symbol>,
|
||||
target: Target,
|
||||
target_span: Span,
|
||||
target_node_id: NodeId,
|
||||
features: Option<&'sess Features>,
|
||||
emit_errors: ShouldEmit,
|
||||
) -> Vec<Attribute> {
|
||||
let mut p =
|
||||
Self { features, tools: Vec::new(), parse_only, sess, stage: Early { emit_errors } };
|
||||
p.parse_attribute_list(
|
||||
attrs,
|
||||
target_span,
|
||||
target_node_id,
|
||||
Target::Crate, // Does not matter, we're not going to emit errors anyways
|
||||
target,
|
||||
OmitDoc::Skip,
|
||||
std::convert::identity,
|
||||
|_lint| {
|
||||
panic!("can't emit lints here for now (nothing uses this atm)");
|
||||
// FIXME: Can't emit lints here for now
|
||||
// This branch can be hit when an attribute produces a warning during early parsing (such as attributes on macro calls)
|
||||
},
|
||||
);
|
||||
assert!(parsed.len() <= 1);
|
||||
|
||||
parsed.pop()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn parse_single<T>(
|
||||
|
|
@ -79,9 +98,9 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
target_node_id: NodeId,
|
||||
features: Option<&'sess Features>,
|
||||
emit_errors: ShouldEmit,
|
||||
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
|
||||
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> Option<T>,
|
||||
template: &AttributeTemplate,
|
||||
) -> T {
|
||||
) -> Option<T> {
|
||||
let mut parser = Self {
|
||||
features,
|
||||
tools: Vec::new(),
|
||||
|
|
@ -92,7 +111,9 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
|
||||
panic!("parse_single called on a doc attr")
|
||||
};
|
||||
let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx());
|
||||
let parts =
|
||||
normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
||||
let meta_parser = MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors)?;
|
||||
let path = meta_parser.path();
|
||||
let args = meta_parser.args();
|
||||
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
|
||||
|
|
@ -199,14 +220,22 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
// }))
|
||||
// }
|
||||
ast::AttrKind::Normal(n) => {
|
||||
attr_paths.push(PathParser::Ast(&n.item.path));
|
||||
attr_paths.push(PathParser(Cow::Borrowed(&n.item.path)));
|
||||
|
||||
let parser = MetaItemParser::from_attr(n, self.dcx());
|
||||
let path = parser.path();
|
||||
let args = parser.args();
|
||||
let path_parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
|
||||
let parts =
|
||||
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
||||
|
||||
if let Some(accepts) = S::parsers().accepters.get(path_parts.as_slice()) {
|
||||
if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
|
||||
let Some(parser) = MetaItemParser::from_attr(
|
||||
n,
|
||||
&parts,
|
||||
&self.sess.psess,
|
||||
self.stage.should_emit(),
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
let path = parser.path();
|
||||
let args = parser.args();
|
||||
for accept in accepts {
|
||||
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
||||
shared: SharedContext {
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ pub mod parser;
|
|||
mod lints;
|
||||
mod session_diagnostics;
|
||||
mod target_checking;
|
||||
pub mod validate_attr;
|
||||
|
||||
pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr};
|
||||
pub use attributes::cfg_old::*;
|
||||
|
|
|
|||
|
|
@ -3,45 +3,30 @@
|
|||
//!
|
||||
//! FIXME(jdonszelmann): delete `rustc_ast/attr/mod.rs`
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::iter::Peekable;
|
||||
|
||||
use rustc_ast::token::{self, Delimiter, Token};
|
||||
use rustc_ast::tokenstream::{TokenStreamIter, TokenTree};
|
||||
use rustc_ast::token::{self, Delimiter, MetaVarKind};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_hir::{self as hir, AttrPath};
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::{Parser, PathStyle, token_descr};
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
pub struct SegmentIterator<'a> {
|
||||
offset: usize,
|
||||
path: &'a PathParser<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for SegmentIterator<'a> {
|
||||
type Item = &'a Ident;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.offset >= self.path.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let res = match self.path {
|
||||
PathParser::Ast(ast_path) => &ast_path.segments[self.offset].ident,
|
||||
PathParser::Attr(attr_path) => &attr_path.segments[self.offset],
|
||||
};
|
||||
|
||||
self.offset += 1;
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
use crate::ShouldEmit;
|
||||
use crate::session_diagnostics::{
|
||||
InvalidMetaItem, InvalidMetaItemQuoteIdentSugg, InvalidMetaItemRemoveNegSugg, MetaBadDelim,
|
||||
MetaBadDelimSugg, SuffixedLiteralInAttribute,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PathParser<'a> {
|
||||
Ast(&'a Path),
|
||||
Attr(AttrPath),
|
||||
}
|
||||
pub struct PathParser<'a>(pub Cow<'a, Path>);
|
||||
|
||||
impl<'a> PathParser<'a> {
|
||||
pub fn get_attribute_path(&self) -> hir::AttrPath {
|
||||
|
|
@ -52,21 +37,15 @@ impl<'a> PathParser<'a> {
|
|||
}
|
||||
|
||||
pub fn segments(&'a self) -> impl Iterator<Item = &'a Ident> {
|
||||
SegmentIterator { offset: 0, path: self }
|
||||
self.0.segments.iter().map(|seg| &seg.ident)
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
PathParser::Ast(path) => path.span,
|
||||
PathParser::Attr(attr_path) => attr_path.span,
|
||||
}
|
||||
self.0.span
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
PathParser::Ast(path) => path.segments.len(),
|
||||
PathParser::Attr(attr_path) => attr_path.segments.len(),
|
||||
}
|
||||
self.0.segments.len()
|
||||
}
|
||||
|
||||
pub fn segments_is(&self, segments: &[Symbol]) -> bool {
|
||||
|
|
@ -99,10 +78,7 @@ impl<'a> PathParser<'a> {
|
|||
|
||||
impl Display for PathParser<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
PathParser::Ast(path) => write!(f, "{}", pprust::path_to_string(path)),
|
||||
PathParser::Attr(attr_path) => write!(f, "{attr_path}"),
|
||||
}
|
||||
write!(f, "{}", pprust::path_to_string(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -123,21 +99,39 @@ impl<'a> ArgParser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_attr_args<'sess>(value: &'a AttrArgs, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
match value {
|
||||
pub fn from_attr_args<'sess>(
|
||||
value: &'a AttrArgs,
|
||||
parts: &[Symbol],
|
||||
psess: &'sess ParseSess,
|
||||
should_emit: ShouldEmit,
|
||||
) -> Option<Self> {
|
||||
Some(match value {
|
||||
AttrArgs::Empty => Self::NoArgs,
|
||||
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
||||
Self::List(MetaItemListParser::new(args, dcx))
|
||||
}
|
||||
AttrArgs::Delimited(args) => {
|
||||
Self::List(MetaItemListParser { sub_parsers: vec![], span: args.dspan.entire() })
|
||||
// The arguments of rustc_dummy are not validated if the arguments are delimited
|
||||
if parts == &[sym::rustc_dummy] {
|
||||
return Some(ArgParser::List(MetaItemListParser {
|
||||
sub_parsers: ThinVec::new(),
|
||||
span: args.dspan.entire(),
|
||||
}));
|
||||
}
|
||||
|
||||
if args.delim != Delimiter::Parenthesis {
|
||||
psess.dcx().emit_err(MetaBadDelim {
|
||||
span: args.dspan.entire(),
|
||||
sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
|
||||
});
|
||||
return None;
|
||||
}
|
||||
|
||||
Self::List(MetaItemListParser::new(args, psess, should_emit)?)
|
||||
}
|
||||
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
|
||||
eq_span: *eq_span,
|
||||
value: expr_to_lit(dcx, &expr, *eq_span),
|
||||
value: expr_to_lit(psess, &expr, expr.span, should_emit)?,
|
||||
value_span: expr.span,
|
||||
}),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Asserts that this MetaItem is a list
|
||||
|
|
@ -249,11 +243,16 @@ impl<'a> Debug for MetaItemParser<'a> {
|
|||
impl<'a> MetaItemParser<'a> {
|
||||
/// Create a new parser from a [`NormalAttr`], which is stored inside of any
|
||||
/// [`ast::Attribute`](rustc_ast::Attribute)
|
||||
pub fn from_attr<'sess>(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
Self {
|
||||
path: PathParser::Ast(&attr.item.path),
|
||||
args: ArgParser::from_attr_args(&attr.item.args, dcx),
|
||||
}
|
||||
pub fn from_attr<'sess>(
|
||||
attr: &'a NormalAttr,
|
||||
parts: &[Symbol],
|
||||
psess: &'sess ParseSess,
|
||||
should_emit: ShouldEmit,
|
||||
) -> Option<Self> {
|
||||
Some(Self {
|
||||
path: PathParser(Cow::Borrowed(&attr.item.path)),
|
||||
args: ArgParser::from_attr_args(&attr.item.args, parts, psess, should_emit)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -318,215 +317,232 @@ impl NameValueParser {
|
|||
}
|
||||
}
|
||||
|
||||
fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit {
|
||||
// In valid code the value always ends up as a single literal. Otherwise, a dummy
|
||||
// literal suffices because the error is handled elsewhere.
|
||||
if let ExprKind::Lit(token_lit) = expr.kind
|
||||
&& let Ok(lit) = MetaItemLit::from_token_lit(token_lit, expr.span)
|
||||
{
|
||||
lit
|
||||
fn expr_to_lit(
|
||||
psess: &ParseSess,
|
||||
expr: &Expr,
|
||||
span: Span,
|
||||
should_emit: ShouldEmit,
|
||||
) -> Option<MetaItemLit> {
|
||||
if let ExprKind::Lit(token_lit) = expr.kind {
|
||||
let res = MetaItemLit::from_token_lit(token_lit, expr.span);
|
||||
match res {
|
||||
Ok(lit) => {
|
||||
if token_lit.suffix.is_some() {
|
||||
psess
|
||||
.dcx()
|
||||
.create_err(SuffixedLiteralInAttribute { span: lit.span })
|
||||
.emit_unless_delay(!should_emit.should_emit());
|
||||
None
|
||||
} else {
|
||||
if should_emit.should_emit() && !lit.kind.is_unsuffixed() {
|
||||
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
|
||||
psess.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span });
|
||||
}
|
||||
|
||||
Some(lit)
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
let guar = report_lit_error(psess, err, token_lit, expr.span);
|
||||
let lit = MetaItemLit {
|
||||
symbol: token_lit.symbol,
|
||||
suffix: token_lit.suffix,
|
||||
kind: LitKind::Err(guar),
|
||||
span: expr.span,
|
||||
};
|
||||
Some(lit)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let guar = dcx.span_delayed_bug(
|
||||
span,
|
||||
"expr in place where literal is expected (builtin attr parsing)",
|
||||
);
|
||||
MetaItemLit { symbol: sym::dummy, suffix: None, kind: LitKind::Err(guar), span }
|
||||
// Example cases:
|
||||
// - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
|
||||
// - `#[foo = include_str!("nonexistent-file.rs")]`:
|
||||
// results in `ast::ExprKind::Err`. In that case we delay
|
||||
// the error because an earlier error will have already
|
||||
// been reported.
|
||||
let msg = "attribute value must be a literal";
|
||||
let mut err = psess.dcx().struct_span_err(span, msg);
|
||||
if let ExprKind::Err(_) = expr.kind {
|
||||
err.downgrade_to_delayed_bug();
|
||||
}
|
||||
|
||||
err.emit_unless_delay(!should_emit.should_emit());
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct MetaItemListParserContext<'a, 'sess> {
|
||||
// the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside
|
||||
inside_delimiters: Peekable<TokenStreamIter<'a>>,
|
||||
dcx: DiagCtxtHandle<'sess>,
|
||||
parser: &'a mut Parser<'sess>,
|
||||
should_emit: ShouldEmit,
|
||||
}
|
||||
|
||||
impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
||||
fn done(&mut self) -> bool {
|
||||
self.inside_delimiters.peek().is_none()
|
||||
}
|
||||
fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'sess, MetaItemLit> {
|
||||
let uninterpolated_span = self.parser.token_uninterpolated_span();
|
||||
let Some(token_lit) = self.parser.eat_token_lit() else {
|
||||
return self.parser.handle_missing_lit(Parser::mk_meta_item_lit_char);
|
||||
};
|
||||
|
||||
fn next_path(&mut self) -> Option<AttrPath> {
|
||||
// FIXME: Share code with `parse_path`.
|
||||
let tt = self.inside_delimiters.next().map(|tt| TokenTree::uninterpolate(tt));
|
||||
|
||||
match tt.as_deref()? {
|
||||
&TokenTree::Token(
|
||||
Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
|
||||
_,
|
||||
) => {
|
||||
// here we have either an ident or pathsep `::`.
|
||||
|
||||
let mut segments = if let &token::Ident(name, _) = kind {
|
||||
// when we lookahead another pathsep, more path's coming
|
||||
if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
|
||||
self.inside_delimiters.peek()
|
||||
{
|
||||
self.inside_delimiters.next();
|
||||
vec![Ident::new(name, span)]
|
||||
} else {
|
||||
// else we have a single identifier path, that's all
|
||||
return Some(AttrPath {
|
||||
segments: vec![Ident::new(name, span)].into_boxed_slice(),
|
||||
span,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// if `::` is all we get, we just got a path root
|
||||
vec![Ident::new(kw::PathRoot, span)]
|
||||
};
|
||||
|
||||
// one segment accepted. accept n more
|
||||
loop {
|
||||
// another ident?
|
||||
if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
|
||||
self.inside_delimiters
|
||||
.next()
|
||||
.map(|tt| TokenTree::uninterpolate(tt))
|
||||
.as_deref()
|
||||
{
|
||||
segments.push(Ident::new(name, span));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
// stop unless we see another `::`
|
||||
if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
|
||||
self.inside_delimiters.peek()
|
||||
{
|
||||
self.inside_delimiters.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let span = span.with_hi(segments.last().unwrap().span.hi());
|
||||
Some(AttrPath { segments: segments.into_boxed_slice(), span })
|
||||
let lit = match MetaItemLit::from_token_lit(token_lit, self.parser.prev_token.span) {
|
||||
Ok(lit) => lit,
|
||||
Err(err) => {
|
||||
let guar =
|
||||
report_lit_error(&self.parser.psess, err, token_lit, uninterpolated_span);
|
||||
// Pack possible quotes and prefixes from the original literal into
|
||||
// the error literal's symbol so they can be pretty-printed faithfully.
|
||||
let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None);
|
||||
let symbol = Symbol::intern(&suffixless_lit.to_string());
|
||||
let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix);
|
||||
MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap()
|
||||
}
|
||||
TokenTree::Token(Token { kind, .. }, _) if kind.is_delim() => None,
|
||||
_ => {
|
||||
// malformed attributes can get here. We can't crash, but somewhere else should've
|
||||
// already warned for this.
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn value(&mut self) -> Option<MetaItemLit> {
|
||||
match self.inside_delimiters.next() {
|
||||
Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
|
||||
MetaItemListParserContext {
|
||||
inside_delimiters: inner_tokens.iter().peekable(),
|
||||
dcx: self.dcx,
|
||||
}
|
||||
.value()
|
||||
}
|
||||
Some(TokenTree::Token(token, _)) => MetaItemLit::from_token(token),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// parses one element on the inside of a list attribute like `#[my_attr( <insides> )]`
|
||||
///
|
||||
/// parses a path followed be either:
|
||||
/// 1. nothing (a word attr)
|
||||
/// 2. a parenthesized list
|
||||
/// 3. an equals sign and a literal (name-value)
|
||||
///
|
||||
/// Can also parse *just* a literal. This is for cases like as `#[my_attr("literal")]`
|
||||
/// where no path is given before the literal
|
||||
///
|
||||
/// Some exceptions too for interpolated attributes which are already pre-processed
|
||||
fn next(&mut self) -> Option<MetaItemOrLitParser<'a>> {
|
||||
// a list element is either a literal
|
||||
if let Some(TokenTree::Token(token, _)) = self.inside_delimiters.peek()
|
||||
&& let Some(lit) = MetaItemLit::from_token(token)
|
||||
{
|
||||
self.inside_delimiters.next();
|
||||
return Some(MetaItemOrLitParser::Lit(lit));
|
||||
} else if let Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) =
|
||||
self.inside_delimiters.peek()
|
||||
{
|
||||
self.inside_delimiters.next();
|
||||
return MetaItemListParserContext {
|
||||
inside_delimiters: inner_tokens.iter().peekable(),
|
||||
dcx: self.dcx,
|
||||
}
|
||||
.next();
|
||||
if self.should_emit.should_emit() && !lit.kind.is_unsuffixed() {
|
||||
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
|
||||
self.parser.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span });
|
||||
}
|
||||
|
||||
// or a path.
|
||||
let path = self.next_path()?;
|
||||
|
||||
// Paths can be followed by:
|
||||
// - `(more meta items)` (another list)
|
||||
// - `= lit` (a name-value)
|
||||
// - nothing
|
||||
Some(MetaItemOrLitParser::MetaItemParser(match self.inside_delimiters.peek() {
|
||||
Some(TokenTree::Delimited(dspan, _, Delimiter::Parenthesis, inner_tokens)) => {
|
||||
self.inside_delimiters.next();
|
||||
|
||||
MetaItemParser {
|
||||
path: PathParser::Attr(path),
|
||||
args: ArgParser::List(MetaItemListParser::new_tts(
|
||||
inner_tokens.iter(),
|
||||
dspan.entire(),
|
||||
self.dcx,
|
||||
)),
|
||||
}
|
||||
}
|
||||
Some(TokenTree::Delimited(_, ..)) => {
|
||||
self.inside_delimiters.next();
|
||||
// self.dcx.span_delayed_bug(span.entire(), "wrong delimiters");
|
||||
return None;
|
||||
}
|
||||
Some(TokenTree::Token(Token { kind: token::Eq, span }, _)) => {
|
||||
self.inside_delimiters.next();
|
||||
let value = self.value()?;
|
||||
MetaItemParser {
|
||||
path: PathParser::Attr(path),
|
||||
args: ArgParser::NameValue(NameValueParser {
|
||||
eq_span: *span,
|
||||
value_span: value.span,
|
||||
value,
|
||||
}),
|
||||
}
|
||||
}
|
||||
_ => MetaItemParser { path: PathParser::Attr(path), args: ArgParser::NoArgs },
|
||||
}))
|
||||
Ok(lit)
|
||||
}
|
||||
|
||||
fn parse(mut self, span: Span) -> MetaItemListParser<'a> {
|
||||
let mut sub_parsers = Vec::new();
|
||||
|
||||
while !self.done() {
|
||||
let Some(n) = self.next() else {
|
||||
continue;
|
||||
fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser<'static>> {
|
||||
if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() {
|
||||
return if has_meta_form {
|
||||
let attr_item = self
|
||||
.parser
|
||||
.eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
|
||||
MetaItemListParserContext { parser: this, should_emit: self.should_emit }
|
||||
.parse_attr_item()
|
||||
})
|
||||
.unwrap();
|
||||
Ok(attr_item)
|
||||
} else {
|
||||
self.parser.unexpected_any()
|
||||
};
|
||||
sub_parsers.push(n);
|
||||
}
|
||||
|
||||
match self.inside_delimiters.peek() {
|
||||
None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {
|
||||
self.inside_delimiters.next();
|
||||
}
|
||||
Some(_) => {}
|
||||
let path = self.parser.parse_path(PathStyle::Mod)?;
|
||||
|
||||
// Check style of arguments that this meta item has
|
||||
let args = if self.parser.check(exp!(OpenParen)) {
|
||||
let start = self.parser.token.span;
|
||||
let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| {
|
||||
MetaItemListParserContext { parser, should_emit: self.should_emit }
|
||||
.parse_meta_item_inner()
|
||||
})?;
|
||||
let end = self.parser.prev_token.span;
|
||||
ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) })
|
||||
} else if self.parser.eat(exp!(Eq)) {
|
||||
let eq_span = self.parser.prev_token.span;
|
||||
let value = self.parse_unsuffixed_meta_item_lit()?;
|
||||
|
||||
ArgParser::NameValue(NameValueParser { eq_span, value, value_span: value.span })
|
||||
} else {
|
||||
ArgParser::NoArgs
|
||||
};
|
||||
|
||||
Ok(MetaItemParser { path: PathParser(Cow::Owned(path)), args })
|
||||
}
|
||||
|
||||
fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser<'static>> {
|
||||
match self.parse_unsuffixed_meta_item_lit() {
|
||||
Ok(lit) => return Ok(MetaItemOrLitParser::Lit(lit)),
|
||||
Err(err) => err.cancel(), // we provide a better error below
|
||||
}
|
||||
|
||||
match self.parse_attr_item() {
|
||||
Ok(mi) => return Ok(MetaItemOrLitParser::MetaItemParser(mi)),
|
||||
Err(err) => err.cancel(), // we provide a better error below
|
||||
}
|
||||
|
||||
let mut err = InvalidMetaItem {
|
||||
span: self.parser.token.span,
|
||||
descr: token_descr(&self.parser.token),
|
||||
quote_ident_sugg: None,
|
||||
remove_neg_sugg: None,
|
||||
};
|
||||
|
||||
// Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
|
||||
// don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
|
||||
// when macro metavariables are involved.
|
||||
if self.parser.prev_token == token::Eq
|
||||
&& let token::Ident(..) = self.parser.token.kind
|
||||
{
|
||||
let before = self.parser.token.span.shrink_to_lo();
|
||||
while let token::Ident(..) = self.parser.token.kind {
|
||||
self.parser.bump();
|
||||
}
|
||||
err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
|
||||
before,
|
||||
after: self.parser.prev_token.span.shrink_to_hi(),
|
||||
});
|
||||
}
|
||||
|
||||
if self.parser.token == token::Minus
|
||||
&& self
|
||||
.parser
|
||||
.look_ahead(1, |t| matches!(t.kind, rustc_ast::token::TokenKind::Literal { .. }))
|
||||
{
|
||||
err.remove_neg_sugg =
|
||||
Some(InvalidMetaItemRemoveNegSugg { negative_sign: self.parser.token.span });
|
||||
self.parser.bump();
|
||||
self.parser.bump();
|
||||
}
|
||||
|
||||
Err(self.parser.dcx().create_err(err))
|
||||
}
|
||||
|
||||
fn parse(
|
||||
tokens: TokenStream,
|
||||
psess: &'sess ParseSess,
|
||||
span: Span,
|
||||
should_emit: ShouldEmit,
|
||||
) -> PResult<'sess, MetaItemListParser<'static>> {
|
||||
let mut parser = Parser::new(psess, tokens, None);
|
||||
let mut this = MetaItemListParserContext { parser: &mut parser, should_emit };
|
||||
|
||||
// Presumably, the majority of the time there will only be one attr.
|
||||
let mut sub_parsers = ThinVec::with_capacity(1);
|
||||
while this.parser.token != token::Eof {
|
||||
sub_parsers.push(this.parse_meta_item_inner()?);
|
||||
|
||||
if !this.parser.eat(exp!(Comma)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MetaItemListParser { sub_parsers, span }
|
||||
if parser.token != token::Eof {
|
||||
parser.unexpected()?;
|
||||
}
|
||||
|
||||
Ok(MetaItemListParser { sub_parsers, span })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MetaItemListParser<'a> {
|
||||
sub_parsers: Vec<MetaItemOrLitParser<'a>>,
|
||||
sub_parsers: ThinVec<MetaItemOrLitParser<'a>>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'a> MetaItemListParser<'a> {
|
||||
fn new<'sess>(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx)
|
||||
}
|
||||
|
||||
fn new_tts<'sess>(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span)
|
||||
fn new<'sess>(
|
||||
delim: &'a DelimArgs,
|
||||
psess: &'sess ParseSess,
|
||||
should_emit: ShouldEmit,
|
||||
) -> Option<Self> {
|
||||
match MetaItemListParserContext::parse(
|
||||
delim.tokens.clone(),
|
||||
psess,
|
||||
delim.dspan.entire(),
|
||||
should_emit,
|
||||
) {
|
||||
Ok(s) => Some(s),
|
||||
Err(e) => {
|
||||
e.emit_unless_delay(!should_emit.should_emit());
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lets you pick and choose as what you want to parse each element in the list
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::num::IntErrorKind;
|
||||
|
||||
use rustc_ast::{self as ast, AttrStyle};
|
||||
use rustc_ast::{self as ast, AttrStyle, Path};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
|
||||
|
|
@ -737,3 +737,92 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
|
|||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_attr_unsafe)]
|
||||
#[note]
|
||||
pub(crate) struct InvalidAttrUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub name: Path,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_unsafe_attr_outside_unsafe)]
|
||||
pub(crate) struct UnsafeAttrOutsideUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: UnsafeAttrOutsideUnsafeSuggestion,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
attr_parsing_unsafe_attr_outside_unsafe_suggestion,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
|
||||
#[suggestion_part(code = "unsafe(")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_meta_bad_delim)]
|
||||
pub(crate) struct MetaBadDelim {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: MetaBadDelimSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
attr_parsing_meta_bad_delim_suggestion,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct MetaBadDelimSugg {
|
||||
#[suggestion_part(code = "(")]
|
||||
pub open: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub close: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_meta_item)]
|
||||
pub(crate) struct InvalidMetaItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub descr: String,
|
||||
#[subdiagnostic]
|
||||
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
|
||||
#[subdiagnostic]
|
||||
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(attr_parsing_quote_ident_sugg, applicability = "machine-applicable")]
|
||||
pub(crate) struct InvalidMetaItemQuoteIdentSugg {
|
||||
#[suggestion_part(code = "\"")]
|
||||
pub before: Span,
|
||||
#[suggestion_part(code = "\"")]
|
||||
pub after: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(attr_parsing_remove_neg_sugg, applicability = "machine-applicable")]
|
||||
pub(crate) struct InvalidMetaItemRemoveNegSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub negative_sign: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_suffixed_literal_in_attribute)]
|
||||
#[help]
|
||||
pub(crate) struct SuffixedLiteralInAttribute {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,16 +8,16 @@ use rustc_ast::{
|
|||
self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId,
|
||||
Path, Safety,
|
||||
};
|
||||
use rustc_attr_parsing::{AttributeParser, Late};
|
||||
use rustc_errors::{Applicability, DiagCtxtHandle, FatalError, PResult};
|
||||
use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
|
||||
use rustc_parse::parse_in;
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::{errors, parse_in};
|
||||
use crate::{AttributeParser, Late, session_diagnostics as errors};
|
||||
|
||||
pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
|
||||
if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace)
|
||||
|
|
@ -33,7 +33,10 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
|
|||
// Check input tokens for built-in and key-value attributes.
|
||||
match builtin_attr_info {
|
||||
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
|
||||
Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
|
||||
Some(BuiltinAttribute { name, template, .. }) => {
|
||||
if AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(&name)) {
|
||||
return;
|
||||
}
|
||||
match parse_meta(psess, attr) {
|
||||
// Don't check safety again, we just did that
|
||||
Ok(meta) => {
|
||||
|
|
@ -133,16 +136,6 @@ fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) {
|
|||
});
|
||||
}
|
||||
|
||||
pub(super) fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) {
|
||||
if let Delimiter::Parenthesis = delim {
|
||||
return;
|
||||
}
|
||||
psess.dcx().emit_err(errors::CfgAttrBadDelim {
|
||||
span: span.entire(),
|
||||
sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close },
|
||||
});
|
||||
}
|
||||
|
||||
/// Checks that the given meta-item is compatible with this `AttributeTemplate`.
|
||||
fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool {
|
||||
let is_one_allowed_subword = |items: &[MetaItemInner]| match items {
|
||||
|
|
@ -269,9 +262,6 @@ pub fn check_builtin_meta_item(
|
|||
) {
|
||||
if !is_attr_template_compatible(&template, &meta.kind) {
|
||||
// attrs with new parsers are locally validated so excluded here
|
||||
if AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(&name)) {
|
||||
return;
|
||||
}
|
||||
emit_malformed_attribute(psess, style, meta.span, name, template);
|
||||
}
|
||||
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
//! Implementation of the `#[cfg_accessible(path)]` attribute macro.
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_span::{Span, sym};
|
||||
|
||||
use crate::errors;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::{GenericParamKind, ItemKind, MetaItemInner, MetaItemKind, StmtKind};
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_expand::base::{
|
||||
Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier,
|
||||
};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, sym};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{self as ast, AttrStyle, Attribute, MetaItem, attr, token};
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
|
||||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt};
|
||||
use rustc_expand::expand::AstFragment;
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
|
||||
use rustc_parse::{exp, parser, validate_attr};
|
||||
use rustc_parse::{exp, parser};
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@ use rustc_ast::{
|
|||
NodeId, NormalAttr,
|
||||
};
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::validate_attr::deny_builtin_meta_unsafety;
|
||||
use rustc_attr_parsing::{
|
||||
AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg_attr,
|
||||
validate_attr,
|
||||
};
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_feature::{
|
||||
|
|
@ -20,8 +22,6 @@ use rustc_feature::{
|
|||
REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES,
|
||||
};
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_parse::validate_attr::deny_builtin_meta_unsafety;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym};
|
||||
|
|
@ -415,16 +415,6 @@ impl<'a> StripUnconfigured<'a> {
|
|||
node: NodeId,
|
||||
emit_errors: ShouldEmit,
|
||||
) -> EvalConfigResult {
|
||||
// We need to run this to do basic validation of the attribute, such as that lits are valid, etc
|
||||
// FIXME(jdonszelmann) this should not be necessary in the future
|
||||
match validate_attr::parse_meta(&self.sess.psess, attr) {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
return EvalConfigResult::True;
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafety check needs to be done explicitly here because this attribute will be removed before the normal check
|
||||
deny_builtin_meta_unsafety(
|
||||
self.sess.dcx(),
|
||||
|
|
|
|||
|
|
@ -1,28 +1,28 @@
|
|||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::{iter, mem};
|
||||
use std::{iter, mem, slice};
|
||||
|
||||
use rustc_ast::mut_visit::*;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list};
|
||||
use rustc_ast::{
|
||||
self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, DUMMY_NODE_ID,
|
||||
ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner,
|
||||
MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token,
|
||||
self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, CRATE_NODE_ID,
|
||||
DUMMY_NODE_ID, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle,
|
||||
MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr_parsing::{EvalConfigResult, ShouldEmit};
|
||||
use rustc_attr_parsing::{AttributeParser, EvalConfigResult, ShouldEmit, validate_attr};
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir::Target;
|
||||
use rustc_hir::def::MacroKinds;
|
||||
use rustc_parse::parser::{
|
||||
AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
|
||||
token_descr,
|
||||
};
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
|
||||
use rustc_session::parse::feature_err;
|
||||
|
|
@ -2159,6 +2159,16 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
attr,
|
||||
self.cx.current_expansion.lint_node_id,
|
||||
);
|
||||
AttributeParser::parse_limited_all(
|
||||
self.cx.sess,
|
||||
slice::from_ref(attr),
|
||||
None,
|
||||
Target::MacroCall,
|
||||
call.span(),
|
||||
CRATE_NODE_ID,
|
||||
Some(self.cx.ecfg.features),
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
);
|
||||
|
||||
let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
|
||||
span = Some(current_span);
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ use std::iter::once;
|
|||
use std::path::{self, Path, PathBuf};
|
||||
|
||||
use rustc_ast::{AttrVec, Attribute, Inline, Item, ModSpans};
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_errors::{Diag, ErrorGuaranteed};
|
||||
use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal, validate_attr};
|
||||
use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use std::sync::{Arc, LazyLock, OnceLock};
|
|||
use std::{env, fs, iter};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
|
|
@ -25,9 +26,7 @@ use rustc_middle::arena::Arena;
|
|||
use rustc_middle::dep_graph::DepsType;
|
||||
use rustc_middle::ty::{self, CurrentGcx, GlobalCtxt, RegisteredTools, TyCtxt};
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_parse::{
|
||||
new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr,
|
||||
};
|
||||
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||
use rustc_passes::{abi_test, input_stats, layout_test};
|
||||
use rustc_resolve::{Resolver, ResolverOutputs};
|
||||
use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ use std::sync::{Arc, OnceLock};
|
|||
use std::{env, thread};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_metadata::{DylibError, load_symbol_from_dylib};
|
||||
use rustc_middle::ty::CurrentGcx;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple};
|
||||
use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
|
||||
use rustc_session::output::{CRATE_TYPES, categorize_crate_type};
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ bitflags = "2.4.1"
|
|||
rustc-literal-escaper = "0.0.5"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
|
|
|
|||
|
|
@ -436,11 +436,6 @@ parse_inner_doc_comment_not_permitted = expected outer doc comment
|
|||
.label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item}
|
||||
.sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style
|
||||
|
||||
parse_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
|
||||
.label = this is not an unsafe attribute
|
||||
.suggestion = remove the `unsafe(...)`
|
||||
.note = extraneous unsafe is not allowed in attributes
|
||||
|
||||
parse_invalid_block_macro_segment = cannot use a `block` macro fragment here
|
||||
.label = the `block` fragment is within this context
|
||||
.suggestion = wrap this in another block
|
||||
|
|
@ -601,7 +596,6 @@ parse_maybe_report_ambiguous_plus =
|
|||
ambiguous `+` in a type
|
||||
.suggestion = use parentheses to disambiguate
|
||||
|
||||
parse_meta_bad_delim = wrong meta list delimiters
|
||||
parse_meta_bad_delim_suggestion = the delimiters should be `(` and `)`
|
||||
|
||||
parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}`
|
||||
|
|
@ -990,10 +984,6 @@ parse_unmatched_angle_brackets = {$num_extra_brackets ->
|
|||
*[other] remove extra angle brackets
|
||||
}
|
||||
|
||||
parse_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
|
||||
.label = usage of unsafe attribute
|
||||
parse_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
|
||||
|
||||
|
||||
parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped
|
||||
.label = {parse_unskipped_whitespace}
|
||||
|
|
|
|||
|
|
@ -3345,15 +3345,6 @@ pub(crate) struct KwBadCase<'a> {
|
|||
pub kw: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_meta_bad_delim)]
|
||||
pub(crate) struct MetaBadDelim {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: MetaBadDelimSugg,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_cfg_attr_bad_delim)]
|
||||
pub(crate) struct CfgAttrBadDelim {
|
||||
|
|
@ -3493,38 +3484,6 @@ pub(crate) struct DotDotRangeAttribute {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_invalid_attr_unsafe)]
|
||||
#[note]
|
||||
pub(crate) struct InvalidAttrUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub name: Path,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_unsafe_attr_outside_unsafe)]
|
||||
pub(crate) struct UnsafeAttrOutsideUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: UnsafeAttrOutsideUnsafeSuggestion,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
parse_unsafe_attr_outside_unsafe_suggestion,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
|
||||
#[suggestion_part(code = "unsafe(")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_binder_before_modifiers)]
|
||||
pub(crate) struct BinderBeforeModifiers {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use std::str::Utf8Error;
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::{AttrItem, Attribute, MetaItemInner, token};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize};
|
||||
|
|
@ -31,8 +31,9 @@ pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments");
|
|||
#[macro_use]
|
||||
pub mod parser;
|
||||
use parser::Parser;
|
||||
use rustc_ast::token::Delimiter;
|
||||
|
||||
pub mod lexer;
|
||||
pub mod validate_attr;
|
||||
|
||||
mod errors;
|
||||
|
||||
|
|
@ -235,7 +236,7 @@ pub fn parse_cfg_attr(
|
|||
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
|
||||
if !tokens.is_empty() =>
|
||||
{
|
||||
crate::validate_attr::check_cfg_attr_bad_delim(psess, dspan, delim);
|
||||
check_cfg_attr_bad_delim(psess, dspan, delim);
|
||||
match parse_in(psess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
|
||||
Ok(r) => return Some(r),
|
||||
Err(e) => {
|
||||
|
|
@ -254,3 +255,13 @@ pub fn parse_cfg_attr(
|
|||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) {
|
||||
if let Delimiter::Parenthesis = delim {
|
||||
return;
|
||||
}
|
||||
psess.dcx().emit_err(errors::CfgAttrBadDelim {
|
||||
span: span.entire(),
|
||||
sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close },
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
/// Matches `COMMASEP(meta_item_inner)`.
|
||||
pub(crate) fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec<ast::MetaItemInner>> {
|
||||
pub fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec<ast::MetaItemInner>> {
|
||||
// Presumably, the majority of the time there will only be one attr.
|
||||
let mut nmis = ThinVec::with_capacity(1);
|
||||
while self.token != token::Eof {
|
||||
|
|
|
|||
|
|
@ -2077,7 +2077,7 @@ impl<'a> Parser<'a> {
|
|||
(token::Lit { symbol: name, suffix: None, kind: token::Char }, span)
|
||||
}
|
||||
|
||||
fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
|
||||
pub fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
|
||||
ast::MetaItemLit {
|
||||
symbol: name,
|
||||
suffix: None,
|
||||
|
|
@ -2086,7 +2086,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_missing_lit<L>(
|
||||
pub fn handle_missing_lit<L>(
|
||||
&mut self,
|
||||
mk_lit_char: impl FnOnce(Symbol, Span) -> L,
|
||||
) -> PResult<'a, L> {
|
||||
|
|
@ -2156,7 +2156,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Keep this in sync with `Token::can_begin_literal_maybe_minus` and
|
||||
/// `Lit::from_token` (excluding unary negation).
|
||||
fn eat_token_lit(&mut self) -> Option<token::Lit> {
|
||||
pub fn eat_token_lit(&mut self) -> Option<token::Lit> {
|
||||
let check_expr = |expr: Box<Expr>| {
|
||||
if let ast::ExprKind::Lit(token_lit) = expr.kind {
|
||||
Some(token_lit)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ pub use diagnostics::AttemptLocalParseRecovery;
|
|||
pub(crate) use expr::ForbiddenLetReason;
|
||||
pub(crate) use item::{FnContext, FnParseMode};
|
||||
pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
|
||||
use path::PathStyle;
|
||||
pub use path::PathStyle;
|
||||
use rustc_ast::token::{
|
||||
self, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, TokenKind,
|
||||
};
|
||||
|
|
@ -285,7 +285,7 @@ pub enum FollowedByType {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum Trailing {
|
||||
pub enum Trailing {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
|
|
@ -494,7 +494,7 @@ impl<'a> Parser<'a> {
|
|||
/// This method will automatically add `tok` to `expected_token_types` if `tok` is not
|
||||
/// encountered.
|
||||
#[inline]
|
||||
fn check(&mut self, exp: ExpTokenPair<'_>) -> bool {
|
||||
pub fn check(&mut self, exp: ExpTokenPair<'_>) -> bool {
|
||||
let is_present = self.token == *exp.tok;
|
||||
if !is_present {
|
||||
self.expected_token_types.insert(exp.token_type);
|
||||
|
|
@ -633,7 +633,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
/// Consume a sequence produced by a metavar expansion, if present.
|
||||
fn eat_metavar_seq<T>(
|
||||
pub fn eat_metavar_seq<T>(
|
||||
&mut self,
|
||||
mv_kind: MetaVarKind,
|
||||
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
|
|
@ -1094,7 +1094,7 @@ impl<'a> Parser<'a> {
|
|||
/// Parses a comma-separated sequence delimited by parentheses (e.g. `(x, y)`).
|
||||
/// The function `f` must consume tokens until reaching the next separator or
|
||||
/// closing bracket.
|
||||
fn parse_paren_comma_seq<T>(
|
||||
pub fn parse_paren_comma_seq<T>(
|
||||
&mut self,
|
||||
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
) -> PResult<'a, (ThinVec<T>, Trailing)> {
|
||||
|
|
@ -1355,7 +1355,8 @@ impl<'a> Parser<'a> {
|
|||
AttrArgs::Delimited(args)
|
||||
} else if self.eat(exp!(Eq)) {
|
||||
let eq_span = self.prev_token.span;
|
||||
AttrArgs::Eq { eq_span, expr: self.parse_expr_force_collect()? }
|
||||
let expr = self.parse_expr_force_collect()?;
|
||||
AttrArgs::Eq { eq_span, expr }
|
||||
} else {
|
||||
AttrArgs::Empty
|
||||
})
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use crate::parser::{
|
|||
|
||||
/// Specifies how to parse a path.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub(super) enum PathStyle {
|
||||
pub enum PathStyle {
|
||||
/// In some contexts, notably in expressions, paths with generic arguments are ambiguous
|
||||
/// with something else. For example, in expressions `segment < ....` can be interpreted
|
||||
/// as a comparison and `segment ( ....` can be interpreted as a function call.
|
||||
|
|
@ -150,7 +150,7 @@ impl<'a> Parser<'a> {
|
|||
true
|
||||
}
|
||||
|
||||
pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
|
||||
pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> {
|
||||
self.parse_path_inner(style, None)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ check!(reg_f32, f32, freg, "mov.s");
|
|||
// CHECK: #APP
|
||||
// CHECK: mov.s $f0, $f0
|
||||
// CHECK: #NO_APP
|
||||
#[no_mangle]
|
||||
check_reg!(f0_f32, f32, "$f0", "mov.s");
|
||||
|
||||
// CHECK-LABEL: reg_f32_64:
|
||||
|
|
@ -107,21 +106,18 @@ check!(reg_f32_64, f32, freg, "mov.d");
|
|||
// CHECK: #APP
|
||||
// CHECK: mov.d $f0, $f0
|
||||
// CHECK: #NO_APP
|
||||
#[no_mangle]
|
||||
check_reg!(f0_f32_64, f32, "$f0", "mov.d");
|
||||
|
||||
// CHECK-LABEL: reg_f64:
|
||||
// CHECK: #APP
|
||||
// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}}
|
||||
// CHECK: #NO_APP
|
||||
#[no_mangle]
|
||||
check!(reg_f64, f64, freg, "mov.d");
|
||||
|
||||
// CHECK-LABEL: f0_f64:
|
||||
// CHECK: #APP
|
||||
// CHECK: mov.d $f0, $f0
|
||||
// CHECK: #NO_APP
|
||||
#[no_mangle]
|
||||
check_reg!(f0_f64, f64, "$f0", "mov.d");
|
||||
|
||||
// CHECK-LABEL: reg_ptr:
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
error: attribute value must be a literal
|
||||
--> $DIR/key-value-expansion.rs:21:6
|
||||
|
|
||||
LL | bug!((column!()));
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: attribute value must be a literal
|
||||
--> $DIR/key-value-expansion.rs:27:14
|
||||
|
|
||||
|
|
@ -26,5 +20,11 @@ LL | some_macro!(u8);
|
|||
|
|
||||
= note: this error originates in the macro `some_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: attribute value must be a literal
|
||||
--> $DIR/key-value-expansion.rs:21:6
|
||||
|
|
||||
LL | bug!((column!()));
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ fn f3() {}
|
|||
#[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on functions
|
||||
fn f4() {}
|
||||
|
||||
#[rustc_align(-1)] //~ ERROR expected unsuffixed literal, found `-`
|
||||
#[rustc_align(-1)] //~ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-`
|
||||
fn f5() {}
|
||||
|
||||
#[rustc_align(3)] //~ ERROR invalid alignment value: not a power of two
|
||||
|
|
|
|||
|
|
@ -1,17 +1,3 @@
|
|||
error: expected unsuffixed literal, found `-`
|
||||
--> $DIR/malformed-fn-align.rs:29:15
|
||||
|
|
||||
LL | #[rustc_align(-1)]
|
||||
| ^
|
||||
|
||||
error: suffixed literals are not allowed in attributes
|
||||
--> $DIR/malformed-fn-align.rs:35:15
|
||||
|
|
||||
LL | #[rustc_align(4usize)]
|
||||
| ^^^^^^
|
||||
|
|
||||
= help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
|
||||
|
||||
error[E0539]: malformed `rustc_align` attribute input
|
||||
--> $DIR/malformed-fn-align.rs:10:5
|
||||
|
|
||||
|
|
@ -51,12 +37,32 @@ error[E0589]: invalid alignment value: not a power of two
|
|||
LL | #[rustc_align(0)]
|
||||
| ^
|
||||
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-`
|
||||
--> $DIR/malformed-fn-align.rs:29:15
|
||||
|
|
||||
LL | #[rustc_align(-1)]
|
||||
| ^
|
||||
|
|
||||
help: negative numbers are not literals, try removing the `-` sign
|
||||
|
|
||||
LL - #[rustc_align(-1)]
|
||||
LL + #[rustc_align(1)]
|
||||
|
|
||||
|
||||
error[E0589]: invalid alignment value: not a power of two
|
||||
--> $DIR/malformed-fn-align.rs:32:15
|
||||
|
|
||||
LL | #[rustc_align(3)]
|
||||
| ^
|
||||
|
||||
error: suffixed literals are not allowed in attributes
|
||||
--> $DIR/malformed-fn-align.rs:35:15
|
||||
|
|
||||
LL | #[rustc_align(4usize)]
|
||||
| ^^^^^^
|
||||
|
|
||||
= help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
|
||||
|
||||
error[E0589]: invalid alignment value: not an unsuffixed integer
|
||||
--> $DIR/malformed-fn-align.rs:35:15
|
||||
|
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
macro_rules! pass_nonterminal {
|
||||
($n:expr) => {
|
||||
#[repr(align($n))]
|
||||
//~^ ERROR expected unsuffixed literal, found `expr` metavariable
|
||||
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable
|
||||
struct S;
|
||||
};
|
||||
}
|
||||
|
|
@ -15,6 +15,5 @@ macro_rules! n {
|
|||
}
|
||||
|
||||
pass_nonterminal!(n!());
|
||||
//~^ ERROR incorrect `repr(align)` attribute format: `align` expects a literal integer as argument [E0693]
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
error: expected unsuffixed literal, found `expr` metavariable
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable
|
||||
--> $DIR/nonterminal-expansion.rs:7:22
|
||||
|
|
||||
LL | #[repr(align($n))]
|
||||
|
|
@ -9,12 +9,5 @@ LL | pass_nonterminal!(n!());
|
|||
|
|
||||
= note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0693]: incorrect `repr(align)` attribute format: `align` expects a literal integer as argument
|
||||
--> $DIR/nonterminal-expansion.rs:17:19
|
||||
|
|
||||
LL | pass_nonterminal!(n!());
|
||||
| ^
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0693`.
|
||||
|
|
|
|||
|
|
@ -28,17 +28,6 @@ LL | #[unsafe(proc_macro_derive(Foo))]
|
|||
|
|
||||
= note: extraneous unsafe is not allowed in attributes
|
||||
|
||||
error: expected identifier, found keyword `unsafe`
|
||||
--> $DIR/proc-unsafe-attributes.rs:12:21
|
||||
|
|
||||
LL | #[proc_macro_derive(unsafe(Foo))]
|
||||
| ^^^^^^ expected identifier, found keyword
|
||||
|
|
||||
help: escape `unsafe` to use it as an identifier
|
||||
|
|
||||
LL | #[proc_macro_derive(r#unsafe(Foo))]
|
||||
| ++
|
||||
|
||||
error: `proc_macro_attribute` is not an unsafe attribute
|
||||
--> $DIR/proc-unsafe-attributes.rs:18:3
|
||||
|
|
||||
|
|
@ -114,6 +103,17 @@ LL | #[unsafe(allow(unsafe(dead_code)))]
|
|||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: expected identifier, found keyword `unsafe`
|
||||
--> $DIR/proc-unsafe-attributes.rs:12:21
|
||||
|
|
||||
LL | #[proc_macro_derive(unsafe(Foo))]
|
||||
| ^^^^^^ expected identifier, found keyword
|
||||
|
|
||||
help: escape `unsafe` to use it as an identifier
|
||||
|
|
||||
LL | #[proc_macro_derive(r#unsafe(Foo))]
|
||||
| ++
|
||||
|
||||
error[E0565]: malformed `proc_macro_derive` attribute input
|
||||
--> $DIR/proc-unsafe-attributes.rs:12:1
|
||||
|
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ struct S9;
|
|||
macro_rules! generate_s10 {
|
||||
($expr: expr) => {
|
||||
#[cfg(feature = $expr)]
|
||||
//~^ ERROR expected unsuffixed literal, found `expr` metavariable
|
||||
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable
|
||||
struct S10;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ LL | #[cfg(a = b"hi")]
|
|||
|
|
||||
= note: expected a normal string literal, not a byte string literal
|
||||
|
||||
error: expected unsuffixed literal, found `expr` metavariable
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable
|
||||
--> $DIR/cfg-attr-syntax-validation.rs:45:25
|
||||
|
|
||||
LL | #[cfg(feature = $expr)]
|
||||
|
|
|
|||
|
|
@ -1,15 +1,3 @@
|
|||
error: expected identifier, found `,`
|
||||
--> $DIR/bad-syntax.rs:44:12
|
||||
|
|
||||
LL | #[coverage(,off)]
|
||||
| ^ expected identifier
|
||||
|
|
||||
help: remove this comma
|
||||
|
|
||||
LL - #[coverage(,off)]
|
||||
LL + #[coverage(off)]
|
||||
|
|
||||
|
||||
error: multiple `coverage` attributes
|
||||
--> $DIR/bad-syntax.rs:9:1
|
||||
|
|
||||
|
|
@ -162,6 +150,18 @@ LL - #[coverage(off, bogus)]
|
|||
LL + #[coverage(on)]
|
||||
|
|
||||
|
||||
error: expected identifier, found `,`
|
||||
--> $DIR/bad-syntax.rs:44:12
|
||||
|
|
||||
LL | #[coverage(,off)]
|
||||
| ^ expected identifier
|
||||
|
|
||||
help: remove this comma
|
||||
|
|
||||
LL - #[coverage(,off)]
|
||||
LL + #[coverage(off)]
|
||||
|
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0539, E0805.
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
// was a well-formed `MetaItem`.
|
||||
|
||||
fn main() {
|
||||
foo() //~ WARNING use of deprecated function `foo`
|
||||
foo()
|
||||
}
|
||||
|
||||
#[deprecated(note = test)]
|
||||
//~^ ERROR expected unsuffixed literal, found `test`
|
||||
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `test`
|
||||
fn foo() {}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
error: expected unsuffixed literal, found `test`
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `test`
|
||||
--> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:9:21
|
||||
|
|
||||
LL | #[deprecated(note = test)]
|
||||
|
|
@ -9,13 +9,5 @@ help: surround the identifier with quotation marks to make it into a string lite
|
|||
LL | #[deprecated(note = "test")]
|
||||
| + +
|
||||
|
||||
warning: use of deprecated function `foo`
|
||||
--> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:6:5
|
||||
|
|
||||
LL | foo()
|
||||
| ^^^
|
||||
|
|
||||
= note: `#[warn(deprecated)]` on by default
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ macro_rules! bar (
|
|||
|
||||
macro_rules! foo (
|
||||
() => (
|
||||
#[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps
|
||||
#[allow_internal_unstable()]
|
||||
//~^ ERROR allow_internal_unstable side-steps
|
||||
//~| ERROR `#[allow_internal_unstable]` attribute cannot be used on macro calls
|
||||
bar!();
|
||||
);
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error[E0658]: allow_internal_unstable side-steps feature gating and stability checks
|
||||
--> $DIR/issue-32782.rs:7:9
|
||||
|
|
||||
LL | #[allow_internal_unstable]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[allow_internal_unstable()]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | foo!();
|
||||
| ------ in this macro invocation
|
||||
|
|
@ -11,6 +11,18 @@ LL | foo!();
|
|||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: `#[allow_internal_unstable]` attribute cannot be used on macro calls
|
||||
--> $DIR/issue-32782.rs:7:9
|
||||
|
|
||||
LL | #[allow_internal_unstable()]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | foo!();
|
||||
| ------ in this macro invocation
|
||||
|
|
||||
= help: `#[allow_internal_unstable]` can be applied to macro defs and functions
|
||||
= note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//@ check-pass
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![warn(unused)]
|
||||
|
||||
macro_rules! foo {
|
||||
|
|
@ -7,16 +8,16 @@ macro_rules! foo {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
#[inline] foo!(); //~ WARN unused attribute `inline`
|
||||
#[rustc_dummy] foo!(); //~ WARN unused attribute `rustc_dummy`
|
||||
|
||||
// This does nothing, since `#[allow(warnings)]` is itself
|
||||
// an inert attribute on a macro call
|
||||
#[allow(warnings)] #[inline] foo!(); //~ WARN unused attribute `allow`
|
||||
//~^ WARN unused attribute `inline`
|
||||
#[allow(warnings)] #[rustc_dummy] foo!(); //~ WARN unused attribute `allow`
|
||||
//~^ WARN unused attribute `rustc_dummy`
|
||||
|
||||
// This does work, since the attribute is on a parent
|
||||
// of the macro invocation.
|
||||
#[allow(warnings)] { #[inline] foo!(); }
|
||||
#[allow(warnings)] { #[rustc_dummy] foo!(); }
|
||||
|
||||
// Ok, `cfg` and `cfg_attr` are expanded eagerly and do not warn.
|
||||
#[cfg(true)] foo!();
|
||||
|
|
|
|||
|
|
@ -1,44 +1,44 @@
|
|||
warning: unused attribute `inline`
|
||||
--> $DIR/inert-attr-macro.rs:10:5
|
||||
warning: unused attribute `rustc_dummy`
|
||||
--> $DIR/inert-attr-macro.rs:11:5
|
||||
|
|
||||
LL | #[inline] foo!();
|
||||
| ^^^^^^^^^
|
||||
LL | #[rustc_dummy] foo!();
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo`
|
||||
--> $DIR/inert-attr-macro.rs:10:15
|
||||
note: the built-in attribute `rustc_dummy` will be ignored, since it's applied to the macro invocation `foo`
|
||||
--> $DIR/inert-attr-macro.rs:11:20
|
||||
|
|
||||
LL | #[inline] foo!();
|
||||
| ^^^
|
||||
LL | #[rustc_dummy] foo!();
|
||||
| ^^^
|
||||
note: the lint level is defined here
|
||||
--> $DIR/inert-attr-macro.rs:3:9
|
||||
--> $DIR/inert-attr-macro.rs:4:9
|
||||
|
|
||||
LL | #![warn(unused)]
|
||||
| ^^^^^^
|
||||
= note: `#[warn(unused_attributes)]` implied by `#[warn(unused)]`
|
||||
|
||||
warning: unused attribute `allow`
|
||||
--> $DIR/inert-attr-macro.rs:14:5
|
||||
--> $DIR/inert-attr-macro.rs:15:5
|
||||
|
|
||||
LL | #[allow(warnings)] #[inline] foo!();
|
||||
LL | #[allow(warnings)] #[rustc_dummy] foo!();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo`
|
||||
--> $DIR/inert-attr-macro.rs:14:34
|
||||
--> $DIR/inert-attr-macro.rs:15:39
|
||||
|
|
||||
LL | #[allow(warnings)] #[inline] foo!();
|
||||
| ^^^
|
||||
LL | #[allow(warnings)] #[rustc_dummy] foo!();
|
||||
| ^^^
|
||||
|
||||
warning: unused attribute `inline`
|
||||
--> $DIR/inert-attr-macro.rs:14:24
|
||||
warning: unused attribute `rustc_dummy`
|
||||
--> $DIR/inert-attr-macro.rs:15:24
|
||||
|
|
||||
LL | #[allow(warnings)] #[inline] foo!();
|
||||
| ^^^^^^^^^
|
||||
LL | #[allow(warnings)] #[rustc_dummy] foo!();
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo`
|
||||
--> $DIR/inert-attr-macro.rs:14:34
|
||||
note: the built-in attribute `rustc_dummy` will be ignored, since it's applied to the macro invocation `foo`
|
||||
--> $DIR/inert-attr-macro.rs:15:39
|
||||
|
|
||||
LL | #[allow(warnings)] #[inline] foo!();
|
||||
| ^^^
|
||||
LL | #[allow(warnings)] #[rustc_dummy] foo!();
|
||||
| ^^^
|
||||
|
||||
warning: 3 warnings emitted
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
macro_rules! mac {
|
||||
($attr_item: meta) => {
|
||||
#[cfg($attr_item)]
|
||||
//~^ ERROR expected unsuffixed literal, found `meta` metavariable
|
||||
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `meta` metavariable
|
||||
struct S;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ macro_rules! mac {
|
|||
mac!(an(arbitrary token stream));
|
||||
|
||||
#[cfg(feature = -1)]
|
||||
//~^ ERROR expected unsuffixed literal, found `-`
|
||||
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-`
|
||||
fn handler() {}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
error: expected unsuffixed literal, found `-`
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-`
|
||||
--> $DIR/attr-bad-meta-4.rs:11:17
|
||||
|
|
||||
LL | #[cfg(feature = -1)]
|
||||
| ^
|
||||
|
|
||||
help: negative numbers are not literals, try removing the `-` sign
|
||||
|
|
||||
LL - #[cfg(feature = -1)]
|
||||
LL + #[cfg(feature = 1)]
|
||||
|
|
||||
|
||||
error: expected unsuffixed literal, found `meta` metavariable
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `meta` metavariable
|
||||
--> $DIR/attr-bad-meta-4.rs:3:15
|
||||
|
|
||||
LL | #[cfg($attr_item)]
|
||||
|
|
|
|||
17
tests/ui/parser/attribute/attr-incomplete.rs
Normal file
17
tests/ui/parser/attribute/attr-incomplete.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#[cfg(target-os = "windows")]
|
||||
//~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-`
|
||||
pub fn test1() { }
|
||||
|
||||
#[cfg(target_os = %)]
|
||||
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `%`
|
||||
pub fn test2() { }
|
||||
|
||||
#[cfg(target_os?)]
|
||||
//~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `?`
|
||||
pub fn test3() { }
|
||||
|
||||
#[cfg[target_os]]
|
||||
//~^ ERROR wrong meta list delimiters
|
||||
pub fn test4() { }
|
||||
|
||||
pub fn main() {}
|
||||
32
tests/ui/parser/attribute/attr-incomplete.stderr
Normal file
32
tests/ui/parser/attribute/attr-incomplete.stderr
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
error: expected one of `(`, `,`, `::`, or `=`, found `-`
|
||||
--> $DIR/attr-incomplete.rs:1:13
|
||||
|
|
||||
LL | #[cfg(target-os = "windows")]
|
||||
| ^ expected one of `(`, `,`, `::`, or `=`
|
||||
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `%`
|
||||
--> $DIR/attr-incomplete.rs:5:19
|
||||
|
|
||||
LL | #[cfg(target_os = %)]
|
||||
| ^
|
||||
|
||||
error: expected one of `(`, `,`, `::`, or `=`, found `?`
|
||||
--> $DIR/attr-incomplete.rs:9:16
|
||||
|
|
||||
LL | #[cfg(target_os?)]
|
||||
| ^ expected one of `(`, `,`, `::`, or `=`
|
||||
|
||||
error: wrong meta list delimiters
|
||||
--> $DIR/attr-incomplete.rs:13:6
|
||||
|
|
||||
LL | #[cfg[target_os]]
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
help: the delimiters should be `(` and `)`
|
||||
|
|
||||
LL - #[cfg[target_os]]
|
||||
LL + #[cfg(target_os)]
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
@ -4,13 +4,13 @@
|
|||
|
||||
fn main() {
|
||||
#[cfg(key=foo)]
|
||||
//~^ ERROR expected unsuffixed literal, found `foo`
|
||||
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo`
|
||||
//~| HELP surround the identifier with quotation marks to make it into a string literal
|
||||
println!();
|
||||
#[cfg(key="bar")]
|
||||
println!();
|
||||
#[cfg(key=foo bar baz)]
|
||||
//~^ ERROR expected unsuffixed literal, found `foo`
|
||||
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo`
|
||||
//~| HELP surround the identifier with quotation marks to make it into a string literal
|
||||
println!();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
error: expected unsuffixed literal, found `foo`
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo`
|
||||
--> $DIR/attr-unquoted-ident.rs:6:15
|
||||
|
|
||||
LL | #[cfg(key=foo)]
|
||||
|
|
@ -9,7 +9,7 @@ help: surround the identifier with quotation marks to make it into a string lite
|
|||
LL | #[cfg(key="foo")]
|
||||
| + +
|
||||
|
||||
error: expected unsuffixed literal, found `foo`
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo`
|
||||
--> $DIR/attr-unquoted-ident.rs:12:15
|
||||
|
|
||||
LL | #[cfg(key=foo bar baz)]
|
||||
|
|
|
|||
|
|
@ -10,32 +10,12 @@ error: suffixes on string literals are invalid
|
|||
LL | "C"suffix
|
||||
| ^^^^^^^^^ invalid suffix `suffix`
|
||||
|
||||
error: suffixes on string literals are invalid
|
||||
--> $DIR/bad-lit-suffixes.rs:30:17
|
||||
|
|
||||
LL | #[rustc_dummy = "string"suffix]
|
||||
| ^^^^^^^^^^^^^^ invalid suffix `suffix`
|
||||
|
||||
error: suffixes on string literals are invalid
|
||||
--> $DIR/bad-lit-suffixes.rs:34:14
|
||||
|
|
||||
LL | #[must_use = "string"suffix]
|
||||
| ^^^^^^^^^^^^^^ invalid suffix `suffix`
|
||||
|
||||
error: suffixes on string literals are invalid
|
||||
--> $DIR/bad-lit-suffixes.rs:39:15
|
||||
|
|
||||
LL | #[link(name = "string"suffix)]
|
||||
| ^^^^^^^^^^^^^^ invalid suffix `suffix`
|
||||
|
||||
error: invalid suffix `suffix` for number literal
|
||||
--> $DIR/bad-lit-suffixes.rs:43:41
|
||||
|
|
||||
LL | #[rustc_layout_scalar_valid_range_start(0suffix)]
|
||||
| ^^^^^^^ invalid suffix `suffix`
|
||||
|
|
||||
= help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
|
||||
|
||||
warning: `extern` declarations without an explicit ABI are deprecated
|
||||
--> $DIR/bad-lit-suffixes.rs:3:1
|
||||
|
|
||||
|
|
@ -150,6 +130,18 @@ LL | 1.0e10suffix;
|
|||
|
|
||||
= help: valid suffixes are `f32` and `f64`
|
||||
|
||||
error: suffixes on string literals are invalid
|
||||
--> $DIR/bad-lit-suffixes.rs:30:17
|
||||
|
|
||||
LL | #[rustc_dummy = "string"suffix]
|
||||
| ^^^^^^^^^^^^^^ invalid suffix `suffix`
|
||||
|
||||
error: suffixes on string literals are invalid
|
||||
--> $DIR/bad-lit-suffixes.rs:34:14
|
||||
|
|
||||
LL | #[must_use = "string"suffix]
|
||||
| ^^^^^^^^^^^^^^ invalid suffix `suffix`
|
||||
|
||||
error[E0539]: malformed `must_use` attribute input
|
||||
--> $DIR/bad-lit-suffixes.rs:34:1
|
||||
|
|
||||
|
|
@ -168,16 +160,23 @@ LL - #[must_use = "string"suffix]
|
|||
LL + #[must_use]
|
||||
|
|
||||
|
||||
error[E0805]: malformed `rustc_layout_scalar_valid_range_start` attribute input
|
||||
error: invalid suffix `suffix` for number literal
|
||||
--> $DIR/bad-lit-suffixes.rs:43:41
|
||||
|
|
||||
LL | #[rustc_layout_scalar_valid_range_start(0suffix)]
|
||||
| ^^^^^^^ invalid suffix `suffix`
|
||||
|
|
||||
= help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
|
||||
|
||||
error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input
|
||||
--> $DIR/bad-lit-suffixes.rs:43:1
|
||||
|
|
||||
LL | #[rustc_layout_scalar_valid_range_start(0suffix)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------^
|
||||
| | |
|
||||
| | expected a single argument here
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^
|
||||
| | |
|
||||
| | expected an integer literal here
|
||||
| help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]`
|
||||
|
||||
error: aborting due to 22 previous errors; 2 warnings emitted
|
||||
|
||||
Some errors have detailed explanations: E0539, E0805.
|
||||
For more information about an error, try `rustc --explain E0539`.
|
||||
For more information about this error, try `rustc --explain E0539`.
|
||||
|
|
|
|||
|
|
@ -5,6 +5,5 @@ fn main() {
|
|||
const {
|
||||
#![path = foo!()]
|
||||
//~^ ERROR: cannot find macro `foo` in this scope
|
||||
//~| ERROR malformed `path` attribute input
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,17 +4,5 @@ error: cannot find macro `foo` in this scope
|
|||
LL | #![path = foo!()]
|
||||
| ^^^
|
||||
|
||||
error[E0539]: malformed `path` attribute input
|
||||
--> $DIR/path-attr-in-const-block.rs:6:9
|
||||
|
|
||||
LL | #![path = foo!()]
|
||||
| ^^^^^^^^^^------^
|
||||
| | |
|
||||
| | expected a string literal here
|
||||
| help: must be of the form: `#![path = "file"]`
|
||||
|
|
||||
= note: for more information, visit <https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute>
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0539`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue