diff options
author | Owen Avery <powerboat9.gamer@gmail.com> | 2023-05-28 13:33:52 -0400 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2023-05-30 08:36:00 +0000 |
commit | 019dd7b55ff05854569bc7e271a8b695e4c27065 (patch) | |
tree | c4d29695b754de2958bab8ad4a5ca61c884682df /gcc | |
parent | 0162ff3900ae032958d16c0a4af6c76ca3dd4335 (diff) | |
download | gcc-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>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/expand/rust-macro-substitute-ctx.cc | 49 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-substitute-ctx.h | 9 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/issue-2225.rs | 14 |
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 +} |