aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Avery <powerboat9.gamer@gmail.com>2023-05-28 13:33:52 -0400
committerPhilip Herron <philip.herron@embecosm.com>2023-05-30 08:36:00 +0000
commit019dd7b55ff05854569bc7e271a8b695e4c27065 (patch)
treec4d29695b754de2958bab8ad4a5ca61c884682df
parent0162ff3900ae032958d16c0a4af6c76ca3dd4335 (diff)
downloadgcc-019dd7b55ff05854569bc7e271a8b695e4c27065.zip
gcc-019dd7b55ff05854569bc7e271a8b695e4c27065.tar.gz
gcc-019dd7b55ff05854569bc7e271a8b695e4c27065.tar.bz2
Avoid invalid metavariable substitutions
gcc/rust/ChangeLog: * expand/rust-macro-substitute-ctx.cc (SubstituteCtx::substitute_metavar): Allow substitution failure. (SubstituteCtx::substitute_token): Handle substitution failure, include dollar sign in count of tokens to substitute. (SubstituteCtx::substitute_tokens): Include dollar sign in count of tokens to substitute. * expand/rust-macro-substitute-ctx.h (SubstituteCtx::substitute_metavar): Adjust signature and document new substitution failure handling. gcc/testsuite/ChangeLog: * rust/compile/issue-2225.rs: New test. Signed-off-by: Owen Avery <powerboat9.gamer@gmail.com>
-rw-r--r--gcc/rust/expand/rust-macro-substitute-ctx.cc49
-rw-r--r--gcc/rust/expand/rust-macro-substitute-ctx.h9
-rw-r--r--gcc/testsuite/rust/compile/issue-2225.rs14
3 files changed, 46 insertions, 26 deletions
diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.cc b/gcc/rust/expand/rust-macro-substitute-ctx.cc
index 85c9d7e..84df2c2 100644
--- a/gcc/rust/expand/rust-macro-substitute-ctx.cc
+++ b/gcc/rust/expand/rust-macro-substitute-ctx.cc
@@ -2,17 +2,18 @@
namespace Rust {
-std::vector<std::unique_ptr<AST::Token>>
-SubstituteCtx::substitute_metavar (std::unique_ptr<AST::Token> &metavar)
+bool
+SubstituteCtx::substitute_metavar (
+ std::unique_ptr<AST::Token> &metavar,
+ std::vector<std::unique_ptr<AST::Token>> &expanded)
{
auto metavar_name = metavar->get_str ();
- std::vector<std::unique_ptr<AST::Token>> expanded;
auto it = fragments.find (metavar_name);
if (it == fragments.end ())
{
- // Return a copy of the original token
- expanded.push_back (metavar->clone_token ());
+ // fail to substitute
+ return false;
}
else
{
@@ -28,7 +29,7 @@ SubstituteCtx::substitute_metavar (std::unique_ptr<AST::Token> &metavar)
metavar->get_locus (),
"you probably forgot the repetition operator: %<%s%s%s%>", "$(",
metavar->as_string ().c_str (), ")*");
- return expanded;
+ return true;
}
// We only care about the vector when expanding repetitions.
@@ -42,7 +43,7 @@ SubstituteCtx::substitute_metavar (std::unique_ptr<AST::Token> &metavar)
}
}
- return expanded;
+ return true;
}
bool
@@ -209,14 +210,17 @@ SubstituteCtx::substitute_token (size_t token_idx)
if (token_id_is_keyword (token->get_id ()))
{
case IDENTIFIER:
+ std::vector<std::unique_ptr<AST::Token>> expanded;
+
rust_debug ("expanding metavar: %s", token->get_str ().c_str ());
- return {substitute_metavar (token), 1};
+
+ if (substitute_metavar (token, expanded))
+ return {std::move (expanded), 2};
}
- rust_error_at (token->get_locus (),
- "unexpected token in macro transcribe: expected "
- "%<(%> or identifier after %<$%>, got %<%s%>",
- get_token_description (token->get_id ()));
- break;
+
+ // don't substitute, dollar sign is alone/metavar is unknown
+ return {std::vector<std::unique_ptr<AST::Token>> (), 0};
+
case LEFT_PAREN: {
// We need to parse up until the closing delimiter and expand this
// fragment->n times.
@@ -285,17 +289,11 @@ SubstituteCtx::substitute_token (size_t token_idx)
return {substitute_repetition (pattern_start, pattern_end,
std::move (separator_token)),
- pattern_end - pattern_start + to_skip};
+ pattern_end - pattern_start + to_skip + 1};
}
- // TODO: We need to check if the $ was alone. In that case, do
- // not error out: Simply act as if there was an empty identifier
- // with no associated fragment and paste the dollar sign in the
- // transcription. Unsure how to do that since we always have at
- // least the closing curly brace after an empty $...
}
- // FIXME: gcc_unreachable() error case?
- return {std::vector<std::unique_ptr<AST::Token>> (), 0};
+ gcc_unreachable ();
}
std::vector<std::unique_ptr<AST::Token>>
@@ -304,7 +302,7 @@ SubstituteCtx::substitute_tokens ()
std::vector<std::unique_ptr<AST::Token>> replaced_tokens;
rust_debug ("expanding tokens");
- for (size_t i = 0; i < macro.size (); i++)
+ for (size_t i = 0; i < macro.size ();)
{
auto &tok = macro.at (i);
if (tok->get_id () == DOLLAR_SIGN)
@@ -315,6 +313,12 @@ SubstituteCtx::substitute_tokens ()
auto expanded = std::move (p.first);
auto tok_to_skip = p.second;
+ if (!tok_to_skip)
+ {
+ replaced_tokens.emplace_back (tok->clone_token ());
+ tok_to_skip++;
+ }
+
i += tok_to_skip;
for (auto &token : expanded)
@@ -323,6 +327,7 @@ SubstituteCtx::substitute_tokens ()
else
{
replaced_tokens.emplace_back (tok->clone_token ());
+ i++;
}
}
diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.h b/gcc/rust/expand/rust-macro-substitute-ctx.h
index a4f8beb..d8e4e31 100644
--- a/gcc/rust/expand/rust-macro-substitute-ctx.h
+++ b/gcc/rust/expand/rust-macro-substitute-ctx.h
@@ -49,12 +49,13 @@ public:
* i.e. replacing $var with the associated fragment.
*
* @param metavar Metavariable to try and replace
+ * @param expanded Reference to a vector upon which expanded tokens will be
+ * pushed
*
- * @return A token containing the associated fragment expanded into tokens if
- * any, or the cloned token if no fragment was associated
+ * @return True iff the substitution succeeded
*/
- std::vector<std::unique_ptr<AST::Token>>
- substitute_metavar (std::unique_ptr<AST::Token> &metavar);
+ bool substitute_metavar (std::unique_ptr<AST::Token> &metavar,
+ std::vector<std::unique_ptr<AST::Token>> &expanded);
/**
* Substitute a macro repetition by its given fragments
diff --git a/gcc/testsuite/rust/compile/issue-2225.rs b/gcc/testsuite/rust/compile/issue-2225.rs
new file mode 100644
index 0000000..53757c1
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2225.rs
@@ -0,0 +1,14 @@
+macro_rules! foo {
+ ($_:tt) => {};
+ () => {foo!($);};
+}
+
+macro_rules! bar {
+ () => {let $_a = 12;} // { dg-error "unrecognised token" }
+}
+
+pub fn main() -> i32 {
+ foo!();
+ bar!();
+ 0
+}