8304: Support the new `panic!()` macro r=jonas-schievink a=jonas-schievink

Includes a minor fixup to macro 2.0 parsing.

bors r+

Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
bors[bot] 2021-04-03 01:14:56 +00:00 committed by GitHub
commit bf695c487a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 67 additions and 5 deletions

View file

@ -1402,8 +1402,18 @@ impl ModCollector<'_, '_> {
// Case 1: builtin macros
if attrs.by_key("rustc_builtin_macro").exists() {
// `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name.
let name;
let name = match attrs.by_key("rustc_builtin_macro").string_value() {
Some(it) => {
// FIXME: a hacky way to create a Name from string.
name = tt::Ident { text: it.clone(), id: tt::TokenId::unspecified() }.as_name();
&name
}
None => &mac.name,
};
let krate = self.def_collector.def_map.krate;
if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) {
if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) {
self.def_collector.define_macro_rules(
self.module_id,
mac.name.clone(),

View file

@ -1,10 +1,10 @@
//! Builtin macro
use crate::{
db::AstDatabase, name, quote, AstId, CrateId, EagerMacroId, LazyMacroId, MacroCallId,
MacroDefId, MacroDefKind, TextSize,
MacroCallLoc, MacroDefId, MacroDefKind, TextSize,
};
use base_db::{AnchoredPath, FileId};
use base_db::{AnchoredPath, Edition, FileId};
use cfg::CfgExpr;
use either::Either;
use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult};
@ -111,6 +111,8 @@ register_builtin! {
(llvm_asm, LlvmAsm) => asm_expand,
(asm, Asm) => asm_expand,
(cfg, Cfg) => cfg_expand,
(core_panic, CorePanic) => panic_expand,
(std_panic, StdPanic) => panic_expand,
EAGER:
(compile_error, CompileError) => compile_error_expand,
@ -284,6 +286,25 @@ fn cfg_expand(
ExpandResult::ok(expanded)
}
fn panic_expand(
db: &dyn AstDatabase,
id: LazyMacroId,
tt: &tt::Subtree,
) -> ExpandResult<tt::Subtree> {
let loc: MacroCallLoc = db.lookup_intern_macro(id);
// Expand to a macro call `$crate::panic::panic_{edition}`
let krate = tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() };
let mut call = if db.crate_graph()[loc.krate].edition == Edition::Edition2021 {
quote!(#krate::panic::panic_2021!)
} else {
quote!(#krate::panic::panic_2015!)
};
// Pass the original arguments
call.token_trees.push(tt::TokenTree::Subtree(tt.clone()));
ExpandResult::ok(call)
}
fn unquote_str(lit: &tt::Literal) -> Option<String> {
let lit = ast::make::tokens::literal(&lit.to_string());
let token = ast::String::cast(lit)?;

View file

@ -208,6 +208,8 @@ pub mod known {
line,
module_path,
assert,
core_panic,
std_panic,
stringify,
concat,
include,

View file

@ -104,6 +104,7 @@ macro_rules! __quote {
( . ) => {$crate::__quote!(@PUNCT '.')};
( < ) => {$crate::__quote!(@PUNCT '<')};
( > ) => {$crate::__quote!(@PUNCT '>')};
( ! ) => {$crate::__quote!(@PUNCT '!')};
( $first:tt $($tail:tt)+ ) => {
{

View file

@ -220,9 +220,11 @@ impl MacroDef {
while src.len() > 0 {
let rule = Rule::parse(&mut src, true)?;
rules.push(rule);
if let Err(()) = src.expect_char(';') {
if let Err(()) = src.expect_any_char(&[';', ',']) {
if src.len() > 0 {
return Err(ParseError::Expected("expected `;`".to_string()));
return Err(ParseError::Expected(
"expected `;` or `,` to delimit rules".to_string(),
));
}
break;
}

View file

@ -662,6 +662,21 @@ macro foo {
.assert_expand_items("foo!(bar);", "fn bar () {}");
}
#[test]
fn test_macro_2_0_panic_2015() {
parse_macro2(
r#"
macro panic_2015 {
() => (
),
(bar) => (
),
}
"#,
)
.assert_expand_items("panic_2015!(bar);", "");
}
#[test]
fn test_path() {
parse_macro(

View file

@ -34,6 +34,17 @@ impl<'a> TtIter<'a> {
}
}
pub(crate) fn expect_any_char(&mut self, chars: &[char]) -> Result<(), ()> {
match self.next() {
Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: c, .. })))
if chars.contains(c) =>
{
Ok(())
}
_ => Err(()),
}
}
pub(crate) fn expect_subtree(&mut self) -> Result<&'a tt::Subtree, ()> {
match self.next() {
Some(tt::TokenTree::Subtree(it)) => Ok(it),