macros: Allow repetitions of tokens in follow-set in follow-set

When checking if a follow-up is valid, we previously always returned
false when comparing with MacroMatchRepetitions. This is however
invalid, as we should be comparing with the first match of the
repetition to be sure.
This commit is contained in:
Arthur Cohen 2022-03-23 16:50:47 +01:00
parent 8283724bc2
commit d859ab0146
4 changed files with 36 additions and 27 deletions

View File

@ -100,6 +100,30 @@ contains (std::vector<T> &vec, T elm)
return std::find (vec.begin (), vec.end (), elm) != vec.end ();
}
/**
* Avoid UB by calling .front() and .back() on empty containers...
*/
template <typename T>
static T *
get_back_ptr (std::vector<std::unique_ptr<T>> &values)
{
if (values.empty ())
return nullptr;
return values.back ().get ();
}
template <typename T>
static T *
get_front_ptr (std::vector<std::unique_ptr<T>> &values)
{
if (values.empty ())
return nullptr;
return values.front ().get ();
}
static bool
peculiar_fragment_match_compatible_fragment (
const AST::MacroFragSpec &last_spec, const AST::MacroFragSpec &spec,
@ -196,8 +220,9 @@ peculiar_fragment_match_compatible (AST::MacroMatchFragment &last_match,
case AST::MacroMatch::Repetition: {
auto repetition = static_cast<AST::MacroMatchRepetition *> (&match);
auto &matches = repetition->get_matches ();
if (!matches.empty ())
error_locus = matches.front ()->get_match_locus ();
auto first_frag = get_front_ptr (matches);
if (first_frag)
return peculiar_fragment_match_compatible (last_match, *first_frag);
break;
}
case AST::MacroMatch::Matcher: {
@ -231,30 +256,6 @@ peculiar_fragment_match_compatible (AST::MacroMatchFragment &last_match,
return false;
}
/**
* Avoid UB by calling .front() and .back() on empty containers...
*/
template <typename T>
static T *
get_back_ptr (std::vector<std::unique_ptr<T>> &values)
{
if (values.empty ())
return nullptr;
return values.back ().get ();
}
template <typename T>
static T *
get_front_ptr (std::vector<std::unique_ptr<T>> &values)
{
if (values.empty ())
return nullptr;
return values.front ().get ();
}
bool
is_match_compatible (AST::MacroMatch &last_match, AST::MacroMatch &match)
{

View File

@ -0,0 +1,5 @@
macro_rules! m {
($e:expr $(forbidden)*) => {{}}; // { dg-error "token .identifier. is not allowed after .expr. fragment" }
// { dg-error "required first macro rule in macro rules definition could not be parsed" "" { target *-*-* } .-1 }
// { dg-error "failed to parse item in crate" "" { target *-*-* } .-2 }
}

View File

@ -0,0 +1,3 @@
macro_rules! m {
($e:expr $(,)*) => {{}};
}

View File

@ -1,6 +1,6 @@
macro_rules! m {
($a:expr $(tok $es:expr)*) => {
// { dg-error "fragment is not allowed after .expr. fragment" "" { target *-*-* } .-1 }
// { dg-error "token .identifier. is not allowed after .expr. fragment" "" { target *-*-* } .-1 }
// { dg-error "required first macro rule in macro rules definition could not be parsed" "" { target *-*-* } .-2 }
// { dg-error "failed to parse item in crate" "" { target *-*-* } .-3 }
$a