[PATCH] Fix debug info when compiling preprocessed fortran sources (.F, .F90, .F95)
Jakub Jelinek
jakub@redhat.com
Sat Dec 31 12:52:00 GMT 2005
Hi!
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=175071
Given say
echo ' END' > D.F
gfortran -g -dA -S -o D.s D.F
gfortran outputs incorrect debug info, referencing the temporary
preprocessed source as the actual source file rather than the original
file. This patch changes specs so that when preprocessing a Fortran
source, new -fpreprocessed flag is passed to f951 and f951 then immitates
what libcpp's cpp_read_main_file and read_original_filename do, i.e.
in post_options lang hook read the original filename and current directory
from the preprocessed Fortran source.
On this particular file the assembly difference is:
- .ascii "/tmp/ccIn9mww.f\0" # DW_AT_name
+ .ascii "D.F\0" # DW_AT_name
(plus changes due to different debug info sizes), but it might change
the current directory in DW_AT_comp_dir too in certain cases:
.ascii "/usr/src/gcc/obj/gcc\0" # DW_AT_comp_dir
(e.g. when the preprocessing and compilation happens separately, with
different current directories).
It also fixes handling of say
# 1 "abc\"de.f"
and
# 1 "abc\\de.f"
Bootstrapped/regtested on i386-linux/trunk, bootstrap/regression testing
on x86_64-linux/trunk and ppc64-linux/4.1 in progress.
Ok for 4.1/trunk if testing succeeds?
2005-12-31 Jakub Jelinek <jakub@redhat.com>
* Make-lang.in (fortran/scanner.o): Depend on toplev.h.
* lang.opt (fpreprocessed): New option.
* scanner.c: Include toplev.h.
(gfc_src_file, gfc_src_preprocessor_lines): New variables.
(preprocessor_line): Unescape filename if there were any
backslashes.
(load_file): If initial and gfc_src_file is not NULL,
use it rather than opening the file. If gfc_src_preprocessor_lines
has non-NULL elements, pass it to preprocessor_line.
(unescape_filename, gfc_read_orig_filename): New functions.
* gfortran.h (gfc_option_t): Add flag_preprocessed.
(gfc_read_orig_filename): New prototype.
* options.c (gfc_init_options): Clear flag_preprocessed.
(gfc_post_options): If flag_preprocessed, call
gfc_read_orig_filename.
(gfc_handle_option): Handle OPT_fpreprocessed.
* lang-specs.h: Pass -fpreprocessed to f951 if preprocessing
sources.
--- gcc/fortran/Make-lang.in.jj 2005-12-13 08:47:45.000000000 +0100
+++ gcc/fortran/Make-lang.in 2005-12-31 01:01:57.000000000 +0100
@@ -269,6 +269,7 @@ GFORTRAN_TRANS_DEPS = fortran/gfortran.h
fortran/f95-lang.o: $(GFORTRAN_TRANS_DEPS) fortran/mathbuiltins.def \
gt-fortran-f95-lang.h gtype-fortran.h cgraph.h $(TARGET_H)
+fortran/scanner.o: toplev.h
fortran/convert.o: $(GFORTRAN_TRANS_DEPS)
fortran/trans.o: $(GFORTRAN_TRANS_DEPS)
fortran/trans-decl.o: $(GFORTRAN_TRANS_DEPS) gt-fortran-trans-decl.h \
--- gcc/fortran/lang.opt.jj 2005-12-12 11:57:24.000000000 +0100
+++ gcc/fortran/lang.opt 2005-12-29 16:23:28.000000000 +0100
@@ -173,6 +173,10 @@ frepack-arrays
Fortran
Copy array sections into a contiguous block on procedure entry
+fpreprocessed
+Fortran
+Treat the input file as preprocessed
+
qkind=
Fortran RejectNegative Joined UInteger
-qkind=<n> Set the kind for a real with the 'q' exponent to 'n'
--- gcc/fortran/scanner.c.jj 2005-12-02 23:46:26.000000000 +0100
+++ gcc/fortran/scanner.c 2005-12-31 01:12:17.000000000 +0100
@@ -45,6 +45,7 @@ Software Foundation, 51 Franklin Street,
#include "config.h"
#include "system.h"
#include "gfortran.h"
+#include "toplev.h"
/* Structure for holding module and include file search path. */
typedef struct gfc_directorylist
@@ -66,7 +67,9 @@ static gfc_linebuf *line_head, *line_tai
locus gfc_current_locus;
const char *gfc_source_file;
-
+static FILE *gfc_src_file;
+static char *gfc_src_preprocessor_lines[2];
+
/* Main scanner initialization. */
@@ -859,7 +862,7 @@ preprocessor_line (char *c)
int i, line;
char *filename;
gfc_file *f;
- int escaped;
+ int escaped, unescape;
c++;
while (*c == ' ' || *c == '\t')
@@ -890,13 +893,17 @@ preprocessor_line (char *c)
filename = c;
/* Make filename end at quote. */
+ unescape = 0;
escaped = false;
while (*c && ! (! escaped && *c == '"'))
{
if (escaped)
escaped = false;
- else
- escaped = *c == '\\';
+ else if (*c == '\\')
+ {
+ escaped = true;
+ unescape++;
+ }
++c;
}
@@ -906,7 +913,23 @@ preprocessor_line (char *c)
*c++ = '\0';
+ /* Undo effects of cpp_quote_string. */
+ if (unescape)
+ {
+ char *s = filename;
+ char *d = gfc_getmem (c - filename - unescape);
+ filename = d;
+ while (*s)
+ {
+ if (*s == '\\')
+ *d++ = *++s;
+ else
+ *d++ = *s;
+ s++;
+ }
+ *d = '\0';
+ }
/* Get flags. */
@@ -942,6 +965,8 @@ preprocessor_line (char *c)
gfc_warning_now ("%s:%d: file %s left but not entered",
current_file->filename, current_file->line,
filename);
+ if (unescape)
+ gfc_free (filename);
return;
}
current_file = current_file->up;
@@ -959,6 +984,8 @@ preprocessor_line (char *c)
/* Set new line number. */
current_file->line = line;
+ if (unescape)
+ gfc_free (filename);
return;
bad_cpp_line:
@@ -1043,7 +1070,13 @@ load_file (const char *filename, bool in
if (initial)
{
- input = gfc_open_file (filename);
+ if (gfc_src_file)
+ {
+ input = gfc_src_file;
+ gfc_src_file = NULL;
+ }
+ else
+ input = gfc_open_file (filename);
if (input == NULL)
{
gfc_error_now ("Can't open file '%s'", filename);
@@ -1069,6 +1102,19 @@ load_file (const char *filename, bool in
line = NULL;
line_len = 0;
+ if (initial && gfc_src_preprocessor_lines[0])
+ {
+ preprocessor_line (gfc_src_preprocessor_lines[0]);
+ gfc_free (gfc_src_preprocessor_lines[0]);
+ gfc_src_preprocessor_lines[0] = NULL;
+ if (gfc_src_preprocessor_lines[1])
+ {
+ preprocessor_line (gfc_src_preprocessor_lines[1]);
+ gfc_free (gfc_src_preprocessor_lines[1]);
+ gfc_src_preprocessor_lines[1] = NULL;
+ }
+ }
+
for (;;)
{
int trunc = load_line (input, &line, &line_len);
@@ -1157,3 +1203,112 @@ gfc_new_file (void)
return result;
}
+
+static char *
+unescape_filename (const char *ptr)
+{
+ const char *p = ptr, *s;
+ char *d, *ret;
+ int escaped, unescape = 0;
+
+ /* Make filename end at quote. */
+ escaped = false;
+ while (*p && ! (! escaped && *p == '"'))
+ {
+ if (escaped)
+ escaped = false;
+ else if (*p == '\\')
+ {
+ escaped = true;
+ unescape++;
+ }
+ ++p;
+ }
+
+ if (! *p || p[1])
+ return NULL;
+
+ /* Undo effects of cpp_quote_string. */
+ s = ptr;
+ d = gfc_getmem (p + 1 - ptr - unescape);
+ ret = d;
+
+ while (s != p)
+ {
+ if (*s == '\\')
+ *d++ = *++s;
+ else
+ *d++ = *s;
+ s++;
+ }
+ *d = '\0';
+ return ret;
+}
+
+/* For preprocessed files, if the first tokens are of the form # NUM.
+ handle the directives so we know the original file name. */
+
+const char *
+gfc_read_orig_filename (const char *filename, const char **canon_source_file)
+{
+ int c, len;
+ char *dirname;
+
+ gfc_src_file = gfc_open_file (filename);
+ if (gfc_src_file == NULL)
+ return NULL;
+
+ c = fgetc (gfc_src_file);
+ ungetc (c, gfc_src_file);
+
+ if (c != '#')
+ return NULL;
+
+ len = 0;
+ load_line (gfc_src_file, &gfc_src_preprocessor_lines[0], &len);
+
+ if (strncmp (gfc_src_preprocessor_lines[0], "# 1 \"", 5) != 0)
+ return NULL;
+
+ filename = unescape_filename (gfc_src_preprocessor_lines[0] + 5);
+ if (filename == NULL)
+ return NULL;
+
+ c = fgetc (gfc_src_file);
+ ungetc (c, gfc_src_file);
+
+ if (c != '#')
+ return filename;
+
+ len = 0;
+ load_line (gfc_src_file, &gfc_src_preprocessor_lines[1], &len);
+
+ if (strncmp (gfc_src_preprocessor_lines[1], "# 1 \"", 5) != 0)
+ return filename;
+
+ dirname = unescape_filename (gfc_src_preprocessor_lines[1] + 5);
+ if (dirname == NULL)
+ return filename;
+
+ len = strlen (dirname);
+ if (len < 3 || dirname[len - 1] != '/' || dirname[len - 2] != '/')
+ {
+ gfc_free (dirname);
+ return filename;
+ }
+ dirname[len - 2] = '\0';
+ set_src_pwd (dirname);
+
+ if (! IS_ABSOLUTE_PATH (filename))
+ {
+ char *p = gfc_getmem (len + strlen (filename));
+
+ memcpy (p, dirname, len - 2);
+ p[len - 2] = '/';
+ strcpy (p + len - 1, filename);
+ *canon_source_file = p;
+ }
+
+ gfc_free (dirname);
+ return filename;
+}
--- gcc/fortran/gfortran.h.jj 2005-12-23 00:03:12.000000000 +0100
+++ gcc/fortran/gfortran.h 2005-12-31 01:05:01.000000000 +0100
@@ -1515,6 +1515,7 @@ typedef struct
int flag_no_backend;
int flag_pack_derived;
int flag_repack_arrays;
+ int flag_preprocessed;
int flag_f2c;
int flag_automatic;
int flag_backslash;
@@ -1595,6 +1596,7 @@ int gfc_peek_char (void);
void gfc_error_recovery (void);
void gfc_gobble_whitespace (void);
try gfc_new_file (void);
+const char * gfc_read_orig_filename (const char *, const char **);
extern gfc_source_form gfc_current_form;
extern const char *gfc_source_file;
--- gcc/fortran/options.c.jj 2005-12-02 23:46:26.000000000 +0100
+++ gcc/fortran/options.c 2005-12-31 01:03:52.000000000 +0100
@@ -72,6 +72,7 @@ gfc_init_options (unsigned int argc ATTR
gfc_option.flag_no_backend = 0;
gfc_option.flag_pack_derived = 0;
gfc_option.flag_repack_arrays = 0;
+ gfc_option.flag_preprocessed = 0;
gfc_option.flag_automatic = 1;
gfc_option.flag_backslash = 1;
gfc_option.flag_cray_pointer = 0;
@@ -172,7 +173,7 @@ form_from_filename (const char *filename
bool
gfc_post_options (const char **pfilename)
{
- const char *filename = *pfilename;
+ const char *filename = *pfilename, *canon_source_file = NULL;
char *source_path;
int i;
@@ -182,23 +183,40 @@ gfc_post_options (const char **pfilename
filename = "";
}
- gfc_source_file = filename;
+ if (gfc_option.flag_preprocessed)
+ {
+ /* For preprocessed files, if the first tokens are of the form # NUM.
+ handle the directives so we know the original file name. */
+ gfc_source_file = gfc_read_orig_filename (filename, &canon_source_file);
+ if (gfc_source_file == NULL)
+ gfc_source_file = filename;
+ else
+ *pfilename = gfc_source_file;
+ }
+ else
+ gfc_source_file = filename;
+
+ if (canon_source_file == NULL)
+ canon_source_file = gfc_source_file;
/* Adds the path where the source file is to the list of include files. */
- i = strlen(gfc_source_file);
- while (i > 0 && !IS_DIR_SEPARATOR(gfc_source_file[i]))
+ i = strlen (canon_source_file);
+ while (i > 0 && !IS_DIR_SEPARATOR (canon_source_file[i]))
i--;
if (i != 0)
{
source_path = alloca (i + 1);
- memcpy (source_path, gfc_source_file, i);
+ memcpy (source_path, canon_source_file, i);
source_path[i] = 0;
gfc_add_include_path (source_path);
}
else
gfc_add_include_path (".");
+ if (canon_source_file != gfc_source_file)
+ gfc_free ((void *) canon_source_file);
+
/* Decide which form the file will be read in as. */
if (gfc_option.source_form != FORM_UNKNOWN)
@@ -211,7 +229,7 @@ gfc_post_options (const char **pfilename
{
gfc_current_form = FORM_FREE;
gfc_warning_now ("Reading file '%s' as free form.",
- (filename[0] == '\0') ? "<stdin>" : filename);
+ (filename[0] == '\0') ? "<stdin>" : filename);
}
}
@@ -478,6 +496,10 @@ gfc_handle_option (size_t scode, const c
gfc_option.flag_repack_arrays = value;
break;
+ case OPT_fpreprocessed:
+ gfc_option.flag_preprocessed = value;
+ break;
+
case OPT_fmax_identifier_length_:
if (value > GFC_MAX_SYMBOL_LEN)
gfc_fatal_error ("Maximum supported idenitifier length is %d",
--- gcc/fortran/lang-specs.h.jj 2005-11-04 09:40:59.000000000 +0100
+++ gcc/fortran/lang-specs.h 2005-12-29 16:30:48.000000000 +0100
@@ -1,6 +1,6 @@
/* Contribution to the specs for the GNU Compiler Collection
from GNU Fortran 95 compiler.
- Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is licensed under the GPL. */
@@ -15,7 +15,7 @@ This file is licensed under the GPL. */
%{E|M|MM:%(cpp_debug_options)}\
%{!M:%{!MM:%{!E: -o %|.f |\n\
f951 %|.f %{!ffree-form:-ffixed-form} %(cc1_options) %{J*} %{I*}\
- %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 0},
+ -fpreprocessed %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 0},
{".F90", "@f95-cpp-input", 0, 0, 0},
{".F95", "@f95-cpp-input", 0, 0, 0},
{"@f95-cpp-input",
@@ -23,7 +23,7 @@ This file is licensed under the GPL. */
%{E|M|MM:%(cpp_debug_options)}\
%{!M:%{!MM:%{!E: -o %|.f95 |\n\
f951 %|.f95 %(cc1_options) %{J*} %{I*}\
- %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 0},
+ -fpreprocessed %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 0},
{".f90", "@f95", 0, 0, 0},
{".f95", "@f95", 0, 0, 0},
{"@f95", "%{!E:f951 %i %(cc1_options) %{J*} %{I*}\
Jakub
More information about the Gcc-patches
mailing list