internal: macro_arg query always returns a TokenTree
This commit is contained in:
parent
e2a985e93f
commit
2fa57d90bc
@ -1000,10 +1000,6 @@ fn collect_macro_call<T, U>(
|
|||||||
krate: *krate,
|
krate: *krate,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Some(ExpandError::RecursionOverflowPoisoned) => {
|
|
||||||
// Recursion limit has been reached in the macro expansion tree, but not in
|
|
||||||
// this very macro call. Don't add diagnostics to avoid duplication.
|
|
||||||
}
|
|
||||||
Some(err) => {
|
Some(err) => {
|
||||||
self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
|
self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
|
||||||
node: InFile::new(outer_file, syntax_ptr),
|
node: InFile::new(outer_file, syntax_ptr),
|
||||||
|
@ -140,13 +140,11 @@ fn within_limit<F, T: ast::AstNode>(
|
|||||||
// The overflow error should have been reported when it occurred (see the next branch),
|
// The overflow error should have been reported when it occurred (see the next branch),
|
||||||
// so don't return overflow error here to avoid diagnostics duplication.
|
// so don't return overflow error here to avoid diagnostics duplication.
|
||||||
cov_mark::hit!(overflow_but_not_me);
|
cov_mark::hit!(overflow_but_not_me);
|
||||||
return ExpandResult::only_err(ExpandError::RecursionOverflowPoisoned);
|
return ExpandResult::ok(None);
|
||||||
} else if self.recursion_limit.check(self.recursion_depth as usize + 1).is_err() {
|
} else if self.recursion_limit.check(self.recursion_depth as usize + 1).is_err() {
|
||||||
self.recursion_depth = u32::MAX;
|
self.recursion_depth = u32::MAX;
|
||||||
cov_mark::hit!(your_stack_belongs_to_me);
|
cov_mark::hit!(your_stack_belongs_to_me);
|
||||||
return ExpandResult::only_err(ExpandError::other(
|
return ExpandResult::only_err(ExpandError::RecursionOverflow);
|
||||||
"reached recursion limit during macro expansion",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let ExpandResult { value, err } = op(self);
|
let ExpandResult { value, err } = op(self);
|
||||||
|
@ -33,7 +33,7 @@ fn test_expand_bad_literal() {
|
|||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
macro_rules! m { ($i:literal) => {}; }
|
macro_rules! m { ($i:literal) => {}; }
|
||||||
/* error: invalid token tree */"#]],
|
/* error: mismatched delimiters */"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,26 +68,26 @@ macro_rules! m2 { () => ( ${invalid()} ) }
|
|||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
macro_rules! i1 { invalid }
|
macro_rules! i1 { invalid }
|
||||||
/* error: invalid macro definition: expected subtree */
|
/* error: macro definition has parse errors */
|
||||||
|
|
||||||
macro_rules! e1 { $i:ident => () }
|
macro_rules! e1 { $i:ident => () }
|
||||||
/* error: invalid macro definition: expected subtree */
|
/* error: macro definition has parse errors */
|
||||||
macro_rules! e2 { ($i:ident) () }
|
macro_rules! e2 { ($i:ident) () }
|
||||||
/* error: invalid macro definition: expected `=` */
|
/* error: macro definition has parse errors */
|
||||||
macro_rules! e3 { ($(i:ident)_) => () }
|
macro_rules! e3 { ($(i:ident)_) => () }
|
||||||
/* error: invalid macro definition: invalid repeat */
|
/* error: macro definition has parse errors */
|
||||||
|
|
||||||
macro_rules! f1 { ($i) => ($i) }
|
macro_rules! f1 { ($i) => ($i) }
|
||||||
/* error: invalid macro definition: missing fragment specifier */
|
/* error: macro definition has parse errors */
|
||||||
macro_rules! f2 { ($i:) => ($i) }
|
macro_rules! f2 { ($i:) => ($i) }
|
||||||
/* error: invalid macro definition: missing fragment specifier */
|
/* error: macro definition has parse errors */
|
||||||
macro_rules! f3 { ($i:_) => () }
|
macro_rules! f3 { ($i:_) => () }
|
||||||
/* error: invalid macro definition: missing fragment specifier */
|
/* error: macro definition has parse errors */
|
||||||
|
|
||||||
macro_rules! m1 { ($$i) => () }
|
macro_rules! m1 { ($$i) => () }
|
||||||
/* error: invalid macro definition: `$$` is not allowed on the pattern side */
|
/* error: macro definition has parse errors */
|
||||||
macro_rules! m2 { () => ( ${invalid()} ) }
|
macro_rules! m2 { () => ( ${invalid()} ) }
|
||||||
/* error: invalid macro definition: invalid metavariable expression */
|
/* error: macro definition has parse errors */
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -137,18 +137,18 @@ fn test_rustc_issue_57597() {
|
|||||||
macro_rules! mA { ($($($($i:ident)+)?)*) => {}; }
|
macro_rules! mA { ($($($($i:ident)+)?)*) => {}; }
|
||||||
macro_rules! mB { ($($($($i:ident)+)*)?) => {}; }
|
macro_rules! mB { ($($($($i:ident)+)*)?) => {}; }
|
||||||
|
|
||||||
/* error: invalid macro definition: empty token tree in repetition */
|
/* error: macro definition has parse errors */
|
||||||
/* error: invalid macro definition: empty token tree in repetition */
|
/* error: macro definition has parse errors */
|
||||||
/* error: invalid macro definition: empty token tree in repetition */
|
/* error: macro definition has parse errors */
|
||||||
/* error: invalid macro definition: empty token tree in repetition */
|
/* error: macro definition has parse errors */
|
||||||
/* error: invalid macro definition: empty token tree in repetition */
|
/* error: macro definition has parse errors */
|
||||||
/* error: invalid macro definition: empty token tree in repetition */
|
/* error: macro definition has parse errors */
|
||||||
/* error: invalid macro definition: empty token tree in repetition */
|
/* error: macro definition has parse errors */
|
||||||
/* error: invalid macro definition: empty token tree in repetition */
|
/* error: macro definition has parse errors */
|
||||||
/* error: invalid macro definition: empty token tree in repetition */
|
/* error: macro definition has parse errors */
|
||||||
/* error: invalid macro definition: empty token tree in repetition */
|
/* error: macro definition has parse errors */
|
||||||
/* error: invalid macro definition: empty token tree in repetition */
|
/* error: macro definition has parse errors */
|
||||||
/* error: invalid macro definition: empty token tree in repetition */
|
/* error: macro definition has parse errors */
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -275,9 +275,9 @@ macro_rules! depth_too_large {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
/* error: invalid macro definition: invalid metavariable expression */;
|
/* error: macro definition has parse errors */;
|
||||||
/* error: invalid macro definition: invalid metavariable expression */;
|
/* error: macro definition has parse errors */;
|
||||||
/* error: invalid macro definition: invalid metavariable expression */;
|
/* error: macro definition has parse errors */;
|
||||||
}
|
}
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
@ -97,8 +97,8 @@ macro_rules! m2 { ($x:ident) => {} }
|
|||||||
macro_rules! m1 { ($x:ident) => { ($x } }
|
macro_rules! m1 { ($x:ident) => { ($x } }
|
||||||
macro_rules! m2 { ($x:ident) => {} }
|
macro_rules! m2 { ($x:ident) => {} }
|
||||||
|
|
||||||
/* error: invalid macro definition: expected subtree */
|
/* error: macro definition has parse errors */
|
||||||
/* error: invalid token tree */
|
/* error: mismatched delimiters */
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -446,7 +446,7 @@ fn compile_error_expand(
|
|||||||
) -> ExpandResult<tt::Subtree> {
|
) -> ExpandResult<tt::Subtree> {
|
||||||
let err = match &*tt.token_trees {
|
let err = match &*tt.token_trees {
|
||||||
[tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => match unquote_str(it) {
|
[tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => match unquote_str(it) {
|
||||||
Some(unquoted) => ExpandError::other(unquoted),
|
Some(unquoted) => ExpandError::other(unquoted.into_boxed_str()),
|
||||||
None => ExpandError::other("`compile_error!` argument must be a string"),
|
None => ExpandError::other("`compile_error!` argument must be a string"),
|
||||||
},
|
},
|
||||||
_ => ExpandError::other("`compile_error!` argument must be a string"),
|
_ => ExpandError::other("`compile_error!` argument must be a string"),
|
||||||
|
@ -108,7 +108,7 @@ fn parse_macro_expansion(
|
|||||||
fn macro_arg(
|
fn macro_arg(
|
||||||
&self,
|
&self,
|
||||||
id: MacroCallId,
|
id: MacroCallId,
|
||||||
) -> ValueResult<Option<(Arc<tt::Subtree>, SyntaxFixupUndoInfo)>, Arc<Box<[SyntaxError]>>>;
|
) -> ValueResult<(Arc<tt::Subtree>, SyntaxFixupUndoInfo), Arc<Box<[SyntaxError]>>>;
|
||||||
/// Fetches the expander for this macro.
|
/// Fetches the expander for this macro.
|
||||||
#[salsa::transparent]
|
#[salsa::transparent]
|
||||||
#[salsa::invoke(TokenExpander::macro_expander)]
|
#[salsa::invoke(TokenExpander::macro_expander)]
|
||||||
@ -326,58 +326,77 @@ fn macro_arg(
|
|||||||
db: &dyn ExpandDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
id: MacroCallId,
|
id: MacroCallId,
|
||||||
// FIXME: consider the following by putting fixup info into eager call info args
|
// FIXME: consider the following by putting fixup info into eager call info args
|
||||||
// ) -> ValueResult<Option<Arc<(tt::Subtree, SyntaxFixupUndoInfo)>>, Arc<Box<[SyntaxError]>>> {
|
// ) -> ValueResult<Arc<(tt::Subtree, SyntaxFixupUndoInfo)>, Arc<Box<[SyntaxError]>>> {
|
||||||
) -> ValueResult<Option<(Arc<tt::Subtree>, SyntaxFixupUndoInfo)>, Arc<Box<[SyntaxError]>>> {
|
) -> ValueResult<(Arc<tt::Subtree>, SyntaxFixupUndoInfo), Arc<Box<[SyntaxError]>>> {
|
||||||
let mismatched_delimiters = |arg: &SyntaxNode| {
|
|
||||||
let first = arg.first_child_or_token().map_or(T![.], |it| it.kind());
|
|
||||||
let last = arg.last_child_or_token().map_or(T![.], |it| it.kind());
|
|
||||||
let well_formed_tt =
|
|
||||||
matches!((first, last), (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']));
|
|
||||||
if !well_formed_tt {
|
|
||||||
// Don't expand malformed (unbalanced) macro invocations. This is
|
|
||||||
// less than ideal, but trying to expand unbalanced macro calls
|
|
||||||
// sometimes produces pathological, deeply nested code which breaks
|
|
||||||
// all kinds of things.
|
|
||||||
//
|
|
||||||
// Some day, we'll have explicit recursion counters for all
|
|
||||||
// recursive things, at which point this code might be removed.
|
|
||||||
cov_mark::hit!(issue9358_bad_macro_stack_overflow);
|
|
||||||
Some(Arc::new(Box::new([SyntaxError::new(
|
|
||||||
"unbalanced token tree".to_owned(),
|
|
||||||
arg.text_range(),
|
|
||||||
)]) as Box<[_]>))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let loc = db.lookup_intern_macro_call(id);
|
let loc = db.lookup_intern_macro_call(id);
|
||||||
if let Some(EagerCallInfo { arg, .. }) = matches!(loc.def.kind, MacroDefKind::BuiltInEager(..))
|
if let Some(EagerCallInfo { arg, .. }) = matches!(loc.def.kind, MacroDefKind::BuiltInEager(..))
|
||||||
.then(|| loc.eager.as_deref())
|
.then(|| loc.eager.as_deref())
|
||||||
.flatten()
|
.flatten()
|
||||||
{
|
{
|
||||||
ValueResult::ok(Some((arg.clone(), SyntaxFixupUndoInfo::NONE)))
|
ValueResult::ok((arg.clone(), SyntaxFixupUndoInfo::NONE))
|
||||||
} else {
|
} else {
|
||||||
let (parse, map) = parse_with_map(db, loc.kind.file_id());
|
let (parse, map) = parse_with_map(db, loc.kind.file_id());
|
||||||
let root = parse.syntax_node();
|
let root = parse.syntax_node();
|
||||||
|
|
||||||
let syntax = match loc.kind {
|
let syntax = match loc.kind {
|
||||||
MacroCallKind::FnLike { ast_id, .. } => {
|
MacroCallKind::FnLike { ast_id, .. } => {
|
||||||
|
let dummy_tt = |kind| {
|
||||||
|
(
|
||||||
|
Arc::new(tt::Subtree {
|
||||||
|
delimiter: tt::Delimiter {
|
||||||
|
open: loc.call_site,
|
||||||
|
close: loc.call_site,
|
||||||
|
kind,
|
||||||
|
},
|
||||||
|
token_trees: Box::default(),
|
||||||
|
}),
|
||||||
|
SyntaxFixupUndoInfo::default(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let node = &ast_id.to_ptr(db).to_node(&root);
|
let node = &ast_id.to_ptr(db).to_node(&root);
|
||||||
let offset = node.syntax().text_range().start();
|
let offset = node.syntax().text_range().start();
|
||||||
match node.token_tree() {
|
let Some(tt) = node.token_tree() else {
|
||||||
Some(tt) => {
|
return ValueResult::new(
|
||||||
let tt = tt.syntax();
|
dummy_tt(tt::DelimiterKind::Invisible),
|
||||||
if let Some(e) = mismatched_delimiters(tt) {
|
Arc::new(Box::new([SyntaxError::new_at_offset(
|
||||||
return ValueResult::only_err(e);
|
"missing token tree".to_owned(),
|
||||||
}
|
offset,
|
||||||
tt.clone()
|
)])),
|
||||||
}
|
);
|
||||||
None => {
|
};
|
||||||
return ValueResult::only_err(Arc::new(Box::new([
|
let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']);
|
||||||
SyntaxError::new_at_offset("missing token tree".to_owned(), offset),
|
let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]);
|
||||||
])));
|
|
||||||
}
|
let mismatched_delimiters = !matches!(
|
||||||
|
(first, last),
|
||||||
|
(T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}'])
|
||||||
|
);
|
||||||
|
if mismatched_delimiters {
|
||||||
|
// Don't expand malformed (unbalanced) macro invocations. This is
|
||||||
|
// less than ideal, but trying to expand unbalanced macro calls
|
||||||
|
// sometimes produces pathological, deeply nested code which breaks
|
||||||
|
// all kinds of things.
|
||||||
|
//
|
||||||
|
// So instead, we'll return an empty subtree here
|
||||||
|
cov_mark::hit!(issue9358_bad_macro_stack_overflow);
|
||||||
|
|
||||||
|
let kind = match first {
|
||||||
|
_ if loc.def.is_proc_macro() => tt::DelimiterKind::Invisible,
|
||||||
|
T!['('] => tt::DelimiterKind::Parenthesis,
|
||||||
|
T!['['] => tt::DelimiterKind::Bracket,
|
||||||
|
T!['{'] => tt::DelimiterKind::Brace,
|
||||||
|
_ => tt::DelimiterKind::Invisible,
|
||||||
|
};
|
||||||
|
return ValueResult::new(
|
||||||
|
dummy_tt(kind),
|
||||||
|
Arc::new(Box::new([SyntaxError::new_at_offset(
|
||||||
|
"mismatched delimiters".to_owned(),
|
||||||
|
offset,
|
||||||
|
)])),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
tt.syntax().clone()
|
||||||
}
|
}
|
||||||
MacroCallKind::Derive { ast_id, .. } => {
|
MacroCallKind::Derive { ast_id, .. } => {
|
||||||
ast_id.to_ptr(db).to_node(&root).syntax().clone()
|
ast_id.to_ptr(db).to_node(&root).syntax().clone()
|
||||||
@ -427,15 +446,15 @@ fn macro_arg(
|
|||||||
|
|
||||||
if matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) {
|
if matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) {
|
||||||
match parse.errors() {
|
match parse.errors() {
|
||||||
[] => ValueResult::ok(Some((Arc::new(tt), undo_info))),
|
[] => ValueResult::ok((Arc::new(tt), undo_info)),
|
||||||
errors => ValueResult::new(
|
errors => ValueResult::new(
|
||||||
Some((Arc::new(tt), undo_info)),
|
(Arc::new(tt), undo_info),
|
||||||
// Box::<[_]>::from(res.errors()), not stable yet
|
// Box::<[_]>::from(res.errors()), not stable yet
|
||||||
Arc::new(errors.to_vec().into_boxed_slice()),
|
Arc::new(errors.to_vec().into_boxed_slice()),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ValueResult::ok(Some((Arc::new(tt), undo_info)))
|
ValueResult::ok((Arc::new(tt), undo_info))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -519,21 +538,20 @@ fn macro_expand(
|
|||||||
expander.expand(db, macro_call_id, &node, map.as_ref())
|
expander.expand(db, macro_call_id, &node, map.as_ref())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let ValueResult { value, err } = db.macro_arg(macro_call_id);
|
let ValueResult { value: (macro_arg, undo_info), err } = db.macro_arg(macro_call_id);
|
||||||
let Some((macro_arg, undo_info)) = value else {
|
let format_parse_err = |err: Arc<Box<[SyntaxError]>>| {
|
||||||
return ExpandResult {
|
let mut buf = String::new();
|
||||||
value: CowArc::Owned(tt::Subtree {
|
for err in &**err {
|
||||||
delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
|
use std::fmt::Write;
|
||||||
token_trees: Box::new([]),
|
_ = write!(buf, "{}, ", err);
|
||||||
}),
|
}
|
||||||
// FIXME: We should make sure to enforce an invariant that invalid macro
|
buf.pop();
|
||||||
// calls do not reach this call path!
|
buf.pop();
|
||||||
err: Some(ExpandError::other("invalid token tree")),
|
ExpandError::other(buf)
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let arg = &*macro_arg;
|
let arg = &*macro_arg;
|
||||||
match loc.def.kind {
|
let res = match loc.def.kind {
|
||||||
MacroDefKind::Declarative(id) => {
|
MacroDefKind::Declarative(id) => {
|
||||||
db.decl_macro_expander(loc.def.krate, id).expand(db, arg.clone(), macro_call_id)
|
db.decl_macro_expander(loc.def.krate, id).expand(db, arg.clone(), macro_call_id)
|
||||||
}
|
}
|
||||||
@ -549,16 +567,7 @@ fn macro_expand(
|
|||||||
MacroDefKind::BuiltInEager(..) if loc.eager.is_none() => {
|
MacroDefKind::BuiltInEager(..) if loc.eager.is_none() => {
|
||||||
return ExpandResult {
|
return ExpandResult {
|
||||||
value: CowArc::Arc(macro_arg.clone()),
|
value: CowArc::Arc(macro_arg.clone()),
|
||||||
err: err.map(|err| {
|
err: err.map(format_parse_err),
|
||||||
let mut buf = String::new();
|
|
||||||
for err in &**err {
|
|
||||||
use std::fmt::Write;
|
|
||||||
_ = write!(buf, "{}, ", err);
|
|
||||||
}
|
|
||||||
buf.pop();
|
|
||||||
buf.pop();
|
|
||||||
ExpandError::other(buf)
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
MacroDefKind::BuiltInEager(it, _) => {
|
MacroDefKind::BuiltInEager(it, _) => {
|
||||||
@ -570,6 +579,11 @@ fn macro_expand(
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
ExpandResult {
|
||||||
|
value: res.value,
|
||||||
|
// if the arg had parse errors, show them instead of the expansion errors
|
||||||
|
err: err.map(format_parse_err).or(res.err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -597,17 +611,7 @@ fn macro_expand(
|
|||||||
|
|
||||||
fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> {
|
fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> {
|
||||||
let loc = db.lookup_intern_macro_call(id);
|
let loc = db.lookup_intern_macro_call(id);
|
||||||
let Some((macro_arg, undo_info)) = db.macro_arg(id).value else {
|
let (macro_arg, undo_info) = db.macro_arg(id).value;
|
||||||
return ExpandResult {
|
|
||||||
value: Arc::new(tt::Subtree {
|
|
||||||
delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
|
|
||||||
token_trees: Box::new([]),
|
|
||||||
}),
|
|
||||||
// FIXME: We should make sure to enforce an invariant that invalid macro
|
|
||||||
// calls do not reach this call path!
|
|
||||||
err: Some(ExpandError::other("invalid token tree")),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let expander = match loc.def.kind {
|
let expander = match loc.def.kind {
|
||||||
MacroDefKind::ProcMacro(expander, ..) => expander,
|
MacroDefKind::ProcMacro(expander, ..) => expander,
|
||||||
|
@ -44,9 +44,9 @@ pub fn expand(
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
match self.mac.err() {
|
match self.mac.err() {
|
||||||
Some(e) => ExpandResult::new(
|
Some(_) => ExpandResult::new(
|
||||||
tt::Subtree::empty(tt::DelimSpan { open: loc.call_site, close: loc.call_site }),
|
tt::Subtree::empty(tt::DelimSpan { open: loc.call_site, close: loc.call_site }),
|
||||||
ExpandError::other(format!("invalid macro definition: {e}")),
|
ExpandError::MacroDefinition,
|
||||||
),
|
),
|
||||||
None => self
|
None => self
|
||||||
.mac
|
.mac
|
||||||
@ -80,9 +80,9 @@ pub fn expand_unhygienic(
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
match self.mac.err() {
|
match self.mac.err() {
|
||||||
Some(e) => ExpandResult::new(
|
Some(_) => ExpandResult::new(
|
||||||
tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
|
tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
|
||||||
ExpandError::other(format!("invalid macro definition: {e}")),
|
ExpandError::MacroDefinition,
|
||||||
),
|
),
|
||||||
None => self.mac.expand(&tt, |_| (), new_meta_vars, call_site).map_err(Into::into),
|
None => self.mac.expand(&tt, |_| (), new_meta_vars, call_site).map_err(Into::into),
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,6 @@
|
|||||||
builtin_derive_macro::BuiltinDeriveExpander,
|
builtin_derive_macro::BuiltinDeriveExpander,
|
||||||
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
|
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
|
||||||
db::{ExpandDatabase, TokenExpander},
|
db::{ExpandDatabase, TokenExpander},
|
||||||
fixup::SyntaxFixupUndoInfo,
|
|
||||||
hygiene::SyntaxContextData,
|
hygiene::SyntaxContextData,
|
||||||
mod_path::ModPath,
|
mod_path::ModPath,
|
||||||
proc_macro::{CustomProcMacroExpander, ProcMacroKind},
|
proc_macro::{CustomProcMacroExpander, ProcMacroKind},
|
||||||
@ -131,8 +130,9 @@ pub enum ExpandError {
|
|||||||
UnresolvedProcMacro(CrateId),
|
UnresolvedProcMacro(CrateId),
|
||||||
/// The macro expansion is disabled.
|
/// The macro expansion is disabled.
|
||||||
MacroDisabled,
|
MacroDisabled,
|
||||||
|
MacroDefinition,
|
||||||
Mbe(mbe::ExpandError),
|
Mbe(mbe::ExpandError),
|
||||||
RecursionOverflowPoisoned,
|
RecursionOverflow,
|
||||||
Other(Box<Box<str>>),
|
Other(Box<Box<str>>),
|
||||||
ProcMacroPanic(Box<Box<str>>),
|
ProcMacroPanic(Box<Box<str>>),
|
||||||
}
|
}
|
||||||
@ -154,15 +154,14 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|||||||
match self {
|
match self {
|
||||||
ExpandError::UnresolvedProcMacro(_) => f.write_str("unresolved proc-macro"),
|
ExpandError::UnresolvedProcMacro(_) => f.write_str("unresolved proc-macro"),
|
||||||
ExpandError::Mbe(it) => it.fmt(f),
|
ExpandError::Mbe(it) => it.fmt(f),
|
||||||
ExpandError::RecursionOverflowPoisoned => {
|
ExpandError::RecursionOverflow => f.write_str("overflow expanding the original macro"),
|
||||||
f.write_str("overflow expanding the original macro")
|
|
||||||
}
|
|
||||||
ExpandError::ProcMacroPanic(it) => {
|
ExpandError::ProcMacroPanic(it) => {
|
||||||
f.write_str("proc-macro panicked: ")?;
|
f.write_str("proc-macro panicked: ")?;
|
||||||
f.write_str(it)
|
f.write_str(it)
|
||||||
}
|
}
|
||||||
ExpandError::Other(it) => f.write_str(it),
|
ExpandError::Other(it) => f.write_str(it),
|
||||||
ExpandError::MacroDisabled => f.write_str("macro disabled"),
|
ExpandError::MacroDisabled => f.write_str("macro disabled"),
|
||||||
|
ExpandError::MacroDefinition => f.write_str("macro definition has parse errors"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -761,15 +760,7 @@ pub fn new(db: &dyn ExpandDatabase, macro_file: MacroFileId) -> ExpansionInfo {
|
|||||||
let (parse, exp_map) = db.parse_macro_expansion(macro_file).value;
|
let (parse, exp_map) = db.parse_macro_expansion(macro_file).value;
|
||||||
let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() };
|
let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() };
|
||||||
|
|
||||||
let (macro_arg, _) = db.macro_arg(macro_file.macro_call_id).value.unwrap_or_else(|| {
|
let (macro_arg, _) = db.macro_arg(macro_file.macro_call_id).value;
|
||||||
(
|
|
||||||
Arc::new(tt::Subtree {
|
|
||||||
delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
|
|
||||||
token_trees: Box::new([]),
|
|
||||||
}),
|
|
||||||
SyntaxFixupUndoInfo::NONE,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let def = loc.def.ast_id().left().and_then(|id| {
|
let def = loc.def.ast_id().left().and_then(|id| {
|
||||||
let def_tt = match id.to_node(db) {
|
let def_tt = match id.to_node(db) {
|
||||||
|
@ -542,7 +542,26 @@ fn quux(x: i32) {
|
|||||||
m!(x$0
|
m!(x$0
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#""#]],
|
expect![[r#"
|
||||||
|
fn quux(…) fn(i32)
|
||||||
|
lc x i32
|
||||||
|
lc y i32
|
||||||
|
ma m!(…) macro_rules! m
|
||||||
|
bt u32 u32
|
||||||
|
kw crate::
|
||||||
|
kw false
|
||||||
|
kw for
|
||||||
|
kw if
|
||||||
|
kw if let
|
||||||
|
kw loop
|
||||||
|
kw match
|
||||||
|
kw return
|
||||||
|
kw self::
|
||||||
|
kw true
|
||||||
|
kw unsafe
|
||||||
|
kw while
|
||||||
|
kw while let
|
||||||
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ macro_rules! foo {
|
|||||||
|
|
||||||
fn f() {
|
fn f() {
|
||||||
foo!();
|
foo!();
|
||||||
//^^^ error: invalid macro definition: expected subtree
|
//^^^ error: macro definition has parse errors
|
||||||
|
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
|
Loading…
Reference in New Issue
Block a user