PR tree-optimization/83431 - -Wformat-truncation may incorrectly report truncation
authorMartin Sebor <msebor@redhat.com>
Mon, 26 Aug 2019 18:29:45 +0000 (18:29 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Mon, 26 Aug 2019 18:29:45 +0000 (12:29 -0600)
gcc/ChangeLog:

PR c++/83431
* gimple-ssa-sprintf.c (pass_data_sprintf_length): Remove object.
(sprintf_dom_walker): Remove class.
(get_int_range): Make argument const.
(directive::fmtfunc, directive::set_precision): Same.
(format_none): Same.
(build_intmax_type_nodes): Same.
(adjust_range_for_overflow): Same.
(format_floating): Same.
(format_character): Same.
(format_string): Same.
(format_plain): Same.
(get_int_range): Cast away constness.
(format_integer): Same.
(get_string_length): Call get_range_strlen_dynamic.  Handle
null lendata.maxbound.
(should_warn_p): Adjust argument scope qualifier.
(maybe_warn): Same.
(format_directive): Same.
(parse_directive): Same.
(is_call_safe): Same.
(try_substitute_return_value): Same.
(sprintf_dom_walker::handle_printf_call): Rename...
(handle_printf_call): ...to this.  Initialize target to host charmap
here instead of in pass_sprintf_length::execute.
(struct call_info): Make global.
(sprintf_dom_walker::compute_format_length): Make global.
(sprintf_dom_walker::handle_gimple_call): Same.
* passes.def (pass_sprintf_length): Replace with pass_strlen.
* print-rtl.c (print_pattern): Reduce the number of spaces to
avoid -Wformat-truncation.
* tree-pass.h (make_pass_warn_printf): New function.
* tree-ssa-strlen.c (strlen_optimize): New variable.
(get_string_length): Add comments.
(get_range_strlen_dynamic): New function.
(check_and_optimize_call): New function.
(handle_integral_assign): New function.
(strlen_check_and_optimize_stmt): Factor code out into
strlen_check_and_optimize_call and handle_integral_assign.
(strlen_dom_walker::evrp): New member.
(strlen_dom_walker::before_dom_children): Use evrp member.
(strlen_dom_walker::after_dom_children): Use evrp member.
(printf_strlen_execute): New function.
(pass_strlen::gate): Update to handle printf calls.
(dump_strlen_info): New function.
(pass_data_warn_printf): New variable.
(pass_warn_printf): New class.
* tree-ssa-strlen.h (get_range_strlen_dynamic): Declare.
(handle_printf_call): Same.
* tree-vrp.c (value_range_base::type): Adjust assertion.
* vr-values.c (vr_values::update_value_range): Use type of the first
argument rather than the second.

gcc/testsuite/ChangeLog:

PR c++/83431
* gcc.dg/strlenopt-63.c: New test.
* gcc.dg/pr79538.c: Adjust text of expected warning.
* gcc.dg/pr81292-1.c: Adjust pass name.
* gcc.dg/pr81292-2.c: Same.
* gcc.dg/pr81703.c: Same.
* gcc.dg/strcmpopt_2.c: Same.
* gcc.dg/strcmpopt_3.c: Same.
* gcc.dg/strcmpopt_4.c: Same.
* gcc.dg/strlenopt-1.c: Same.
* gcc.dg/strlenopt-10.c: Same.
* gcc.dg/strlenopt-11.c: Same.
* gcc.dg/strlenopt-13.c: Same.
* gcc.dg/strlenopt-14g.c: Same.
* gcc.dg/strlenopt-14gf.c: Same.
* gcc.dg/strlenopt-15.c: Same.
* gcc.dg/strlenopt-16g.c: Same.
* gcc.dg/strlenopt-17g.c: Same.
* gcc.dg/strlenopt-18g.c: Same.
* gcc.dg/strlenopt-19.c: Same.
* gcc.dg/strlenopt-1f.c: Same.
* gcc.dg/strlenopt-2.c: Same.
* gcc.dg/strlenopt-20.c: Same.
* gcc.dg/strlenopt-21.c: Same.
* gcc.dg/strlenopt-22.c: Same.
* gcc.dg/strlenopt-22g.c: Same.
* gcc.dg/strlenopt-24.c: Same.
* gcc.dg/strlenopt-25.c: Same.
* gcc.dg/strlenopt-26.c: Same.
* gcc.dg/strlenopt-27.c: Same.
* gcc.dg/strlenopt-28.c: Same.
* gcc.dg/strlenopt-29.c: Same.
* gcc.dg/strlenopt-2f.c: Same.
* gcc.dg/strlenopt-3.c: Same.
* gcc.dg/strlenopt-30.c: Same.
* gcc.dg/strlenopt-31g.c: Same.
* gcc.dg/strlenopt-32.c: Same.
* gcc.dg/strlenopt-33.c: Same.
* gcc.dg/strlenopt-33g.c: Same.
* gcc.dg/strlenopt-34.c: Same.
* gcc.dg/strlenopt-35.c: Same.
* gcc.dg/strlenopt-4.c: Same.
* gcc.dg/strlenopt-48.c: Same.
* gcc.dg/strlenopt-49.c: Same.
* gcc.dg/strlenopt-4g.c: Same.
* gcc.dg/strlenopt-4gf.c: Same.
* gcc.dg/strlenopt-5.c: Same.
* gcc.dg/strlenopt-50.c: Same.
* gcc.dg/strlenopt-51.c: Same.
* gcc.dg/strlenopt-52.c: Same.
* gcc.dg/strlenopt-53.c: Same.
* gcc.dg/strlenopt-54.c: Same.
* gcc.dg/strlenopt-55.c: Same.
* gcc.dg/strlenopt-56.c: Same.
* gcc.dg/strlenopt-6.c: Same.
* gcc.dg/strlenopt-61.c: Same.
* gcc.dg/strlenopt-7.c: Same.
* gcc.dg/strlenopt-8.c: Same.
* gcc.dg/strlenopt-9.c: Same.
* gcc.dg/strlenopt.h (snprintf, snprintf): Declare.
* gcc.dg/tree-ssa/builtin-snprintf-6.c: New test.
* gcc.dg/tree-ssa/builtin-snprintf-7.c: New test.
* gcc.dg/tree-ssa/builtin-snprintf-8.c: New test.
* gcc.dg/tree-ssa/builtin-snprintf-9.c: New test.
* gcc.dg/tree-ssa/builtin-sprintf-warn-21.c: New test.
* gcc.dg/tree-ssa/dump-4.c: New test.
* gcc.dg/tree-ssa/pr83501.c: Adjust pass name.

From-SVN: r274933

77 files changed:
gcc/ChangeLog
gcc/gimple-ssa-sprintf.c
gcc/passes.def
gcc/print-rtl.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr79538.c
gcc/testsuite/gcc.dg/pr81292-1.c
gcc/testsuite/gcc.dg/pr81292-2.c
gcc/testsuite/gcc.dg/pr81703.c
gcc/testsuite/gcc.dg/strcmpopt_2.c
gcc/testsuite/gcc.dg/strcmpopt_3.c
gcc/testsuite/gcc.dg/strcmpopt_4.c
gcc/testsuite/gcc.dg/strlenopt-1.c
gcc/testsuite/gcc.dg/strlenopt-10.c
gcc/testsuite/gcc.dg/strlenopt-11.c
gcc/testsuite/gcc.dg/strlenopt-13.c
gcc/testsuite/gcc.dg/strlenopt-14g.c
gcc/testsuite/gcc.dg/strlenopt-14gf.c
gcc/testsuite/gcc.dg/strlenopt-15.c
gcc/testsuite/gcc.dg/strlenopt-16g.c
gcc/testsuite/gcc.dg/strlenopt-17g.c
gcc/testsuite/gcc.dg/strlenopt-18g.c
gcc/testsuite/gcc.dg/strlenopt-19.c
gcc/testsuite/gcc.dg/strlenopt-1f.c
gcc/testsuite/gcc.dg/strlenopt-2.c
gcc/testsuite/gcc.dg/strlenopt-20.c
gcc/testsuite/gcc.dg/strlenopt-21.c
gcc/testsuite/gcc.dg/strlenopt-22.c
gcc/testsuite/gcc.dg/strlenopt-22g.c
gcc/testsuite/gcc.dg/strlenopt-24.c
gcc/testsuite/gcc.dg/strlenopt-25.c
gcc/testsuite/gcc.dg/strlenopt-26.c
gcc/testsuite/gcc.dg/strlenopt-27.c
gcc/testsuite/gcc.dg/strlenopt-28.c
gcc/testsuite/gcc.dg/strlenopt-29.c
gcc/testsuite/gcc.dg/strlenopt-2f.c
gcc/testsuite/gcc.dg/strlenopt-3.c
gcc/testsuite/gcc.dg/strlenopt-30.c
gcc/testsuite/gcc.dg/strlenopt-31g.c
gcc/testsuite/gcc.dg/strlenopt-32.c
gcc/testsuite/gcc.dg/strlenopt-33.c
gcc/testsuite/gcc.dg/strlenopt-33g.c
gcc/testsuite/gcc.dg/strlenopt-34.c
gcc/testsuite/gcc.dg/strlenopt-35.c
gcc/testsuite/gcc.dg/strlenopt-4.c
gcc/testsuite/gcc.dg/strlenopt-48.c
gcc/testsuite/gcc.dg/strlenopt-49.c
gcc/testsuite/gcc.dg/strlenopt-4g.c
gcc/testsuite/gcc.dg/strlenopt-4gf.c
gcc/testsuite/gcc.dg/strlenopt-5.c
gcc/testsuite/gcc.dg/strlenopt-50.c
gcc/testsuite/gcc.dg/strlenopt-51.c
gcc/testsuite/gcc.dg/strlenopt-52.c
gcc/testsuite/gcc.dg/strlenopt-53.c
gcc/testsuite/gcc.dg/strlenopt-54.c
gcc/testsuite/gcc.dg/strlenopt-55.c
gcc/testsuite/gcc.dg/strlenopt-56.c
gcc/testsuite/gcc.dg/strlenopt-6.c
gcc/testsuite/gcc.dg/strlenopt-61.c
gcc/testsuite/gcc.dg/strlenopt-68.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/strlenopt-7.c
gcc/testsuite/gcc.dg/strlenopt-9.c
gcc/testsuite/gcc.dg/strlenopt.h
gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-8.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-9.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-21.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/dump-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr83501.c
gcc/testsuite/gcc.dg/tree-ssa/strlen-2.c
gcc/tree-pass.h
gcc/tree-ssa-strlen.c
gcc/tree-ssa-strlen.h
gcc/tree-vrp.c
gcc/vr-values.c

index b2c9767490472c7f7efdbe08fc85af7a76243582..852382efcb52d5efcba8bc996dedd9cd9da64756 100644 (file)
@@ -1,3 +1,58 @@
+2019-08-23  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/83431
+       * gimple-ssa-sprintf.c (pass_data_sprintf_length): Remove object.
+       (sprintf_dom_walker): Remove class.
+       (get_int_range): Make argument const.
+       (directive::fmtfunc, directive::set_precision): Same.
+       (format_none): Same.
+       (build_intmax_type_nodes): Same.
+       (adjust_range_for_overflow): Same.
+       (format_floating): Same.
+       (format_character): Same.
+       (format_string): Same.
+       (format_plain): Same.
+       (get_int_range): Cast away constness.
+       (format_integer): Same.
+       (get_string_length): Call get_range_strlen_dynamic.  Handle
+       null lendata.maxbound.
+       (should_warn_p): Adjust argument scope qualifier.
+       (maybe_warn): Same.
+       (format_directive): Same.
+       (parse_directive): Same.
+       (is_call_safe): Same.
+       (try_substitute_return_value): Same.
+       (sprintf_dom_walker::handle_printf_call): Rename...
+       (handle_printf_call): ...to this.  Initialize target to host charmap
+       here instead of in pass_sprintf_length::execute.
+       (struct call_info): Make global.
+       (sprintf_dom_walker::compute_format_length): Make global.
+       (sprintf_dom_walker::handle_gimple_call): Same.
+       * passes.def (pass_sprintf_length): Replace with pass_strlen.
+       * print-rtl.c (print_pattern): Reduce the number of spaces to
+       avoid -Wformat-truncation.
+       * tree-pass.h (make_pass_warn_printf): New function.
+       * tree-ssa-strlen.c (strlen_optimize): New variable.
+       (get_string_length): Add comments.
+       (get_range_strlen_dynamic): New function.
+       (check_and_optimize_call): New function.
+       (handle_integral_assign): New function.
+       (strlen_check_and_optimize_stmt): Factor code out into
+       strlen_check_and_optimize_call and handle_integral_assign.
+       (strlen_dom_walker::evrp): New member.
+       (strlen_dom_walker::before_dom_children): Use evrp member.
+       (strlen_dom_walker::after_dom_children): Use evrp member.
+       (printf_strlen_execute): New function.
+       (pass_strlen::gate): Update to handle printf calls.
+       (dump_strlen_info): New function.
+       (pass_data_warn_printf): New variable.
+       (pass_warn_printf): New class.
+       * tree-ssa-strlen.h (get_range_strlen_dynamic): Declare.
+       (handle_printf_call): Same.
+       * tree-vrp.c (value_range_base::type): Adjust assertion.
+       * vr-values.c (vr_values::update_value_range): Use type of the first
+       argument rather than the second.
+
 2019-08-26  Richard Biener  <rguenther@suse.de>
 
        * config/i386/i386-features.c (general_remove_non_convertible_regs):
index 88ba1f2cac1690aa77de8cee3c41432bd68200dc..6a39a71900a05d264b7e854e4243cd3b88df89ec 100644 (file)
@@ -85,7 +85,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "domwalk.h"
 #include "alloc-pool.h"
 #include "vr-values.h"
-#include "gimple-ssa-evrp-analyze.h"
+#include "tree-ssa-strlen.h"
 
 /* The likely worst case value of MB_LEN_MAX for the target, large enough
    for UTF-8.  Ideally, this would be obtained by a target hook if it were
@@ -100,80 +100,15 @@ along with GCC; see the file COPYING3.  If not see
 
 namespace {
 
-const pass_data pass_data_sprintf_length = {
-  GIMPLE_PASS,             // pass type
-  "printf-return-value",   // pass name
-  OPTGROUP_NONE,           // optinfo_flags
-  TV_NONE,                 // tv_id
-  PROP_cfg,                // properties_required
-  0,                      // properties_provided
-  0,                      // properties_destroyed
-  0,                      // properties_start
-  0,                      // properties_finish
-};
-
 /* Set to the warning level for the current function which is equal
    either to warn_format_trunc for bounded functions or to
    warn_format_overflow otherwise.  */
 
 static int warn_level;
 
+struct call_info;
 struct format_result;
 
-class sprintf_dom_walker : public dom_walker
-{
- public:
-  sprintf_dom_walker ()
-    : dom_walker (CDI_DOMINATORS),
-      evrp_range_analyzer (false) {}
-  ~sprintf_dom_walker () {}
-
-  edge before_dom_children (basic_block) FINAL OVERRIDE;
-  void after_dom_children (basic_block) FINAL OVERRIDE;
-  bool handle_gimple_call (gimple_stmt_iterator *);
-
-  struct call_info;
-  bool compute_format_length (call_info &, format_result *);
-  class evrp_range_analyzer evrp_range_analyzer;
-};
-
-class pass_sprintf_length : public gimple_opt_pass
-{
-  bool fold_return_value;
-
-public:
-  pass_sprintf_length (gcc::context *ctxt)
-    : gimple_opt_pass (pass_data_sprintf_length, ctxt),
-    fold_return_value (false)
-  { }
-
-  opt_pass * clone () { return new pass_sprintf_length (m_ctxt); }
-
-  virtual bool gate (function *);
-
-  virtual unsigned int execute (function *);
-
-  void set_pass_param (unsigned int n, bool param)
-    {
-      gcc_assert (n == 0);
-      fold_return_value = param;
-    }
-
-};
-
-bool
-pass_sprintf_length::gate (function *)
-{
-  /* Run the pass iff -Warn-format-overflow or -Warn-format-truncation
-     is specified and either not optimizing and the pass is being invoked
-     early, or when optimizing and the pass is being invoked during
-     optimization (i.e., "late").  */
-  return ((warn_format_overflow > 0
-          || warn_format_trunc > 0
-          || flag_printf_return_value)
-         && (optimize > 0) == fold_return_value);
-}
-
 /* The minimum, maximum, likely, and unlikely maximum number of bytes
    of output either a formatting function or an individual directive
    can result in.  */
@@ -684,7 +619,7 @@ fmtresult::type_max_digits (tree type, int base)
 
 static bool
 get_int_range (tree, HOST_WIDE_INT *, HOST_WIDE_INT *, bool, HOST_WIDE_INT,
-              class vr_values *vr_values);
+              const vr_values *);
 
 /* Description of a format directive.  A directive is either a plain
    string or a conversion specification that starts with '%'.  */
@@ -719,7 +654,7 @@ struct directive
 
   /* Format conversion function that given a directive and an argument
      returns the formatting result.  */
-  fmtresult (*fmtfunc) (const directive &, tree, vr_values *);
+  fmtresult (*fmtfunc) (const directive &, tree, const vr_values *);
 
   /* Return True when a the format flag CHR has been used.  */
   bool get_flag (char chr) const
@@ -756,9 +691,9 @@ struct directive
      or 0, whichever is greater.  For a non-constant ARG in some range
      set width to its range adjusting each bound to -1 if it's less.
      For an indeterminate ARG set width to [0, INT_MAX].  */
-  void set_width (tree arg, vr_values *vr_values)
+  void set_width (tree arg, const vr_values *vr)
   {
-    get_int_range (arg, width, width + 1, true, 0, vr_values);
+    get_int_range (arg, width, width + 1, true, 0, vr);
   }
 
   /* Set both bounds of the precision range to VAL.  */
@@ -772,9 +707,9 @@ struct directive
      or -1 whichever is greater.  For a non-constant ARG in some range
      set precision to its range adjusting each bound to -1 if it's less.
      For an indeterminate ARG set precision to [-1, INT_MAX].  */
-  void set_precision (tree arg, vr_values *vr_values)
+  void set_precision (tree arg, const vr_values *vr)
   {
-    get_int_range (arg, prec, prec + 1, false, -1, vr_values);
+    get_int_range (arg, prec, prec + 1, false, -1, vr);
   }
 
   /* Return true if both width and precision are known to be
@@ -904,7 +839,7 @@ bytes_remaining (unsigned HOST_WIDE_INT navail, const format_result &res)
 
 /* Description of a call to a formatted function.  */
 
-struct sprintf_dom_walker::call_info
+struct call_info
 {
   /* Function call statement.  */
   gimple *callstmt;
@@ -978,7 +913,7 @@ struct sprintf_dom_walker::call_info
 /* Return the result of formatting a no-op directive (such as '%n').  */
 
 static fmtresult
-format_none (const directive &, tree, vr_values *)
+format_none (const directive &, tree, const vr_values *)
 {
   fmtresult res (0);
   return res;
@@ -987,7 +922,7 @@ format_none (const directive &, tree, vr_values *)
 /* Return the result of formatting the '%%' directive.  */
 
 static fmtresult
-format_percent (const directive &, tree, vr_values *)
+format_percent (const directive &, tree, const vr_values *)
 {
   fmtresult res (1);
   return res;
@@ -1047,7 +982,7 @@ build_intmax_type_nodes (tree *pintmax, tree *puintmax)
 static bool
 get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
               bool absolute, HOST_WIDE_INT negbound,
-              class vr_values *vr_values)
+              const class vr_values *vr_values)
 {
   /* The type of the result.  */
   const_tree type = integer_type_node;
@@ -1086,7 +1021,9 @@ get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
          && TYPE_PRECISION (argtype) <= TYPE_PRECISION (type))
        {
          /* Try to determine the range of values of the integer argument.  */
-         const value_range *vr = vr_values->get_value_range (arg);
+         const value_range *vr
+           = CONST_CAST (class vr_values *, vr_values)->get_value_range (arg);
+
          if (range_int_cst_p (vr))
            {
              HOST_WIDE_INT type_min
@@ -1203,7 +1140,7 @@ adjust_range_for_overflow (tree dirtype, tree *argmin, tree *argmax)
    used when the directive argument or its value isn't known.  */
 
 static fmtresult
-format_integer (const directive &dir, tree arg, vr_values *vr_values)
+format_integer (const directive &dir, tree arg, const vr_values *vr_values)
 {
   tree intmax_type_node;
   tree uintmax_type_node;
@@ -1386,7 +1323,9 @@ format_integer (const directive &dir, tree arg, vr_values *vr_values)
     {
       /* Try to determine the range of values of the integer argument
         (range information is not available for pointers).  */
-      const value_range *vr = vr_values->get_value_range (arg);
+      const value_range *vr
+       = CONST_CAST (class vr_values *, vr_values)->get_value_range (arg);
+
       if (range_int_cst_p (vr))
        {
          argmin = vr->min ();
@@ -1836,7 +1775,7 @@ format_floating (const directive &dir, const HOST_WIDE_INT prec[2])
    ARG.  */
 
 static fmtresult
-format_floating (const directive &dir, tree arg, vr_values *)
+format_floating (const directive &dir, tree arg, const vr_values *)
 {
   HOST_WIDE_INT prec[] = { dir.prec[0], dir.prec[1] };
   tree type = (dir.modifier == FMT_LEN_L || dir.modifier == FMT_LEN_ll
@@ -2030,21 +1969,33 @@ format_floating (const directive &dir, tree arg, vr_values *)
    Used by the format_string function below.  */
 
 static fmtresult
-get_string_length (tree str, unsigned eltsize)
+get_string_length (tree str, unsigned eltsize, const vr_values *vr)
 {
   if (!str)
     return fmtresult ();
 
-  /* Determine the length of the shortest and longest string referenced
-     by STR.  Strings of unknown lengths are bounded by the sizes of
-     arrays that subexpressions of STR may refer to.  Pointers that
-     aren't known to point any such arrays result in LENDATA.MAXLEN
-     set to SIZE_MAX.  */
+  /* Try to determine the dynamic string length first.  */
   c_strlen_data lendata = { };
-  get_range_strlen (str, &lendata, eltsize);
+  if (eltsize == 1)
+    get_range_strlen_dynamic (str, &lendata, vr);
+  else
+    {
+      /* Determine the length of the shortest and longest string referenced
+        by STR.  Strings of unknown lengths are bounded by the sizes of
+        arrays that subexpressions of STR may refer to.  Pointers that
+        aren't known to point any such arrays result in LENDATA.MAXLEN
+        set to SIZE_MAX.  */
+      get_range_strlen (str, &lendata, eltsize);
+    }
+
+  /* LENDATA.MAXBOUND is null when LENDATA.MIN corresponds to the shortest
+     string referenced by STR.  Otherwise, if it's not equal to .MINLEN it
+     corresponds to the bound of the largest array STR refers to, if known,
+     or it's SIZE_MAX otherwise.  */
 
-  /* Return the default result when nothing is known about the string. */
-  if (integer_all_onesp (lendata.maxbound)
+  /* Return the default result when nothing is known about the string.  */
+  if (lendata.maxbound
+      && integer_all_onesp (lendata.maxbound)
       && integer_all_onesp (lendata.maxlen))
     return fmtresult ();
 
@@ -2054,7 +2005,7 @@ get_string_length (tree str, unsigned eltsize)
        : 0);
 
   HOST_WIDE_INT max
-    = (tree_fits_uhwi_p (lendata.maxbound)
+    = (lendata.maxbound && tree_fits_uhwi_p (lendata.maxbound)
        ? tree_to_uhwi (lendata.maxbound)
        : HOST_WIDE_INT_M1U);
 
@@ -2093,10 +2044,11 @@ get_string_length (tree str, unsigned eltsize)
   else
     {
       /* When the upper bound is unknown (it can be zero or excessive)
-        set the likely length to the greater of 1 and the length of
-        the shortest string and reset the lower bound to zero.  */
+        set the likely length to the greater of 1.  If MAXBOUND is
+        set, also reset the length of the lower bound to zero.  */
       res.range.likely = res.range.min ? res.range.min : warn_level > 1;
-      res.range.min = 0;
+      if (lendata.maxbound)
+       res.range.min = 0;
     }
 
   res.range.unlikely = unbounded ? HOST_WIDE_INT_MAX : res.range.max;
@@ -2110,7 +2062,7 @@ get_string_length (tree str, unsigned eltsize)
    vsprinf).  */
 
 static fmtresult
-format_character (const directive &dir, tree arg, vr_values *vr_values)
+format_character (const directive &dir, tree arg, const vr_values *vr_values)
 {
   fmtresult res;
 
@@ -2186,7 +2138,7 @@ format_character (const directive &dir, tree arg, vr_values *vr_values)
    vsprinf).  */
 
 static fmtresult
-format_string (const directive &dir, tree arg, vr_values *)
+format_string (const directive &dir, tree arg, const vr_values *vr_values)
 {
   fmtresult res;
 
@@ -2204,7 +2156,7 @@ format_string (const directive &dir, tree arg, vr_values *)
       gcc_checking_assert (count_by == 2 || count_by == 4);
     }
 
-  fmtresult slen = get_string_length (arg, count_by);
+  fmtresult slen = get_string_length (arg, count_by, vr_values);
   if (slen.range.min == slen.range.max
       && slen.range.min < HOST_WIDE_INT_MAX)
     {
@@ -2376,7 +2328,7 @@ format_string (const directive &dir, tree arg, vr_values *)
 /* Format plain string (part of the format string itself).  */
 
 static fmtresult
-format_plain (const directive &dir, tree, vr_values *)
+format_plain (const directive &dir, tree, const vr_values *)
 {
   fmtresult res (dir.len);
   return res;
@@ -2386,7 +2338,7 @@ format_plain (const directive &dir, tree, vr_values *)
    should be diagnosed given the AVAILable space in the destination.  */
 
 static bool
-should_warn_p (const sprintf_dom_walker::call_info &info,
+should_warn_p (const call_info &info,
               const result_range &avail, const result_range &result)
 {
   if (result.max <= avail.min)
@@ -2457,7 +2409,7 @@ should_warn_p (const sprintf_dom_walker::call_info &info,
 
 static bool
 maybe_warn (substring_loc &dirloc, location_t argloc,
-           const sprintf_dom_walker::call_info &info,
+           const call_info &info,
            const result_range &avail_range, const result_range &res,
            const directive &dir)
 {
@@ -2737,9 +2689,9 @@ maybe_warn (substring_loc &dirloc, location_t argloc,
    in *RES.  Return true if the directive has been handled.  */
 
 static bool
-format_directive (const sprintf_dom_walker::call_info &info,
+format_directive (const call_info &info,
                  format_result *res, const directive &dir,
-                 class vr_values *vr_values)
+                 const class vr_values *vr_values)
 {
   /* Offset of the beginning of the directive from the beginning
      of the format string.  */
@@ -3086,10 +3038,10 @@ format_directive (const sprintf_dom_walker::call_info &info,
    the directive.  */
 
 static size_t
-parse_directive (sprintf_dom_walker::call_info &info,
+parse_directive (call_info &info,
                 directive &dir, format_result *res,
                 const char *str, unsigned *argno,
-                vr_values *vr_values)
+                const vr_values *vr_values)
 {
   const char *pcnt = strchr (str, target_percent);
   dir.beg = str;
@@ -3526,9 +3478,8 @@ parse_directive (sprintf_dom_walker::call_info &info,
    on, false otherwise (e.g., when a unknown or unhandled directive was seen
    that caused the processing to be terminated early).  */
 
-bool
-sprintf_dom_walker::compute_format_length (call_info &info,
-                                          format_result *res)
+static bool
+compute_format_length (call_info &info, format_result *res, const vr_values *vr)
 {
   if (dump_file)
     {
@@ -3564,12 +3515,10 @@ sprintf_dom_walker::compute_format_length (call_info &info,
       directive dir = directive ();
       dir.dirno = dirno;
 
-      size_t n = parse_directive (info, dir, res, pf, &argno,
-                                 evrp_range_analyzer.get_vr_values ());
+      size_t n = parse_directive (info, dir, res, pf, &argno, vr);
 
       /* Return failure if the format function fails.  */
-      if (!format_directive (info, res, dir,
-                            evrp_range_analyzer.get_vr_values ()))
+      if (!format_directive (info, res, dir, vr))
        return false;
 
       /* Return success the directive is zero bytes long and it's
@@ -3617,7 +3566,7 @@ get_destination_size (tree dest)
    of its return values.  */
 
 static bool
-is_call_safe (const sprintf_dom_walker::call_info &info,
+is_call_safe (const call_info &info,
              const format_result &res, bool under4k,
              unsigned HOST_WIDE_INT retval[2])
 {
@@ -3676,7 +3625,7 @@ is_call_safe (const sprintf_dom_walker::call_info &info,
 
 static bool
 try_substitute_return_value (gimple_stmt_iterator *gsi,
-                            const sprintf_dom_walker::call_info &info,
+                            const call_info &info,
                             const format_result &res)
 {
   tree lhs = gimple_get_lhs (info.callstmt);
@@ -3794,7 +3743,7 @@ try_substitute_return_value (gimple_stmt_iterator *gsi,
 
 static bool
 try_simplify_call (gimple_stmt_iterator *gsi,
-                  const sprintf_dom_walker::call_info &info,
+                  const call_info &info,
                   const format_result &res)
 {
   unsigned HOST_WIDE_INT dummy[2];
@@ -3847,13 +3796,17 @@ get_user_idx_format (tree fndecl, unsigned *idx_args)
   return tree_to_uhwi (fmtarg) - 1;
 }
 
-/* Determine if a GIMPLE CALL is to one of the sprintf-like built-in
-   functions and if so, handle it.  Return true if the call is removed
-   and gsi_next should not be performed in the caller.  */
+}   /* Unnamed namespace.  */
+
+/* Determine if a GIMPLE call at *GSI is to one of the sprintf-like built-in
+   functions and if so, handle it.  Return true if the call is removed and
+   gsi_next should not be performed in the caller.  */
 
 bool
-sprintf_dom_walker::handle_gimple_call (gimple_stmt_iterator *gsi)
+handle_printf_call (gimple_stmt_iterator *gsi, const vr_values *vr_values)
 {
+  init_target_to_host_charmap ();
+
   call_info info = call_info ();
 
   info.callstmt = gsi_stmt (*gsi);
@@ -4119,7 +4072,9 @@ sprintf_dom_walker::handle_gimple_call (gimple_stmt_iterator *gsi)
          /* Try to determine the range of values of the argument
             and use the greater of the two at level 1 and the smaller
             of them at level 2.  */
-         const value_range *vr = evrp_range_analyzer.get_value_range (size);
+         const value_range *vr
+           = CONST_CAST (class vr_values *, vr_values)->get_value_range (size);
+
          if (range_int_cst_p (vr))
            {
              unsigned HOST_WIDE_INT minsize = TREE_INT_CST_LOW (vr->min ());
@@ -4230,7 +4185,7 @@ sprintf_dom_walker::handle_gimple_call (gimple_stmt_iterator *gsi)
      never set to true again).  */
   res.posunder4k = posunder4k && dstptr;
 
-  bool success = compute_format_length (info, &res);
+  bool success = compute_format_length (info, &res, vr_values);
   if (res.warned)
     gimple_set_no_warning (info.callstmt, true);
 
@@ -4256,71 +4211,3 @@ sprintf_dom_walker::handle_gimple_call (gimple_stmt_iterator *gsi)
 
   return call_removed;
 }
-
-edge
-sprintf_dom_walker::before_dom_children (basic_block bb)
-{
-  evrp_range_analyzer.enter (bb);
-  for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si); )
-    {
-      /* Iterate over statements, looking for function calls.  */
-      gimple *stmt = gsi_stmt (si);
-
-      /* First record ranges generated by this statement.  */
-      evrp_range_analyzer.record_ranges_from_stmt (stmt, false);
-
-      if (is_gimple_call (stmt) && handle_gimple_call (&si))
-       /* If handle_gimple_call returns true, the iterator is
-          already pointing to the next statement.  */
-       continue;
-
-      gsi_next (&si);
-    }
-  return NULL;
-}
-
-void
-sprintf_dom_walker::after_dom_children (basic_block bb)
-{
-  evrp_range_analyzer.leave (bb);
-}
-
-/* Execute the pass for function FUN.  */
-
-unsigned int
-pass_sprintf_length::execute (function *fun)
-{
-  init_target_to_host_charmap ();
-
-  calculate_dominance_info (CDI_DOMINATORS);
-  bool use_scev = optimize > 0 && flag_printf_return_value;
-  if (use_scev)
-    {
-      loop_optimizer_init (LOOPS_NORMAL);
-      scev_initialize ();
-    }
-
-  sprintf_dom_walker sprintf_dom_walker;
-  sprintf_dom_walker.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
-
-  if (use_scev)
-    {
-      scev_finalize ();
-      loop_optimizer_finalize ();
-    }
-
-  /* Clean up object size info.  */
-  fini_object_sizes ();
-  return 0;
-}
-
-}   /* Unnamed namespace.  */
-
-/* Return a pointer to a pass object newly constructed from the context
-   CTXT.  */
-
-gimple_opt_pass *
-make_pass_sprintf_length (gcc::context *ctxt)
-{
-  return new pass_sprintf_length (ctxt);
-}
index fe5a411504defd658bc38e599dba78aacc6b1e1c..e50cf62657c8797848fa7c9ae838a5f3f1d1e44c 100644 (file)
@@ -42,7 +42,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_build_cfg);
   NEXT_PASS (pass_warn_function_return);
   NEXT_PASS (pass_expand_omp);
-  NEXT_PASS (pass_sprintf_length, false);
+  NEXT_PASS (pass_warn_printf);
   NEXT_PASS (pass_walloca, /*strict_mode_p=*/true);
   NEXT_PASS (pass_build_cgraph_edges);
   TERMINATE_PASS_LIST (all_lowering_passes)
@@ -307,7 +307,6 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_lower_vector_ssa);
       NEXT_PASS (pass_lower_switch);
       NEXT_PASS (pass_cse_reciprocals);
-      NEXT_PASS (pass_sprintf_length, true);
       NEXT_PASS (pass_reassoc, false /* insert_powi_p */);
       NEXT_PASS (pass_strength_reduction);
       NEXT_PASS (pass_split_paths);
@@ -358,7 +357,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_object_sizes);
       /* Fold remaining builtins.  */
       NEXT_PASS (pass_fold_builtins);
-      NEXT_PASS (pass_sprintf_length, true);
+      NEXT_PASS (pass_strlen);
       /* Copy propagation also copy-propagates constants, this is necessary
          to forward object-size and builtin folding results properly.  */
       NEXT_PASS (pass_copy_prop);
index 10948efddd910f9f9d424ad4abbe3a1e66b21e78..b96ab5e0544aa717d87428451ca5975cf4aba2d2 100644 (file)
@@ -1815,7 +1815,7 @@ print_pattern (pretty_printer *pp, const_rtx x, int verbose)
            gcc_assert (strlen (print_rtx_head) < sizeof (indented_print_rtx_head) - 4);
            snprintf (indented_print_rtx_head,
                      sizeof (indented_print_rtx_head),
-                     "%s     ", print_rtx_head);
+                     "%s    ", print_rtx_head);
            print_rtx_head = indented_print_rtx_head;
            for (int i = 0; i < seq->len (); i++)
              print_insn_with_notes (pp, seq->insn (i));
index fab9d338e30c32672c07cc185ba5a12ee4207b8c..9bdc2f9b0fb20787ec5e807f206c03cd92e3475f 100644 (file)
 
        * gcc.target/mips/get-fcsr-3.c: New test.
 
+2019-08-23  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/83431
+       * gcc.dg/strlenopt-63.c: New test.
+       * gcc.dg/pr79538.c: Adjust text of expected warning.
+       * gcc.dg/pr81292-1.c: Adjust pass name.
+       * gcc.dg/pr81292-2.c: Same.
+       * gcc.dg/pr81703.c: Same.
+       * gcc.dg/strcmpopt_2.c: Same.
+       * gcc.dg/strcmpopt_3.c: Same.
+       * gcc.dg/strcmpopt_4.c: Same.
+       * gcc.dg/strlenopt-1.c: Same.
+       * gcc.dg/strlenopt-10.c: Same.
+       * gcc.dg/strlenopt-11.c: Same.
+       * gcc.dg/strlenopt-13.c: Same.
+       * gcc.dg/strlenopt-14g.c: Same.
+       * gcc.dg/strlenopt-14gf.c: Same.
+       * gcc.dg/strlenopt-15.c: Same.
+       * gcc.dg/strlenopt-16g.c: Same.
+       * gcc.dg/strlenopt-17g.c: Same.
+       * gcc.dg/strlenopt-18g.c: Same.
+       * gcc.dg/strlenopt-19.c: Same.
+       * gcc.dg/strlenopt-1f.c: Same.
+       * gcc.dg/strlenopt-2.c: Same.
+       * gcc.dg/strlenopt-20.c: Same.
+       * gcc.dg/strlenopt-21.c: Same.
+       * gcc.dg/strlenopt-22.c: Same.
+       * gcc.dg/strlenopt-22g.c: Same.
+       * gcc.dg/strlenopt-24.c: Same.
+       * gcc.dg/strlenopt-25.c: Same.
+       * gcc.dg/strlenopt-26.c: Same.
+       * gcc.dg/strlenopt-27.c: Same.
+       * gcc.dg/strlenopt-28.c: Same.
+       * gcc.dg/strlenopt-29.c: Same.
+       * gcc.dg/strlenopt-2f.c: Same.
+       * gcc.dg/strlenopt-3.c: Same.
+       * gcc.dg/strlenopt-30.c: Same.
+       * gcc.dg/strlenopt-31g.c: Same.
+       * gcc.dg/strlenopt-32.c: Same.
+       * gcc.dg/strlenopt-33.c: Same.
+       * gcc.dg/strlenopt-33g.c: Same.
+       * gcc.dg/strlenopt-34.c: Same.
+       * gcc.dg/strlenopt-35.c: Same.
+       * gcc.dg/strlenopt-4.c: Same.
+       * gcc.dg/strlenopt-48.c: Same.
+       * gcc.dg/strlenopt-49.c: Same.
+       * gcc.dg/strlenopt-4g.c: Same.
+       * gcc.dg/strlenopt-4gf.c: Same.
+       * gcc.dg/strlenopt-5.c: Same.
+       * gcc.dg/strlenopt-50.c: Same.
+       * gcc.dg/strlenopt-51.c: Same.
+       * gcc.dg/strlenopt-52.c: Same.
+       * gcc.dg/strlenopt-53.c: Same.
+       * gcc.dg/strlenopt-54.c: Same.
+       * gcc.dg/strlenopt-55.c: Same.
+       * gcc.dg/strlenopt-56.c: Same.
+       * gcc.dg/strlenopt-6.c: Same.
+       * gcc.dg/strlenopt-61.c: Same.
+       * gcc.dg/strlenopt-7.c: Same.
+       * gcc.dg/strlenopt-8.c: Same.
+       * gcc.dg/strlenopt-9.c: Same.
+       * gcc.dg/strlenopt.h (snprintf, snprintf): Declare.
+       * gcc.dg/tree-ssa/builtin-snprintf-6.c: New test.
+       * gcc.dg/tree-ssa/builtin-snprintf-7.c: New test.
+       * gcc.dg/tree-ssa/builtin-snprintf-8.c: New test.
+       * gcc.dg/tree-ssa/builtin-snprintf-9.c: New test.
+       * gcc.dg/tree-ssa/builtin-sprintf-warn-21.c: New test.
+       * gcc.dg/tree-ssa/dump-4.c: New test.
+       * gcc.dg/tree-ssa/pr83501.c: Adjust pass name.
+
 2019-08-23  Martin Sebor  <msebor@redhat.com>
 
        * gcc.dg/Warray-bounds-36.c: Make functions static to avoid failures
index 6cdab45128afdc3672a4cdcb7ccd6c2d46082ec4..4f10d97395e73af32a8a6fb051eab2b0c03e0313 100644 (file)
@@ -17,6 +17,6 @@ void f ()
 {
   char des[3];
   char src[] = "abcd";
-  __builtin_sprintf (des, "%s", src); /* { dg-warning "directive writing up to 4 bytes into a region of size 3" } */
+  __builtin_sprintf (des, "%s", src); /* { dg-warning "directive writing 4 bytes into a region of size 3" } */
   return;
 }
index 931e4c37c171f7c7d2cad5f766bc6123002f8189..2a454df88a1b2343114fd48930794c210e060236 100644 (file)
@@ -32,4 +32,4 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
index c1c507f982e94ef224dcf82a66a36e2f4408af60..252884abca7f30c951b2c0b44f54bf92836a1b5e 100644 (file)
@@ -32,4 +32,4 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 6 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 6 "strlen1" } } */
index 190f4a833ddd6ca3ca96992a5592da22354e2269..02edf267437ff14aaf36c810b3b14057e3bbb40b 100644 (file)
@@ -9,4 +9,4 @@ unsigned g (void)
   return __builtin_strlen (d);
 }
 
-/* { dg-final { scan-tree-dump-not "__builtin_strlen" "strlen" } } */
+/* { dg-final { scan-tree-dump-not "__builtin_strlen" "strlen1" } } */
index 0131b8f7d69d644eb428a88d3162e95f6d826ee0..57d8f651c28593361a20ac5525f378d1846d10c1 100644 (file)
@@ -64,4 +64,4 @@ int main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 8 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 8 "strlen1" } } */
index 86a0d7a08b3a4c081d83c782b1e586e9694d1318..571646ce001d9cc127e166e6252145e3bd058005 100644 (file)
@@ -28,4 +28,4 @@ int main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strcmp" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcmp" 0 "strlen1" } } */
index d727bc363e5c353997407580fa81ac0cddd2ccf6..4e26522eed14f638fc1f33ab8dead3ff94a5e299 100644 (file)
@@ -13,4 +13,4 @@ f1 (S * s)
   return result;
 }
 
-/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 1 "strlen1" } } */
index 910ec672e96038bc5d41a4f2ef772a0dc14b2fa8..24772c1449948970c8e842586bc793e9b5a912a3 100644 (file)
@@ -36,9 +36,9 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
index 97167df959f9ad0bac0304036d7945e59db52524..ce959c34a80e5277d4b692a3882870f96db9e035 100644 (file)
@@ -69,14 +69,14 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
 /* avr has BIGGEST_ALIGNMENT 8, allowing fold_builtin_memory_op
    to expand the memcpy call at the end of fn2.  */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 8 "strlen" { target { ! avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" { target { avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "\\*q_\[0-9\]* = 32;" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(\[^\n\r\]*, 1\\)" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 8 "strlen1" { target { ! avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen1" { target { avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "\\*q_\[0-9\]* = 32;" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(\[^\n\r\]*, 1\\)" 1 "strlen1" } } */
index f7fa44bde35a084b94de26953f86b104509f6111..abd9faebed6b4bffd9e7ebebaa0f60c8f3dd881a 100644 (file)
@@ -58,18 +58,18 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen1" } } */
 /* avr has BIGGEST_ALIGNMENT 8, allowing fold_builtin_memory_op
    to expand the memcpy call at the end of fn1.  */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" { target { ! avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" { target { avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen1" { target { ! avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen1" { target { avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
 /* Where the memcpy is expanded, the assignemts to elements of l are
    propagated.  */
-/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.0. = " 1 "strlen" { target { ! avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.6. = " 1 "strlen" { target { ! avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.9. = " 1 "strlen" { target { ! avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;" 3 "strlen" { target { avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.0. = " 1 "strlen1" { target { ! avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.6. = " 1 "strlen1" { target { ! avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.9. = " 1 "strlen1" { target { ! avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;" 3 "strlen1" { target { avr-*-* } } } } */
index 3502599b28c4e4816805cd1d0feecd42c2fb5d6b..27ecc79c2d9153a4d71b8b6c4b80cbf60514f39c 100644 (file)
@@ -55,19 +55,19 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen1" } } */
 /* avr has BIGGEST_ALIGNMENT 8, allowing fold_builtin_memory_op
    to expand the memcpy call at the end of fn1.  */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" { target { ! avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" { target { avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen1" { target { ! avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen1" { target { avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
 /* Where the memcpy is expanded, the assignemts to elements of l are
    propagated.  */
-/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.0. = " 1 "strlen" { target { ! avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.1. = " 1 "strlen" { target { ! avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.5. = " 1 "strlen" { target { ! avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.6. = " 1 "strlen" { target { ! avr-*-* } } } } */
-/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;" 4 "strlen" { target { avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.0. = " 1 "strlen1" { target { ! avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.1. = " 1 "strlen1" { target { ! avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.5. = " 1 "strlen1" { target { ! avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;\[\n\r\]*  l.6. = " 1 "strlen1" { target { ! avr-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "  _\[0-9\]* = strlen \\(\[^\n\r\]*;" 4 "strlen1" { target { avr-*-* } } } } */
index 62a83bf8fd7e08b8df2f3eb85672357933bcbcec..1368ed3f68e9b6dabfc91d7184ecbe3a7ae8f8e0 100644 (file)
@@ -107,10 +107,10 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "mempcpy \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "mempcpy \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen1" } } */
index 8b126fcb7eafbf593f30eff0ec90f6a4858e5425..f7db2a8a53eb3acf6aff3a6ee3c8b44aaa0b90a2 100644 (file)
 /* Compared to strlenopt-14gf.c, strcpy_chk with string literal as
    second argument isn't being optimized by builtins.c into
    memcpy.  */
-/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__mempcpy_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "mempcpy \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__mempcpy_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "mempcpy \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen1" } } */
index 827ea07b6ea30b51ee95cf5736a34012c4f51f19..b72c096ffa9c9fbe56829b875e33d7b3aa01e736 100644 (file)
@@ -51,9 +51,9 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
index 0cf8410735a9e3a2f5d3bd22e283e40e8f7228e4..816cbbce8013bea4632451506d812e173b478e2b 100644 (file)
@@ -24,10 +24,10 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen1" } } */
index 184e530788ec90b534a96f0584a168a6a5cdfde4..aa86f78ec7f27ce2286b5a70553a8879ce9325bf 100644 (file)
@@ -47,10 +47,10 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "mempcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen1" } } */
index f734675ec404519f868e10d078fe70d4460b3d11..de692e0767ac965d98330744adbc4440b5e6a3de 100644 (file)
@@ -73,9 +73,9 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen1" } } */
index 022ba8b47871b1fefb85f889fc821dd7a15f477c..814f51b27f6a84fc44da062fe5a31cd0c2ad8bd3 100644 (file)
@@ -72,9 +72,9 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
index 856774de7adfdee478ad5b3315ded273bd36ea4c..4e3abd9472d67e7728a8512450bef44e977caa9d 100644 (file)
@@ -5,13 +5,13 @@
 #define FORTIFY_SOURCE 2
 #include "strlenopt-1.c"
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
index fd59a3cd513802e0d427be84eef9300c8ecbdd9f..b09f7c17e39d03a713dde64569589b8c21c6cf90 100644 (file)
@@ -40,9 +40,9 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 5 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 5 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
index 7b483eaeac1aa47278111a92148a16f00b2aaa2d..79db12bc1028928466e2b16843db270953475ba9 100644 (file)
@@ -86,9 +86,9 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
index 05b85a49dde0a7f5d269174fd4269e40be910dbd..7924ff30b511d676bad74beb558000e825f6e466 100644 (file)
@@ -57,9 +57,9 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
index b4ef772f0e59252f10a5419ede6837b3c8ca8265..2d127b118325717a2614e7b57ebd77efdae3e7f2 100644 (file)
@@ -31,9 +31,9 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
index 9c5d020588f3f338a9acf51d36facfea55810760..1ecb85eae0cbb9fcd141a420b19ee46ce797cd10 100644 (file)
@@ -5,9 +5,9 @@
 #define USE_GNU
 #include "strlenopt-22.c"
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen1" } } */
index 639501a53e0e0ad7daa1035a59e684e1de8e6bd3..275b5602b70f93a96df6f158fb9e4c473ad1af45 100644 (file)
@@ -13,4 +13,4 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */
index 89b60e3ebed3bbac489f6db7705cdb5014f634d9..faed5bec88954533171b240320080f41f59a792e 100644 (file)
@@ -14,4 +14,4 @@ main ()
   return len - len2;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */
index 6bb0263d315b4443a93f9d859aebcd1d04f9c289..0385aceaad3cd54bec8de8027ee6bef43bd4f3a4 100644 (file)
@@ -20,5 +20,5 @@ main (void)
   return fn1 (p, q);
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
index c539edb821ccc7cc0e14c8a850c743e0aef30641..e3655930b3e9102e75d4e912435748e10e511e38 100644 (file)
@@ -19,4 +19,4 @@ main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */
index 03fb01781bd4fe92687fe30c1fb89573965139e9..6bdbed7e9d0fa0127bb94856ab976a8c9b2a7bbd 100644 (file)
@@ -56,4 +56,4 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */
index fb4b4c9cc71c671f5f84ca83ec6c5376736ac245..8922101f549e06f03496d8aad488987805d72fa5 100644 (file)
@@ -24,4 +24,4 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */
index 1e915dac928f87fefa84cbf8230b0fde4acdd078..5786f8a1904764ba830163740ed113649d77d197 100644 (file)
@@ -5,13 +5,13 @@
 #define FORTIFY_SOURCE 2
 #include "strlenopt-2.c"
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 5 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 5 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
index f17779c0a66247ef04d1cd228577956399f96332..a748f011c80161d100478291e89c323d9fa5eb67 100644 (file)
@@ -53,12 +53,12 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
 /* { dg-final { scan-tree-dump-times "return 0" 3 "optimized" } } */
 /* { dg-final { scan-tree-dump-times "return 4" 1 "optimized" } } */
 /* { dg-final { scan-tree-dump-times "return 3" 1 "optimized" } } */
index a85df686ce2f68ea53970d5534bd0a69af7026bd..2a3098ba96f78641477703501711b4829340bdb0 100644 (file)
@@ -60,4 +60,4 @@ _Bool f7(char *s)
   return (t1 == s);
 }
 
-/* { dg-final { scan-tree-dump-times "__builtin_strncmp" 5 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "__builtin_strncmp" 5 "strlen1" } } */
index 45cc29c1024b71822d8b25df793e8dd151ae5ca3..4eff86448f1562be193e38e47850bebfc899edb0 100644 (file)
@@ -4,6 +4,6 @@
 #define USE_GNU
 #include "strlenopt-31.c"
 
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-not "strlen \\(" "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-not "strlen \\(" "strlen1" } } */
index 08eb6bc2b082f4048cd57e8633fb900c4ea8cc59..4220314fb3f06074e55319d8dc971d9e012f4e11 100644 (file)
@@ -190,4 +190,4 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */
index 1e1c4dee1f8fea1b7d2e15d3fa40069732a45fe1..4903a91a0a4ff3722ae20ccca66d0c8e09eab9e8 100644 (file)
@@ -39,4 +39,4 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
index 7d24d2bfc32c9d1af72ebc86ae467c11b6667d41..a814160e234253e068d0a48aad318d280d72ab36 100644 (file)
@@ -40,5 +40,5 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 2 "strlen1" } } */
index c9433c0399e01e194dc067a7aada9316f8c06f8d..1979370cb5e352687f24ae955fffa2d332c7a84b 100644 (file)
@@ -35,4 +35,4 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
index 03b3e13a8e278c510f58b21cd61ef151bdf419b6..d175fd7ff5051048907cdd90e0b5f6fbcf3bf96c 100644 (file)
@@ -28,4 +28,4 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen1" } } */
index 802e4ca7ce49fca4c4b005a93e03d252e83f7801..1d0a6e615bc2be39da05642981e149612f46332a 100644 (file)
@@ -66,9 +66,9 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 3 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 3 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 3 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 3 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
index 179edd82a43338ca3e47058d711a47b6ac32da23..c2d0ac66521bcecf0b950e9bb97553e4efd9b4ae 100644 (file)
@@ -31,5 +31,5 @@ void h (void)
     abort();
 }
 
-/* { dg-final { scan-tree-dump-times "strlen" 0 "optimized" } }
+/* { dg-final { scan-tree-dump-times "strlen1" 0 "optimized" } }
    { dg-final { scan-tree-dump-times "abort" 0 "optimized" } } */
index f901fd14b54bf953a39ab3e29ba7a2150e37c63a..bbea0e2db7247d26435c4910360504979ddf0177 100644 (file)
@@ -45,7 +45,7 @@ int cmp88 (void)
   return cmp88;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } }
+/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } }
    { dg-final { scan-tree-dump-times "len0 = 0;" 1 "gimple" } }
    { dg-final { scan-tree-dump-times "len = 18;" 1 "gimple" } }
    { dg-final { scan-tree-dump-times "lenx = 8;" 1 "gimple" } }
index 879d5666c90eb64bd1e622d20f63e610b1e115a7..88dcec647e7a9bbd2acce301b03c08e09be04d1a 100644 (file)
@@ -5,9 +5,9 @@
 #define USE_GNU
 #include "strlenopt-4.c"
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 5 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 5 "strlen1" } } */
index 7f261b7d34df13210d7d459d7fcf31385274bbff..033661ad4a96a91a97813d49e99793cf0b4638ba 100644 (file)
@@ -6,13 +6,13 @@
 #define FORTIFY_SOURCE 2
 #include "strlenopt-4.c"
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 5 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__memcpy_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__strcpy_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__strcat_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "__stpcpy_chk \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 4 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 5 "strlen1" } } */
index a24aea44e8b00ff7b35a907aaa941b4c509642c4..5a31322bfa15f1ee495fba3fa7dea6ee9cbc8be8 100644 (file)
@@ -48,9 +48,9 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
index 1d1d36808a946f45c2bda24d779940af0e9ad5f6..8e7c9dbd93df14758d4d499f22f73fe8603040d8 100644 (file)
@@ -112,5 +112,5 @@ void test_array_ref (void)
   T (&b[16], 0);  T (&b[17], 0);  T (&b[18], 0);  T (&b[19], 0);
 }
 
-/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } }
+/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } }
    { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated" 0 "ccp1" } } */
index 3d879f1329ac946203d6f35d36976d10e0958519..22a89385f5ef12152bc6949b8253e030092c3f2f 100644 (file)
@@ -84,4 +84,4 @@ void test_elim_a9_9 (unsigned i)
   T (0); T (1); T (2); T (3); T (4); T (5); T (6); T (7); T (8);
 }
 
-/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } } */
index 03e063b435ed4e855b577eab73711ec078672392..97b3da7cd0e468897493cd423a5e547e425f6f77 100644 (file)
@@ -284,5 +284,5 @@ void test_global_struct_struct_array (void)
   T (ssa[5].sa9[3].a6, 3);
 }
 
-/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } }
+/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } }
    { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated" 0 "ccp1" } } */
index baa680d125b90b3c2d5355c613842df1a9b70a8c..489c22b69372cd5695f8552715a296a274f4cf2e 100644 (file)
@@ -112,5 +112,5 @@ void test_array_ref (void)
   T (&b[16], 0);  T (&b[17], 0);  T (&b[18], 0);  T (&b[19], 0);
 }
 
-/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } }
+/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } }
    { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated" 0 "ccp1" } } */
index c38e7918f8bc2d71b1ad91a4adbd57245294e18e..d4e57ff62559212a8d3951fc9846b6f1f9087f1d 100644 (file)
@@ -105,5 +105,5 @@ void elim_after_init_memcpy (void)
   T ("AB\000CD", 0, "ab\000c", 4, 2);
 }
 
-/* { dg-final { scan-tree-dump-times "strlen" 0 "optimized" } }
+/* { dg-final { scan-tree-dump-times "strlen1" 0 "optimized" } }
    { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated" 0 "optimized" } } */
index d5a02953d36ff747a3625e18d9b618b034568d50..ea6fb22a2edbb7899def39581c998c9cc7f56aad 100644 (file)
@@ -224,7 +224,7 @@ const void test_large_string_size (void)
 }
 
 
-/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } }
+/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } }
    { dg-final { scan-tree-dump-times "memcmp" 0 "gimple" } }
    { dg-final { scan-tree-dump-times "strcmp" 0 "gimple" } }
    { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated" 0 "optimized" } } */
index 39a532bf8d4892babcacd3d81cb8952cdf1f82b6..ffd02f1b6cfde89c683e8a2c1865641c5cc07d18 100644 (file)
@@ -45,6 +45,6 @@ void test_contents (void)
 }
 
 
-/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } }
+/* { dg-final { scan-tree-dump-times "strlen1" 0 "gimple" } }
    { dg-final { scan-tree-dump-times "strcmp" 0 "gimple" } }
    { dg-final { scan-tree-dump-times "abort" 0 "optimized" } } */
index fbff14c4fdbacce3ae44221fed53447de46be41e..dcbe778a27a988e921bbcc35ace4de3c9ce34eaf 100644 (file)
@@ -77,9 +77,9 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 7 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
index 4f8e9c053e450c60399f7872d283789d44a76136..3ddfa2ebc9f569e1c87e93490ede1321d803b551 100644 (file)
@@ -215,4 +215,4 @@ void test_ta2 (void)
 }
 
 /* { dg-final { scan-tree-dump-not "failure" "optimized" } }
-   { dg-final { scan-tree-dump-not "strlen" "gimple" } } */
+   { dg-final { scan-tree-dump-not "strlen1" "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-68.c b/gcc/testsuite/gcc.dg/strlenopt-68.c
new file mode 100644 (file)
index 0000000..56d314e
--- /dev/null
@@ -0,0 +1,382 @@
+/* PR tree-optimization/83431 - Verify that snprintf (0, 0, "%s",
+   with an argument that's a conditional expression evaluates to
+   the expected result regardless of the order of the expression
+   operands.
+   { dg-do run }
+   { dg-options "-O2 -Wall" } */
+
+#include "strlenopt.h"
+
+#define A(expr)                                                 \
+  ((expr)                                                       \
+   ? (void)0                                                    \
+   : (__builtin_printf ("assertion failed on line %i: %s\n",    \
+                        __LINE__, #expr),                       \
+      __builtin_abort ()))
+
+const char gs0[] = "";
+const char gs3[] = "123";
+
+char gc;
+char ga5[7];
+
+struct S { char n, ma7[7], max[]; };
+
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_gs0_gs3_ga5_m1 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? gs0 : 0 < i ? gs3 : ga5;
+
+  A (snprintf (0, 0, "%s", p) == 0);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_gs0_gs3_ga5_0 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? gs0 : 0 < i ? gs3 : ga5;
+
+  A (snprintf (0, 0, "%s", p) == 4);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_gs0_gs3_ga5_p1 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? gs0 : 0 < i ? gs3 : ga5;
+
+  A (snprintf (0, 0, "%s", p) == 3);
+}
+
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_gs0_ga5_gs3_m1 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? gs0 : 0 < i ? ga5 : gs3;
+
+  A (snprintf (0, 0, "%s", p) == 0);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_gs0_ga5_gs3_0 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? gs0 : 0 < i ? ga5 : gs3;
+
+  A (snprintf (0, 0, "%s", p) == 3);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_gs0_ga5_gs3_p1 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? gs0 : 0 < i ? ga5 : gs3;
+
+  A (snprintf (0, 0, "%s", p) == 4);
+}
+
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_ga5_gs0_gs3_m1 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? ga5 : 0 < i ? gs0 : gs3;
+
+  A (snprintf (0, 0, "%s", p) == 4);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_ga5_gs0_gs3_0 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? ga5 : 0 < i ? gs0 : gs3;
+
+  A (snprintf (0, 0, "%s", p) == 3);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_ga5_gs0_gs3_p1 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? ga5 : 0 < i ? gs0 : gs3;
+
+  A (snprintf (0, 0, "%s", p) == 0);
+}
+
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_ga5_gs3_gs0_m1 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? ga5 : 0 < i ? gs3 : gs0;
+
+  A (snprintf (0, 0, "%s", p) == 4);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_ga5_gs3_gs0_0 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? ga5 : 0 < i ? gs3 : gs0;
+
+  A (snprintf (0, 0, "%s", p) == 0);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_ga5_gs3_gs0_p1 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? ga5 : 0 < i ? gs3 : gs0;
+
+  A (snprintf (0, 0, "%s", p) == 3);
+}
+
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_gs3_gs0_ga5_m1 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? gs3 : 0 < i ? gs0 : ga5;
+
+  A (snprintf (0, 0, "%s", p) == 3);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_gs3_gs0_ga5_0 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? gs3 : 0 < i ? gs0 : ga5;
+
+  A (snprintf (0, 0, "%s", p) == 4);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+equal_4_gs3_gs0_ga5_p1 (int i)
+{
+  strcpy (ga5, "1234");
+  const char *p = i < 0 ? gs3 : 0 < i ? gs0 : ga5;
+
+  A (snprintf (0, 0, "%s", p) == 0);
+}
+
+
+/* Similar to the above but with memcpy creating a string at least
+   four characters long, and the address of the NUL character.  */
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_gc_gs3_ga5_m1 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? &gc : 0 < i ? gs3 : ga5;
+
+  A (snprintf (0, 0, "%s", p) == 0);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_gc_gs3_ga5_0 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? &gc : 0 < i ? gs3 : ga5;
+
+  A (snprintf (0, 0, "%s", p) == 4);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_gc_gs3_ga5_p1 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? &gc : 0 < i ? gs3 : ga5;
+
+  A (snprintf (0, 0, "%s", p) == 3);
+}
+
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_gc_ga5_gs3_m1 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? &gc : 0 < i ? ga5 : gs3;
+
+  A (snprintf (0, 0, "%s", p) == 0);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_gc_ga5_gs3_0 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? &gc : 0 < i ? ga5 : gs3;
+
+  A (snprintf (0, 0, "%s", p) == 3);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_gc_ga5_gs3_p1 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? &gc : 0 < i ? ga5 : gs3;
+
+  A (snprintf (0, 0, "%s", p) == 4);
+}
+
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_ga5_gc_gs3_m1 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? ga5 : 0 < i ? &gc : gs3;
+
+  A (snprintf (0, 0, "%s", p) == 4);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_ga5_gc_gs3_0 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? ga5 : 0 < i ? &gc : gs3;
+
+  A (snprintf (0, 0, "%s", p) == 3);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_ga5_gc_gs3_p1 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? ga5 : 0 < i ? &gc : gs3;
+
+  A (snprintf (0, 0, "%s", p) == 0);
+}
+
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_ga5_gs3_gc_m1 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? ga5 : 0 < i ? gs3 : &gc;
+
+  A (snprintf (0, 0, "%s", p) == 4);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_ga5_gs3_gc_0 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? ga5 : 0 < i ? gs3 : &gc;
+
+  A (snprintf (0, 0, "%s", p) == 0);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_ga5_gs3_gc_p1 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? ga5 : 0 < i ? gs3 : &gc;
+
+  A (snprintf (0, 0, "%s", p) == 3);
+}
+
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_gs3_gc_ga5_m1 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? gs3 : 0 < i ? &gc : ga5;
+
+  A (snprintf (0, 0, "%s", p) == 3);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_gs3_gc_ga5_0 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? gs3 : 0 < i ? &gc : ga5;
+
+  A (snprintf (0, 0, "%s", p) == 4);
+}
+
+__attribute__ ((noclone, noinline, noipa)) void
+min_4_gs3_gc_ga5_p1 (int i)
+{
+  gc = 0;
+  memcpy (ga5, "1234", 4);
+  const char *p = i < 0 ? gs3 : 0 < i ? &gc : ga5;
+
+  A (snprintf (0, 0, "%s", p) == 0);
+}
+
+
+int main (void)
+{
+  equal_4_gs0_gs3_ga5_m1 (-1);
+  equal_4_gs0_gs3_ga5_0  ( 0);
+  equal_4_gs0_gs3_ga5_p1 (+1);
+
+  equal_4_gs0_ga5_gs3_m1 (-1);
+  equal_4_gs0_ga5_gs3_0  ( 0);
+  equal_4_gs0_ga5_gs3_p1 (+1);
+
+  equal_4_ga5_gs0_gs3_m1 (-1);
+  equal_4_ga5_gs0_gs3_0  ( 0);
+  equal_4_ga5_gs0_gs3_p1 (+1);
+
+  equal_4_ga5_gs3_gs0_m1 (-1);
+  equal_4_ga5_gs3_gs0_0  ( 0);
+  equal_4_ga5_gs3_gs0_p1 (+1);
+
+  equal_4_gs3_gs0_ga5_m1 (-1);
+  equal_4_gs3_gs0_ga5_0  ( 0);
+  equal_4_gs3_gs0_ga5_p1 (+1);
+
+  /* Same as aabove but with memcpy creating a string at least four
+     characters long.  */
+  memset (ga5, 0, sizeof ga5);
+  min_4_gc_gs3_ga5_m1 (-1);
+  memset (ga5, 0, sizeof ga5);
+  min_4_gc_gs3_ga5_0  ( 0);
+  memset (ga5, 0, sizeof ga5);
+  min_4_gc_gs3_ga5_p1 (+1);
+
+  memset (ga5, 0, sizeof ga5);
+  min_4_gc_ga5_gs3_m1 (-1);
+  memset (ga5, 0, sizeof ga5);
+  min_4_gc_ga5_gs3_0  ( 0);
+  memset (ga5, 0, sizeof ga5);
+  min_4_gc_ga5_gs3_p1 (+1);
+
+  memset (ga5, 0, sizeof ga5);
+  min_4_ga5_gc_gs3_m1 (-1);
+  memset (ga5, 0, sizeof ga5);
+  min_4_ga5_gc_gs3_0  ( 0);
+  memset (ga5, 0, sizeof ga5);
+  min_4_ga5_gc_gs3_p1 (+1);
+
+  memset (ga5, 0, sizeof ga5);
+  min_4_ga5_gs3_gc_m1 (-1);
+  memset (ga5, 0, sizeof ga5);
+  min_4_ga5_gs3_gc_0  ( 0);
+  memset (ga5, 0, sizeof ga5);
+  min_4_ga5_gs3_gc_p1 (+1);
+
+  memset (ga5, 0, sizeof ga5);
+  min_4_gs3_gc_ga5_m1 (-1);
+  memset (ga5, 0, sizeof ga5);
+  min_4_gs3_gc_ga5_0  ( 0);
+  memset (ga5, 0, sizeof ga5);
+  min_4_gs3_gc_ga5_p1 (+1);
+}
index aa53d7e75254dfe56c93172afc49f95e5b7901e6..ba62c03962208ba560878715ccb0121d1a7e1af8 100644 (file)
@@ -40,12 +40,12 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "\\*r_\[0-9\]* = 0;" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 2 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "\\*r_\[0-9\]* = 0;" 1 "strlen1" } } */
 /* { dg-final { scan-tree-dump-times "return 3;" 1 "optimized" } } */
 /* { dg-final { scan-tree-dump-times "return 0;" 2 "optimized" } } */
index e8ff1023d71268e2067993189d5f62eab37a16e5..df6b594946aa60d4989762fb5f6a6fa346655473 100644 (file)
@@ -98,10 +98,10 @@ main ()
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "strlen \\(" 5 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen" } } */
-/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen \\(" 5 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 0 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen1" } } */
 /* { dg-final { scan-tree-dump-times "return 4;" 1 "optimized" } } */
index d25e08a8a42ea0eb96f78b8c254ecd8834e7f140..518d0cf08b26ec85f1acab3979c663e3c9c8659e 100644 (file)
@@ -1,4 +1,4 @@
-/* This is a replacement of needed parts from stdlib.h and string.h
+/* This is a replacement of needed parts from <stdlib.h> and <string.h>
    for -foptimize-strlen testing, to ensure we are testing the builtins
    rather than whatever the OS has in its headers.  */
 
@@ -25,6 +25,9 @@ void *mempcpy (void *__restrict, const void *__restrict, size_t);
 char *stpcpy (char *__restrict, const char *__restrict);
 #endif
 
+int sprintf (char * __restrict, const char *__restrict, ...);
+int snprintf (char * __restrict, size_t, const char *__restrict, ...);
+
 #if defined(FORTIFY_SOURCE) && FORTIFY_SOURCE > 0 && __OPTIMIZE__
 # define bos(ptr) __builtin_object_size (ptr, FORTIFY_SOURCE > 0)
 # define bos0(ptr) __builtin_object_size (ptr, 0)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-6.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-6.c
new file mode 100644 (file)
index 0000000..0d9b275
--- /dev/null
@@ -0,0 +1,139 @@
+/* Test to verify that snprintf can determine the length of a dynamically
+   constructed string argument and fold the result into a constant.
+   { dg-do compile }
+   { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+char* strcpy (char * restrict, const char * restrict);
+int sprintf (char * restrict, const char *restrict, ...);
+int snprintf (char * restrict, size_t, const char *restrict, ...);
+
+
+#define CONCAT(x, y) x ## y
+#define CAT(x, y) CONCAT (x, y)
+#define FAILNAME(name, counter)                                                \
+  CAT (CAT (CAT (call_ ## name ##_on_line_, __LINE__), _), counter)
+
+#define FAIL(name, counter) do {                       \
+    extern void FAILNAME (name, counter) (void);       \
+    FAILNAME (name, counter)();                                \
+  } while (0)
+
+/* Macro to emit a call to funcation named
+   call_in_true_branch_not_eliminated_on_line_NNN()
+   for each call that's expected to be eliminated.  The dg-final
+   scan-tree-dump-time directive at the bottom of the test verifies
+   that no such call appears in output.  */
+#define ELIM(expr)                                                     \
+  if (!(expr)) FAIL (in_true_branch_not_eliminated, __COUNTER__); else (void)0
+
+#define ARGS(...) __VA_ARGS__
+
+#define T(expect, init, fmt, ...)                      \
+  do {                                                 \
+    char a[] = init;                                   \
+    ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__));        \
+  } while (0)
+
+/* Exercise a non-const local char array initialized by a string literal.  */
+void test_assign_string (void)
+{
+  T (0, "", "%s", a);
+  T (1, "1", "%s", a);
+  T (4, "1234", "%s", a);
+  T (5, "123", "s=%s", a);
+  T (5, "1234", "s=%s", a + 1);
+  T (2, "1234", "s=%s", a + 4);
+  T (5, "12345", "s=%s", &a[2]);
+  T (5, "123456", "s=%.*s", 3, &a[2]);
+}
+
+/* Exercise a non-const local char array initialized by an initializer
+   list.  */
+void test_assign_init_list (void)
+{
+  T (0, ARGS ({ 0 }), "%s", a);
+  T (1, ARGS ({ 1, 0 }), "%s", a);
+  T (3, ARGS ({ [3] = 0, [1] = 2, [0] = 1, [2] = 3 }), "%s", a);
+  T (3, ARGS ({ [3] = 0, [1] = 2, [0] = 1, [2] = 3, [4] = 0 }), "%s", a);
+  T (4, ARGS ({ 1, 2, 3, 4, 0 }), "%s", a);
+  T (5, ARGS ({ 1, 2, 3, 0 }), "s=%s", a);
+  T (5, ARGS ({ 1, 2, 3, 4, 0 }), "s=%s", a + 1);
+  T (2, ARGS ({ 1, 2, 3, 4, 0 }), "s=%s", a + 4);
+  T (5, ARGS ({ 1, 2, 3, 4, 5, 0 }), "s=%s", &a[2]);
+  T (5, ARGS ({ 1, 2, 3, 4, 5, 6, 0 }), "s=%.*s", 3, &a[2]);
+}
+
+#undef T
+#define T(expect, init, fmt, ...)                      \
+  do {                                                 \
+    struct { int n; char a[sizeof init]; }             \
+    s = { sizeof init, init };                         \
+    ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__));        \
+  } while (0)
+
+/* Exercise a non-const local struct initialized by an initializer
+   list.  */
+void test_assign_aggregate (void)
+{
+  T (0, "", "%s", s.a);
+  T (1, "1", "%s", s.a);
+  T (4, "1234", "%s", s.a);
+  T (5, "123", "s=%s", s.a);
+  T (5, "1234", "s=%s", s.a + 1);
+  T (2, "1234", "s=%s", s.a + 4);
+  T (5, "12345", "s=%s", &s.a[2]);
+  T (5, "123456", "s=%.*s", 3, &s.a[2]);
+}
+
+
+#undef T
+#define T(expect, init, fmt, ...)                      \
+  do {                                                 \
+    char a[sizeof init];                               \
+    strcpy (a, init);                                  \
+    ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__));        \
+  } while (0)
+
+/* Exercise a local char array initialized by a call to strcpy.  */
+void test_local_strcpy (void)
+{
+  T (0, "", "%s", a);
+  T (1, "1", "%s", a);
+  T (2, "12", "%s", a);
+  T (3, "123", "%s", a);
+  T (4, "1234", "%s", a);
+  T (5, "123", "s=%s", a);
+  T (5, "1234", "s=%s", a + 1);
+  T (2, "1234", "s=%s", a + 4);
+  T (5, "12345", "s=%s", &a[2]);
+  T (5, "123456", "s=%.*s", 3, &a[2]);
+}
+
+#undef T
+#define T(expect, init, fmt, ...)                      \
+  do {                                                 \
+    char a[n];                                         \
+    strcpy (a, init);                                  \
+    ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__));        \
+  } while (0)
+
+/* Exercise a VLA initialized by a call to strcpy.  */
+void test_vla_strcpy (unsigned n)
+{
+  T (0, "", "%s", a);
+  T (1, "1", "%s", a);
+  T (2, "12", "%s", a);
+  T (3, "123", "%s", a);
+  T (4, "1234", "%s", a);
+  T (5, "123", "s=%s", a);
+  T (5, "1234", "s=%s", a + 1);
+  T (2, "1234", "s=%s", a + 4);
+  T (5, "12345", "s=%s", &a[2]);
+  T (5, "123456", "s=%.*s", 3, &a[2]);
+}
+
+/* { dg-final { scan-tree-dump-times "printf" 0 "optimized" } }
+   { dg-final { scan-tree-dump-times "strlen" 0 "optimized" } }
+   { dg-final { scan-tree-dump-times "not_eliminated" 0 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-7.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-7.c
new file mode 100644 (file)
index 0000000..bf5072e
--- /dev/null
@@ -0,0 +1,152 @@
+/* Test to verify that snprintf can determine the correct range
+   of lengths of dynamically constructed string arguments.
+   { dg-do compile }
+   { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+void* memcpy (void*, const void*, size_t);
+
+char* strcpy (char * restrict, const char * restrict);
+int snprintf (char * restrict, size_t, const char *restrict, ...);
+
+void sink (void*, ...);
+
+#define CONCAT(x, y) x ## y
+#define CAT(x, y) CONCAT (x, y)
+#define FAILNAME(name, counter)                                                \
+  CAT (CAT (CAT (call_ ## name ##_on_line_, __LINE__), _), counter)
+
+#define FAIL(name, counter) do {                       \
+    extern void FAILNAME (name, counter) (void);       \
+    FAILNAME (name, counter)();                                \
+  } while (0)
+
+/* Macro to emit a call to funcation named
+   call_in_true_branch_not_eliminated_on_line_NNN()
+   for each call that's expected to be eliminated.  The dg-final
+   scan-tree-dump-time directive at the bottom of the test verifies
+   that no such call appears in output.  */
+#define VERIFY_ELIM(expr)                                              \
+  if (!(expr)) FAIL (in_true_branch_not_eliminated, __COUNTER__); else (void)0
+
+/* Macro to emit a call to a function named
+     call_made_in_{true,false}_branch_on_line_NNN()
+   for each call that's expected to be retained.  The dg-final
+   scan-tree-dump-time directive at the bottom of the test verifies
+   that the expected number of both kinds of calls appears in output
+   (a pair for each line with the invocation of the KEEP() macro.  */
+#define VERIFY_KEEP(expr)                      \
+  if (expr)                                    \
+    FAIL (made_in_true_branch, __COUNTER__);   \
+  else                                         \
+    FAIL (made_in_false_branch, __COUNTER__)
+
+#define ARGS(...) __VA_ARGS__
+
+/* Each test macro expands to a new function to get around bug 81776
+   - missing sprintf optimization due to pointer escape analysis.  */
+#define ELIM(expect, dst, init, fmt, ...)              \
+  void CAT (test_func_on_line_, __LINE__)(void)                \
+  {                                                    \
+    memcpy (dst, init, sizeof (init) - 1);             \
+    const int res = snprintf (0, 0, fmt, __VA_ARGS__); \
+    VERIFY_ELIM (expect res);                          \
+  } typedef void dummy_typedef
+
+#define KEEP(expect, dst, init, fmt, ...)              \
+  void CAT (test_func_on_line_, __LINE__)(void)                \
+  {                                                    \
+    memcpy (dst, init, sizeof (init) - 1);             \
+    const int ret = snprintf (0, 0, fmt, __VA_ARGS__); \
+    VERIFY_KEEP (expect ret);                          \
+  } typedef void dummy_typedef
+
+
+/* Verify that conditions involving snprintf calls with a string
+   of some minimum but otherwise unbounded length stored in an array
+   of unknown bound are not folded unless the format string itself
+   restricts the maximum.  The string could be longer than INT_MAX
+   making the snprintf call fail and return a negative value.  */
+
+extern char gax[];
+
+KEEP (1 <=, gax, "1",  "%s", gax);
+KEEP (2 <=, gax, "12", "%s", gax);
+KEEP (3 <=, gax, "123", "%s", gax);
+
+ELIM (3 ==, gax, "123", "%.3s", gax);
+ELIM (5 ==, gax, "123", "%.3s%.2s", gax, gax);
+
+
+/* Disabled.  The global pointer passed to memcpy as the destination
+   might point at itself, i.e., gptr == &gptr is a valid argument to
+   memcpy.
+
+extern char *gptr;
+
+KEEP (1 <=, gptr, "1",  "%s", gptr);
+KEEP (2 <=, gptr, "12", "%s", gptr);
+KEEP (3 <=, gptr, "123", "%s", gptr);
+
+ELIM (3 ==, gptr, "123", "%.3s", gptr);
+ELIM (5 ==, gptr, "123", "%.3s%.2s", gptr, gptr);
+
+*/
+
+/* Verify that conditions involving snprintf calls with a string
+   of some minimum but otherwise unbounded length stored in an array
+   of a known bound are folded.  The longest string that can be
+   stored in such arrays is bounded by the size of the array.  */
+
+extern char ga4[4];
+
+ELIM (0 <=, ga4, "\0",   "%s", ga4);
+ELIM (3 >=, ga4, "\0",   "%s", ga4);
+
+ELIM (1 <=, ga4, "1",  "%s", ga4);
+ELIM (0 <=, ga4, "1",  "%s", ga4 + 1);
+ELIM (0 <=, ga4, "1",  "%s", &ga4[1]);
+
+ELIM (3 >=, ga4, "1",  "%s", ga4);
+ELIM (2 >=, ga4, "1",  "%s", ga4 + 1);
+ELIM (2 >=, ga4, "1",  "%s", &ga4[1]);
+
+ELIM (2 <=, ga4, "12", "%s", ga4);
+ELIM (3 >=, ga4, "12", "%s", ga4);
+
+ELIM (3 <=, ga4, "123", "%s", ga4);
+ELIM (3 ==, ga4, "123", "%.3s", ga4);
+ELIM (5 ==, ga4, "123", "%.3s%.2s", ga4, ga4);
+
+/* Verify conditionals involving dynamically created strings of known
+   length stored in local arrays.  */
+
+#undef ELIM
+#define ELIM(expect, N1, N2, init1, init2, fmt, ...)   \
+  void CAT (test_func_on_line_, __LINE__)(int i)       \
+  {                                                    \
+    char a1[N1], a2[N2];                               \
+    memcpy (a1, init1, sizeof (init1) - 1);            \
+    memcpy (a2, init2, sizeof (init2) - 1);            \
+    const int res = snprintf (0, 0, fmt, __VA_ARGS__); \
+    VERIFY_ELIM (expect res);                          \
+  } typedef void dummy_typedef
+
+ELIM (0 ==, 2, 2, "\0", "\0",   "%s",         i ? a1 : a2);
+ELIM (2 ==, 2, 2, "\0", "\0",   "s=%s",       i ? a1 : a2);
+
+ELIM (1 ==, 2, 2, "a\0", "b\0", "%s",         i ? a1 : a2);
+ELIM (3 ==, 2, 2, "a\0", "b\0", "s=%s",       i ? a1 : a2);
+
+ELIM (2 ==, 3, 5, "ab\0", "cd\0", "%s",       i ? a1 : a2);
+ELIM (3 ==, 3, 5, "ab\0", "cd\0", "%3s",      i ? a1 : a2);
+ELIM (3 ==, 5, 5, "abcd\0", "efgh\0", "%.3s", i ? a1 : a2);
+
+ELIM (3 ==, 4, 1, "abc\0", "", "%s",          i ? a1 : "def");
+ELIM (4 ==, 1, 5, "", "efgh\0", "%s",         i ? "abcd" : a2);
+
+ELIM (4 ==, 5, 5, "abcd\0", "efgh\0", "%s",   i < 0 ? a1 : 0 < i ? a2 : "ijkl");
+
+/* { dg-final { scan-tree-dump-times "_not_eliminated" 0 "optimized" } }
+   { dg-final { scan-tree-dump-times "call_made_" 6 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-8.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-8.c
new file mode 100644 (file)
index 0000000..95b0b44
--- /dev/null
@@ -0,0 +1,41 @@
+/* Test to verify that snprintf can determine the correct range
+   of lengths of string arguments based on the results of prior
+   calls to strlen.
+   { dg-do compile }
+   { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+void abort (void);
+size_t strlen (const char *);
+int snprintf (char * restrict, size_t, const char *restrict, ...);
+
+void one_str_exact (const char *str)
+{
+  if (1 == strlen (str))
+    if (1 != snprintf (0, 0, "%s", str))
+      abort ();
+}
+
+void two_str_exact (const char *s1, const char *s2)
+{
+  if (1 == strlen (s1) && 2 == strlen (s2))
+    if (3 != snprintf (0, 0, "%s%s", s1, s2))
+      abort ();
+}
+
+void one_str_maxlen (const char *str)
+{
+  if (2 >= strlen (str))
+    if (2 < snprintf (0, 0, "%s", str))
+      abort ();
+}
+
+void two_str_maxlen (const char *s1, const char *s2)
+{
+  if (2 >= strlen (s1) && 3 >= strlen (s2))
+    if (5 < snprintf (0, 0, "%s%s", s1, s2))
+      abort ();
+}
+
+/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-9.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-9.c
new file mode 100644 (file)
index 0000000..9c238ce
--- /dev/null
@@ -0,0 +1,163 @@
+/* Test to verify that --param ssa_name_def_chain_limit can be used to
+   limit the maximum number of SSA_NAME assignments the built-in code
+   follows to determine the variable value/string length.
+   { dg-do compile }
+   { dg-options "-O2 -Wall --param ssa-name-def-chain-limit=4 -fdump-tree-optimized" } */
+
+void abort (void);
+int sprintf (char * restrict, const char *restrict, ...);
+
+void sink (const char*, ...);
+
+const char a0[] = "";
+const char a1[] = "1";
+const char a2[] = "12";
+const char a3[] = "123";
+const char a4[] = "1234";
+const char a5[] = "12345";
+const char a6[] = "123456";
+const char a7[] = "1234567";
+const char a8[] = "12345678";
+const char a9[] = "123456789";
+
+int i0, i1, i2, i3, i4, i5, i6, i7, i8;
+
+void g1 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+
+  sink (p0, p1);
+
+  if (sprintf (d, "%s", p1) > 2)
+    abort ();
+}
+
+void g2 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+
+  sink (p0, p1, p2);
+
+  if (sprintf (d, "%s", p2) > 3)
+    abort ();
+}
+
+void g3 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+  const char *p3 = i3 ? p2 : a4;
+
+  sink (p0, p1, p2, p3);
+
+  if (sprintf (d, "%s", p3) > 4)
+    abort ();
+}
+
+void g4 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+  const char *p3 = i3 ? p2 : a4;
+  const char *p4 = i4 ? p3 : a5;
+
+  sink (p0, p1, p2, p3, p4);
+
+  // p4 below is the result of the following five PHI assignments
+  // and with the limit set to 4 the sprintf call result is not
+  // determined:
+  //   iftmp.0_7 = PHI <&a0(2), &a1(3)>
+  //   iftmp.2_8 = PHI <iftmp.0_7(4), &a2(5)>
+  //   iftmp.4_9 = PHI <iftmp.2_8(6), &a3(7)>
+  //   iftmp.6_10 = PHI <iftmp.4_9(8), &a4(9)>
+  //   iftmp.8_17 = PHI <iftmp.6_10(10), &a5(11)>
+  //   p4 = iftmp.8_17
+  extern void keep_g4 (void);
+  if (sprintf (d, "%s", p4) > 5)
+    keep_g4 ();
+}
+
+void g5 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+  const char *p3 = i3 ? p2 : a4;
+  const char *p4 = i4 ? p3 : a5;
+  const char *p5 = i5 ? p4 : a6;
+
+  sink (p0, p1, p2, p3, p4, p5);
+
+  extern void keep_g5 (void);
+  if (sprintf (d, "%s", p5) > 6)
+    keep_g5 ();
+
+  /* { dg-final { scan-tree-dump-times "keep_g5" 1 "optimized" } } */
+}
+
+void g6 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+  const char *p3 = i3 ? p2 : a4;
+  const char *p4 = i4 ? p3 : a5;
+  const char *p5 = i5 ? p4 : a6;
+  const char *p6 = i6 ? p5 : a7;
+
+  sink (p0, p1, p2, p3, p4, p5, p6);
+
+  extern void keep_g6 (void);
+  if (sprintf (d, "%s", p6) > 7)
+    keep_g6 ();
+
+  /* { dg-final { scan-tree-dump-times "keep_g6" 1 "optimized" } } */
+}
+
+void g7 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+  const char *p3 = i3 ? p2 : a4;
+  const char *p4 = i4 ? p3 : a5;
+  const char *p5 = i5 ? p4 : a6;
+  const char *p6 = i6 ? p5 : a7;
+  const char *p7 = i7 ? p6 : a8;
+
+  sink (p0, p1, p2, p3, p4, p5, p6, p7);
+
+  extern void keep_g7 (void);
+  if (sprintf (d, "%s", p7) > 8)
+    keep_g7 ();
+
+  /* { dg-final { scan-tree-dump-times "keep_g7" 1 "optimized" } } */
+}
+
+void g8 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+  const char *p3 = i3 ? p2 : a4;
+  const char *p4 = i4 ? p3 : a5;
+  const char *p5 = i5 ? p4 : a6;
+  const char *p6 = i6 ? p5 : a7;
+  const char *p7 = i7 ? p6 : a8;
+  const char *p8 = i8 ? p7 : a9;
+
+  sink (p0, p1, p2, p3, p4, p5, p6, p7, p8);
+
+  extern void keep_g8 (void);
+  if (sprintf (d, "%s", p8) > 9)
+    keep_g8 ();
+
+  /* { dg-final { scan-tree-dump-times "keep_g8" 1 "optimized" } } */
+}
+
+/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-5.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-5.c
new file mode 100644 (file)
index 0000000..becba05
--- /dev/null
@@ -0,0 +1,140 @@
+/* Test to verify that --param ssa_name_def_chain_limit can be used to
+   limit the maximum number of SSA_NAME assignments the built-in code
+   follows.
+   { dg-do compile }
+   { dg-options "-O2 -Wall -Wformat-truncation=2 --param ssa-name-def-chain-limit=4 -fdump-tree-optimized" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+int snprintf (char * restrict, size_t, const char *restrict, ...);
+
+void sink (const char*, ...);
+
+const char a0[] = "";
+const char a1[] = "1";
+const char a2[] = "12";
+const char a3[] = "123";
+const char a4[] = "1234";
+const char a5[] = "12345";
+const char a6[] = "123456";
+const char a7[] = "1234567";
+const char a8[] = "12345678";
+const char a9[] = "123456789";
+
+int i0, i1, i2, i3, i4, i5, i6, i7, i8;
+
+void g1 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+
+  sink (p0, p1);
+
+  snprintf (d, 1, "%s", p1);    // { dg-warning "\\\[-Wformat-truncation" }
+}
+
+void g2 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+
+  sink (p0, p1, p2);
+
+  snprintf (d, 2, "%s", p2);    // { dg-warning "\\\[-Wformat-truncation" }
+}
+
+void g3 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+  const char *p3 = i3 ? p2 : a4;
+
+  sink (p0, p1, p2, p3);
+
+  snprintf (d, 3, "%s", p3);    // { dg-warning "\\\[-Wformat-truncation" }
+}
+
+void g4 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+  const char *p3 = i3 ? p2 : a4;
+  const char *p4 = i4 ? p3 : a5;
+
+  sink (p0, p1, p2, p3, p4);
+
+  // p4 below is the result of the following five PHI assignments
+  // and with the limit set to 4 the snprintf call is not diagnosed
+  //   iftmp.0_7 = PHI <&a0(2), &a1(3)>
+  //   iftmp.2_8 = PHI <iftmp.0_7(4), &a2(5)>
+  //   iftmp.4_9 = PHI <iftmp.2_8(6), &a3(7)>
+  //   iftmp.6_10 = PHI <iftmp.4_9(8), &a4(9)>
+  //   iftmp.8_17 = PHI <iftmp.6_10(10), &a5(11)>
+  //   p4 = iftmp.8_17
+  snprintf (d, 4, "%s", p4);
+}
+
+void g5 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+  const char *p3 = i3 ? p2 : a4;
+  const char *p4 = i4 ? p3 : a5;
+  const char *p5 = i5 ? p4 : a6;
+
+  sink (p0, p1, p2, p3, p4, p5);
+
+  snprintf (d, 5, "%s", p5);
+}
+
+void g6 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+  const char *p3 = i3 ? p2 : a4;
+  const char *p4 = i4 ? p3 : a5;
+  const char *p5 = i5 ? p4 : a6;
+  const char *p6 = i6 ? p5 : a7;
+
+  sink (p0, p1, p2, p3, p4, p5, p6);
+
+  snprintf (d, 6, "%s", p6);
+}
+
+void g7 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+  const char *p3 = i3 ? p2 : a4;
+  const char *p4 = i4 ? p3 : a5;
+  const char *p5 = i5 ? p4 : a6;
+  const char *p6 = i6 ? p5 : a7;
+  const char *p7 = i7 ? p6 : a8;
+
+  sink (p0, p1, p2, p3, p4, p5, p6, p7);
+
+  snprintf (d, 7, "%s", p7);
+}
+
+void g8 (char *d)
+{
+  const char *p0 = i0 ? a0 : a1;
+  const char *p1 = i1 ? p0 : a2;
+  const char *p2 = i2 ? p1 : a3;
+  const char *p3 = i3 ? p2 : a4;
+  const char *p4 = i4 ? p3 : a5;
+  const char *p5 = i5 ? p4 : a6;
+  const char *p6 = i6 ? p5 : a7;
+  const char *p7 = i7 ? p6 : a8;
+  const char *p8 = i8 ? p7 : a9;
+
+  sink (p0, p1, p2, p3, p4, p5, p6, p7, p8);
+
+  snprintf (d, 8, "%s", p8);
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-21.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-21.c
new file mode 100644 (file)
index 0000000..41f932a
--- /dev/null
@@ -0,0 +1,94 @@
+/* PR tree-optimization/83431 -Wformat-truncation may incorrectly report
+   truncation
+   { dg-do compile }
+   { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern int snprintf (char*, size_t, const char*, ...);
+extern char* strcpy (char*, const char*);
+
+struct S
+{
+  char a9[9];
+  char a5[5];
+  int x;
+};
+
+
+void test_assign_nowarn (struct S* s)
+{
+  int i = 0;
+
+  {
+    char a9[9] = "1234";
+    snprintf (s[i].a5, sizeof (s[i].a5), "%s", a9);         /* { dg-bogus "\\\[-Wformat-truncation]" } */
+  }
+
+  {
+    ++i;
+    char a8[8] = "123";
+    snprintf (s[i].a5, sizeof (s[i].a5), "%s\n", a8);       /* { dg-bogus "\\\[-Wformat-truncation]" } */
+  }
+
+  {
+    ++i;
+    char a7[7] = "12";
+    snprintf (s[i].a5, sizeof (s[i].a5), "[%s]", a7);       /* { dg-bogus "\\\[-Wformat-truncation]" } */
+  }
+
+  {
+    ++i;
+    char a6[6] = "1";
+    snprintf (s[i].a5, sizeof (s[i].a5), "[%s]\n", a6);     /* { dg-bogus "\\\[-Wformat-truncation]" } */
+  }
+}
+
+
+void test_strcpy_nowarn (struct S* s)
+{
+  int i = 0;
+
+  strcpy (s[i].a9, "1234");
+  snprintf (s[i].a5, sizeof (s[i].a5), "%s", s[i].a9);
+
+  ++i;
+  strcpy (s[i].a9, "123");
+  snprintf (s[i].a5, sizeof (s[i].a5), "%s\n", s[i].a9);    /* { dg-bogus "\\\[-Wformat-truncation]" } */
+
+  ++i;
+  strcpy (s[i].a9, "12");
+  snprintf (s[i].a5, sizeof (s[i].a5), "[%s]", s[i].a9);    /* { dg-bogus "\\\[-Wformat-truncation]" } */
+
+  ++i;
+  strcpy (s[i].a9, "1");
+  snprintf (s[i].a5, sizeof (s[i].a5), "[%s]\n", s[i].a9);  /* { dg-bogus "\\\[-Wformat-truncation]" } */
+}
+
+
+void test_warn (struct S* s)
+{
+  int i = 0;
+  strcpy (s[i].a9, "12345678");
+  snprintf (s[i].a5, sizeof (s[i].a5), "%s", s[i].a9);      /* { dg-warning "'%s' directive output truncated writing 8 bytes into a region of size 5" } */
+
+  ++i;
+  strcpy (s[i].a9, "1234567");
+  snprintf (s[i].a5, sizeof (s[i].a5), "%s", s[i].a9);      /* { dg-warning "'%s' directive output truncated writing 7 bytes into a region of size 5" } */
+
+  ++i;
+  strcpy (s[i].a9, "123456");
+  snprintf (s[i].a5, sizeof (s[i].a5), "%s", s[i].a9);      /* { dg-warning "'%s' directive output truncated writing 6 bytes into a region of size 5" } */
+
+  ++i;
+  strcpy (s[i].a9, "12345");
+  snprintf (s[i].a5, sizeof (s[i].a5), "%s", s[i].a9);      /* { dg-warning "'snprintf' output truncated before the last format character" } */
+
+  ++i;
+  strcpy (s[i].a9, "1234");
+  snprintf (s[i].a5, sizeof (s[i].a5), "%s\n", s[i].a9);    /* { dg-warning "output truncated before the last format character" } */
+
+  ++i;
+  strcpy (s[i].a9, "123");
+  snprintf (s[i].a5, sizeof (s[i].a5), ">%s<", s[i].a9);    /* { dg-warning "output truncated before the last format character" } */
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/dump-4.c b/gcc/testsuite/gcc.dg/tree-ssa/dump-4.c
new file mode 100644 (file)
index 0000000..9377ed4
--- /dev/null
@@ -0,0 +1,11 @@
+/* PR middle-end/87052 - STRING_CST printing incomplete in Gimple dumps
+   { dg-do compile }
+   { dg-options "-fdump-tree-original" } */
+
+void* f (char *d, int c)
+{
+  return __builtin_memchr ("1\0\0", c, 4);
+}
+
+/* Veriy the full string appears in the dump:
+  { dg-final { scan-tree-dump "\"1\\\\x00\\\\x00\"" "original" } } */
index d8d3bf6039a8f8636002746f6433ccd3833f810a..a301d0d2e2b4336235e253a45847ea8b8f030b31 100644 (file)
@@ -11,4 +11,4 @@ void f (void)
     __builtin_abort ();
 }
 
-/* { dg-final { scan-tree-dump-not "__builtin_strlen" "strlen" } } */
+/* { dg-final { scan-tree-dump-not "__builtin_strlen" "strlen1" } } */
index 1bca06fb1a4a77d50e55a875161a707c59743b57..079ee745a2c2c4171c5534fcbd3e9b9951103bc5 100644 (file)
@@ -12,4 +12,4 @@ void f3 (void)
   f (__builtin_strlen (s));
 }
 
-/* { dg-final { scan-tree-dump-times "strlen" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strlen" 0 "strlen1" } } */
index 1c8df3d0a719b97322b89f69711bfbd09e43d3d4..be7603a4c72dd18413aa7045a9e09408bd6a9e8d 100644 (file)
@@ -419,6 +419,7 @@ extern gimple_opt_pass *make_pass_omp_target_link (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_oacc_device_lower (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_omp_device_lower (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_object_sizes (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_warn_printf (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_strlen (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_fold_builtins (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_post_ipa_warn (gcc::context *ctxt);
index ef2b6ae65f29709b2a1ce11ce868d8e903fb5cf4..5c5b83833c8f0ced8d5074fe9f35637a1acfe944 100644 (file)
@@ -55,6 +55,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "attribs.h"
 #include "calls.h"
+#include "cfgloop.h"
+#include "tree-ssa-loop.h"
+#include "tree-scalar-evolution.h"
+
+#include "vr-values.h"
+#include "gimple-ssa-evrp-analyze.h"
 
 /* A vector indexed by SSA_NAME_VERSION.  0 means unknown, positive value
    is an index into strinfo vector, negative value stands for
@@ -64,6 +70,9 @@ static vec<int> ssa_ver_to_stridx;
 /* Number of currently active string indexes plus one.  */
 static int max_stridx;
 
+/* Set to true to optimize, false when just checking.  */
+static bool strlen_optimize;
+
 /* String information record.  */
 struct strinfo
 {
@@ -154,7 +163,8 @@ struct decl_stridxlist_map
 
 /* Hash table for mapping decls to a chained list of offset -> idx
    mappings.  */
-static hash_map<tree_decl_hash, stridxlist> *decl_to_stridxlist_htab;
+typedef hash_map<tree_decl_hash, stridxlist> decl_to_stridxlist_htab_t;
+static decl_to_stridxlist_htab_t *decl_to_stridxlist_htab;
 
 /* Hash table mapping strlen (or strnlen with constant bound and return
    smaller than bound) calls to stridx instances describing
@@ -604,14 +614,21 @@ set_endptr_and_length (location_t loc, strinfo *si, tree endptr)
   si->full_string_p = true;
 }
 
-/* Return string length, or NULL if it can't be computed.  */
+/* Return the string length, or NULL if it can't be computed.
+   The length may but need not be constant.  Instead, it might be
+   the result of a strlen() call.  */
 
 static tree
 get_string_length (strinfo *si)
 {
+  /* If the length has already been computed return it if it's exact
+     (i.e., the string is nul-terminated at NONZERO_CHARS), or return
+     null if it isn't.  */
   if (si->nonzero_chars)
     return si->full_string_p ? si->nonzero_chars : NULL;
 
+  /* If the string is the result of one of the built-in calls below
+     attempt to compute the length from the call statement.  */
   if (si->stmt)
     {
       gimple *stmt = si->stmt, *lenstmt;
@@ -702,6 +719,336 @@ get_string_length (strinfo *si)
   return si->nonzero_chars;
 }
 
+/* Dump strlen data to FP for statement STMT.  When non-null, RVALS
+   points to EVRP info and is used to dump strlen range for non-constant
+   results.  */
+
+DEBUG_FUNCTION void
+dump_strlen_info (FILE *fp, gimple *stmt, const vr_values *rvals)
+{
+  if (stmt)
+    {
+      fprintf (fp, "\nDumping strlen pass data after ");
+      print_gimple_expr (fp, stmt, TDF_LINENO);
+      fputc ('\n', fp);
+    }
+  else
+    fprintf (fp, "\nDumping strlen pass data\n");
+
+  fprintf (fp, "max_stridx = %i\n", max_stridx);
+  fprintf (fp, "ssa_ver_to_stridx has %u elements\n",
+          ssa_ver_to_stridx.length ());
+  fprintf (fp, "stridx_to_strinfo");
+  if (stridx_to_strinfo)
+    {
+      fprintf (fp, " has %u elements\n", stridx_to_strinfo->length ());
+      for (unsigned i = 0; i != stridx_to_strinfo->length (); ++i)
+       {
+         if (strinfo *si = (*stridx_to_strinfo)[i])
+           {
+             if (!si->idx)
+               continue;
+             fprintf (fp, "  idx = %i", si->idx);
+             if (si->ptr)
+               {
+                 fprintf (fp, ", ptr = ");
+                 print_generic_expr (fp, si->ptr);
+               }
+             fprintf (fp, ", nonzero_chars = ");
+             print_generic_expr (fp, si->nonzero_chars);
+             if (TREE_CODE (si->nonzero_chars) == SSA_NAME)
+               {
+                 value_range_kind rng = VR_UNDEFINED;
+                 wide_int min, max;
+                 if (rvals)
+                   {
+                     const value_range *vr
+                       = CONST_CAST (class vr_values *, rvals)
+                       ->get_value_range (si->nonzero_chars);
+                     rng = vr->kind ();
+                     if (range_int_cst_p (vr))
+                       {
+                         min = wi::to_wide (vr->min ());
+                         max = wi::to_wide (vr->max ());
+                       }
+                     else
+                       rng = VR_UNDEFINED;
+                   }
+                 else
+                   rng = get_range_info (si->nonzero_chars, &min, &max);
+
+                 if (rng == VR_RANGE || rng == VR_ANTI_RANGE)
+                   {
+                     fprintf (fp, " %s[%llu, %llu]",
+                              rng == VR_RANGE ? "" : "~",
+                              (long long) min.to_uhwi (),
+                              (long long) max.to_uhwi ());
+                   }
+               }
+             fprintf (fp, " , refcount = %i", si->refcount);
+             if (si->stmt)
+               {
+                 fprintf (fp, ", stmt = ");
+                 print_gimple_expr (fp, si->stmt, 0);
+               }
+             if (si->writable)
+               fprintf (fp, ", writable");
+             if (si->full_string_p)
+               fprintf (fp, ", full_string_p");
+             if (strinfo *next = get_next_strinfo (si))
+               {
+                 fprintf (fp, ", {");
+                 do
+                   fprintf (fp, "%i%s", next->idx, next->first ? ", " : "");
+                 while ((next = get_next_strinfo (next)));
+                 fprintf (fp, "}");
+               }
+             fputs ("\n", fp);
+           }
+       }
+    }
+  else
+    fprintf (fp, " = null\n");
+
+  fprintf (fp, "decl_to_stridxlist_htab");
+  if (decl_to_stridxlist_htab)
+    {
+      fputs ("\n", fp);
+      typedef decl_to_stridxlist_htab_t::iterator iter_t;
+      for (iter_t it = decl_to_stridxlist_htab->begin ();
+          it != decl_to_stridxlist_htab->end (); ++it)
+       {
+         tree decl = (*it).first;
+         stridxlist *list = &(*it).second;
+         fprintf (fp, "  decl = ");
+         print_generic_expr (fp, decl);
+         if (list)
+           {
+             fprintf (fp, ", offsets = {");
+             for (; list; list = list->next)
+               fprintf (fp, "%lli%s", (long long) list->offset,
+                        list->next ? ", " : "");
+             fputs ("}", fp);
+           }
+         fputs ("\n", fp);
+       }
+    }
+  else
+    fprintf (fp, " = null\n");
+
+  if (laststmt.stmt)
+    {
+      fprintf (fp, "laststmt = ");
+      print_gimple_expr (fp, laststmt.stmt, 0);
+      fprintf (fp, ", len = ");
+      print_generic_expr (fp, laststmt.len);
+      fprintf (fp, ", stridx = %i\n", laststmt.stridx);
+    }
+}
+
+/* Attempt to determine the length of the string SRC.  On success, store
+   the length in *PDATA and return true.  Otherwise, return false.
+   VISITED is a bitmap of visited PHI nodes.  RVALS points to EVRP info
+   and PSSA_DEF_MAX to an SSA_NAME assignment limit used to prevent runaway
+   recursion.  */
+
+static bool
+get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited,
+                         const vr_values *rvals, unsigned *pssa_def_max)
+{
+  int idx = get_stridx (src);
+  if (!idx)
+    {
+      if (TREE_CODE (src) == SSA_NAME)
+       {
+         gimple *def_stmt = SSA_NAME_DEF_STMT (src);
+         if (gimple_code (def_stmt) == GIMPLE_PHI)
+           {
+             if (!*visited)
+               *visited = BITMAP_ALLOC (NULL);
+
+             if (!bitmap_set_bit (*visited, SSA_NAME_VERSION (src)))
+               return true;
+
+             if (*pssa_def_max == 0)
+               return false;
+
+             --*pssa_def_max;
+
+             /* Iterate over the PHI arguments and determine the minimum
+                and maximum length/size of each and incorporate them into
+                the overall result.  */
+             gphi *phi = as_a <gphi *> (def_stmt);
+             for (unsigned i = 0; i != gimple_phi_num_args (phi); ++i)
+               {
+                 tree arg = gimple_phi_arg_def (phi, i);
+                 if (arg == gimple_phi_result (def_stmt))
+                   continue;
+
+                 c_strlen_data argdata = { };
+                 if (get_range_strlen_dynamic (arg, &argdata, visited, rvals,
+                                               pssa_def_max))
+                   {
+                     /* Set the DECL of an unterminated array this argument
+                        refers to if one hasn't been found yet.  */
+                     if (!pdata->decl && argdata.decl)
+                       pdata->decl = argdata.decl;
+
+                     if (!argdata.minlen
+                         || (integer_zerop (argdata.minlen)
+                             && integer_all_onesp (argdata.maxbound)
+                             && integer_all_onesp (argdata.maxlen)))
+                       {
+                         /* Set the upper bound of the length to unbounded.  */
+                         pdata->maxlen = build_all_ones_cst (size_type_node);
+                         continue;
+                       }
+
+                     /* Adjust the minimum and maximum length determined
+                        so far and the upper bound on the array size.  */
+                     if (!pdata->minlen
+                         || tree_int_cst_lt (argdata.minlen, pdata->minlen))
+                       pdata->minlen = argdata.minlen;
+                     if (!pdata->maxlen
+                         || tree_int_cst_lt (pdata->maxlen, argdata.maxlen))
+                       pdata->maxlen = argdata.maxlen;
+                     if (!pdata->maxbound
+                         || (tree_int_cst_lt (pdata->maxbound,
+                                              argdata.maxbound)
+                             && !integer_all_onesp (argdata.maxbound)))
+                       pdata->maxbound = argdata.maxbound;
+                   }
+                 else
+                   pdata->maxlen = build_all_ones_cst (size_type_node);
+               }
+
+             return true;
+           }
+       }
+
+      /* Return success regardless of the result and handle *PDATA
+        in the caller.  */
+      get_range_strlen (src, pdata, 1);
+      return true;
+    }
+
+  if (idx < 0)
+    {
+      /* SRC is a string of constant length.  */
+      pdata->minlen = build_int_cst (size_type_node, ~idx);
+      pdata->maxlen = pdata->minlen;
+      pdata->maxbound = pdata->maxlen;
+      return true;
+    }
+
+  if (strinfo *si = get_strinfo (idx))
+    {
+      pdata->minlen = get_string_length (si);
+      if (!pdata->minlen
+         && si->nonzero_chars)
+       {
+         if (TREE_CODE (si->nonzero_chars) == INTEGER_CST)
+           pdata->minlen = si->nonzero_chars;
+         else if (TREE_CODE (si->nonzero_chars) == SSA_NAME)
+           {
+             const value_range *vr
+               = CONST_CAST (class vr_values *, rvals)
+               ->get_value_range (si->nonzero_chars);
+             if (vr->kind () == VR_RANGE
+                 && range_int_cst_p (vr))
+               {
+                 pdata->minlen = vr->min ();
+                 pdata->maxlen = vr->max ();
+               }
+             else
+               pdata->minlen = build_zero_cst (size_type_node);
+           }
+         else
+           pdata->minlen = build_zero_cst (size_type_node);
+
+         tree base = si->ptr;
+         if (TREE_CODE (base) == ADDR_EXPR)
+           base = TREE_OPERAND (base, 0);
+
+         HOST_WIDE_INT off;
+         poly_int64 poff;
+         base = get_addr_base_and_unit_offset (base, &poff);
+         if (base
+             && DECL_P (base)
+             && TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE
+             && TYPE_SIZE_UNIT (TREE_TYPE (base))
+             && poff.is_constant (&off))
+           {
+             tree basetype = TREE_TYPE (base);
+             tree size = TYPE_SIZE_UNIT (basetype);
+             ++off;   /* Increment for the terminating nul.  */
+             pdata->maxlen = fold_build2 (MINUS_EXPR, size_type_node, size,
+                                          build_int_cst (size_type_node, off));
+             pdata->maxbound = pdata->maxlen;
+           }
+         else
+           pdata->maxlen = build_all_ones_cst (size_type_node);
+       }
+      else if (TREE_CODE (pdata->minlen) == SSA_NAME)
+       {
+         const value_range *vr
+           = CONST_CAST (class vr_values *, rvals)
+           ->get_value_range (si->nonzero_chars);
+         if (vr->kind () == VR_RANGE
+             && range_int_cst_p (vr))
+           {
+             pdata->minlen = vr->min ();
+             pdata->maxlen = vr->max ();
+             pdata->maxbound = pdata->maxlen;
+           }
+         else
+           {
+             pdata->minlen = build_zero_cst (size_type_node);
+             pdata->maxlen = build_all_ones_cst (size_type_node);
+           }
+       }
+      else
+       {
+         pdata->maxlen = pdata->minlen;
+         pdata->maxbound = pdata->minlen;
+       }
+
+      return true;
+    }
+
+  return false;
+}
+
+/* Analogous to get_range_strlen but for dynamically created strings,
+   i.e., those created by calls to strcpy as opposed to just string
+   constants.
+   Try to obtain the range of the lengths of the string(s) referenced
+   by SRC, or the size of the largest array SRC refers to if the range
+   of lengths cannot be determined, and store all in *PDATA.  RVALS
+   points to EVRP info.  */
+
+void
+get_range_strlen_dynamic (tree src, c_strlen_data *pdata,
+                         const vr_values *rvals)
+{
+  bitmap visited = NULL;
+
+  unsigned limit = PARAM_VALUE (PARAM_SSA_NAME_DEF_CHAIN_LIMIT);
+  if (!get_range_strlen_dynamic (src, pdata, &visited, rvals, &limit))
+    {
+      /* On failure extend the length range to an impossible maximum
+        (a valid MAXLEN must be less than PTRDIFF_MAX - 1).  Other
+        members can stay unchanged regardless.  */
+      pdata->minlen = ssize_int (0);
+      pdata->maxlen = build_all_ones_cst (size_type_node);
+    }
+  else if (!pdata->minlen)
+    pdata->minlen = ssize_int (0);
+
+  if (visited)
+    BITMAP_FREE (visited);
+}
+
 /* Invalidate string length information for strings whose length
    might change due to stores in stmt.  */
 
@@ -4017,84 +4364,232 @@ is_char_type (tree type)
          && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node));
 }
 
+/* Check the built-in call at GSI for validity and optimize it.
+   Return true to let the caller advance *GSI to the statement
+   in the CFG and false otherwise.  */
+
+static bool
+strlen_check_and_optimize_call (gimple_stmt_iterator *gsi,
+                               const vr_values *rvals)
+{
+  gimple *stmt = gsi_stmt (*gsi);
+
+  if (!flag_optimize_strlen
+      || !strlen_optimize
+      || !valid_builtin_call (stmt))
+    {
+      /* When not optimizing we must be checking printf calls which
+        we do even for user-defined functions when they are declared
+        with attribute format.  */
+      handle_printf_call (gsi, rvals);
+      return true;
+    }
+
+  tree callee = gimple_call_fndecl (stmt);
+  switch (DECL_FUNCTION_CODE (callee))
+    {
+    case BUILT_IN_STRLEN:
+    case BUILT_IN_STRNLEN:
+      handle_builtin_strlen (gsi);
+      break;
+    case BUILT_IN_STRCHR:
+      handle_builtin_strchr (gsi);
+      break;
+    case BUILT_IN_STRCPY:
+    case BUILT_IN_STRCPY_CHK:
+    case BUILT_IN_STPCPY:
+    case BUILT_IN_STPCPY_CHK:
+      handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
+      break;
+
+    case BUILT_IN_STRNCAT:
+    case BUILT_IN_STRNCAT_CHK:
+      handle_builtin_strncat (DECL_FUNCTION_CODE (callee), gsi);
+      break;
+
+    case BUILT_IN_STPNCPY:
+    case BUILT_IN_STPNCPY_CHK:
+    case BUILT_IN_STRNCPY:
+    case BUILT_IN_STRNCPY_CHK:
+      handle_builtin_stxncpy (DECL_FUNCTION_CODE (callee), gsi);
+      break;
+
+    case BUILT_IN_MEMCPY:
+    case BUILT_IN_MEMCPY_CHK:
+    case BUILT_IN_MEMPCPY:
+    case BUILT_IN_MEMPCPY_CHK:
+      handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
+      break;
+    case BUILT_IN_STRCAT:
+    case BUILT_IN_STRCAT_CHK:
+      handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
+      break;
+    case BUILT_IN_MALLOC:
+    case BUILT_IN_CALLOC:
+      handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
+      break;
+    case BUILT_IN_MEMSET:
+      if (handle_builtin_memset (gsi))
+       return false;
+      break;
+    case BUILT_IN_MEMCMP:
+      if (handle_builtin_memcmp (gsi))
+       return false;
+      break;
+    case BUILT_IN_STRCMP:
+    case BUILT_IN_STRNCMP:
+      if (handle_builtin_string_cmp (gsi))
+       return false;
+      break;
+    default:
+      handle_printf_call (gsi, rvals);
+      break;
+    }
+
+  return true;
+}
+
+/* Handle an assignment statement at *GSI to a LHS of integral type.
+   If GSI's basic block needs clean-up of EH, set *CLEANUP_EH to true.  */
+
+static void
+handle_integral_assign (gimple_stmt_iterator *gsi, bool *cleanup_eh)
+{
+  gimple *stmt = gsi_stmt (*gsi);
+  tree lhs = gimple_assign_lhs (stmt);
+  tree lhs_type = TREE_TYPE (lhs);
+
+  enum tree_code code = gimple_assign_rhs_code (stmt);
+  if (code == COND_EXPR)
+    {
+      tree cond = gimple_assign_rhs1 (stmt);
+      enum tree_code cond_code = TREE_CODE (cond);
+
+      if (cond_code == EQ_EXPR || cond_code == NE_EXPR)
+       fold_strstr_to_strncmp (TREE_OPERAND (cond, 0),
+                               TREE_OPERAND (cond, 1), stmt);
+    }
+  else if (code == EQ_EXPR || code == NE_EXPR)
+    fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt),
+                           gimple_assign_rhs2 (stmt), stmt);
+  else if (gimple_assign_load_p (stmt)
+          && TREE_CODE (lhs_type) == INTEGER_TYPE
+          && TYPE_MODE (lhs_type) == TYPE_MODE (char_type_node)
+          && (TYPE_PRECISION (lhs_type)
+              == TYPE_PRECISION (char_type_node))
+          && !gimple_has_volatile_ops (stmt))
+    {
+      tree off = integer_zero_node;
+      unsigned HOST_WIDE_INT coff = 0;
+      int idx = 0;
+      tree rhs1 = gimple_assign_rhs1 (stmt);
+      if (code == MEM_REF)
+       {
+         idx = get_stridx (TREE_OPERAND (rhs1, 0));
+         if (idx > 0)
+           {
+             strinfo *si = get_strinfo (idx);
+             if (si
+                 && si->nonzero_chars
+                 && TREE_CODE (si->nonzero_chars) == INTEGER_CST
+                 && (wi::to_widest (si->nonzero_chars)
+                     >= wi::to_widest (off)))
+               off = TREE_OPERAND (rhs1, 1);
+             else
+               /* This case is not useful.  See if get_addr_stridx
+                  returns something usable.  */
+               idx = 0;
+           }
+       }
+      if (idx <= 0)
+       idx = get_addr_stridx (rhs1, NULL_TREE, &coff);
+      if (idx > 0)
+       {
+         strinfo *si = get_strinfo (idx);
+         if (si
+             && si->nonzero_chars
+             && TREE_CODE (si->nonzero_chars) == INTEGER_CST)
+           {
+             widest_int w1 = wi::to_widest (si->nonzero_chars);
+             widest_int w2 = wi::to_widest (off) + coff;
+             if (w1 == w2
+                 && si->full_string_p)
+               {
+                 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
+                   {
+                     fprintf (dump_file, "Optimizing: ");
+                     print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+                   }
+
+                 /* Reading the final '\0' character.  */
+                 tree zero = build_int_cst (lhs_type, 0);
+                 gimple_set_vuse (stmt, NULL_TREE);
+                 gimple_assign_set_rhs_from_tree (gsi, zero);
+                 *cleanup_eh
+                   |= maybe_clean_or_replace_eh_stmt (stmt,
+                                                      gsi_stmt (*gsi));
+                 stmt = gsi_stmt (*gsi);
+                 update_stmt (stmt);
+
+                 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
+                   {
+                     fprintf (dump_file, "into: ");
+                     print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+                   }
+               }
+             else if (w1 > w2)
+               {
+                 /* Reading a character before the final '\0'
+                    character.  Just set the value range to ~[0, 0]
+                    if we don't have anything better.  */
+                 wide_int min, max;
+                 signop sign = TYPE_SIGN (lhs_type);
+                 int prec = TYPE_PRECISION (lhs_type);
+                 value_range_kind vr = get_range_info (lhs, &min, &max);
+                 if (vr == VR_VARYING
+                     || (vr == VR_RANGE
+                         && min == wi::min_value (prec, sign)
+                         && max == wi::max_value (prec, sign)))
+                   set_range_info (lhs, VR_ANTI_RANGE,
+                                   wi::zero (prec), wi::zero (prec));
+               }
+           }
+       }
+    }
+
+  if (strlen_to_stridx)
+    {
+      tree rhs1 = gimple_assign_rhs1 (stmt);
+      if (stridx_strlenloc *ps = strlen_to_stridx->get (rhs1))
+       strlen_to_stridx->put (lhs, stridx_strlenloc (*ps));
+    }
+}
+
 /* Attempt to check for validity of the performed access a single statement
    at *GSI using string length knowledge, and to optimize it.
    If the given basic block needs clean-up of EH, CLEANUP_EH is set to
    true.  */
 
 static bool
-strlen_check_and_optimize_stmt (gimple_stmt_iterator *gsi, bool *cleanup_eh)
+check_and_optimize_stmt (gimple_stmt_iterator *gsi, bool *cleanup_eh,
+                        const vr_values *rvals)
 {
   gimple *stmt = gsi_stmt (*gsi);
 
   if (is_gimple_call (stmt))
     {
-      tree callee = gimple_call_fndecl (stmt);
-      if (valid_builtin_call (stmt))
-       switch (DECL_FUNCTION_CODE (callee))
-         {
-         case BUILT_IN_STRLEN:
-         case BUILT_IN_STRNLEN:
-           handle_builtin_strlen (gsi);
-           break;
-         case BUILT_IN_STRCHR:
-           handle_builtin_strchr (gsi);
-           break;
-         case BUILT_IN_STRCPY:
-         case BUILT_IN_STRCPY_CHK:
-         case BUILT_IN_STPCPY:
-         case BUILT_IN_STPCPY_CHK:
-           handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
-           break;
-
-         case BUILT_IN_STRNCAT:
-         case BUILT_IN_STRNCAT_CHK:
-           handle_builtin_strncat (DECL_FUNCTION_CODE (callee), gsi);
-           break;
-
-         case BUILT_IN_STPNCPY:
-         case BUILT_IN_STPNCPY_CHK:
-         case BUILT_IN_STRNCPY:
-         case BUILT_IN_STRNCPY_CHK:
-           handle_builtin_stxncpy (DECL_FUNCTION_CODE (callee), gsi);
-           break;
-
-         case BUILT_IN_MEMCPY:
-         case BUILT_IN_MEMCPY_CHK:
-         case BUILT_IN_MEMPCPY:
-         case BUILT_IN_MEMPCPY_CHK:
-           handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
-           break;
-         case BUILT_IN_STRCAT:
-         case BUILT_IN_STRCAT_CHK:
-           handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
-           break;
-         case BUILT_IN_MALLOC:
-         case BUILT_IN_CALLOC:
-           handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
-           break;
-         case BUILT_IN_MEMSET:
-           if (handle_builtin_memset (gsi))
-             return false;
-           break;
-         case BUILT_IN_MEMCMP:
-           if (handle_builtin_memcmp (gsi))
-             return false;
-           break;
-         case BUILT_IN_STRCMP:
-         case BUILT_IN_STRNCMP:
-           if (handle_builtin_string_cmp (gsi))
-             return false;
-           break;
-         default:
-           break;
-         }
+      if (!strlen_check_and_optimize_call (gsi, rvals))
+       return false;
     }
+  else if (!flag_optimize_strlen || !strlen_optimize)
+    return true;
   else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
     {
+      /* Handle non-clobbering assignment.  */
       tree lhs = gimple_assign_lhs (stmt);
+      tree lhs_type = TREE_TYPE (lhs);
 
-      if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
+      if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (lhs_type))
        {
          if (gimple_assign_single_p (stmt)
              || (gimple_assign_cast_p (stmt)
@@ -4106,117 +4601,10 @@ strlen_check_and_optimize_stmt (gimple_stmt_iterator *gsi, bool *cleanup_eh)
          else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
            handle_pointer_plus (gsi);
        }
-    else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
-      {
-       enum tree_code code = gimple_assign_rhs_code (stmt);
-       if (code == COND_EXPR)
-         {
-           tree cond = gimple_assign_rhs1 (stmt);
-           enum tree_code cond_code = TREE_CODE (cond);
-
-           if (cond_code == EQ_EXPR || cond_code == NE_EXPR)
-             fold_strstr_to_strncmp (TREE_OPERAND (cond, 0),
-                                     TREE_OPERAND (cond, 1), stmt);
-         }
-       else if (code == EQ_EXPR || code == NE_EXPR)
-         fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt),
-                                 gimple_assign_rhs2 (stmt), stmt);
-       else if (gimple_assign_load_p (stmt)
-                && TREE_CODE (TREE_TYPE (lhs)) == INTEGER_TYPE
-                && TYPE_MODE (TREE_TYPE (lhs)) == TYPE_MODE (char_type_node)
-                && (TYPE_PRECISION (TREE_TYPE (lhs))
-                    == TYPE_PRECISION (char_type_node))
-                && !gimple_has_volatile_ops (stmt))
-         {
-           tree off = integer_zero_node;
-           unsigned HOST_WIDE_INT coff = 0;
-           int idx = 0;
-           tree rhs1 = gimple_assign_rhs1 (stmt);
-           if (code == MEM_REF)
-             {
-               idx = get_stridx (TREE_OPERAND (rhs1, 0));
-               if (idx > 0)
-                 {
-                   strinfo *si = get_strinfo (idx);
-                   if (si
-                       && si->nonzero_chars
-                       && TREE_CODE (si->nonzero_chars) == INTEGER_CST
-                       && (wi::to_widest (si->nonzero_chars)
-                           >= wi::to_widest (off)))
-                     off = TREE_OPERAND (rhs1, 1);
-                   else
-                     /* This case is not useful.  See if get_addr_stridx
-                        returns something usable.  */
-                     idx = 0;
-                 }
-             }
-           if (idx <= 0)
-             idx = get_addr_stridx (rhs1, NULL_TREE, &coff);
-           if (idx > 0)
-             {
-               strinfo *si = get_strinfo (idx);
-               if (si
-                   && si->nonzero_chars
-                   && TREE_CODE (si->nonzero_chars) == INTEGER_CST)
-                 {
-                   widest_int w1 = wi::to_widest (si->nonzero_chars);
-                   widest_int w2 = wi::to_widest (off) + coff;
-                   if (w1 == w2
-                       && si->full_string_p)
-                     {
-                       if (dump_file && (dump_flags & TDF_DETAILS) != 0)
-                         {
-                           fprintf (dump_file, "Optimizing: ");
-                           print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
-                         }
-
-                       /* Reading the final '\0' character.  */
-                       tree zero = build_int_cst (TREE_TYPE (lhs), 0);
-                       gimple_set_vuse (stmt, NULL_TREE);
-                       gimple_assign_set_rhs_from_tree (gsi, zero);
-                       *cleanup_eh
-                         |= maybe_clean_or_replace_eh_stmt (stmt,
-                                                            gsi_stmt (*gsi));
-                       stmt = gsi_stmt (*gsi);
-                       update_stmt (stmt);
-
-                       if (dump_file && (dump_flags & TDF_DETAILS) != 0)
-                         {
-                           fprintf (dump_file, "into: ");
-                           print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
-                         }
-                     }
-                   else if (w1 > w2)
-                     {
-                       /* Reading a character before the final '\0'
-                          character.  Just set the value range to ~[0, 0]
-                          if we don't have anything better.  */
-                       wide_int min, max;
-                       tree type = TREE_TYPE (lhs);
-                       enum value_range_kind vr
-                         = get_range_info (lhs, &min, &max);
-                       if (vr == VR_VARYING
-                           || (vr == VR_RANGE
-                               && min == wi::min_value (TYPE_PRECISION (type),
-                                                        TYPE_SIGN (type))
-                               && max == wi::max_value (TYPE_PRECISION (type),
-                                                        TYPE_SIGN (type))))
-                         set_range_info (lhs, VR_ANTI_RANGE,
-                                         wi::zero (TYPE_PRECISION (type)),
-                                         wi::zero (TYPE_PRECISION (type)));
-                     }
-                 }
-             }
-         }
-
-       if (strlen_to_stridx)
-         {
-           tree rhs1 = gimple_assign_rhs1 (stmt);
-           if (stridx_strlenloc *ps = strlen_to_stridx->get (rhs1))
-             strlen_to_stridx->put (lhs, stridx_strlenloc (*ps));
-         }
-      }
-    else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
+      else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (lhs_type))
+       /* Handle assignment to a character.  */
+       handle_integral_assign (gsi, cleanup_eh);
+      else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
       {
        tree type = TREE_TYPE (lhs);
        if (TREE_CODE (type) == ARRAY_TYPE)
@@ -4312,12 +4700,18 @@ class strlen_dom_walker : public dom_walker
 {
 public:
   strlen_dom_walker (cdi_direction direction)
-    : dom_walker (direction), m_cleanup_cfg (false)
+    : dom_walker (direction),
+    evrp (false),
+    m_cleanup_cfg (false)
   {}
 
   virtual edge before_dom_children (basic_block);
   virtual void after_dom_children (basic_block);
 
+  /* EVRP analyzer used for printf argument range processing, and
+     to track strlen results across integer variable assignments.  */
+  evrp_range_analyzer evrp;
+
   /* Flag that will trigger TODO_cleanup_cfg to be returned in strlen
      execute function.  */
   bool m_cleanup_cfg;
@@ -4329,6 +4723,8 @@ public:
 edge
 strlen_dom_walker::before_dom_children (basic_block bb)
 {
+  evrp.enter (bb);
+
   basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
 
   if (dombb == NULL)
@@ -4402,8 +4798,16 @@ strlen_dom_walker::before_dom_children (basic_block bb)
 
   /* Attempt to optimize individual statements.  */
   for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
-    if (strlen_check_and_optimize_stmt (&gsi, &cleanup_eh))
-      gsi_next (&gsi);
+    {
+      gimple *stmt = gsi_stmt (gsi);
+
+      /* First record ranges generated by this statement so they
+        can be used by printf argument processing.  */
+      evrp.record_ranges_from_stmt (stmt, false);
+
+      if (check_and_optimize_stmt (&gsi, &cleanup_eh, evrp.get_vr_values ()))
+       gsi_next (&gsi);
+    }
 
   if (cleanup_eh && gimple_purge_dead_eh_edges (bb))
       m_cleanup_cfg = true;
@@ -4420,6 +4824,8 @@ strlen_dom_walker::before_dom_children (basic_block bb)
 void
 strlen_dom_walker::after_dom_children (basic_block bb)
 {
+  evrp.leave (bb);
+
   if (bb->aux)
     {
       stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);
@@ -4437,39 +4843,13 @@ strlen_dom_walker::after_dom_children (basic_block bb)
     }
 }
 
-/* Main entry point.  */
-
 namespace {
 
-const pass_data pass_data_strlen =
-{
-  GIMPLE_PASS, /* type */
-  "strlen", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  TV_TREE_STRLEN, /* tv_id */
-  ( PROP_cfg | PROP_ssa ), /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  0, /* todo_flags_finish */
-};
-
-class pass_strlen : public gimple_opt_pass
+static unsigned int
+printf_strlen_execute (function *fun, bool warn_only)
 {
-public:
-  pass_strlen (gcc::context *ctxt)
-    : gimple_opt_pass (pass_data_strlen, ctxt)
-  {}
+  strlen_optimize = !warn_only;
 
-  /* opt_pass methods: */
-  virtual bool gate (function *) { return flag_optimize_strlen != 0; }
-  virtual unsigned int execute (function *);
-
-}; // class pass_strlen
-
-unsigned int
-pass_strlen::execute (function *fun)
-{
   gcc_assert (!strlen_to_stridx);
   if (warn_stringop_overflow || warn_stringop_truncation)
     strlen_to_stridx = new hash_map<tree, stridx_strlenloc> ();
@@ -4479,10 +4859,17 @@ pass_strlen::execute (function *fun)
 
   calculate_dominance_info (CDI_DOMINATORS);
 
+  bool use_scev = optimize > 0 && flag_printf_return_value;
+  if (use_scev)
+    {
+      loop_optimizer_init (LOOPS_NORMAL);
+      scev_initialize ();
+    }
+
   /* String length optimization is implemented as a walk of the dominator
      tree and a forward walk of statements within each block.  */
   strlen_dom_walker walker (CDI_DOMINATORS);
-  walker.walk (fun->cfg->x_entry_block_ptr);
+  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
 
   ssa_ver_to_stridx.release ();
   strinfo_pool.release ();
@@ -4503,11 +4890,113 @@ pass_strlen::execute (function *fun)
       strlen_to_stridx = NULL;
     }
 
+  if (use_scev)
+    {
+      scev_finalize ();
+      loop_optimizer_finalize ();
+    }
+
+  /* Clean up object size info.  */
+  fini_object_sizes ();
+
   return walker.m_cleanup_cfg ? TODO_cleanup_cfg : 0;
 }
 
+/* This file defines two passes: one for warnings that runs only when
+   optimization is disabled, and another that implements optimizations
+   and also issues warnings.  */
+
+const pass_data pass_data_warn_printf =
+{
+  GIMPLE_PASS, /* type */
+  "warn-printf", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  /* Normally an optimization pass would require PROP_ssa but because
+     this pass runs early, with no optimization, to do sprintf format
+     checking, it only requires PROP_cfg.  */
+  PROP_cfg, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_warn_printf : public gimple_opt_pass
+{
+public:
+  pass_warn_printf (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_warn_printf, ctxt)
+  {}
+
+  virtual bool gate (function *);
+  virtual unsigned int execute (function *fun)
+  {
+    return printf_strlen_execute (fun, true);
+  }
+};
+
+
+/* Return true to run the warning pass only when not optimizing and
+   iff either -Wformat-overflow or -Wformat-truncation is specified.  */
+
+bool
+pass_warn_printf::gate (function *)
+{
+  return !optimize && (warn_format_overflow > 0 || warn_format_trunc > 0);
+}
+
+const pass_data pass_data_strlen =
+{
+  GIMPLE_PASS, /* type */
+  "strlen", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_STRLEN, /* tv_id */
+  PROP_cfg | PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_strlen : public gimple_opt_pass
+{
+public:
+  pass_strlen (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_strlen, ctxt)
+  {}
+
+  opt_pass * clone () { return new pass_strlen (m_ctxt); }
+
+  virtual bool gate (function *);
+  virtual unsigned int execute (function *fun)
+  {
+    return printf_strlen_execute (fun, false);
+  }
+};
+
+/* Return true to run the pass only when the sprintf and/or strlen
+   optimizations are enabled and -Wformat-overflow or -Wformat-truncation
+   are specified.  */
+
+bool
+pass_strlen::gate (function *)
+{
+  return ((warn_format_overflow > 0
+          || warn_format_trunc > 0
+          || flag_optimize_strlen > 0
+          || flag_printf_return_value)
+         && optimize > 0);
+}
+
 } // anon namespace
 
+gimple_opt_pass *
+make_pass_warn_printf (gcc::context *ctxt)
+{
+  return new pass_warn_printf (ctxt);
+}
+
 gimple_opt_pass *
 make_pass_strlen (gcc::context *ctxt)
 {
index 395c74e88e10e0f4d725935680c234d975cb0d93..4d43fc65e9eef6f26f9d70675d57be0f78cddf6a 100644 (file)
@@ -25,4 +25,11 @@ extern bool is_strlen_related_p (tree, tree);
 extern bool maybe_diag_stxncpy_trunc (gimple_stmt_iterator, tree, tree);
 extern tree set_strlen_range (tree, wide_int, wide_int, tree = NULL_TREE);
 
+struct c_strlen_data;
+class vr_values;
+extern void get_range_strlen_dynamic (tree , c_strlen_data *, const vr_values *);
+
+/* APIs internal to strlen pass.  Defined in in gimple-ssa-sprintf.c.  */
+extern bool handle_printf_call (gimple_stmt_iterator *,  const vr_values *);
+
 #endif   // GCC_TREE_SSA_STRLEN_H
index 4145bcc83a9da4ff7ecd90db480427cd017a8739..5ec4d17f23b2d752e0455f4fb4d0e004a5409159 100644 (file)
@@ -369,7 +369,7 @@ value_range_base::singleton_p (tree *result) const
 tree
 value_range_base::type () const
 {
-  gcc_assert (m_min || undefined_p ());
+  gcc_assert (m_min);
   return TREE_TYPE (min ());
 }
 
index 6f9a3612931cbff15612b6266844295ea7ef1184..96c764c987be96f71f5b4369d85e77f461130582 100644 (file)
@@ -234,7 +234,7 @@ vr_values::update_value_range (const_tree var, value_range *new_vr)
         called, if we are anyway, keep it VARYING.  */
       if (old_vr->varying_p ())
        {
-         new_vr->set_varying (new_vr->type ());
+         new_vr->set_varying (TREE_TYPE (var));
          is_new = false;
        }
       else if (new_vr->undefined_p ())