aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/ast/rust-macro.cc
diff options
context:
space:
mode:
authorArthur Cohen <arthur.cohen@embecosm.com>2023-01-18 12:23:37 +0100
committerArthur Cohen <arthur.cohen@embecosm.com>2023-02-08 12:02:54 +0100
commitc6db68ee151234eb7fead8e6631273bbe5302277 (patch)
tree40a40cfe7eae0a0c24b5912c8a6d23fb5263ff47 /gcc/rust/ast/rust-macro.cc
parentb9501cbe2624a80365e33550fc92035620a64e7b (diff)
downloadgcc-c6db68ee151234eb7fead8e6631273bbe5302277.zip
gcc-c6db68ee151234eb7fead8e6631273bbe5302277.tar.gz
gcc-c6db68ee151234eb7fead8e6631273bbe5302277.tar.bz2
macros: Perform macro expansion in a fixed-point fashion.
This commit changes our macro expansion system from an eager and recursive macro expansion to a fixed-point like system. Instead of, when seeing a macro invocation, expanding it and all of the macros within it, we now perform multiple passes of expansion on the entire crate. This, however, leads to a problem. Rust macros are expanded lazily, but Rust builtin macros should be expanded eagerly. Due to this, we must work around the lazy expansion in builtin macros and perform eager expansion for each pass of the fixed-point, before finally expanding the builtin when there are no longer any inner macro invocations. To perform proper macro scoping, the ENR now keeps track of the current scope (`current_scope` member) and resolves macros accordingly. This is done through the use of the `scoped` method, which creates a new scope, runs a specified lambda and then exits the scope. This prevents pushing/popping errors that we've seen happen already in similar contexts. We might think about generalizing it to other classes, providing a `Scoped<EntryFn, ExitFn>` class or similar gcc/rust/ChangeLog: * ast/rust-macro.cc: New file. * Make-lang.in: Add `rust-macro.o` object * ast/rust-ast-fragment.cc (Fragment::Fragment): Change API around the construction of AST fragments. (Fragment::operator=): Correct `Fragment::operator=` to take into account the fragment tokens. (Fragment::create_error): Use new constructor. (Fragment::complete): Remove in favor of new constructor. (Fragment::unexpanded): Remove as that Fragment type is no longer used or possible. (Fragment::get_tokens): Add helper to access a fragment's tokens. * ast/rust-ast-fragment.h (enum class): Remove `FragmentKind::Unused` * ast/rust-ast.cc (MacroInvocation::as_string): Display builtin macro invocations properly. * ast/rust-ast.h: Fix `DelimTokenTree` class copy constructors and handling of its token vector. * ast/rust-macro.h (class MacroMatcher): Format. (class MetaItemSeq): Likewise. (builtin_macro_from_string): Get a `BuiltinMacroKind` from a given string, i.e the name of the macro (`assert!`, `cfg!` and so on). * expand/rust-attribute-visitor.cc (AttrVisitor::visit): Do not expand macros recursively anymore. (AttrVisitor::maybe_expand_expr): Likewise. (AttrVisitor::maybe_expand_type): Likewise. * expand/rust-attribute-visitor.h: Likewise, and remove `expand_macro_fragment_recursively` function. * expand/rust-macro-builtins.cc (make_token): Add shorthand for returning `std::unique_ptr<AST::Token>`s. (make_macro_invocation): Add shorthand for returning fragments containing builtin macro invocations. (try_expand_macro_expression): Do not expand macros recursively. (try_expand_single_string_literal): Likewise. (try_expand_many_expr): Likewise. (parse_single_string_literal): Error out more appropriately. (MacroBuiltin::file_handler): Return the proper tokens associated with macro invocation, and builtin macros in the case of necessary eager expansion. (MacroBuiltin::column_handler): Likewise. (MacroBuiltin::include_bytes_handler): Likewise. (MacroBuiltin::include_str_handler): Likewise. (MacroBuiltin::concat_handler): Likewise. (MacroBuiltin::env_handler): Likewise. (MacroBuiltin::cfg_handler): Likewise. (MacroBuiltin::include_handler): Likewise. (MacroBuiltin::line_handler): Likewise. * expand/rust-macro-expand.cc (MacroExpander::expand_eager_invocations): Add function to expand eager invocations *once* in the fixed point pipeline. (MacroExpander::expand_invoc): Call into `expand_eager_invocations` for builtin macro invocations. (MacroExpander::expand_crate): Use new `AttrVisitor` API. (parse_many): Return tokens in `AST::Fragment`. (transcribe_expression): Likewise. (transcribe_type): Likewise. * expand/rust-macro-expand.h (struct MacroExpander): Add `has_changed` flag for fixed point checking. * resolve/rust-early-name-resolver.cc (EarlyNameResolver::EarlyNameResolver): Keep track of the current macro scope. (EarlyNameResolver::go): Use `scoped` API. (EarlyNameResolver::visit): Likewise. * resolve/rust-early-name-resolver.h: Add `scoped` API. * rust-session-manager.cc (Session::expansion): Perform macro expansion in a fixed-point fashion. gcc/testsuite/ChangeLog: * rust/compile/macro17.rs: Fix testsuite for new recursion errors. * rust/compile/macro44.rs: Fix invalid testcase assertions. * rust/compile/builtin_macro_recurse.rs: Fix invalid test. * rust/compile/builtin_macro_recurse2.rs: New test. * rust/compile/macro46.rs: New test.
Diffstat (limited to 'gcc/rust/ast/rust-macro.cc')
-rw-r--r--gcc/rust/ast/rust-macro.cc64
1 files changed, 64 insertions, 0 deletions
diff --git a/gcc/rust/ast/rust-macro.cc b/gcc/rust/ast/rust-macro.cc
new file mode 100644
index 0000000..b90cc15
--- /dev/null
+++ b/gcc/rust/ast/rust-macro.cc
@@ -0,0 +1,64 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-macro.h"
+
+namespace Rust {
+namespace AST {
+
+BuiltinMacro
+builtin_macro_from_string (const std::string &identifier)
+{
+ if (identifier == "assert")
+ return BuiltinMacro::Assert;
+
+ if (identifier == "file")
+ return BuiltinMacro::File;
+
+ if (identifier == "line")
+ return BuiltinMacro::Line;
+
+ if (identifier == "column")
+ return BuiltinMacro::Column;
+
+ if (identifier == "include_bytes")
+ return BuiltinMacro::IncludeBytes;
+
+ if (identifier == "include_str")
+ return BuiltinMacro::IncludeStr;
+
+ if (identifier == "compile_error")
+ return BuiltinMacro::CompileError;
+
+ if (identifier == "concat")
+ return BuiltinMacro::Concat;
+
+ if (identifier == "env")
+ return BuiltinMacro::Env;
+
+ if (identifier == "cfg")
+ return BuiltinMacro::Cfg;
+
+ if (identifier == "include")
+ return BuiltinMacro::Include;
+
+ gcc_unreachable ();
+}
+
+} // namespace AST
+} // namespace Rust