]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
backport: re PR fortran/90329 (Incompatibility between gfortran and C lapack calls)
authorJakub Jelinek <jakub@redhat.com>
Fri, 30 Aug 2019 12:41:43 +0000 (14:41 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 30 Aug 2019 12:41:43 +0000 (14:41 +0200)
Backported from mainline
2019-05-29  Jakub Jelinek  <jakub@redhat.com>

PR fortran/90329
* lto-streamer.h (LTO_minor_version): Bump to 1.

Backported from mainline
2019-05-16  Jakub Jelinek  <jakub@redhat.com>

PR fortran/90329
* tree-core.h (struct tree_decl_common): Document
decl_nonshareable_flag for PARM_DECLs.
* tree.h (DECL_HIDDEN_STRING_LENGTH): Define.
* calls.c (expand_call): Don't try tail call if caller
has any DECL_HIDDEN_STRING_LENGTH PARM_DECLs that are or might be
passed on the stack and callee needs to pass any arguments on the
stack.
* tree-streamer-in.c (unpack_ts_decl_common_value_fields): Use
else if instead of series of mutually exclusive ifs.  Handle
DECL_HIDDEN_STRING_LENGTH for PARM_DECLs.
* tree-streamer-out.c (pack_ts_decl_common_value_fields): Likewise.

* lang.opt (fbroken-callers): Remove.
(ftail-call-workaround, ftail-call-workaround=): New options.
* gfortran.h (struct gfc_namespace): Add implicit_interface_calls.
* interface.c (gfc_procedure_use): Set implicit_interface_calls
for calls to implicit interface procedures.
* trans-decl.c (create_function_arglist): Use flag_tail_call_workaround
instead of flag_broken_callers.  If it is not 2, also require
sym->ns->implicit_interface_calls.
* invoke.texi (fbroken-callers): Remove documentation.
(ftail-call-workaround, ftail-call-workaround=): Document.

2019-05-19  Thomas Koenig  <tkoenig@gcc.gnu.org>

PR fortran/90329
* invoke.texi: Document -fbroken-callers.
* lang.opt: Add -fbroken-callers.
* trans-decl.c (create_function_arglist): Only set
DECL_HIDDEN_STRING_LENGTH if flag_broken_callers is set.

2019-05-16  Jakub Jelinek  <jakub@redhat.com>

PR fortran/90329
* trans-decl.c (create_function_arglist): Set
DECL_HIDDEN_STRING_LENGTH on hidden string length PARM_DECLs if
len is constant.

From-SVN: r275153

13 files changed:
gcc/ChangeLog
gcc/calls.c
gcc/fortran/ChangeLog
gcc/fortran/gfortran.h
gcc/fortran/interface.c
gcc/fortran/invoke.texi
gcc/fortran/lang.opt
gcc/fortran/trans-decl.c
gcc/lto-streamer.h
gcc/tree-core.h
gcc/tree-streamer-in.c
gcc/tree-streamer-out.c
gcc/tree.h

index 3662abf12c514255f9ded7f9c65c544a4515cdd5..6a9190f8b422411a3d1784b61a5067f80cdf9543 100644 (file)
@@ -1,6 +1,26 @@
 2019-08-30  Jakub Jelinek  <jakub@redhat.com>
 
        Backported from mainline
+       2019-05-29  Jakub Jelinek  <jakub@redhat.com>
+
+       PR fortran/90329
+       * lto-streamer.h (LTO_minor_version): Bump to 1.
+
+       2019-05-16  Jakub Jelinek  <jakub@redhat.com>
+
+       PR fortran/90329
+       * tree-core.h (struct tree_decl_common): Document
+       decl_nonshareable_flag for PARM_DECLs.
+       * tree.h (DECL_HIDDEN_STRING_LENGTH): Define.
+       * calls.c (expand_call): Don't try tail call if caller
+       has any DECL_HIDDEN_STRING_LENGTH PARM_DECLs that are or might be
+       passed on the stack and callee needs to pass any arguments on the
+       stack.
+       * tree-streamer-in.c (unpack_ts_decl_common_value_fields): Use
+       else if instead of series of mutually exclusive ifs.  Handle
+       DECL_HIDDEN_STRING_LENGTH for PARM_DECLs.
+       * tree-streamer-out.c (pack_ts_decl_common_value_fields): Likewise.
+
        2019-04-24  Jakub Jelinek  <jakub@redhat.com>
 
        PR target/90187
index 8eec155cf7de1186538a007a113f02dbf275379d..cff26c41e249f57cfbe5b0147cff5c6d48bb9b9b 100644 (file)
@@ -3333,6 +3333,28 @@ expand_call (tree exp, rtx target, int ignore)
       || dbg_cnt (tail_call) == false)
     try_tail_call = 0;
 
+  /* Workaround buggy C/C++ wrappers around Fortran routines with
+     character(len=constant) arguments if the hidden string length arguments
+     are passed on the stack; if the callers forget to pass those arguments,
+     attempting to tail call in such routines leads to stack corruption.
+     Avoid tail calls in functions where at least one such hidden string
+     length argument is passed (partially or fully) on the stack in the
+     caller and the callee needs to pass any arguments on the stack.
+     See PR90329.  */
+  if (try_tail_call && args_size.constant != 0)
+    for (tree arg = DECL_ARGUMENTS (current_function_decl);
+        arg; arg = DECL_CHAIN (arg))
+      if (DECL_HIDDEN_STRING_LENGTH (arg) && DECL_INCOMING_RTL (arg))
+       {
+         subrtx_iterator::array_type array;
+         FOR_EACH_SUBRTX (iter, array, DECL_INCOMING_RTL (arg), NONCONST)
+           if (MEM_P (*iter))
+             {
+               try_tail_call = 0;
+               break;
+             }
+       }
+
   /* If the user has marked the function as requiring tail-call
      optimization, attempt it.  */
   if (must_tail_call)
index 51d6a4ebbcfdc49d8d32279037bd9b0afbd632e6..f86ff34758fc1c506a84298e9b30400e93a8c3a9 100644 (file)
@@ -1,6 +1,35 @@
 2019-08-30  Jakub Jelinek  <jakub@redhat.com>
 
        Backported from mainline
+       2019-05-16  Jakub Jelinek  <jakub@redhat.com>
+
+       PR fortran/90329
+       * lang.opt (fbroken-callers): Remove.
+       (ftail-call-workaround, ftail-call-workaround=): New options.
+       * gfortran.h (struct gfc_namespace): Add implicit_interface_calls.
+       * interface.c (gfc_procedure_use): Set implicit_interface_calls
+       for calls to implicit interface procedures.
+       * trans-decl.c (create_function_arglist): Use flag_tail_call_workaround
+       instead of flag_broken_callers.  If it is not 2, also require
+       sym->ns->implicit_interface_calls.
+       * invoke.texi (fbroken-callers): Remove documentation.
+       (ftail-call-workaround, ftail-call-workaround=): Document.
+
+       2019-05-19  Thomas Koenig  <tkoenig@gcc.gnu.org>
+
+       PR fortran/90329
+       * invoke.texi: Document -fbroken-callers.
+       * lang.opt: Add -fbroken-callers.
+       * trans-decl.c (create_function_arglist): Only set
+       DECL_HIDDEN_STRING_LENGTH if flag_broken_callers is set.
+
+       2019-05-16  Jakub Jelinek  <jakub@redhat.com>
+
+       PR fortran/90329
+       * trans-decl.c (create_function_arglist): Set
+       DECL_HIDDEN_STRING_LENGTH on hidden string length PARM_DECLs if
+       len is constant.
+
        2019-03-11  Jakub Jelinek  <jakub@redhat.com>
 
        PR fortran/89651
index 47b98bbd5ae121846978e9688797241ebdeb97ba..f7f1fa58de3e30441d985c74257cfce550f1d8bf 100644 (file)
@@ -1828,6 +1828,9 @@ typedef struct gfc_namespace
 
   /* Set to 1 for !$ACC ROUTINE namespaces.  */
   unsigned oacc_routine:1;
+
+  /* Set to 1 if there are any calls to procedures with implicit interface.  */
+  unsigned implicit_interface_calls:1;
 }
 gfc_namespace;
 
index 5625a2e6ab625d7403bacbebb04108befec59152..6b7fbcc3275a39acdc419af3c1022d8313767236 100644 (file)
@@ -3585,6 +3585,7 @@ gfc_procedure_use (gfc_symbol *sym, gfc_actual_arglist **ap, locus *where)
        gfc_warning (OPT_Wimplicit_procedure,
                     "Procedure %qs called at %L is not explicitly declared",
                     sym->name, where);
+      gfc_find_proc_namespace (sym->ns)->implicit_interface_calls = 1;
     }
 
   if (sym->attr.if_source == IFSRC_UNKNOWN)
index 636432fead8b8645490112cd58ff679f6c1f32b2..9c63eb2b0d67225603c3a67bec8d74e670fcc731 100644 (file)
@@ -174,7 +174,8 @@ and warnings}.
 @item Code Generation Options
 @xref{Code Gen Options,,Options for code generation conventions}.
 @gccoptlist{-faggressive-function-elimination -fblas-matmul-limit=@var{n} @gol
--fbounds-check -fcheck-array-temporaries @gol
+-fbounds-check -ftail-call-workaround -ftail-call-workaround=@var{n} @gol
+-fcheck-array-temporaries @gol
 -fcheck=@var{<all|array-temps|bounds|do|mem|pointer|recursion>} @gol
 -fcoarray=@var{<none|single|lib>} -fexternal-blas -ff2c
 -ffrontend-optimize @gol
@@ -1522,6 +1523,39 @@ warnings for generated array temporaries.
 @c Note: This option is also referred in gcc's manpage
 Deprecated alias for @option{-fcheck=bounds}.
 
+@item -ftail-call-workaround
+@itemx -ftail-call-workaround=@var{n}
+@opindex @code{tail-call-workaround}
+Some C interfaces to Fortran codes violate the gfortran ABI by
+omitting the hidden character length arguments as described in
+@xref{Argument passing conventions}.  This can lead to crashes
+because pushing arguments for tail calls can overflow the stack.
+
+To provide a workaround for existing binary packages, this option
+disables tail call optimization for gfortran procedures with character
+arguments.  With @option{-ftail-call-workaround=2} tail call optimization
+is disabled in all gfortran procedures with character arguments,
+with @option{-ftail-call-workaround=1} or equivalent
+@option{-ftail-call-workaround} only in gfortran procedures with character
+arguments that call implicitly prototyped procedures.
+
+Using this option can lead to problems including crashes due to
+insufficient stack space.
+
+It is @emph{very strongly} recommended to fix the code in question.
+The @option{-fc-prototypes-external} option can be used to generate
+prototypes which conform to gfortran's ABI, for inclusion in the
+source code.
+
+Support for this option will likely be withdrawn in a future release
+of gfortran.
+
+The negative form, @option{-fno-tail-call-workaround} or equivalent
+@option{-ftail-call-workaround=0}, can be used to disable this option.
+
+Default is currently @option{-ftail-call-workaround}, this will change
+in future releases.
+
 @item -fcheck-array-temporaries
 @opindex @code{fcheck-array-temporaries}
 Deprecated alias for @option{-fcheck=array-temps}.
index 4421ce4268721c73ab78ad34218240d8b9133720..019ca8865da1ff429fa29dc3abefaa033c239286 100644 (file)
@@ -718,6 +718,13 @@ fsign-zero
 Fortran Var(flag_sign_zero) Init(1)
 Apply negative sign to zero values.
 
+ftail-call-workaround
+Frotran Alias(ftail-call-workaround=,1,0)
+
+ftail-call-workaround=
+Fortran RejectNegative Joined UInteger IntegerRange(0, 2) Var(flag_tail_call_workaround) Init(1)
+Disallow tail call optimization when a calling routine may have omitted character lenghts.
+
 funderscoring
 Fortran Var(flag_underscoring) Init(1)
 Append underscores to externally visible names.
index 73a37ae1275f4f6fd4583ff3df98534f261b1b87..8c14400e33da175f5f71f58a9470169d5566cf89 100644 (file)
@@ -2521,6 +2521,17 @@ create_function_arglist (gfc_symbol * sym)
          TREE_READONLY (length) = 1;
          gfc_finish_decl (length);
 
+         /* Marking the length DECL_HIDDEN_STRING_LENGTH will lead
+            to tail calls being disabled.  Only do that if we
+            potentially have broken callers.  */
+         if (flag_tail_call_workaround
+             && f->sym->ts.u.cl
+             && f->sym->ts.u.cl->length
+             && f->sym->ts.u.cl->length->expr_type == EXPR_CONSTANT
+             && (flag_tail_call_workaround == 2
+                 || f->sym->ns->implicit_interface_calls))
+           DECL_HIDDEN_STRING_LENGTH (length) = 1;
+
          /* Remember the passed value.  */
           if (!f->sym->ts.u.cl ||  f->sym->ts.u.cl->passed_length)
             {
index 08bfc13af7582fafdae215b24f7c14c516147720..15c7704ceb2e913dee0298c5753b37cc2e842e7b 100644 (file)
@@ -129,7 +129,7 @@ along with GCC; see the file COPYING3.  If not see
      form followed by the data for the string.  */
 
 #define LTO_major_version 6
-#define LTO_minor_version 0
+#define LTO_minor_version 1
 
 typedef unsigned char  lto_decl_flags_t;
 
index 38154e384c00ec5d6a98efee01d633cbc0812ff0..cb3b3de3e0471c078d53adf39094d06c6837fc42 100644 (file)
@@ -1614,6 +1614,7 @@ struct GTY(()) tree_decl_common {
   /* In a VAR_DECL and PARM_DECL, this is DECL_READ_P.  */
   unsigned decl_read_flag : 1;
   /* In a VAR_DECL or RESULT_DECL, this is DECL_NONSHAREABLE.  */
+  /* In a PARM_DECL, this is DECL_HIDDEN_STRING_LENGTH.  */
   unsigned decl_nonshareable_flag : 1;
 
   /* DECL_OFFSET_ALIGN, used only for FIELD_DECLs.  */
index f0099c050325b87fe55b6de91cc8d9d4cef628a5..cd3e1a96776b021b80e9917bb74214e4dbcbe442 100644 (file)
@@ -244,19 +244,22 @@ unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
       LABEL_DECL_UID (expr) = -1;
     }
 
-  if (TREE_CODE (expr) == FIELD_DECL)
+  else if (TREE_CODE (expr) == FIELD_DECL)
     {
       DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1);
       DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
       expr->decl_common.off_align = bp_unpack_value (bp, 8);
     }
 
-  if (VAR_P (expr))
+  else if (VAR_P (expr))
     {
       DECL_HAS_DEBUG_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1);
       DECL_NONLOCAL_FRAME (expr) = (unsigned) bp_unpack_value (bp, 1);
     }
 
+  else if (TREE_CODE (expr) == PARM_DECL)
+    DECL_HIDDEN_STRING_LENGTH (expr) = (unsigned) bp_unpack_value (bp, 1);
+
   if (TREE_CODE (expr) == RESULT_DECL
       || TREE_CODE (expr) == PARM_DECL
       || VAR_P (expr))
index 5cf904493410e78ed08b2034089473d2e25c9afd..6b0822ad31035e2355af76e8b8dd1c1c95ab2492 100644 (file)
@@ -207,19 +207,22 @@ pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
       bp_pack_var_len_unsigned (bp, EH_LANDING_PAD_NR (expr));
     }
 
-  if (TREE_CODE (expr) == FIELD_DECL)
+  else if (TREE_CODE (expr) == FIELD_DECL)
     {
       bp_pack_value (bp, DECL_PACKED (expr), 1);
       bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1);
       bp_pack_value (bp, expr->decl_common.off_align, 8);
     }
 
-  if (VAR_P (expr))
+  else if (VAR_P (expr))
     {
       bp_pack_value (bp, DECL_HAS_DEBUG_EXPR_P (expr), 1);
       bp_pack_value (bp, DECL_NONLOCAL_FRAME (expr), 1);
     }
 
+  else if (TREE_CODE (expr) == PARM_DECL)
+    bp_pack_value (bp, DECL_HIDDEN_STRING_LENGTH (expr), 1);
+
   if (TREE_CODE (expr) == RESULT_DECL
       || TREE_CODE (expr) == PARM_DECL
       || VAR_P (expr))
index 961dba39403de5d1cd00089932646e1a13766475..a49ccf6d076923771dc601111579a9ea99a4e19e 100644 (file)
@@ -912,6 +912,11 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
   (TREE_CHECK2 (NODE, VAR_DECL, \
                RESULT_DECL)->decl_common.decl_nonshareable_flag)
 
+/* In a PARM_DECL, set for Fortran hidden string length arguments that some
+   buggy callers don't pass to the callee.  */
+#define DECL_HIDDEN_STRING_LENGTH(NODE) \
+  (TREE_CHECK (NODE, PARM_DECL)->decl_common.decl_nonshareable_flag)
+
 /* In a CALL_EXPR, means that the call is the jump from a thunk to the
    thunked-to function.  */
 #define CALL_FROM_THUNK_P(NODE) (CALL_EXPR_CHECK (NODE)->base.protected_flag)