Skip to content

Commit 6e78326

Browse files
committed
Fortran: Improve OpenMP/OpenACC syntax diagnostic
The way the OpenMP and OpenACC parser is written is such that when the directive name has been successfully matched, any error returned by the match function should be real. However, 'match_word' resets he locus to the before-match locus such that all information is lost, except that error vs. no match data is still available. Thus, for OpenMP and OpenACC, the error often was Unclassifiable OpenMP directive at (1) which is odd when knowing that one used a supported directive; that the caret pointed to the directive name did not really help, either. With this commit, the match errors for OpenMP and OpenACC yield the following error if no buffered message exists: Syntax error in statement at (1) pointing the the current locus. (Still, a more explicit error would be better, e.g. for many errors in 'omp declare reduction', but still better than previously.) gcc/fortran/ChangeLog: * parse.cc (match_word): Add no_substring and reject_stmt_on_error arguments, defaulting to false and true, respectively. (match_word_omp_simd): Do not reject_statement on error and enable no-substring matching. (matcha, matcho, matchdo): Call match_word with no_substring set to true and reject_stmt_on_error set to false. (decode_omp_directive): Distinguish unknown directive name from errors found during matching. (decode_oacc_directive): Likewise; use matcha not match. (matcha, matcho, matchdo, matchs, matchds): #undef after use. gcc/testsuite/ChangeLog: * gfortran.dg/goacc/asyncwait-4.f95: Update dg-error. * gfortran.dg/goacc/routine-6.f90: Likewise. * gfortran.dg/gomp/udr1.f90: Likewise. * gfortran.dg/gomp/udr2.f90: Likewise. * gfortran.dg/gomp/udr4.f90: Likewise. * gfortran.dg/gomp/declare-reduction-2.f90: New test.
1 parent 3377399 commit 6e78326

7 files changed

Lines changed: 123 additions & 77 deletions

File tree

gcc/fortran/parse.cc

Lines changed: 103 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -72,23 +72,39 @@ static void reject_statement (void);
7272
input with the passed string. If this succeeds, we call the
7373
keyword-dependent matching function that will match the rest of the
7474
statement. For single keywords, the matching subroutine is
75-
gfc_match_eos(). */
75+
gfc_match_eos().
76+
77+
If NO_SUBSTRING, the keyword must be followed by a character not
78+
permitted in a name (for free form); EOF is not handled here. Due
79+
to fixed-form Fortran, longer keywords still need to be matched
80+
before shorter substrings.
81+
82+
If REJECT_STMT_ON_ERROR is false, it is assumed that no error
83+
recovery handling is needed. */
7684

7785
static match
78-
match_word (const char *str, match (*subr) (void), locus *old_locus)
86+
match_word (const char *str, match (*subr) (void), locus *old_locus,
87+
bool no_substring = false, bool reject_stmt_on_error = true)
7988
{
8089
match m;
90+
char c;
8191

8292
if (str != NULL)
8393
{
8494
m = gfc_match (str);
8595
if (m != MATCH_YES)
8696
return m;
97+
if (no_substring && gfc_current_form == FORM_FREE
98+
&& ((c = gfc_peek_ascii_char ()) == '_' || c == '$' || ISALNUM (c)))
99+
{
100+
gfc_current_locus = *old_locus;
101+
return MATCH_NO;
102+
}
87103
}
88104

89105
m = (*subr) ();
90106

91-
if (m != MATCH_YES)
107+
if (m == MATCH_NO || (reject_stmt_on_error && m == MATCH_ERROR))
92108
{
93109
gfc_current_locus = *old_locus;
94110
reject_statement ();
@@ -99,24 +115,33 @@ match_word (const char *str, match (*subr) (void), locus *old_locus)
99115

100116

101117
/* Like match_word, but if str is matched, set a flag that it
102-
was matched. */
118+
was matched. Note that reject_statement() is not called if
119+
SUBR returned a match error - and no substring matching is
120+
assumed. */
103121
static match
104122
match_word_omp_simd (const char *str, match (*subr) (void), locus *old_locus,
105123
bool *simd_matched)
106124
{
107125
match m;
126+
char c;
108127

109128
if (str != NULL)
110129
{
111130
m = gfc_match (str);
112131
if (m != MATCH_YES)
113132
return m;
133+
if (gfc_current_form == FORM_FREE
134+
&& ((c = gfc_peek_ascii_char ()) == '_' || c == '$' || ISALNUM (c)))
135+
{
136+
gfc_current_locus = *old_locus;
137+
return MATCH_NO;
138+
}
114139
*simd_matched = true;
115140
}
116141

117142
m = (*subr) ();
118143

119-
if (m != MATCH_YES)
144+
if (m == MATCH_NO)
120145
{
121146
gfc_current_locus = *old_locus;
122147
reject_statement ();
@@ -677,21 +702,20 @@ decode_statement (void)
677702
}
678703

679704
/* Like match and if spec_only, goto do_spec_only without actually
680-
matching. */
681-
/* If the directive matched but the clauses failed, do not start
682-
matching the next directive in the same switch statement. */
683-
#define matcha(keyword, subr, st) \
684-
do { \
685-
match m2; \
686-
if (spec_only && gfc_match (keyword) == MATCH_YES) \
687-
goto do_spec_only; \
688-
else if ((m2 = match_word (keyword, subr, &old_locus)) \
689-
== MATCH_YES) \
690-
return st; \
691-
else if (m2 == MATCH_ERROR) \
692-
goto error_handling; \
693-
else \
694-
undo_new_statement (); \
705+
matching. If the directive matched but the parsing then failed,
706+
do not start matching the next directive in the same switch statement. */
707+
#define matcha(keyword, subr, st) \
708+
do { \
709+
match m2; \
710+
if (spec_only && gfc_match (keyword) == MATCH_YES) \
711+
goto do_spec_only; \
712+
else if ((m2 = match_word (keyword, subr, &old_locus, true, \
713+
false)) == MATCH_YES) \
714+
return st; \
715+
else if (m2 == MATCH_ERROR) \
716+
goto error_handling; \
717+
else \
718+
undo_new_statement (); \
695719
} while (0)
696720

697721
static gfc_statement
@@ -745,7 +769,7 @@ decode_oacc_directive (void)
745769
break;
746770
case 'd':
747771
matcha ("data", gfc_match_oacc_data, ST_OACC_DATA);
748-
match ("declare", gfc_match_oacc_declare, ST_OACC_DECLARE);
772+
matcha ("declare", gfc_match_oacc_declare, ST_OACC_DECLARE);
749773
break;
750774
case 'e':
751775
matcha ("end atomic", gfc_match_omp_eos_error, ST_OACC_END_ATOMIC);
@@ -791,17 +815,19 @@ decode_oacc_directive (void)
791815
break;
792816
}
793817

794-
/* Directive not found or stored an error message.
795-
Check and give up. */
818+
/* Directive not found. */
819+
gfc_error_now ("Unclassifiable OpenACC directive at %C");
820+
goto recover;
796821

822+
/* Directive found but failed with an error, possibly with
823+
a stored an error message. */
797824
error_handling:
798825
if (gfc_error_check () == 0)
799-
gfc_error_now ("Unclassifiable OpenACC directive at %C");
826+
gfc_error_now ("Syntax error in statement at %C");
800827

828+
recover:
801829
reject_statement ();
802-
803830
gfc_error_recovery ();
804-
805831
return ST_NONE;
806832

807833
do_spec_only:
@@ -812,6 +838,8 @@ decode_oacc_directive (void)
812838
return ST_GET_FCN_CHARACTERISTICS;
813839
}
814840

841+
#undef matcha
842+
815843
/* Checks for the ST_OMP_ALLOCATE. First, check whether all list items
816844
are allocatables/pointers - and if so, assume it is associated with a Fortran
817845
ALLOCATE stmt. If not, do some initial parsing-related checks and append
@@ -911,23 +939,23 @@ check_omp_allocate_stmt (locus *loc)
911939
and if spec_only, goto do_spec_only without actually matching. */
912940
/* If the directive matched but the clauses failed, do not start
913941
matching the next directive in the same switch statement. */
914-
#define matcho(keyword, subr, st) \
915-
do { \
916-
match m2; \
917-
if (!flag_openmp) \
918-
; \
919-
else if (spec_only && gfc_match (keyword) == MATCH_YES) \
920-
goto do_spec_only; \
921-
else if ((m2 = match_word (keyword, subr, &old_locus)) \
922-
== MATCH_YES) \
923-
{ \
924-
ret = st; \
925-
goto finish; \
926-
} \
927-
else if (m2 == MATCH_ERROR) \
928-
goto error_handling; \
929-
else \
930-
undo_new_statement (); \
942+
#define matcho(keyword, subr, st) \
943+
do { \
944+
match m2; \
945+
if (!flag_openmp) \
946+
; \
947+
else if (spec_only && gfc_match (keyword) == MATCH_YES) \
948+
goto do_spec_only; \
949+
else if ((m2 = match_word (keyword, subr, &old_locus, true, \
950+
false)) == MATCH_YES) \
951+
{ \
952+
ret = st; \
953+
goto finish; \
954+
} \
955+
else if (m2 == MATCH_ERROR) \
956+
goto error_handling; \
957+
else \
958+
undo_new_statement (); \
931959
} while (0)
932960

933961
/* Like match, but set a flag simd_matched if keyword matched. */
@@ -947,21 +975,21 @@ check_omp_allocate_stmt (locus *loc)
947975
} while (0)
948976

949977
/* Like match, but don't match anything if not -fopenmp. */
950-
#define matchdo(keyword, subr, st) \
951-
do { \
952-
match m2; \
953-
if (!flag_openmp) \
954-
; \
955-
else if ((m2 = match_word (keyword, subr, &old_locus)) \
956-
== MATCH_YES) \
957-
{ \
958-
ret = st; \
959-
goto finish; \
960-
} \
961-
else if (m2 == MATCH_ERROR) \
962-
goto error_handling; \
963-
else \
964-
undo_new_statement (); \
978+
#define matchdo(keyword, subr, st) \
979+
do { \
980+
match m2; \
981+
if (!flag_openmp) \
982+
; \
983+
else if ((m2 = match_word (keyword, subr, &old_locus, true, \
984+
false)) == MATCH_YES) \
985+
{ \
986+
ret = st; \
987+
goto finish; \
988+
} \
989+
else if (m2 == MATCH_ERROR) \
990+
goto error_handling; \
991+
else \
992+
undo_new_statement (); \
965993
} while (0)
966994

967995
static gfc_statement
@@ -1330,17 +1358,20 @@ decode_omp_directive (void)
13301358
break;
13311359
}
13321360

1333-
/* All else has failed, so give up. See if any of the matchers has
1334-
stored an error message of some sort. Don't error out if
1335-
not -fopenmp and simd_matched is false, i.e. if a directive other
1336-
than one marked with match has been seen. */
1361+
/* Directive not found. Don't error out if not -fopenmp and
1362+
simd_matched is false, i.e. if a directive other than one marked
1363+
with match has been seen. */
1364+
if (flag_openmp || simd_matched)
1365+
gfc_error_now ("Unclassifiable OpenMP directive at %C");
1366+
goto recover;
13371367

13381368
error_handling:
1339-
if (flag_openmp || simd_matched)
1340-
{
1341-
if (!gfc_error_check ())
1342-
gfc_error_now ("Unclassifiable OpenMP directive at %C");
1343-
}
1369+
/* Directive found but failed with an error, possibly with
1370+
a stored an error message. */
1371+
if ((flag_openmp || simd_matched) && gfc_error_check () == 0)
1372+
gfc_error_now ("Syntax error in statement at %C");
1373+
1374+
recover:
13441375

13451376
/* If parsing a metadirective, let the caller deal with the cleanup. */
13461377
if (gfc_matching_omp_context_selector)
@@ -1467,6 +1498,11 @@ decode_omp_directive (void)
14671498
return ST_GET_FCN_CHARACTERISTICS;
14681499
}
14691500

1501+
#undef matchs
1502+
#undef matcho
1503+
#undef matchds
1504+
#undef matchdo
1505+
14701506
gfc_statement
14711507
match_omp_directive (void)
14721508
{

gcc/testsuite/gfortran.dg/goacc/asyncwait-4.f95

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ program asyncwait
3535

3636
!$acc wait async 1 ! { dg-error "Failed to match clause" }
3737

38-
!$acc waitasync ! { dg-error "Failed to match clause" }
38+
!$acc waitasync ! { dg-error "Unclassifiable OpenACC directive" }
3939

4040
!$acc wait,async ! { dg-error "Failed to match clause" }
4141
end program asyncwait

gcc/testsuite/gfortran.dg/goacc/routine-6.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ end program main
6363
! Ensure that we recover from incomplete function definitions.
6464

6565
integer function f1 ! { dg-error "Expected formal argument list in function definition" }
66-
!$acc routine ! { dg-error "Unclassifiable OpenACC directive" }
66+
!$acc routine ! { dg-error "16: Syntax error in statement" }
6767
end function f1 ! { dg-error "Expecting END PROGRAM statement" }
6868

6969
subroutine subr1 (x)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
! Ensure that a someone sensible error message is printed
2+
3+
type t
4+
end type t
5+
!$omp declare reduction(+:t)
6+
! { dg-error "28: Syntax error in statement at .1." "" { target *-*-* } .-1 }
7+
! { dg-bogus "Unclassifiable OpenMP directive" "" { target *-*-* } .-2 }
8+
9+
10+
end

gcc/testsuite/gfortran.dg/gomp/udr1.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ subroutine f2
2222
end do
2323
end subroutine f2
2424
subroutine f3
25-
!$omp declare reduction (foo:blah:omp_out=omp_out + omp_in) ! { dg-error "Unclassifiable OpenMP directive" }
25+
!$omp declare reduction (foo:blah:omp_out=omp_out + omp_in) ! { dg-error "30: Syntax error in statement at .1." }
2626
end subroutine f3
2727
subroutine f4
2828
!$omp declare reduction (foo:integer:a => null()) ! { dg-error "Invalid character in name" }

gcc/testsuite/gfortran.dg/gomp/udr2.f90

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
! { dg-do compile }
22

33
subroutine f6
4-
!$omp declare reduction (foo:real:omp_out (omp_in)) ! { dg-error "Unclassifiable OpenMP directive" }
5-
!$omp declare reduction (bar:real:omp_out = omp_in * omp_out) & ! { dg-error "Unclassifiable OpenMP directive" }
4+
!$omp declare reduction (foo:real:omp_out (omp_in)) ! { dg-error "35: Syntax error in statement at .1." }
5+
!$omp declare reduction (bar:real:omp_out = omp_in * omp_out) & ! { dg-error "35: Syntax error in statement at .1." }
66
!$omp & initializer (omp_priv (omp_orig))
77
end subroutine f6
88
subroutine f7
99
integer :: a
10-
!$omp declare reduction (foo:integer:a (omp_out, omp_in)) ! { dg-error "Unclassifiable OpenMP directive" }
10+
!$omp declare reduction (foo:integer:a (omp_out, omp_in)) ! { dg-error "38: Syntax error in statement at .1." }
1111
!$omp declare reduction (bar:real:omp_out = omp_out.or.omp_in) ! { dg-error "Operands of logical operator" }
1212
!$omp declare reduction (baz:real:omp_out = omp_out + omp_in)
1313
!$omp & initializer (a (omp_priv, omp_orig)) ! { dg-error "Unclassifiable OpenMP directive" }

gcc/testsuite/gfortran.dg/gomp/udr4.f90

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
! { dg-do compile }
22

33
subroutine f3
4-
!$omp declare reduction ! { dg-error "Unclassifiable OpenMP directive" }
5-
!$omp declare reduction foo ! { dg-error "Unclassifiable OpenMP directive" }
6-
!$omp declare reduction (foo) ! { dg-error "Unclassifiable OpenMP directive" }
7-
!$omp declare reduction (foo:integer) ! { dg-error "Unclassifiable OpenMP directive" }
4+
!$omp declare reduction ! { dg-error "24: Syntax error in statement at .1." }
5+
!$omp declare reduction foo ! { dg-error "24: Syntax error in statement at .1." }
6+
!$omp declare reduction (foo) ! { dg-error "26: Syntax error in statement at .1." }
7+
!$omp declare reduction (foo:integer) ! { dg-error "37: Syntax error in statement at .1." }
88
!$omp declare reduction (foo:integer:omp_out=omp_out+omp_in) &
99
!$omp & initializer(omp_priv=0) initializer(omp_priv=0) ! { dg-error "Unexpected junk after" }
1010
end subroutine f3

0 commit comments

Comments
 (0)