1054: Fix overzealous follow set ambiguity r=CohenArthur a=CohenArthur

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.

Closes #1053 
Addresses #947 

Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
This commit is contained in:
bors[bot] 2022-03-24 15:58:07 +00:00 committed by GitHub
commit 3a90596517
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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