From 7136063b1a7a591994cd8b16cf482caa12ba5fc7 Mon Sep 17 00:00:00 2001 From: fxcoudert Date: Sun, 29 Jun 2014 14:14:16 +0000 Subject: [PATCH] PR fortran/36275 PR fortran/38839 * decl.c (check_bind_name_identifier): New function. (gfc_match_bind_c): Match any constant expression as binding label. * match.c (gfc_match_name_C): Remove. * gfortran.dg/binding_label_tests_2.f03: Adjust error messages. * gfortran.dg/binding_label_tests_27.f90: New file. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@212123 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/fortran/ChangeLog | 9 ++ gcc/fortran/decl.c | 113 ++++++++++++++------- gcc/fortran/match.c | 93 ----------------- gcc/testsuite/ChangeLog | 7 ++ .../gfortran.dg/binding_label_tests_2.f03 | 21 ++-- .../gfortran.dg/binding_label_tests_27.f90 | 27 +++++ 6 files changed, 131 insertions(+), 139 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/binding_label_tests_27.f90 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index a5f6f9d529d..5ebf40b3b2e 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,12 @@ +2014-06-29 Francois-Xavier Coudert + + PR fortran/36275 + PR fortran/38839 + * decl.c (check_bind_name_identifier): New function. + (gfc_match_bind_c): Match any constant expression as binding + label. + * match.c (gfc_match_name_C): Remove. + 2014-06-28 Francois-Xavier Coudert PR fortran/29383 diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c index 4048ac91353..7f7428156e3 100644 --- a/gcc/fortran/decl.c +++ b/gcc/fortran/decl.c @@ -5779,6 +5779,54 @@ gfc_match_subroutine (void) } +/* Check that the NAME identifier in a BIND attribute or statement + is conform to C identifier rules. */ + +match +check_bind_name_identifier (char **name) +{ + char *n = *name, *p; + + /* Remove leading spaces. */ + while (*n == ' ') + n++; + + /* On an empty string, free memory and set name to NULL. */ + if (*n == '\0') + { + free (*name); + *name = NULL; + return MATCH_YES; + } + + /* Remove trailing spaces. */ + p = n + strlen(n) - 1; + while (*p == ' ') + *(p--) = '\0'; + + /* Insert the identifier into the symbol table. */ + p = xstrdup (n); + free (*name); + *name = p; + + /* Now check that identifier is valid under C rules. */ + if (ISDIGIT (*p)) + { + gfc_error ("Invalid C identifier in NAME= specifier at %C"); + return MATCH_ERROR; + } + + for (; *p; p++) + if (!(ISALNUM (*p) || *p == '_' || *p == '$')) + { + gfc_error ("Invalid C identifier in NAME= specifier at %C"); + return MATCH_ERROR; + } + + return MATCH_YES; +} + + /* Match a BIND(C) specifier, with the optional 'name=' specifier if given, and set the binding label in either the given symbol (if not NULL), or in the current_ts. The symbol may be NULL because we may @@ -5793,10 +5841,8 @@ gfc_match_subroutine (void) match gfc_match_bind_c (gfc_symbol *sym, bool allow_binding_name) { - /* binding label, if exists */ - const char* binding_label = NULL; - match double_quote; - match single_quote; + char *binding_label = NULL; + gfc_expr *e = NULL; /* Initialize the flag that specifies whether we encountered a NAME= specifier or not. */ @@ -5821,44 +5867,37 @@ gfc_match_bind_c (gfc_symbol *sym, bool allow_binding_name) has_name_equals = 1; - /* Get the opening quote. */ - double_quote = MATCH_YES; - single_quote = MATCH_YES; - double_quote = gfc_match_char ('"'); - if (double_quote != MATCH_YES) - single_quote = gfc_match_char ('\''); - if (double_quote != MATCH_YES && single_quote != MATCH_YES) - { - gfc_error ("Syntax error in NAME= specifier for binding label " - "at %C"); - return MATCH_ERROR; - } - - /* Grab the binding label, using functions that will not lower - case the names automatically. */ - if (gfc_match_name_C (&binding_label) != MATCH_YES) - return MATCH_ERROR; + if (gfc_match_init_expr (&e) != MATCH_YES) + { + gfc_free_expr (e); + return MATCH_ERROR; + } - /* Get the closing quotation. */ - if (double_quote == MATCH_YES) + if (!gfc_simplify_expr(e, 0)) { - if (gfc_match_char ('"') != MATCH_YES) - { - gfc_error ("Missing closing quote '\"' for binding label at %C"); - /* User started string with '"' so looked to match it. */ - return MATCH_ERROR; - } + gfc_error ("NAME= specifier at %C should be a constant expression"); + gfc_free_expr (e); + return MATCH_ERROR; } - else + + if (e->expr_type != EXPR_CONSTANT || e->ts.type != BT_CHARACTER + || e->ts.kind != gfc_default_character_kind || e->rank != 0) { - if (gfc_match_char ('\'') != MATCH_YES) - { - gfc_error ("Missing closing quote '\'' for binding label at %C"); - /* User started string with "'" char. */ - return MATCH_ERROR; - } + gfc_error ("NAME= specifier at %C should be a scalar of " + "default character kind"); + gfc_free_expr(e); + return MATCH_ERROR; } - } + + // Get a C string from the Fortran string constant + binding_label = gfc_widechar_to_char (e->value.character.string, + e->value.character.length); + gfc_free_expr(e); + + // Check that it is valid (old gfc_match_name_C) + if (check_bind_name_identifier (&binding_label) != MATCH_YES) + return MATCH_ERROR; + } /* Get the required right paren. */ if (gfc_match_char (')') != MATCH_YES) diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c index b3f47a8e73e..84e2764e131 100644 --- a/gcc/fortran/match.c +++ b/gcc/fortran/match.c @@ -569,99 +569,6 @@ gfc_match_name (char *buffer) } -/* Match a valid name for C, which is almost the same as for Fortran, - except that you can start with an underscore, etc.. It could have - been done by modifying the gfc_match_name, but this way other - things C allows can be done, such as no limits on the length. - Also, by rewriting it, we use the gfc_next_char_C() to prevent the - input characters from being automatically lower cased, since C is - case sensitive. The parameter, buffer, is used to return the name - that is matched. Return MATCH_ERROR if the name is not a valid C - name, MATCH_NO if what we're seeing isn't a name, and MATCH_YES if - we successfully match a C name. */ - -match -gfc_match_name_C (const char **buffer) -{ - locus old_loc; - size_t i = 0; - gfc_char_t c; - char* buf; - size_t cursz = 16; - - old_loc = gfc_current_locus; - gfc_gobble_whitespace (); - - /* Get the next char (first possible char of name) and see if - it's valid for C (either a letter or an underscore). */ - c = gfc_next_char_literal (INSTRING_WARN); - - /* If the user put nothing expect spaces between the quotes, it is valid - and simply means there is no name= specifier and the name is the Fortran - symbol name, all lowercase. */ - if (c == '"' || c == '\'') - { - gfc_current_locus = old_loc; - return MATCH_YES; - } - - if (!ISALPHA (c) && c != '_') - { - gfc_error ("Invalid C name in NAME= specifier at %C"); - return MATCH_ERROR; - } - - buf = XNEWVEC (char, cursz); - /* Continue to read valid variable name characters. */ - do - { - gcc_assert (gfc_wide_fits_in_byte (c)); - - buf[i++] = (unsigned char) c; - - if (i >= cursz) - { - cursz *= 2; - buf = XRESIZEVEC (char, buf, cursz); - } - - old_loc = gfc_current_locus; - - /* Get next char; param means we're in a string. */ - c = gfc_next_char_literal (INSTRING_WARN); - } while (ISALNUM (c) || c == '_'); - - /* The binding label will be needed later anyway, so just insert it - into the symbol table. */ - buf[i] = '\0'; - *buffer = IDENTIFIER_POINTER (get_identifier (buf)); - XDELETEVEC (buf); - gfc_current_locus = old_loc; - - /* See if we stopped because of whitespace. */ - if (c == ' ') - { - gfc_gobble_whitespace (); - c = gfc_peek_ascii_char (); - if (c != '"' && c != '\'') - { - gfc_error ("Embedded space in NAME= specifier at %C"); - return MATCH_ERROR; - } - } - - /* If we stopped because we had an invalid character for a C name, report - that to the user by returning MATCH_NO. */ - if (c != '"' && c != '\'') - { - gfc_error ("Invalid C name in NAME= specifier at %C"); - return MATCH_ERROR; - } - - return MATCH_YES; -} - - /* Match a symbol on the input. Modifies the pointer to the symbol pointer if successful. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 879a8443359..86276d9bd38 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2014-06-29 Francois-Xavier Coudert + + PR fortran/36275 + PR fortran/38839 + * gfortran.dg/binding_label_tests_2.f03: Adjust error messages. + * gfortran.dg/binding_label_tests_27.f90: New file. + 2014-06-29 Andreas Schwab * gfortran.dg/ieee/ieee_6.f90: Allow inexact together with diff --git a/gcc/testsuite/gfortran.dg/binding_label_tests_2.f03 b/gcc/testsuite/gfortran.dg/binding_label_tests_2.f03 index 46bbbbd04ce..c2ec632d10d 100644 --- a/gcc/testsuite/gfortran.dg/binding_label_tests_2.f03 +++ b/gcc/testsuite/gfortran.dg/binding_label_tests_2.f03 @@ -7,25 +7,28 @@ contains subroutine ok() end subroutine ok - subroutine sub0() bind(c, name=" 1") ! { dg-error "Invalid C name" } + subroutine sub0() bind(c, name=" 1") ! { dg-error "Invalid C identifier" } end subroutine sub0 ! { dg-error "Expecting END MODULE" } - subroutine sub1() bind(c, name="$") ! { dg-error "Invalid C name" } - end subroutine sub1 ! { dg-error "Expecting END MODULE" } + subroutine sub1() bind(c, name="$") + end subroutine sub1 - subroutine sub2() bind(c, name="abc$") ! { dg-error "Invalid C name" } - end subroutine sub2 ! { dg-error "Expecting END MODULE" } + subroutine sub2() bind(c, name="abc$") + end subroutine sub2 - subroutine sub3() bind(c, name="abc d") ! { dg-error "Embedded space" } + subroutine sub3() bind(c, name="abc d") ! { dg-error "Invalid C identifier" } end subroutine sub3 ! { dg-error "Expecting END MODULE" } - subroutine sub5() BIND(C, name=" myvar 2 ") ! { dg-error "Embedded space" } + subroutine sub4() bind(c, name="2foo") ! { dg-error "Invalid C identifier" } + end subroutine sub4 ! { dg-error "Expecting END MODULE" } + + subroutine sub5() BIND(C, name=" myvar 2 ") ! { dg-error "Invalid C identifier" } end subroutine sub5 ! { dg-error "Expecting END MODULE" } - subroutine sub6() bind(c, name=" ) ! { dg-error "Invalid C name" } + subroutine sub6() bind(c, name=" ) ! { dg-error "Invalid C identifier" } end subroutine sub6 ! { dg-error "Expecting END MODULE" } - subroutine sub7() bind(c, name=) ! { dg-error "Syntax error" } + subroutine sub7() bind(c, name=) ! { dg-error "Invalid character" } end subroutine sub7 ! { dg-error "Expecting END MODULE" } subroutine sub8() bind(c, name) ! { dg-error "Syntax error" } diff --git a/gcc/testsuite/gfortran.dg/binding_label_tests_27.f90 b/gcc/testsuite/gfortran.dg/binding_label_tests_27.f90 new file mode 100644 index 00000000000..b0cd74e5cd0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/binding_label_tests_27.f90 @@ -0,0 +1,27 @@ +! { dg-do compile } + +module p + + implicit none + integer i1, i2, i3, i4, i5, i6, i7, i8, i9, i10 + + character(len=*), parameter :: s = "toto" + character(len=*), parameter :: t(2) = ["x", "y"] + + bind(c,name=" foo ") :: i1 + bind(c, name=trim("Hello ") // "There") :: i2 + bind(c, name=1_"name") :: i3 + bind(c, name=4_"") :: i4 ! { dg-error "scalar of default character kind" } + bind(c, name=1) :: i5 ! { dg-error "scalar of default character kind" } + bind(c, name=1.0) :: i6 ! { dg-error "scalar of default character kind" } + bind(c, name=["","",""]) :: i7 ! { dg-error "scalar of default character kind" } + bind(c, name=s) :: i8 + bind(c, name=t(2)) :: i9 + +end module + +subroutine foobar(s) + character(len=*) :: s + integer :: i + bind(c, name=s) :: i ! { dg-error "constant expression" } +end subroutine -- 2.11.4.GIT