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
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fn b() {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"Gccrs is GREAT!"

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

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

8+
macro_rules! my_file {
9+
() => {"include.txt"}
10+
}
11+
12+
static G_STR:[u8;16] = include_str!(my_file!());
13+
814
fn main() {
915
let file = "include.txt";
1016
include_str!(file); // { dg-error "argument must be a string literal" "" }
@@ -13,4 +19,6 @@ fn main() {
1319
include_str!("include_str.rs"); // ok
1420
include_str!("include_str.rs",); // trailing comma ok
1521
include_str!("invalid_utf8"); // { dg-error "invalid_utf8 was not a valid utf-8 file" "" }
22+
include_str!(my_file!());
23+
include_str!(my_file!(),);
1624
}
Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
// { dg-output "104\r*\n33\r*\n1\r*\n" }
1+
// { dg-output "1\r*\n1\r*\n1\r*\n" }
2+
23
#![feature(rustc_attrs)]
34

45
#[rustc_builtin_macro]
56
macro_rules! include_bytes {
67
() => {{}};
78
}
89

10+
macro_rules! my_file {
11+
() => {"include.txt"};
12+
}
13+
914
extern "C" {
1015
fn printf(s: *const i8, ...);
1116
}
@@ -17,32 +22,30 @@ fn print_int(value: i32) {
1722
}
1823
}
1924

20-
fn main() -> i32 {
21-
let bytes = include_bytes!("include.txt");
22-
23-
print_int(bytes[0] as i32);
24-
print_int(bytes[14] as i32);
25-
25+
fn check_bytes(bytes: &[u8; 16]) {
2626
let the_bytes = b"hello, include!\n";
2727

28-
let x = bytes[0] == the_bytes[0]
29-
&& bytes[1] == the_bytes[1]
30-
&& bytes[2] == the_bytes[2]
31-
&& bytes[3] == the_bytes[3]
32-
&& bytes[4] == the_bytes[4]
33-
&& bytes[5] == the_bytes[5]
34-
&& bytes[6] == the_bytes[6]
35-
&& bytes[7] == the_bytes[7]
36-
&& bytes[8] == the_bytes[8]
37-
&& bytes[9] == the_bytes[9]
38-
&& bytes[10] == the_bytes[10]
39-
&& bytes[11] == the_bytes[11]
40-
&& bytes[12] == the_bytes[12]
41-
&& bytes[13] == the_bytes[13]
42-
&& bytes[14] == the_bytes[14]
43-
&& bytes[15] == the_bytes[15];
28+
let x = true;
29+
let mut i = 0;
30+
31+
// X is true iff bytes == the_bytes
32+
while i < 16 {
33+
x = x && (bytes[i] == the_bytes[i]);
34+
i += 1;
35+
}
4436

4537
print_int(x as i32);
38+
}
39+
40+
fn main() -> i32 {
41+
let bytes1: &'static [u8; 16] = include_bytes!("include.txt");
42+
check_bytes(bytes1);
43+
44+
let bytes2: &'static [u8; 16] = include_bytes!(my_file!());
45+
check_bytes(bytes2);
46+
47+
let bytes3 = include_bytes!(my_file!(),);
48+
check_bytes(bytes3);
4649

4750
0
4851
}

gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
// { dg-output "hello, include!\r*\n" }
1+
// { dg-output "hello, include!\r*\nhello, include!\r*\nhello, include!\r*\n" }
22
#![feature(rustc_attrs)]
33

44
#[rustc_builtin_macro]
55
macro_rules! include_str {
66
() => {{}};
77
}
88

9+
macro_rules! my_file {
10+
() => {"include.txt"};
11+
}
12+
913
extern "C" {
1014
fn printf(fmt: *const i8, ...);
1115
}
@@ -22,7 +26,10 @@ fn print(s: &str) {
2226
fn main() -> i32 {
2327
// include_str! (and include_bytes!) allow for an optional trailing comma.
2428
let my_str = include_str!("include.txt",);
25-
29+
print(my_str);
30+
let my_str = include_str!(my_file!());
31+
print(my_str);
32+
let my_str = include_str!(my_file!(),);
2633
print(my_str);
2734

2835
0

0 commit comments

Comments
 (0)