From d8d42618b4dc2f653887b7723b17d1f6bf4e8f63 Mon Sep 17 00:00:00 2001
From: Mark Eggleston <markeggleston@codethink.com>
Date: Fri, 30 Aug 2019 11:08:26 +0100
Subject: [PATCH] Character typenames in errors and warnings
Character type names now incorporate length, kind is only shown if
the default character is not being used.
Examples:
character(7) is reported as CHARACTER(7)
character(len=20,kind=4) is reported as CHARACTER(20,4)
dummy character variables with assumed length:
character(*) is reported as CHARACTER(*)
character(*,kind=4) is reported as CHARACTER(*,4)
---
gcc/fortran/arith.c | 1 +
gcc/fortran/expr.c | 1 +
gcc/fortran/gfortran.h | 2 +
gcc/fortran/interface.c | 10 +--
gcc/fortran/intrinsic.c | 11 ++--
gcc/fortran/misc.c | 41 +++++++++++-
gcc/testsuite/gfortran.dg/bad_operands.f90 | 10 +++
gcc/testsuite/gfortran.dg/character_mismatch.f90 | 76 ++++++++++++++++++++++
gcc/testsuite/gfortran.dg/compare_interfaces.f90 | 73 +++++++++++++++++++++
.../gfortran.dg/widechar_intrinsics_1.f90 | 12 ++--
.../gfortran.dg/widechar_intrinsics_2.f90 | 10 +--
.../gfortran.dg/widechar_intrinsics_3.f90 | 4 +-
12 files changed, 228 insertions(+), 23 deletions(-)
create mode 100644 gcc/testsuite/gfortran.dg/bad_operands.f90
create mode 100644 gcc/testsuite/gfortran.dg/character_mismatch.f90
create mode 100644 gcc/testsuite/gfortran.dg/compare_interfaces.f90
@@ -1005,6 +1005,7 @@ gfc_arith_concat (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp)
result->value.character.string = gfc_get_wide_string (len + 1);
result->value.character.length = len;
+ result->ts.length = len;
memcpy (result->value.character.string, op1->value.character.string,
op1->value.character.length * sizeof (gfc_char_t));
@@ -203,6 +203,7 @@ gfc_get_character_expr (int kind, locus *where, const char *src, gfc_charlen_t l
where ? where : &gfc_current_locus);
e->value.character.string = dest;
e->value.character.length = len;
+ e->ts.length = len;
return e;
}
@@ -1032,6 +1032,7 @@ typedef struct
{
bt type;
int kind;
+ int length; /* For type name reporting. */
union
{
@@ -2880,6 +2881,7 @@ void gfc_end_source_files (void);
void gfc_clear_ts (gfc_typespec *);
FILE *gfc_open_file (const char *);
const char *gfc_basic_typename (bt);
+const char *gfc_dummy_typename (gfc_typespec *);
const char *gfc_typename (gfc_typespec *);
const char *gfc_op2string (gfc_intrinsic_op);
const char *gfc_code2string (const mstring *, int);
@@ -1330,7 +1330,8 @@ gfc_check_dummy_characteristics (gfc_symbol *s1, gfc_symbol *s2,
|| !compare_type_characteristics (s2, s1))
{
snprintf (errmsg, err_len, "Type mismatch in argument '%s' (%s/%s)",
- s1->name, gfc_typename (&s1->ts), gfc_typename (&s2->ts));
+ s1->name, gfc_dummy_typename (&s1->ts),
+ gfc_dummy_typename (&s2->ts));
return false;
}
if (!compare_rank (s1, s2))
@@ -2313,9 +2314,10 @@ compare_parameter (gfc_symbol *formal, gfc_expr *actual,
{
if (where)
gfc_error_opt (OPT_Wargument_mismatch,
- "Type mismatch in argument %qs at %L; passed %s to %s",
- formal->name, where, gfc_typename (&actual->ts),
- gfc_typename (&formal->ts));
+ "Type mismatch in argument %qs at %L; passed %s "
+ "to %s", formal->name, where,
+ gfc_typename (&actual->ts),
+ gfc_dummy_typename (&formal->ts));
return false;
}
@@ -4363,11 +4363,12 @@ check_arglist (gfc_actual_arglist **ap, gfc_intrinsic_sym *sym,
if (!gfc_compare_types (&ts, &actual->expr->ts))
{
if (error_flag)
- gfc_error ("Type of argument %qs in call to %qs at %L should "
- "be %s, not %s", gfc_current_intrinsic_arg[i]->name,
- gfc_current_intrinsic, &actual->expr->where,
- gfc_typename (&formal->ts),
- gfc_typename (&actual->expr->ts));
+ gfc_error ("In call to %qs at %L, type mismatch in argument "
+ "%qs; pass %qs to %qs", gfc_current_intrinsic,
+ &actual->expr->where,
+ gfc_current_intrinsic_arg[i]->name,
+ gfc_typename (&actual->expr->ts),
+ gfc_dummy_typename (&formal->ts));
return false;
}
@@ -129,6 +129,7 @@ gfc_typename (gfc_typespec *ts)
static int flag = 0;
char *buffer;
gfc_typespec *ts1;
+ int length = ts->length;
buffer = flag ? buffer1 : buffer2;
flag = !flag;
@@ -148,7 +149,12 @@ gfc_typename (gfc_typespec *ts)
sprintf (buffer, "LOGICAL(%d)", ts->kind);
break;
case BT_CHARACTER:
- sprintf (buffer, "CHARACTER(%d)", ts->kind);
+ if (ts->u.cl && ts->u.cl->length)
+ length = mpz_get_si (ts->u.cl->length->value.integer);
+ if (ts->kind == gfc_default_character_kind)
+ sprintf (buffer, "CHARACTER(%d)", length);
+ else
+ sprintf (buffer, "CHARACTER(%d,%d)", length, ts->kind);
break;
case BT_HOLLERITH:
sprintf (buffer, "HOLLERITH");
@@ -186,6 +192,39 @@ gfc_typename (gfc_typespec *ts)
}
+/* The type of a dummy variable can also be CHARACTER(*). */
+
+const char *
+gfc_dummy_typename (gfc_typespec *ts)
+{
+ static char buffer1[15]; /* 15 for "CHARACTER(*,4)" + '\0'. */
+ static char buffer2[15];
+ static int flag = 0;
+ char *buffer;
+
+ buffer = flag ? buffer1 : buffer2;
+ flag = !flag;
+
+ if (ts->type == BT_CHARACTER)
+ {
+ bool has_length = false;
+ if (ts->u.cl)
+ has_length = ts->u.cl->length != NULL;
+ if (!has_length)
+ {
+ if (ts->kind == gfc_default_character_kind)
+ sprintf(buffer, "CHARACTER(*)");
+ else if (ts->kind < 10)
+ sprintf(buffer, "CHARACTER(*,%d)", ts->kind);
+ else
+ sprintf(buffer, "CHARACTER(*,?)");
+ return buffer;
+ }
+ }
+ return gfc_typename(ts);
+}
+
+
/* Given an mstring array and a code, locate the code in the table,
returning a pointer to the string. */
new file mode 100644
@@ -0,0 +1,10 @@
+! { dg-do compile }
+!
+! Test case contributed by Mark Eggleston <mark.eggleston@codethink.com>
+
+program test
+ integer(4) :: x
+
+ x = x // "rubbish" ! { dg-error "INTEGER\\(4\\)/CHARACTER\\(7\\)" }
+ x = 4_"more rubbish" + 6 ! { dg-error "CHARACTER\\(12,4\\)/INTEGER\\(4\\)" }
+end program
new file mode 100644
@@ -0,0 +1,76 @@
+! { dg-do compile }
+!
+! Test case contributed by Mark Eggleston <mark.eggleston@codethink.com>
+
+program test
+ use iso_fortran_env
+ implicit none
+ integer, parameter :: ucs4 = selected_char_kind('ISO_10646')
+ integer :: x
+ character(len=7) :: s = "abcd123"
+ character(4, ucs4) :: s4 = char(int(z'20ac'), ucs4) // ucs4_"100"
+
+ x = s
+ x = "string"
+ x = "A longer string" // " plus a bit"
+ x = s // s
+ x = s // "a bit more"
+ x = "prefix:" // s
+ x = s4
+ x = ucs4_"string"
+ x = ucs4_"A longer string" // ucs4_" plus a bit"
+ x = s4 // s4
+ x = s4 // ucs4_"a bit more"
+ x = ucs4_"prefix:" // s4
+
+ call f(s)
+ call f("string")
+ call f("A longer string" // " plus a bit")
+ call f(s // s)
+ call f(s // "a bit more")
+ call f("a string:" // s)
+
+ call f(s4)
+ call f(ucs4_"string")
+ call f(ucs4_"A longer string" // ucs4_" plus a bit")
+ call f(s4 // s4)
+ call f(s4 // ucs4_"a bit more")
+ call f(ucs4_"a string:" // s4)
+
+ write(*,*) "" // ucs4_""
+
+contains
+ subroutine f(y)
+ integer, intent(in) :: y
+
+ write(*,*) y
+ end subroutine f
+
+end program
+
+! { dg-error "CHARACTER\\(7\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 13 }
+! { dg-error "CHARACTER\\(6\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 14 }
+! { dg-error "CHARACTER\\(26\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 15 }
+! { dg-error "CHARACTER\\(14\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 16 }
+! { dg-error "CHARACTER\\(17\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 17 }
+! { dg-error "CHARACTER\\(14\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 18 }
+! { dg-error "CHARACTER\\(4,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 19 }
+! { dg-error "CHARACTER\\(6,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 20 }
+! { dg-error "CHARACTER\\(26,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 21 }
+! { dg-error "CHARACTER\\(8,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 22 }
+! { dg-error "CHARACTER\\(14,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 23 }
+! { dg-error "CHARACTER\\(11,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 24 }
+! { dg-error "CHARACTER\\(7\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 26 }
+! { dg-error "CHARACTER\\(6\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 27 }
+! { dg-error "CHARACTER\\(26\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 28 }
+! { dg-error "CHARACTER\\(14\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 29 }
+! { dg-error "CHARACTER\\(17\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 30 }
+! { dg-error "CHARACTER\\(16\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 31 }
+! { dg-error "CHARACTER\\(4,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 33 }
+! { dg-error "CHARACTER\\(6,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 34 }
+! { dg-error "CHARACTER\\(26,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 35 }
+! { dg-error "CHARACTER\\(8,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 36 }
+! { dg-error "CHARACTER\\(14,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 37 }
+! { dg-error "CHARACTER\\(13,4\\) to INTEGER\\(4\\)" "type mismatch" { target \*-\*-\* } 38 }
+! { dg-error "CHARACTER\\(0\\)/CHARACTER\\(0,4\\)" "operand type mismatch" { target \*-\*-\* } 40 }
+
new file mode 100644
@@ -0,0 +1,73 @@
+! { dg-do compile }
+!
+! Contributed by Mark Eggleston <mark.eggleston@codethink.co.uk>
+
+subroutine f(a, b)
+ integer :: a
+ real :: b
+
+ write(*,*) a, b
+end subroutine
+
+subroutine g(a, b)
+ integer :: a
+ character(*) :: b
+
+ write(*,*) a, b
+end subroutine
+
+subroutine h
+ interface
+ subroutine f(a, b) ! { dg-error "\\(CHARACTER\\(\\*\\)/REAL\\(4\\)\\)" }
+ integer :: a
+ character(*) :: b
+ end subroutine
+ subroutine g(a, b) ! { dg-error "\\(REAL\\(4\\)/CHARACTER\\(\\*\\)\\)" }
+ integer :: a
+ real :: b
+ end subroutine
+ end interface
+
+ call f(6, 6.0)
+ call g(6, "abcdef")
+end subroutine
+
+subroutine f4(a, b)
+ integer :: a
+ real :: b
+
+ write(*,*) a, b
+end subroutine
+
+subroutine g4(a, b)
+ integer :: a
+ character(*,4) :: b
+
+ write(*,*) a, b
+end subroutine
+
+subroutine h4
+ interface
+ subroutine f4(a, b) ! { dg-error "\\(CHARACTER\\(\\*,4\\)/REAL\\(4\\)\\)" }
+ integer :: a
+ character(*,4) :: b
+ end subroutine
+ subroutine g4(a, b) ! { dg-error "REAL\\(4\\)/CHARACTER\\(\\*,4\\)" }
+ integer :: a
+ real :: b
+ end subroutine
+ end interface
+
+ call f4(6, 6.0)
+ call g4(6, 4_"abcdef")
+end subroutine
+
+program test
+ call h
+ call h4
+end program
+
+! { dg-error "passed REAL\\(4\\) to CHARACTER\\(\\*\\)" "type mismatch" { target \*-\*-\* } 31 }
+! { dg-error "passed CHARACTER\\(6\\) to REAL\\(4\\)" "type mismatch" { target \*-\*-\* } 32 }
+! { dg-error "passed REAL\\(4\\) to CHARACTER\\(\\*,4\\)" "type mismatch" { target \*-\*-\* } 61 }
+! { dg-error "passed CHARACTER\\(6,4\\) to REAL\\(4\\)" "type mismatch" { target \*-\*-\* } 62 }
@@ -15,18 +15,18 @@
call date_and_time(s4, t4, u4) ! { dg-error "must be of kind 1" }
call get_command(s1)
- call get_command(s4) ! { dg-error "Type of argument" }
+ call get_command(s4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" }
call get_command_argument(1, s1)
- call get_command_argument(1, s4) ! { dg-error "Type of argument" }
+ call get_command_argument(1, s4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" }
call get_environment_variable("PATH", s1)
call get_environment_variable(s1)
call get_environment_variable(s1, t1)
- call get_environment_variable(4_"PATH", s1) ! { dg-error "Type of argument" }
- call get_environment_variable(s4) ! { dg-error "Type of argument" }
- call get_environment_variable(s1, t4) ! { dg-error "Type of argument" }
- call get_environment_variable(s4, t1) ! { dg-error "Type of argument" }
+ call get_environment_variable(4_"PATH", s1) ! { dg-error "'CHARACTER\\(4,4\\)' to 'CHARACTER\\(\\*\\)'" }
+ call get_environment_variable(s4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" }
+ call get_environment_variable(s1, t4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" }
+ call get_environment_variable(s4, t1) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" }
print *, lge(s1,t1)
print *, lge(s1,"foo")
@@ -38,9 +38,9 @@ program failme
call getcwd (s4, i) ! { dg-error "must be of kind" }
call getenv (s1, t1)
- call getenv (s1, t4) ! { dg-error "Type of argument" }
- call getenv (s4, t1) ! { dg-error "Type of argument" }
- call getenv (s4, t4) ! { dg-error "Type of argument" }
+ call getenv (s1, t4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" }
+ call getenv (s4, t1) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" }
+ call getenv (s4, t4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" }
call getarg (i, s1)
call getarg (i, s4) ! { dg-error "must be of kind" }
@@ -115,8 +115,8 @@ program failme
call system (s1)
call system (s1, i)
- call system (s4) ! { dg-error "Type of argument" }
- call system (s4, i) ! { dg-error "Type of argument" }
+ call system (s4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" }
+ call system (s4, i) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" }
call ttynam (i, s1)
call ttynam (i, s4) ! { dg-error "must be of kind" }
@@ -35,7 +35,7 @@ program failme
print *, fputc (i, s4) ! { dg-error "must be of kind" }
print *, getcwd (s1)
- print *, getcwd (s4) ! { dg-error "Type of argument" }
+ print *, getcwd (s4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" }
print *, hostnm (s1)
print *, hostnm (s4) ! { dg-error "must be of kind" }
@@ -61,7 +61,7 @@ program failme
print *, symlnk (s4, t4) ! { dg-error "must be of kind" }
print *, system (s1)
- print *, system (s4) ! { dg-error "Type of argument" }
+ print *, system (s4) ! { dg-error "'CHARACTER\\(20,4\\)' to 'CHARACTER\\(\\*\\)'" }
print *, unlink (s1)
print *, unlink (s4) ! { dg-error "must be of kind" }
--
2.11.0