diff --git a/gcc/rust/expand/rust-macro-builtins-format-args.cc b/gcc/rust/expand/rust-macro-builtins-format-args.cc index b20c84953206..eb2a1cc6a724 100644 --- a/gcc/rust/expand/rust-macro-builtins-format-args.cc +++ b/gcc/rust/expand/rust-macro-builtins-format-args.cc @@ -37,39 +37,42 @@ struct FormatArgsParseError } kind; }; -static tl::expected -format_args_parse_arguments (AST::MacroInvocData &invoc) +static inline tl::expected +format_args_parse_expr (location_t invoc_locus, AST::MacroInvocData &invoc, + Parser &parser, + BuiltinMacro macro_kind) { - MacroInvocLexer lex (invoc.get_delim_tok_tree ().to_token_stream ()); - Parser parser (lex); - - // TODO: check if EOF - return that format_args!() requires at least one - // argument - - auto args = AST::FormatArguments (); - auto last_token_id = macro_end_token (invoc.get_delim_tok_tree (), parser); - std::unique_ptr format_expr = nullptr; + std::unique_ptr format_expr = parser.parse_expr (); + rust_assert (format_expr); - // TODO: Handle the case where we're not parsing a string literal (macro - // invocation for e.g.) - switch (parser.peek_current_token ()->get_id ()) + if (format_expr->get_expr_kind () == AST::Expr::Kind::MacroInvocation) { - case STRING_LITERAL: - case RAW_STRING_LITERAL: - format_expr = parser.parse_literal_expr (); - default: - // do nothing - ; + std::vector> pending; + pending.emplace_back ( + static_cast (format_expr.release ())); + return tl::unexpected ( + make_eager_builtin_invocation (macro_kind, invoc_locus, + invoc.get_delim_tok_tree (), + std::move (pending))); } - rust_assert (format_expr); - // TODO(Arthur): Clean this up - if we haven't parsed a string literal but a // macro invocation, what do we do here? return a tl::unexpected? - auto format_str = static_cast (*format_expr) - .get_literal () - .as_string (); + rust_assert (format_expr->is_literal ()); + return static_cast (*format_expr) + .get_literal () + .as_string (); +} + +static inline tl::expected +format_args_parse_arguments (AST::MacroInvocData &invoc, + Parser &parser, + TokenId last_token_id) +{ + // TODO: check if EOF - return that format_args!() requires at least one + // argument + auto args = AST::FormatArguments (); // TODO: Allow implicit captures ONLY if the the first arg is a string literal // and not a macro invocation @@ -126,7 +129,7 @@ format_args_parse_arguments (AST::MacroInvocData &invoc) // we need to skip commas, don't we? } - return FormatArgsInput{std::move (format_str), std::move (args)}; + return args; } tl::optional @@ -135,9 +138,24 @@ MacroBuiltin::format_args_handler (location_t invoc_locus, AST::InvocKind semicolon, AST::FormatArgs::Newline nl) { - auto input = format_args_parse_arguments (invoc); + MacroInvocLexer lex (invoc.get_delim_tok_tree ().to_token_stream ()); + Parser parser (lex); + + auto last_token_id = macro_end_token (invoc.get_delim_tok_tree (), parser); + + auto format_str = format_args_parse_expr (invoc_locus, invoc, parser, + nl == AST::FormatArgs::Newline::Yes + ? BuiltinMacro::FormatArgsNl + : BuiltinMacro::FormatArgs); + + if (!format_str) + { + return std::move (format_str.error ()); + } + + auto args = format_args_parse_arguments (invoc, parser, last_token_id); - if (!input) + if (!args) { rust_error_at (invoc_locus, "could not parse arguments to %"); @@ -173,7 +191,7 @@ MacroBuiltin::format_args_handler (location_t invoc_locus, bool append_newline = nl == AST::FormatArgs::Newline::Yes; - auto fmt_str = std::move (input->format_str); + auto fmt_str = std::move (format_str.value ()); if (append_newline) fmt_str += '\n'; @@ -189,7 +207,7 @@ MacroBuiltin::format_args_handler (location_t invoc_locus, // for creating the `template` auto fmt_args_node = AST::FormatArgs (invoc_locus, std::move (pieces), - std::move (input->args)); + std::move (args.value ())); auto expanded = Fmt::expand_format_args (fmt_args_node, diff --git a/gcc/testsuite/rust/compile/format_args_concat.rs b/gcc/testsuite/rust/compile/format_args_concat.rs new file mode 100644 index 000000000000..b180667e9e6f --- /dev/null +++ b/gcc/testsuite/rust/compile/format_args_concat.rs @@ -0,0 +1,51 @@ +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +macro_rules! format_args { + () => {}; +} + +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} + +#[lang = "sized"] +trait Sized {} + +pub mod core { + pub mod fmt { + pub struct Formatter; + pub struct Result; + + pub struct Arguments<'a>; + + impl<'a> Arguments<'a> { + pub fn new_v1(_: &'a [&'static str], _: &'a [ArgumentV1<'a>]) -> Arguments<'a> { + Arguments + } + } + + pub struct ArgumentV1<'a>; + + impl<'a> ArgumentV1<'a> { + pub fn new<'b, T>(_: &'b T, _: fn(&T, &mut Formatter) -> Result) -> ArgumentV1 { + ArgumentV1 + } + } + + pub trait Display { + fn fmt(&self, _: &mut Formatter) -> Result; + } + + impl Display for i32 { + fn fmt(&self, _: &mut Formatter) -> Result { + Result + } + } + } +} + +fn main() { + let _formatted = format_args!(concat!("hello ", "{}"), 15); +}