Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 48 additions & 30 deletions gcc/rust/expand/rust-macro-builtins-format-args.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,39 +37,42 @@ struct FormatArgsParseError
} kind;
};

static tl::expected<FormatArgsInput, FormatArgsParseError>
format_args_parse_arguments (AST::MacroInvocData &invoc)
static inline tl::expected<std::string, AST::Fragment>
format_args_parse_expr (location_t invoc_locus, AST::MacroInvocData &invoc,
Parser<MacroInvocLexer> &parser,
BuiltinMacro macro_kind)
{
MacroInvocLexer lex (invoc.get_delim_tok_tree ().to_token_stream ());
Parser<MacroInvocLexer> 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<AST::Expr> format_expr = nullptr;
std::unique_ptr<AST::Expr> 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<std::unique_ptr<AST::MacroInvocation>> pending;
pending.emplace_back (
static_cast<AST::MacroInvocation *> (format_expr.release ()));
return tl::unexpected<AST::Fragment> (
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<AST::LiteralExpr &> (*format_expr)
.get_literal ()
.as_string ();
rust_assert (format_expr->is_literal ());
return static_cast<AST::LiteralExpr &> (*format_expr)
.get_literal ()
.as_string ();
}

static inline tl::expected<AST::FormatArguments, FormatArgsParseError>
format_args_parse_arguments (AST::MacroInvocData &invoc,
Parser<MacroInvocLexer> &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

Expand Down Expand Up @@ -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<AST::Fragment>
Expand All @@ -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<MacroInvocLexer> 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 %<format_args!()%>");
Expand Down Expand Up @@ -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';

Expand All @@ -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,
Expand Down
51 changes: 51 additions & 0 deletions gcc/testsuite/rust/compile/format_args_concat.rs
Original file line number Diff line number Diff line change
@@ -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);
}
Loading