Skip to content

Commit d2f032f

Browse files
liamnaddellP-E-P
authored andcommitted
Eager expansion for include* #1805 #1865
gcc/rust/ChangeLog: * expand/rust-expand-visitor.h: remove auto keyword * expand/rust-macro-builtins-helpers.cc: allow for changing macro invoc types on eager expansions to semicoloned macros * expand/rust-macro-builtins-helpers.h: add default semicoloned argument * expand/rust-macro-builtins-include.cc: allow for eager expansion for include and include_bytes allow for parsing include invocations as items instead of expressions, which allows invocations at global scope * expand/rust-macro-expand.cc: push Expr type for eager invocations gcc/testsuite/ChangeLog: * rust/compile/macros/builtin/include1.rs: add basic include test at global scope * rust/compile/macros/builtin/include2.rs: add basic include test at local scope with expression * rust/compile/macros/builtin/include3.rs: add eager expansion test at global scope * rust/compile/macros/builtin/include4.rs: add eager expansion test at local scope with expression * rust/compile/macros/builtin/include_bytes.rs: add eager expansion test at global scope * rust/compile/macros/builtin/include_rs: supporting test file with dummy function * rust/compile/macros/builtin/include_rs2: supporting test file with dummy string * rust/compile/macros/builtin/include_str.rs: add eager expansion test at global scope * rust/execute/torture/builtin_macro_include_bytes.rs: clean up old test logic, add permutations for eager expansion * rust/execute/torture/builtin_macro_include_str.rs: add eager expansion permutations
1 parent 47c16d7 commit d2f032f

15 files changed

+170
-40
lines changed

gcc/rust/expand/rust-expand-visitor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class ExpandVisitor : public AST::DefaultASTVisitor
140140
it = values.erase (it);
141141
for (auto &node : final_fragment.get_nodes ())
142142
{
143-
auto new_node = extractor (node);
143+
U new_node = extractor (node);
144144
if (new_node != nullptr)
145145
{
146146
it = values.insert (it, std::move (new_node));

gcc/rust/expand/rust-macro-builtins-helpers.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ try_expand_many_expr (Parser<MacroInvocLexer> &parser,
174174
std::unique_ptr<AST::Expr>
175175
parse_single_string_literal (BuiltinMacro kind,
176176
AST::DelimTokenTree &invoc_token_tree,
177-
location_t invoc_locus, MacroExpander *expander)
177+
location_t invoc_locus, MacroExpander *expander,
178+
bool is_semicoloned)
178179
{
179180
MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
180181
Parser<MacroInvocLexer> parser (lex);
@@ -221,7 +222,7 @@ parse_single_string_literal (BuiltinMacro kind,
221222
AST::MacroInvocData (AST::SimplePath ({AST::SimplePathSegment (
222223
path_str, invoc_locus)}),
223224
std::move (invoc_token_tree)),
224-
{}, invoc_locus, std::move (pending_invocations));
225+
{}, invoc_locus, std::move (pending_invocations), is_semicoloned);
225226
}
226227
else
227228
{
@@ -281,4 +282,4 @@ load_file_bytes (location_t invoc_locus, const char *filename)
281282

282283
return buf;
283284
}
284-
} // namespace Rust
285+
} // namespace Rust

gcc/rust/expand/rust-macro-builtins-helpers.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ try_expand_many_expr (Parser<MacroInvocLexer> &parser,
7474
std::unique_ptr<AST::Expr>
7575
parse_single_string_literal (BuiltinMacro kind,
7676
AST::DelimTokenTree &invoc_token_tree,
77-
location_t invoc_locus, MacroExpander *expander);
77+
location_t invoc_locus, MacroExpander *expander,
78+
bool is_semicoloned = false);
7879

7980
// Treat PATH as a path relative to the source file currently being
8081
// compiled, and return the absolute path for it.

gcc/rust/expand/rust-macro-builtins-include.cc

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@ MacroBuiltin::include_bytes_handler (location_t invoc_locus,
4040
if (lit_expr == nullptr)
4141
return AST::Fragment::create_error ();
4242

43-
rust_assert (lit_expr->is_literal ());
43+
if (!lit_expr->is_literal ())
44+
{
45+
auto token_tree = invoc.get_delim_tok_tree ();
46+
return AST::Fragment ({AST::SingleASTNode (std::move (lit_expr))},
47+
token_tree.to_token_stream ());
48+
}
4449

4550
std::string target_filename
4651
= source_relative_path (lit_expr->as_string (), invoc_locus);
@@ -188,16 +193,36 @@ MacroBuiltin::include_handler (location_t invoc_locus,
188193
AST::MacroInvocData &invoc,
189194
AST::InvocKind semicolon)
190195
{
196+
bool is_semicoloned = semicolon == AST::InvocKind::Semicoloned;
191197
/* Get target filename from the macro invocation, which is treated as a path
192198
relative to the include!-ing file (currently being compiled). */
193-
auto lit_expr
199+
std::unique_ptr<AST::Expr> lit_expr
194200
= parse_single_string_literal (BuiltinMacro::Include,
195201
invoc.get_delim_tok_tree (), invoc_locus,
196-
invoc.get_expander ());
202+
invoc.get_expander (), is_semicoloned);
197203
if (lit_expr == nullptr)
198204
return AST::Fragment::create_error ();
199205

200-
rust_assert (lit_expr->is_literal ());
206+
if (!lit_expr->is_literal ())
207+
{
208+
// We have to expand an inner macro eagerly
209+
auto token_tree = invoc.get_delim_tok_tree ();
210+
211+
// parse_single_string_literal returned an AST::MacroInvocation, which
212+
// can either be an AST::Item or AST::Expr. Depending on the context the
213+
// original macro was invoked in, we will set AST::Item or AST::Expr
214+
// appropriately.
215+
if (is_semicoloned)
216+
{
217+
std::unique_ptr<AST::Item> lit_item = std::unique_ptr<AST::Item> (
218+
static_cast<AST::MacroInvocation *> (lit_expr.release ()));
219+
return AST::Fragment ({AST::SingleASTNode (std::move (lit_item))},
220+
token_tree.to_token_stream ());
221+
}
222+
else
223+
return AST::Fragment ({AST::SingleASTNode (std::move (lit_expr))},
224+
token_tree.to_token_stream ());
225+
}
201226

202227
std::string filename
203228
= source_relative_path (lit_expr->as_string (), invoc_locus);
@@ -218,8 +243,14 @@ MacroBuiltin::include_handler (location_t invoc_locus,
218243

219244
Lexer lex (target_filename, std::move (target_file), linemap);
220245
Parser<Lexer> parser (lex);
246+
std::unique_ptr<AST::Expr> parsed_expr = nullptr;
247+
std::vector<std::unique_ptr<AST::Item>> parsed_items{};
248+
249+
if (is_semicoloned)
250+
parsed_items = parser.parse_items ();
251+
else
252+
parsed_expr = parser.parse_expr ();
221253

222-
auto parsed_items = parser.parse_items ();
223254
bool has_error = !parser.get_errors ().empty ();
224255

225256
for (const auto &error : parser.get_errors ())
@@ -233,17 +264,22 @@ MacroBuiltin::include_handler (location_t invoc_locus,
233264
}
234265

235266
std::vector<AST::SingleASTNode> nodes{};
236-
for (auto &item : parsed_items)
267+
if (is_semicoloned)
268+
for (auto &item : parsed_items)
269+
{
270+
AST::SingleASTNode node (std::move (item));
271+
nodes.push_back (node);
272+
}
273+
else
237274
{
238-
AST::SingleASTNode node (std::move (item));
275+
AST::SingleASTNode node (std::move (parsed_expr));
239276
nodes.push_back (node);
240277
}
241-
242278
// FIXME: This returns an empty vector of tokens and works fine, but is that
243279
// the expected behavior? `include` macros are a bit harder to reason about
244280
// since they include tokens. Furthermore, our lexer has no easy way to return
245281
// a slice of tokens like the MacroInvocLexer. So it gets even harder to
246-
// extrac tokens from here. For now, let's keep it that way and see if it
282+
// extract tokens from here. For now, let's keep it that way and see if it
247283
// eventually breaks, but I don't expect it to cause many issues since the
248284
// list of tokens is only used when a macro invocation mixes eager
249285
// macro invocations and already expanded tokens. Think

gcc/rust/expand/rust-macro-expand.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,12 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc,
250250
}
251251

252252
if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
253-
expand_eager_invocations (invoc);
253+
{
254+
// Eager expansions are always expressions
255+
push_context (ContextType::EXPR);
256+
expand_eager_invocations (invoc);
257+
pop_context ();
258+
}
254259

255260
AST::MacroInvocData &invoc_data = invoc.get_invoc_data ();
256261

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(rustc_attrs)]
2+
3+
#[rustc_builtin_macro]
4+
macro_rules! include {
5+
() => {};
6+
}
7+
8+
include!("include_rs");
9+
10+
fn main() -> i32 {
11+
b();
12+
13+
0
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![feature(rustc_attrs)]
2+
3+
#[rustc_builtin_macro]
4+
macro_rules! include {
5+
() => {};
6+
}
7+
8+
fn main() -> i32 {
9+
let _ = include!("include_rs2");
10+
0
11+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![feature(rustc_attrs)]
2+
3+
#[rustc_builtin_macro]
4+
macro_rules! include {
5+
() => {};
6+
}
7+
8+
macro_rules! my_file {
9+
() => {"include_rs"};
10+
}
11+
12+
13+
include!(my_file!());
14+
15+
fn main() -> i32 {
16+
b();
17+
18+
0
19+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(rustc_attrs)]
2+
3+
#[rustc_builtin_macro]
4+
macro_rules! include {
5+
() => {};
6+
}
7+
8+
macro_rules! my_file {
9+
() => {"include_rs2"};
10+
}
11+
fn main() -> i32 {
12+
let _ = include!(my_file!());
13+
14+
0
15+
}

gcc/testsuite/rust/compile/macros/builtin/include_bytes.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,19 @@ macro_rules! include_bytes {
55
() => {{}};
66
}
77

8+
macro_rules! file1 {
9+
() => {"file"};
10+
}
11+
12+
static MY_FILE: &[u32;16] = include_bytes!(file!());
13+
814
fn main() {
915
let file = "include.txt";
1016
include_bytes!(file); // { dg-error "argument must be a string literal" "" }
1117
include_bytes!(); // { dg-error "macro takes 1 argument" "" }
1218
include_bytes!("foo.txt", "bar.txt"); // { dg-error "macro takes 1 argument" "" }
1319
include_bytes!("include_bytes.rs"); // ok
1420
include_bytes!("include_bytes.rs",); // trailing comma ok
21+
include_bytes! (file1!());
22+
include_bytes! (file1!(),); // trailing comma ok
1523
}

0 commit comments

Comments
 (0)