]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c/54381 (-Wsizeof-pointer-memaccess refers to "destination" for strncmp)
authorJakub Jelinek <jakub@redhat.com>
Fri, 12 Oct 2012 18:23:03 +0000 (20:23 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 12 Oct 2012 18:23:03 +0000 (20:23 +0200)
PR c/54381
* c-common.h (sizeof_pointer_memaccess_warning): Adjust prototype.
* c-common.c (sizeof_pointer_memaccess_warning): Take array of 3
locs and array of 3 trees instead of just single loc and single
sizeof_arg tree.  Handle __builtin___*_chk builtins too, and
also stpncpy, bcopy, bcmp, bzero, snprintf and vsnprintf builtins.
For *cmp* builtins that take two sources strings report warnings
about first and second source, not about destination and source.

* c-parser.c (struct c_tree_loc_pair): Removed.
(c_parser_expr_list): Remove struct c_tree_loc_pair * argument,
add location_t * and tree * arguments, fill in array of 3
sizeof_arg trees and corresponding locs.
(c_parser_attributes, c_parser_objc_keywordexpr): Adjust
c_parser_expr_list callers.
(c_parser_postfix_expression_after_primary): Likewise.  Pass
array of 3 sizeof_arg trees and locs (corresponding to first
3 arguments) to sizeof_pointer_memaccess_warning.

* semantics.c (finish_call_expr): Pass array of 3 sizeof_arg
trees and locs (corresponding to first 3 arguments) to
sizeof_pointer_memaccess_warning.

* c-c++-common/Wsizeof-pointer-memaccess1.c: New test.
* c-c++-common/Wsizeof-pointer-memaccess2.c: New test.
* gcc.dg/Wsizeof-pointer-memaccess1.c: New test.
* gcc.dg/torture/Wsizeof-pointer-memaccess1.c: Test also stpncpy.
Adjust expected wording of warnings for *cmp* builtins.
* g++.dg/torture/Wsizeof-pointer-memaccess1.C: Likewise.
* g++.dg/torture/Wsizeof-pointer-memaccess2.C: Likewise.

From-SVN: r192406

14 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c/ChangeLog
gcc/c/c-parser.c
gcc/cp/ChangeLog
gcc/cp/semantics.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c [new file with mode: 0644]
gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C
gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C
gcc/testsuite/gcc.dg/Wsizeof-pointer-memaccess1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c

index c740e449383944a59b09330fc24852c7c5742b21..bb82be4d72d50ef7a86b6e7204670a5534160e70 100644 (file)
@@ -1,3 +1,14 @@
+2012-10-12  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c/54381
+       * c-common.h (sizeof_pointer_memaccess_warning): Adjust prototype.
+       * c-common.c (sizeof_pointer_memaccess_warning): Take array of 3
+       locs and array of 3 trees instead of just single loc and single
+       sizeof_arg tree.  Handle __builtin___*_chk builtins too, and
+       also stpncpy, bcopy, bcmp, bzero, snprintf and vsnprintf builtins.
+       For *cmp* builtins that take two sources strings report warnings
+       about first and second source, not about destination and source.
+
 2012-10-12  Marc Glisse  <marc.glisse@inria.fr>
 
        PR c++/53055
index b9186489a405a4847028fe350cf8336ddac0922e..34cfb98f85ba53e994e1a551649494caddf2fdb5 100644 (file)
@@ -1847,52 +1847,105 @@ strict_aliasing_warning (tree otype, tree type, tree expr)
    sizeof as last operand of certain builtins.  */
 
 void
-sizeof_pointer_memaccess_warning (location_t loc, tree callee,
-                                 VEC(tree, gc) *params, tree sizeof_arg,
+sizeof_pointer_memaccess_warning (location_t *sizeof_arg_loc, tree callee,
+                                 VEC(tree, gc) *params, tree *sizeof_arg,
                                  bool (*comp_types) (tree, tree))
 {
   tree type, dest = NULL_TREE, src = NULL_TREE, tem;
-  bool strop = false;
+  bool strop = false, cmp = false;
+  unsigned int idx = ~0;
+  location_t loc;
 
   if (TREE_CODE (callee) != FUNCTION_DECL
       || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
-      || sizeof_arg == error_mark_node
       || VEC_length (tree, params) <= 1)
     return;
 
-  type = TYPE_P (sizeof_arg) ? sizeof_arg : TREE_TYPE (sizeof_arg);
-  if (!POINTER_TYPE_P (type))
-    return;
-
   switch (DECL_FUNCTION_CODE (callee))
     {
     case BUILT_IN_STRNCMP:
     case BUILT_IN_STRNCASECMP:
+      cmp = true;
+      /* FALLTHRU */
     case BUILT_IN_STRNCPY:
+    case BUILT_IN_STRNCPY_CHK:
     case BUILT_IN_STRNCAT:
+    case BUILT_IN_STRNCAT_CHK:
+    case BUILT_IN_STPNCPY:
+    case BUILT_IN_STPNCPY_CHK:
       strop = true;
       /* FALLTHRU */
     case BUILT_IN_MEMCPY:
+    case BUILT_IN_MEMCPY_CHK:
     case BUILT_IN_MEMMOVE:
+    case BUILT_IN_MEMMOVE_CHK:
+      if (VEC_length (tree, params) < 3)
+       return;
+      src = VEC_index (tree, params, 1);
+      dest = VEC_index (tree, params, 0);
+      idx = 2;
+      break;
+    case BUILT_IN_BCOPY:
+      if (VEC_length (tree, params) < 3)
+       return;
+      src = VEC_index (tree, params, 0);
+      dest = VEC_index (tree, params, 1);
+      idx = 2;
+      break;
     case BUILT_IN_MEMCMP:
+    case BUILT_IN_BCMP:
       if (VEC_length (tree, params) < 3)
        return;
       src = VEC_index (tree, params, 1);
       dest = VEC_index (tree, params, 0);
+      idx = 2;
+      cmp = true;
       break;
     case BUILT_IN_MEMSET:
+    case BUILT_IN_MEMSET_CHK:
       if (VEC_length (tree, params) < 3)
        return;
       dest = VEC_index (tree, params, 0);
+      idx = 2;
+      break;
+    case BUILT_IN_BZERO:
+      dest = VEC_index (tree, params, 0);
+      idx = 1;
       break;
     case BUILT_IN_STRNDUP:
       src = VEC_index (tree, params, 0);
       strop = true;
+      idx = 1;
+      break;
+    case BUILT_IN_MEMCHR:
+      if (VEC_length (tree, params) < 3)
+       return;
+      src = VEC_index (tree, params, 0);
+      idx = 2;
+      break;
+    case BUILT_IN_SNPRINTF:
+    case BUILT_IN_SNPRINTF_CHK:
+    case BUILT_IN_VSNPRINTF:
+    case BUILT_IN_VSNPRINTF_CHK:
+      dest = VEC_index (tree, params, 0);
+      idx = 1;
+      strop = true;
       break;
     default:
       break;
     }
 
+  if (idx >= 3)
+    return;
+
+  if (sizeof_arg[idx] == NULL || sizeof_arg[idx] == error_mark_node)
+    return;
+
+  type = TYPE_P (sizeof_arg[idx])
+        ? sizeof_arg[idx] : TREE_TYPE (sizeof_arg[idx]);
+  if (!POINTER_TYPE_P (type))
+    return;
+
   if (dest
       && (tem = tree_strip_nop_conversions (dest))
       && POINTER_TYPE_P (TREE_TYPE (tem))
@@ -1905,13 +1958,15 @@ sizeof_pointer_memaccess_warning (location_t loc, tree callee,
       && comp_types (TREE_TYPE (TREE_TYPE (tem)), type))
     return;
 
-  if (dest)
+  loc = sizeof_arg_loc[idx];
+
+  if (dest && !cmp)
     {
-      if (!TYPE_P (sizeof_arg)
-         && operand_equal_p (dest, sizeof_arg, 0)
+      if (!TYPE_P (sizeof_arg[idx])
+         && operand_equal_p (dest, sizeof_arg[idx], 0)
          && comp_types (TREE_TYPE (dest), type))
        {
-         if (TREE_CODE (sizeof_arg) == ADDR_EXPR && !strop)
+         if (TREE_CODE (sizeof_arg[idx]) == ADDR_EXPR && !strop)
            warning_at (loc, OPT_Wsizeof_pointer_memaccess,
                        "argument to %<sizeof%> in %qD call is the same "
                        "expression as the destination; did you mean to "
@@ -1945,13 +2000,13 @@ sizeof_pointer_memaccess_warning (location_t loc, tree callee,
        }
     }
 
-  if (src)
+  if (src && !cmp)
     {
-      if (!TYPE_P (sizeof_arg)
-         && operand_equal_p (src, sizeof_arg, 0)
+      if (!TYPE_P (sizeof_arg[idx])
+         && operand_equal_p (src, sizeof_arg[idx], 0)
          && comp_types (TREE_TYPE (src), type))
        {
-         if (TREE_CODE (sizeof_arg) == ADDR_EXPR && !strop)
+         if (TREE_CODE (sizeof_arg[idx]) == ADDR_EXPR && !strop)
            warning_at (loc, OPT_Wsizeof_pointer_memaccess,
                        "argument to %<sizeof%> in %qD call is the same "
                        "expression as the source; did you mean to "
@@ -1984,6 +2039,87 @@ sizeof_pointer_memaccess_warning (location_t loc, tree callee,
          return;
        }
     }
+
+  if (dest)
+    {
+      if (!TYPE_P (sizeof_arg[idx])
+         && operand_equal_p (dest, sizeof_arg[idx], 0)
+         && comp_types (TREE_TYPE (dest), type))
+       {
+         if (TREE_CODE (sizeof_arg[idx]) == ADDR_EXPR && !strop)
+           warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+                       "argument to %<sizeof%> in %qD call is the same "
+                       "expression as the first source; did you mean to "
+                       "remove the addressof?", callee);
+         else if ((TYPE_PRECISION (TREE_TYPE (type))
+                   == TYPE_PRECISION (char_type_node))
+                  || strop)
+           warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+                       "argument to %<sizeof%> in %qD call is the same "
+                       "expression as the first source; did you mean to "
+                       "provide an explicit length?", callee);
+         else
+           warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+                       "argument to %<sizeof%> in %qD call is the same "
+                       "expression as the first source; did you mean to "
+                       "dereference it?", callee);
+         return;
+       }
+
+      if (POINTER_TYPE_P (TREE_TYPE (dest))
+         && !strop
+         && comp_types (TREE_TYPE (dest), type)
+         && !VOID_TYPE_P (TREE_TYPE (type)))
+       {
+         warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+                     "argument to %<sizeof%> in %qD call is the same "
+                     "pointer type %qT as the first source; expected %qT "
+                     "or an explicit length", callee, TREE_TYPE (dest),
+                     TREE_TYPE (TREE_TYPE (dest)));
+         return;
+       }
+    }
+
+  if (src)
+    {
+      if (!TYPE_P (sizeof_arg[idx])
+         && operand_equal_p (src, sizeof_arg[idx], 0)
+         && comp_types (TREE_TYPE (src), type))
+       {
+         if (TREE_CODE (sizeof_arg[idx]) == ADDR_EXPR && !strop)
+           warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+                       "argument to %<sizeof%> in %qD call is the same "
+                       "expression as the second source; did you mean to "
+                       "remove the addressof?", callee);
+         else if ((TYPE_PRECISION (TREE_TYPE (type))
+                   == TYPE_PRECISION (char_type_node))
+                  || strop)
+           warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+                       "argument to %<sizeof%> in %qD call is the same "
+                       "expression as the second source; did you mean to "
+                       "provide an explicit length?", callee);
+         else
+           warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+                       "argument to %<sizeof%> in %qD call is the same "
+                       "expression as the second source; did you mean to "
+                       "dereference it?", callee);
+         return;
+       }
+
+      if (POINTER_TYPE_P (TREE_TYPE (src))
+         && !strop
+         && comp_types (TREE_TYPE (src), type)
+         && !VOID_TYPE_P (TREE_TYPE (type)))
+       {
+         warning_at (loc, OPT_Wsizeof_pointer_memaccess,
+                     "argument to %<sizeof%> in %qD call is the same "
+                     "pointer type %qT as the second source; expected %qT "
+                     "or an explicit length", callee, TREE_TYPE (src),
+                     TREE_TYPE (TREE_TYPE (src)));
+         return;
+       }
+    }
+
 }
 
 /* Warn for unlikely, improbable, or stupid DECL declarations
index 66d90a345709e12a48ba97260234f07ca9602850..94449a5f3f35d134b045b4a72f8aad4157e40664 100644 (file)
@@ -769,8 +769,8 @@ extern tree fix_string_type (tree);
 extern void constant_expression_warning (tree);
 extern void constant_expression_error (tree);
 extern bool strict_aliasing_warning (tree, tree, tree);
-extern void sizeof_pointer_memaccess_warning (location_t, tree,
-                                             VEC(tree, gc) *, tree,
+extern void sizeof_pointer_memaccess_warning (location_t *, tree,
+                                             VEC(tree, gc) *, tree *,
                                              bool (*) (tree, tree));
 extern void warnings_for_convert_and_check (tree, tree, tree);
 extern tree convert_and_check (tree, tree);
index dfe76e63fdaa5a524e71f163a69de0114c5aea74..89d89f7aca26cccdeafae129f2d05c7f09f5d67f 100644 (file)
@@ -1,3 +1,16 @@
+2012-10-12  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c/54381
+       * c-parser.c (struct c_tree_loc_pair): Removed.
+       (c_parser_expr_list): Remove struct c_tree_loc_pair * argument,
+       add location_t * and tree * arguments, fill in array of 3
+       sizeof_arg trees and corresponding locs.
+       (c_parser_attributes, c_parser_objc_keywordexpr): Adjust
+       c_parser_expr_list callers.
+       (c_parser_postfix_expression_after_primary): Likewise.  Pass
+       array of 3 sizeof_arg trees and locs (corresponding to first
+       3 arguments) to sizeof_pointer_memaccess_warning.
+
 2012-10-09  Lawrence Crowl  <crowl@google.com>
 
        * Make-lang.in (c-decl.o): Add dependence on hash-table.h.
index bea9791925c33b1fa19932e8e46222aa51c54b40..bfa98afef01fa62f69374a0de2d646700adb7664 100644 (file)
@@ -1111,12 +1111,6 @@ enum c_parser_prec {
   NUM_PRECS
 };
 
-/* Expression and its location.  */
-struct c_tree_loc_pair {
-  tree expr;
-  location_t loc;
-};
-
 static void c_parser_external_declaration (c_parser *);
 static void c_parser_asm_definition (c_parser *);
 static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
@@ -1185,8 +1179,8 @@ static tree c_parser_transaction_cancel (c_parser *);
 static struct c_expr c_parser_expression (c_parser *);
 static struct c_expr c_parser_expression_conv (c_parser *);
 static VEC(tree,gc) *c_parser_expr_list (c_parser *, bool, bool,
-                                        VEC(tree,gc) **,
-                                        struct c_tree_loc_pair *);
+                                        VEC(tree,gc) **, location_t *,
+                                        tree *);
 static void c_parser_omp_construct (c_parser *);
 static void c_parser_omp_threadprivate (c_parser *);
 static void c_parser_omp_barrier (c_parser *);
@@ -3586,7 +3580,7 @@ c_parser_attributes (c_parser *parser)
                  tree tree_list;
                  c_parser_consume_token (parser);
                  expr_list = c_parser_expr_list (parser, false, true,
-                                                 NULL, NULL);
+                                                 NULL, NULL, NULL);
                  tree_list = build_tree_list_vec (expr_list);
                  attr_args = tree_cons (NULL_TREE, arg1, tree_list);
                  release_tree_vector (expr_list);
@@ -3599,7 +3593,7 @@ c_parser_attributes (c_parser *parser)
              else
                {
                  expr_list = c_parser_expr_list (parser, false, true,
-                                                 NULL, NULL);
+                                                 NULL, NULL, NULL);
                  attr_args = build_tree_list_vec (expr_list);
                  release_tree_vector (expr_list);
                }
@@ -6875,7 +6869,9 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
 {
   struct c_expr orig_expr;
   tree ident, idx;
-  struct c_tree_loc_pair sizeof_arg;
+  location_t sizeof_arg_loc[3];
+  tree sizeof_arg[3];
+  unsigned int i;
   VEC(tree,gc) *exprlist;
   VEC(tree,gc) *origtypes;
   while (true)
@@ -6896,21 +6892,24 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
        case CPP_OPEN_PAREN:
          /* Function call.  */
          c_parser_consume_token (parser);
-         sizeof_arg.expr = NULL_TREE;
+         for (i = 0; i < 3; i++)
+           {
+             sizeof_arg[i] = NULL_TREE;
+             sizeof_arg_loc[i] = UNKNOWN_LOCATION;
+           }
          if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
            exprlist = NULL;
          else
            exprlist = c_parser_expr_list (parser, true, false, &origtypes,
-                                          &sizeof_arg);
+                                          sizeof_arg_loc, sizeof_arg);
          c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
                                     "expected %<)%>");
          orig_expr = expr;
          mark_exp_read (expr.value);
-         if (warn_sizeof_pointer_memaccess
-             && sizeof_arg.expr != NULL_TREE)
-           sizeof_pointer_memaccess_warning (sizeof_arg.loc,
+         if (warn_sizeof_pointer_memaccess)
+           sizeof_pointer_memaccess_warning (sizeof_arg_loc,
                                              expr.value, exprlist,
-                                             sizeof_arg.expr,
+                                             sizeof_arg,
                                              sizeof_ptr_memacc_comptypes);
          /* FIXME diagnostics: Ideally we want the FUNCNAME, not the
             "(" after the FUNCNAME, which is what we have now.    */
@@ -7072,14 +7071,15 @@ c_parser_expression_conv (c_parser *parser)
 
 static VEC(tree,gc) *
 c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
-                   VEC(tree,gc) **p_orig_types,
-                   struct c_tree_loc_pair *sizeof_arg)
+                   VEC(tree,gc) **p_orig_types, location_t *sizeof_arg_loc,
+                   tree *sizeof_arg)
 {
   VEC(tree,gc) *ret;
   VEC(tree,gc) *orig_types;
   struct c_expr expr;
   location_t loc = c_parser_peek_token (parser)->location;
-  location_t sizeof_arg_loc = UNKNOWN_LOCATION;
+  location_t cur_sizeof_arg_loc = UNKNOWN_LOCATION;
+  unsigned int idx = 0;
 
   ret = make_tree_vector ();
   if (p_orig_types == NULL)
@@ -7089,7 +7089,7 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
 
   if (sizeof_arg != NULL
       && c_parser_next_token_is_keyword (parser, RID_SIZEOF))
-    sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
+    cur_sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
   expr = c_parser_expr_no_commas (parser, NULL);
   if (convert_p)
     expr = default_function_array_read_conversion (loc, expr);
@@ -7098,15 +7098,22 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
   VEC_quick_push (tree, ret, expr.value);
   if (orig_types != NULL)
     VEC_quick_push (tree, orig_types, expr.original_type);
+  if (sizeof_arg != NULL
+      && cur_sizeof_arg_loc != UNKNOWN_LOCATION
+      && expr.original_code == SIZEOF_EXPR)
+    {
+      sizeof_arg[0] = c_last_sizeof_arg;
+      sizeof_arg_loc[0] = cur_sizeof_arg_loc;
+    }
   while (c_parser_next_token_is (parser, CPP_COMMA))
     {
       c_parser_consume_token (parser);
       loc = c_parser_peek_token (parser)->location;
       if (sizeof_arg != NULL
          && c_parser_next_token_is_keyword (parser, RID_SIZEOF))
-       sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
+       cur_sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
       else
-       sizeof_arg_loc = UNKNOWN_LOCATION;
+       cur_sizeof_arg_loc = UNKNOWN_LOCATION;
       expr = c_parser_expr_no_commas (parser, NULL);
       if (convert_p)
        expr = default_function_array_read_conversion (loc, expr);
@@ -7115,19 +7122,13 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
       VEC_safe_push (tree, gc, ret, expr.value);
       if (orig_types != NULL)
        VEC_safe_push (tree, gc, orig_types, expr.original_type);
-    }
-  if (sizeof_arg != NULL)
-    {
-      if (sizeof_arg_loc != UNKNOWN_LOCATION
+      if (++idx < 3
+         && sizeof_arg != NULL
+         && cur_sizeof_arg_loc != UNKNOWN_LOCATION
          && expr.original_code == SIZEOF_EXPR)
        {
-         sizeof_arg->expr = c_last_sizeof_arg;
-         sizeof_arg->loc = sizeof_arg_loc;
-       }
-      else
-       {
-         sizeof_arg->expr = NULL_TREE;
-         sizeof_arg->loc = UNKNOWN_LOCATION;
+         sizeof_arg[idx] = c_last_sizeof_arg;
+         sizeof_arg_loc[idx] = cur_sizeof_arg_loc;
        }
     }
   if (orig_types != NULL)
@@ -8209,7 +8210,7 @@ c_parser_objc_keywordexpr (c_parser *parser)
 {
   tree ret;
   VEC(tree,gc) *expr_list = c_parser_expr_list (parser, true, true,
-                                               NULL, NULL);
+                                               NULL, NULL, NULL);
   if (VEC_length (tree, expr_list) == 1)
     {
       /* Just return the expression, remove a level of
index 6730b1093788b108f83dac7d5a5c8e0a66fed8e4..27f0d55ac97342c4058f8e9191f297b099911492 100644 (file)
@@ -1,3 +1,10 @@
+2012-10-12  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c/54381
+       * semantics.c (finish_call_expr): Pass array of 3 sizeof_arg
+       trees and locs (corresponding to first 3 arguments) to
+       sizeof_pointer_memaccess_warning.
+
 2012-10-12  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/24449
index 4beed0073fbbc9a1e918f224f505b1bcdb658bdb..6798c1bf5d4d1ce95348c97ad560bbd5879eba96 100644 (file)
@@ -2173,16 +2173,30 @@ finish_call_expr (tree fn, VEC(tree,gc) **args, bool disallow_virtual,
        {
          if (warn_sizeof_pointer_memaccess
              && !VEC_empty(tree, *args)
-             && TREE_CODE (VEC_last(tree, *args)) == SIZEOF_EXPR
              && !processing_template_decl)
            {
-             tree sizeof_arg = VEC_last(tree, *args);
-             if (SIZEOF_EXPR_TYPE_P (sizeof_arg))
-               sizeof_arg = TREE_TYPE (TREE_OPERAND (sizeof_arg, 0));
-             else
-               sizeof_arg = TREE_OPERAND (sizeof_arg, 0);
+             location_t sizeof_arg_loc[3];
+             tree sizeof_arg[3];
+             unsigned int i;
+             for (i = 0; i < 3; i++)
+               {
+                 tree t;
+
+                 sizeof_arg_loc[i] = UNKNOWN_LOCATION;
+                 sizeof_arg[i] = NULL_TREE;
+                 if (i >= VEC_length (tree, *args))
+                   continue;
+                 t = VEC_index (tree, *args, i);
+                 if (TREE_CODE (t) != SIZEOF_EXPR)
+                   continue;
+                 if (SIZEOF_EXPR_TYPE_P (t))
+                   sizeof_arg[i] = TREE_TYPE (TREE_OPERAND (t, 0));
+                 else
+                   sizeof_arg[i] = TREE_OPERAND (t, 0);
+                 sizeof_arg_loc[i] = EXPR_LOCATION (t);
+               }
              sizeof_pointer_memaccess_warning
-               (EXPR_LOCATION (VEC_last(tree, *args)), fn, *args,
+               (sizeof_arg_loc, fn, *args,
                 sizeof_arg, same_type_ignoring_top_level_qualifiers_p);
            }
 
index 862b4273055419a54ac0f02bd37a8d3bc20d3471..0faa27b8b2aa1fe130f962806fb26bbe7bbb7fac 100644 (file)
@@ -1,3 +1,14 @@
+2012-10-12  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c/54381
+       * c-c++-common/Wsizeof-pointer-memaccess1.c: New test.
+       * c-c++-common/Wsizeof-pointer-memaccess2.c: New test.
+       * gcc.dg/Wsizeof-pointer-memaccess1.c: New test.
+       * gcc.dg/torture/Wsizeof-pointer-memaccess1.c: Test also stpncpy.
+       Adjust expected wording of warnings for *cmp* builtins.
+       * g++.dg/torture/Wsizeof-pointer-memaccess1.C: Likewise.
+       * g++.dg/torture/Wsizeof-pointer-memaccess2.C: Likewise.
+
 2012-10-12  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/24449
diff --git a/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c b/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c
new file mode 100644 (file)
index 0000000..2a5f419
--- /dev/null
@@ -0,0 +1,161 @@
+/* Test -Wsizeof-pointer-memaccess warnings.  */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int snprintf (char *, size_t, const char *, ...);
+extern int vsnprintf (char *, size_t, const char *, __builtin_va_list);
+extern void *memchr (const void *, int, size_t);
+#ifdef __cplusplus
+}
+#endif
+
+struct A { short a, b; int c, d; long e, f; };
+typedef struct A TA;
+typedef struct A *PA;
+typedef TA *PTA;
+struct B {};
+typedef struct B TB;
+typedef struct B *PB;
+typedef TB *PTB;
+typedef int X[3][3][3];
+
+void foo (void **);
+
+void
+f1 (void *x)
+{
+  struct A a, *pa1 = &a;
+  TA *pa2 = &a;
+  PA pa3 = &a;
+  PTA pa4 = &a;
+  void *arr[100];
+  int i = 0;
+  arr[i++] = memchr (&a, 0, sizeof (&a));              /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
+  arr[i++] = memchr (pa1, 0, sizeof (pa1));            /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  arr[i++] = memchr (pa2, 0, sizeof pa2);              /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  arr[i++] = memchr (pa3, 0, sizeof (pa3));            /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  arr[i++] = memchr (pa4, 0, sizeof pa4);              /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  arr[i++] = memchr (pa1, 0, sizeof (struct A *));     /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  arr[i++] = memchr (pa2, 0, sizeof (PTA));            /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  arr[i++] = memchr (pa3, 0, sizeof (PA));             /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  arr[i++] = memchr (pa4, 0, sizeof (__typeof (pa4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+
+  /* These are correct, no warning.  */
+  arr[i++] = memchr (&a, 0, sizeof a);
+  arr[i++] = memchr (&a, 0, sizeof (a));
+  arr[i++] = memchr (&a, 0, sizeof (struct A));
+  arr[i++] = memchr (&a, 0, sizeof (const struct A));
+  arr[i++] = memchr (&a, 0, sizeof (volatile struct A));
+  arr[i++] = memchr (&a, 0, sizeof (volatile const struct A));
+  arr[i++] = memchr (&a, 0, sizeof (TA));
+  arr[i++] = memchr (&a, 0, sizeof (__typeof (*&a)));
+  arr[i++] = memchr (pa1, 0, sizeof (*pa1));
+  arr[i++] = memchr (pa2, 0, sizeof (*pa3));
+  arr[i++] = memchr (pa3, 0, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  arr[i++] = memchr ((void *) &a, 0, sizeof (&a));
+  arr[i++] = memchr ((char *) &a, 0, sizeof (&a));
+  arr[i++] = memchr (&a, 0, sizeof (&a) + 0);
+  arr[i++] = memchr (&a, 0, 0 + sizeof (&a));
+
+  foo (arr);
+}
+
+void
+f2 (void *x)
+{
+  struct B b, *pb1 = &b;
+  TB *pb2 = &b;
+  PB pb3 = &b;
+  PTB pb4 = &b;
+  void *arr[100];
+  int i = 0;
+  arr[i++] = memchr (&b, 0, sizeof (&b));              /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
+  arr[i++] = memchr (pb1, 0, sizeof (pb1));            /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  arr[i++] = memchr (pb2, 0, sizeof pb2);              /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  arr[i++] = memchr (pb3, 0, sizeof (pb3));            /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  arr[i++] = memchr (pb4, 0, sizeof pb4);              /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  arr[i++] = memchr (pb1, 0, sizeof (struct B *));     /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  arr[i++] = memchr (pb2, 0, sizeof (PTB));            /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  arr[i++] = memchr (pb3, 0, sizeof (PB));             /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  arr[i++] = memchr (pb4, 0, sizeof (__typeof (pb4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+
+  /* These are correct, no warning.  */
+  arr[i++] = memchr (&b, 0, sizeof b);
+  arr[i++] = memchr (&b, 0, sizeof (b));
+  arr[i++] = memchr (&b, 0, sizeof (struct B));
+  arr[i++] = memchr (&b, 0, sizeof (const struct B));
+  arr[i++] = memchr (&b, 0, sizeof (volatile struct B));
+  arr[i++] = memchr (&b, 0, sizeof (volatile const struct B));
+  arr[i++] = memchr (&b, 0, sizeof (TB));
+  arr[i++] = memchr (&b, 0, sizeof (__typeof (*&b)));
+  arr[i++] = memchr (pb1, 0, sizeof (*pb1));
+  arr[i++] = memchr (pb2, 0, sizeof (*pb3));
+  arr[i++] = memchr (pb3, 0, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  arr[i++] = memchr ((void *) &b, 0, sizeof (&b));
+  arr[i++] = memchr ((char *) &b, 0, sizeof (&b));
+  arr[i++] = memchr (&b, 0, sizeof (&b) + 0);
+  arr[i++] = memchr (&b, 0, 0 + sizeof (&b));
+
+  foo (arr);
+}
+
+void
+f3 (void *x, char *y, int z, X w)
+{
+  unsigned char *y1 = (unsigned char *) __builtin_alloca (z + 16);
+  char buf1[7];
+  signed char buf2[z + 32];
+  long buf3[17];
+  int *buf4[9];
+  signed char *y2 = buf2;
+  char c;
+  void *arr[100];
+  int i = 0;
+  arr[i++] = memchr (y, 0, sizeof (y));                        /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  arr[i++] = memchr (y1, 0, sizeof (y1));              /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  arr[i++] = memchr (y2, 0, sizeof (y2));              /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  arr[i++] = memchr (&c, 0, sizeof (&c));              /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
+  arr[i++] = memchr (w, 0, sizeof w);                  /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+
+  /* These are correct, no warning.  */
+  arr[i++] = memchr (y, 0, sizeof (*y));
+  arr[i++] = memchr (y1, 0, sizeof (*y2));
+  arr[i++] = memchr (buf1, 0, sizeof buf1);
+  arr[i++] = memchr (buf3, 0, sizeof (buf3));
+  arr[i++] = memchr (&buf3[0], 0, sizeof (buf3));
+  arr[i++] = memchr (&buf4[0], 0, sizeof (buf4));
+  arr[i++] = memchr (w, 0, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  arr[i++] = memchr ((void *) y, 0, sizeof (y));
+  arr[i++] = memchr ((char *) y1, 0, sizeof (y2));
+  arr[i++] = memchr (y, 0, sizeof (y) + 0);
+  arr[i++] = memchr (y1, 0, 0 + sizeof (y2));
+  arr[i++] = memchr ((void *) &c, 0, sizeof (&c));
+  arr[i++] = memchr ((signed char *) &c, 0, sizeof (&c));
+  arr[i++] = memchr (&c, 0, sizeof (&c) + 0);
+  arr[i++] = memchr (&c, 0, 0 + sizeof (&c));
+
+  foo (arr);
+}
+
+void
+f4 (char x[64], char *y, __builtin_va_list ap)
+{
+  char buf[128], *p = buf;
+  snprintf (x, sizeof (x), "%s", y);       /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  vsnprintf (x, sizeof (x), "%s", ap);     /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  snprintf (p, sizeof (p), "%s", y);       /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  vsnprintf (p, sizeof (p), "%s", ap);     /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+
+  /* These are correct, no warning.  */
+  snprintf (buf, sizeof (buf), "%s", y);
+  vsnprintf (buf, sizeof (buf), "%s", ap);
+  snprintf (p, sizeof (buf), "%s", y);
+  vsnprintf (p, sizeof (buf), "%s", ap);
+}
diff --git a/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c b/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c
new file mode 100644 (file)
index 0000000..73cdf0e
--- /dev/null
@@ -0,0 +1,482 @@
+/* Test -Wsizeof-pointer-memaccess warnings.  */
+/* { dg-do compile } */
+/* { dg-options "-Wall -O2" } */
+
+#define bos(ptr) __builtin_object_size (ptr, 1)
+#define bos0(ptr) __builtin_object_size (ptr, 0)
+
+#define memset(dst, val, sz) __builtin___memset_chk (dst, val, sz, bos (dst))
+#define memcpy(dst, src, sz) __builtin___memcpy_chk (dst, src, sz, bos (dst))
+#define memmove(dst, src, sz) __builtin___memmove_chk (dst, src, sz, bos (dst))
+#define strncpy(dst, src, sz) __builtin___strncpy_chk (dst, src, sz, bos (dst))
+#define strncat(dst, src, sz) __builtin___strncat_chk (dst, src, sz, bos (dst))
+#define stpncpy(dst, src, sz) __builtin___stpncpy_chk (dst, src, sz, bos (dst))
+
+struct A { short a, b; int c, d; long e, f; };
+typedef struct A TA;
+typedef struct A *PA;
+typedef TA *PTA;
+struct B {};
+typedef struct B TB;
+typedef struct B *PB;
+typedef TB *PTB;
+typedef int X[3][3][3];
+
+void
+f1 (void *x)
+{
+  struct A a, *pa1 = &a;
+  TA *pa2 = &a;
+  PA pa3 = &a;
+  PTA pa4 = &a;
+  memset (&a, 0, sizeof (&a));             /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  memset (pa1, 0, sizeof (pa1));           /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memset (pa2, 0, sizeof pa2);             /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memset (pa3, 0, sizeof (pa3));           /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memset (pa4, 0, sizeof pa4);             /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memset (pa1, 0, sizeof (struct A *));            /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memset (pa2, 0, sizeof (PTA));           /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memset (pa3, 0, sizeof (PA));                    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memset (pa4, 0, sizeof (__typeof (pa4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+
+  memcpy (&a, x, sizeof (&a));             /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  memcpy (pa1, x, sizeof (pa1));           /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memcpy (pa2, x, sizeof pa2);             /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memcpy (pa3, x, sizeof (pa3));           /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memcpy (pa4, x, sizeof pa4);             /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memcpy (pa1, x, sizeof (struct A *));            /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memcpy (pa2, x, sizeof (PTA));           /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memcpy (pa3, x, sizeof (PA));                    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memcpy (pa4, x, sizeof (__typeof (pa4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+
+  memcpy (x, &a, sizeof (&a));             /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
+  memcpy (x, pa1, sizeof (pa1));           /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memcpy (x, pa2, sizeof pa2);             /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memcpy (x, pa3, sizeof (pa3));           /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memcpy (x, pa4, sizeof pa4);             /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memcpy (x, pa1, sizeof (struct A *));            /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  memcpy (x, pa2, sizeof (PTA));           /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  memcpy (x, pa3, sizeof (PA));                    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  memcpy (x, pa4, sizeof (__typeof (pa4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+
+  memmove (&a, x, sizeof (&a));                    /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  memmove (pa1, x, sizeof (pa1));          /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memmove (pa2, x, sizeof pa2);                    /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memmove (pa3, x, sizeof (pa3));          /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memmove (pa4, x, sizeof pa4);                    /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memmove (pa1, x, sizeof (struct A *));    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memmove (pa2, x, sizeof (PTA));          /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memmove (pa3, x, sizeof (PA));           /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memmove (pa4, x, sizeof (__typeof (pa4)));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+
+  memmove (x, &a, sizeof (&a));                    /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
+  memmove (x, pa1, sizeof (pa1));          /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memmove (x, pa2, sizeof pa2);                    /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memmove (x, pa3, sizeof (pa3));          /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memmove (x, pa4, sizeof pa4);                    /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memmove (x, pa1, sizeof (struct A *));    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  memmove (x, pa2, sizeof (PTA));          /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  memmove (x, pa3, sizeof (PA));           /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  memmove (x, pa4, sizeof (__typeof (pa4)));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+
+  /* These are correct, no warning.  */
+  memset (&a, 0, sizeof a);
+  memset (&a, 0, sizeof (a));
+  memset (&a, 0, sizeof (struct A));
+  memset (&a, 0, sizeof (const struct A));
+  memset (&a, 0, sizeof (volatile struct A));
+  memset (&a, 0, sizeof (volatile const struct A));
+  memset (&a, 0, sizeof (TA));
+  memset (&a, 0, sizeof (__typeof (*&a)));
+  memset (pa1, 0, sizeof (*pa1));
+  memset (pa2, 0, sizeof (*pa3));
+  memset (pa3, 0, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memset ((void *) &a, 0, sizeof (&a));
+  memset ((char *) &a, 0, sizeof (&a));
+  memset (&a, 0, sizeof (&a) + 0);
+  memset (&a, 0, 0 + sizeof (&a));
+
+  /* These are correct, no warning.  */
+  memcpy (&a, x, sizeof a);
+  memcpy (&a, x, sizeof (a));
+  memcpy (&a, x, sizeof (struct A));
+  memcpy (&a, x, sizeof (const struct A));
+  memcpy (&a, x, sizeof (volatile struct A));
+  memcpy (&a, x, sizeof (volatile const struct A));
+  memcpy (&a, x, sizeof (TA));
+  memcpy (&a, x, sizeof (__typeof (*&a)));
+  memcpy (pa1, x, sizeof (*pa1));
+  memcpy (pa2, x, sizeof (*pa3));
+  memcpy (pa3, x, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memcpy ((void *) &a, x, sizeof (&a));
+  memcpy ((char *) &a, x, sizeof (&a));
+  memcpy (&a, x, sizeof (&a) + 0);
+  memcpy (&a, x, 0 + sizeof (&a));
+
+  /* These are correct, no warning.  */
+  memcpy (x, &a, sizeof a);
+  memcpy (x, &a, sizeof (a));
+  memcpy (x, &a, sizeof (struct A));
+  memcpy (x, &a, sizeof (const struct A));
+  memcpy (x, &a, sizeof (volatile struct A));
+  memcpy (x, &a, sizeof (volatile const struct A));
+  memcpy (x, &a, sizeof (TA));
+  memcpy (x, &a, sizeof (__typeof (*&a)));
+  memcpy (x, pa1, sizeof (*pa1));
+  memcpy (x, pa2, sizeof (*pa3));
+  memcpy (x, pa3, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memcpy (x, (void *) &a, sizeof (&a));
+  memcpy (x, (char *) &a, sizeof (&a));
+  memcpy (x, &a, sizeof (&a) + 0);
+  memcpy (x, &a, 0 + sizeof (&a));
+
+  /* These are correct, no warning.  */
+  memmove (&a, x, sizeof a);
+  memmove (&a, x, sizeof (a));
+  memmove (&a, x, sizeof (struct A));
+  memmove (&a, x, sizeof (const struct A));
+  memmove (&a, x, sizeof (volatile struct A));
+  memmove (&a, x, sizeof (volatile const struct A));
+  memmove (&a, x, sizeof (TA));
+  memmove (&a, x, sizeof (__typeof (*&a)));
+  memmove (pa1, x, sizeof (*pa1));
+  memmove (pa2, x, sizeof (*pa3));
+  memmove (pa3, x, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memmove ((void *) &a, x, sizeof (&a));
+  memmove ((char *) &a, x, sizeof (&a));
+  memmove (&a, x, sizeof (&a) + 0);
+  memmove (&a, x, 0 + sizeof (&a));
+
+  /* These are correct, no warning.  */
+  memmove (x, &a, sizeof a);
+  memmove (x, &a, sizeof (a));
+  memmove (x, &a, sizeof (struct A));
+  memmove (x, &a, sizeof (const struct A));
+  memmove (x, &a, sizeof (volatile struct A));
+  memmove (x, &a, sizeof (volatile const struct A));
+  memmove (x, &a, sizeof (TA));
+  memmove (x, &a, sizeof (__typeof (*&a)));
+  memmove (x, pa1, sizeof (*pa1));
+  memmove (x, pa2, sizeof (*pa3));
+  memmove (x, pa3, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memmove (x, (void *) &a, sizeof (&a));
+  memmove (x, (char *) &a, sizeof (&a));
+  memmove (x, &a, sizeof (&a) + 0);
+  memmove (x, &a, 0 + sizeof (&a));
+}
+
+void
+f2 (void *x)
+{
+  struct B b, *pb1 = &b;
+  TB *pb2 = &b;
+  PB pb3 = &b;
+  PTB pb4 = &b;
+  memset (&b, 0, sizeof (&b));             /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  memset (pb1, 0, sizeof (pb1));           /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memset (pb2, 0, sizeof pb2);             /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memset (pb3, 0, sizeof (pb3));           /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memset (pb4, 0, sizeof pb4);             /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memset (pb1, 0, sizeof (struct B *));            /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memset (pb2, 0, sizeof (PTB));           /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memset (pb3, 0, sizeof (PB));                    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memset (pb4, 0, sizeof (__typeof (pb4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+
+  memcpy (&b, x, sizeof (&b));             /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  memcpy (pb1, x, sizeof (pb1));           /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memcpy (pb2, x, sizeof pb2);             /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memcpy (pb3, x, sizeof (pb3));           /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memcpy (pb4, x, sizeof pb4);             /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memcpy (pb1, x, sizeof (struct B *));            /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memcpy (pb2, x, sizeof (PTB));           /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memcpy (pb3, x, sizeof (PB));                    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memcpy (pb4, x, sizeof (__typeof (pb4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+
+  memcpy (x, &b, sizeof (&b));             /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
+  memcpy (x, pb1, sizeof (pb1));           /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memcpy (x, pb2, sizeof pb2);             /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memcpy (x, pb3, sizeof (pb3));           /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memcpy (x, pb4, sizeof pb4);             /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memcpy (x, pb1, sizeof (struct B *));            /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  memcpy (x, pb2, sizeof (PTB));           /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  memcpy (x, pb3, sizeof (PB));                    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  memcpy (x, pb4, sizeof (__typeof (pb4))); /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+
+  memmove (&b, x, sizeof (&b));                    /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  memmove (pb1, x, sizeof (pb1));          /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memmove (pb2, x, sizeof pb2);                    /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memmove (pb3, x, sizeof (pb3));          /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memmove (pb4, x, sizeof pb4);                    /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  memmove (pb1, x, sizeof (struct B *));    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memmove (pb2, x, sizeof (PTB));          /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memmove (pb3, x, sizeof (PB));           /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  memmove (pb4, x, sizeof (__typeof (pb4)));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+
+  memmove (x, &b, sizeof (&b));                    /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
+  memmove (x, pb1, sizeof (pb1));          /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memmove (x, pb2, sizeof pb2);                    /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memmove (x, pb3, sizeof (pb3));          /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memmove (x, pb4, sizeof pb4);                    /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  memmove (x, pb1, sizeof (struct B *));    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  memmove (x, pb2, sizeof (PTB));          /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  memmove (x, pb3, sizeof (PB));           /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  memmove (x, pb4, sizeof (__typeof (pb4)));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+
+  /* These are correct, no warning.  */
+  memset (&b, 0, sizeof b);
+  memset (&b, 0, sizeof (b));
+  memset (&b, 0, sizeof (struct B));
+  memset (&b, 0, sizeof (const struct B));
+  memset (&b, 0, sizeof (volatile struct B));
+  memset (&b, 0, sizeof (volatile const struct B));
+  memset (&b, 0, sizeof (TB));
+  memset (&b, 0, sizeof (__typeof (*&b)));
+  memset (pb1, 0, sizeof (*pb1));
+  memset (pb2, 0, sizeof (*pb3));
+  memset (pb3, 0, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memset ((void *) &b, 0, sizeof (&b));
+  memset ((char *) &b, 0, sizeof (&b));
+  memset (&b, 0, sizeof (&b) + 0);
+  memset (&b, 0, 0 + sizeof (&b));
+
+  /* These are correct, no warning.  */
+  memcpy (&b, x, sizeof b);
+  memcpy (&b, x, sizeof (b));
+  memcpy (&b, x, sizeof (struct B));
+  memcpy (&b, x, sizeof (const struct B));
+  memcpy (&b, x, sizeof (volatile struct B));
+  memcpy (&b, x, sizeof (volatile const struct B));
+  memcpy (&b, x, sizeof (TB));
+  memcpy (&b, x, sizeof (__typeof (*&b)));
+  memcpy (pb1, x, sizeof (*pb1));
+  memcpy (pb2, x, sizeof (*pb3));
+  memcpy (pb3, x, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memcpy ((void *) &b, x, sizeof (&b));
+  memcpy ((char *) &b, x, sizeof (&b));
+  memcpy (&b, x, sizeof (&b) + 0);
+  memcpy (&b, x, 0 + sizeof (&b));
+
+  /* These are correct, no warning.  */
+  memcpy (x, &b, sizeof b);
+  memcpy (x, &b, sizeof (b));
+  memcpy (x, &b, sizeof (struct B));
+  memcpy (x, &b, sizeof (const struct B));
+  memcpy (x, &b, sizeof (volatile struct B));
+  memcpy (x, &b, sizeof (volatile const struct B));
+  memcpy (x, &b, sizeof (TB));
+  memcpy (x, &b, sizeof (__typeof (*&b)));
+  memcpy (x, pb1, sizeof (*pb1));
+  memcpy (x, pb2, sizeof (*pb3));
+  memcpy (x, pb3, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memcpy (x, (void *) &b, sizeof (&b));
+  memcpy (x, (char *) &b, sizeof (&b));
+  memcpy (x, &b, sizeof (&b) + 0);
+  memcpy (x, &b, 0 + sizeof (&b));
+
+  /* These are correct, no warning.  */
+  memmove (&b, x, sizeof b);
+  memmove (&b, x, sizeof (b));
+  memmove (&b, x, sizeof (struct B));
+  memmove (&b, x, sizeof (const struct B));
+  memmove (&b, x, sizeof (volatile struct B));
+  memmove (&b, x, sizeof (volatile const struct B));
+  memmove (&b, x, sizeof (TB));
+  memmove (&b, x, sizeof (__typeof (*&b)));
+  memmove (pb1, x, sizeof (*pb1));
+  memmove (pb2, x, sizeof (*pb3));
+  memmove (pb3, x, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memmove ((void *) &b, x, sizeof (&b));
+  memmove ((char *) &b, x, sizeof (&b));
+  memmove (&b, x, sizeof (&b) + 0);
+  memmove (&b, x, 0 + sizeof (&b));
+
+  /* These are correct, no warning.  */
+  memmove (x, &b, sizeof b);
+  memmove (x, &b, sizeof (b));
+  memmove (x, &b, sizeof (struct B));
+  memmove (x, &b, sizeof (const struct B));
+  memmove (x, &b, sizeof (volatile struct B));
+  memmove (x, &b, sizeof (volatile const struct B));
+  memmove (x, &b, sizeof (TB));
+  memmove (x, &b, sizeof (__typeof (*&b)));
+  memmove (x, pb1, sizeof (*pb1));
+  memmove (x, pb2, sizeof (*pb3));
+  memmove (x, pb3, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memmove (x, (void *) &b, sizeof (&b));
+  memmove (x, (char *) &b, sizeof (&b));
+  memmove (x, &b, sizeof (&b) + 0);
+  memmove (x, &b, 0 + sizeof (&b));
+}
+
+void
+f3 (void *x, char *y, int z, X w)
+{
+  unsigned char *y1 = (unsigned char *) __builtin_alloca (z + 16);
+  char buf1[7];
+  signed char buf2[z + 32];
+  long buf3[17];
+  int *buf4[9];
+  signed char *y2 = buf2;
+  char c;
+  char *y3;
+  memset (y, 0, sizeof (y));               /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  memset (y1, 0, sizeof (y1));             /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  memset (y2, 0, sizeof (y2));             /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  memset (&c, 0, sizeof (&c));             /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  memset (w, 0, sizeof w);                 /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+
+  memcpy (y, x, sizeof (y));               /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  memcpy (y1, x, sizeof (y1));             /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  memcpy (y2, x, sizeof (y2));             /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  memcpy (&c, x, sizeof (&c));             /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  memcpy (w, x, sizeof w);                 /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+
+  memcpy (x, y, sizeof (y));               /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  memcpy (x, y1, sizeof (y1));             /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  memcpy (x, y2, sizeof (y2));             /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  memcpy (x, &c, sizeof (&c));             /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
+  memcpy (x, w, sizeof w);                 /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+
+  memmove (y, x, sizeof (y));              /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  memmove (y1, x, sizeof (y1));                    /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  memmove (y2, x, sizeof (y2));                    /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  memmove (&c, x, sizeof (&c));                    /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  memmove (w, x, sizeof w);                /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+
+  memmove (x, y, sizeof (y));              /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  memmove (x, y1, sizeof (y1));                    /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  memmove (x, y2, sizeof (y2));                    /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  memmove (x, &c, sizeof (&c));                    /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
+  memmove (x, w, sizeof w);                /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+
+  /* These are correct, no warning.  */
+  memset (y, 0, sizeof (*y));
+  memset (y1, 0, sizeof (*y2));
+  memset (buf1, 0, sizeof buf1);
+  memset (buf3, 0, sizeof (buf3));
+  memset (&buf3[0], 0, sizeof (buf3));
+  memset (&buf4[0], 0, sizeof (buf4));
+  memset (w, 0, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memset ((void *) y, 0, sizeof (y));
+  memset ((char *) y1, 0, sizeof (y2));
+  memset (y, 0, sizeof (y) + 0);
+  memset (y1, 0, 0 + sizeof (y2));
+  memset ((void *) &c, 0, sizeof (&c));
+  memset ((signed char *) &c, 0, sizeof (&c));
+  memset (&c, 0, sizeof (&c) + 0);
+  memset (&c, 0, 0 + sizeof (&c));
+
+  /* These are correct, no warning.  */
+  memcpy (y, x, sizeof (*y));
+  memcpy (y1, x, sizeof (*y2));
+  memcpy (buf1, x, sizeof buf1);
+  memcpy (buf3, x, sizeof (buf3));
+  memcpy (&buf3[0], x, sizeof (buf3));
+  memcpy (&buf4[0], x, sizeof (buf4));
+  memcpy (&y3, y, sizeof (y3));
+  memcpy ((char *) &y3, y, sizeof (y3));
+  memcpy (w, x, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memcpy ((void *) y, x, sizeof (y));
+  memcpy ((char *) y1, x, sizeof (y2));
+  memcpy (y, x, sizeof (y) + 0);
+  memcpy (y1, x, 0 + sizeof (y2));
+  memcpy ((void *) &c, x, sizeof (&c));
+  memcpy ((signed char *) &c, x, sizeof (&c));
+  memcpy (&c, x, sizeof (&c) + 0);
+  memcpy (&c, x, 0 + sizeof (&c));
+
+  /* These are correct, no warning.  */
+  memcpy (x, y, sizeof (*y));
+  memcpy (x, y1, sizeof (*y2));
+  memcpy (x, buf1, sizeof buf1);
+  memcpy (x, buf3, sizeof (buf3));
+  memcpy (x, &buf3[0], sizeof (buf3));
+  memcpy (x, &buf4[0], sizeof (buf4));
+  memcpy (y, &y3, sizeof (y3));
+  memcpy (y, (char *) &y3, sizeof (y3));
+  memcpy (x, w, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memcpy (x, (void *) y, sizeof (y));
+  memcpy (x, (char *) y1, sizeof (y2));
+  memcpy (x, y, sizeof (y) + 0);
+  memcpy (x, y1, 0 + sizeof (y2));
+  memcpy (x, (void *) &c, sizeof (&c));
+  memcpy (x, (signed char *) &c, sizeof (&c));
+  memcpy (x, &c, sizeof (&c) + 0);
+  memcpy (x, &c, 0 + sizeof (&c));
+
+  /* These are correct, no warning.  */
+  memmove (y, x, sizeof (*y));
+  memmove (y1, x, sizeof (*y2));
+  memmove (buf1, x, sizeof buf1);
+  memmove (buf3, x, sizeof (buf3));
+  memmove (&buf3[0], x, sizeof (buf3));
+  memmove (&buf4[0], x, sizeof (buf4));
+  memmove (&y3, y, sizeof (y3));
+  memmove ((char *) &y3, y, sizeof (y3));
+  memmove (w, x, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memmove ((void *) y, x, sizeof (y));
+  memmove ((char *) y1, x, sizeof (y2));
+  memmove (y, x, sizeof (y) + 0);
+  memmove (y1, x, 0 + sizeof (y2));
+  memmove ((void *) &c, x, sizeof (&c));
+  memmove ((signed char *) &c, x, sizeof (&c));
+  memmove (&c, x, sizeof (&c) + 0);
+  memmove (&c, x, 0 + sizeof (&c));
+
+  /* These are correct, no warning.  */
+  memmove (x, y, sizeof (*y));
+  memmove (x, y1, sizeof (*y2));
+  memmove (x, buf1, sizeof buf1);
+  memmove (x, buf3, sizeof (buf3));
+  memmove (x, &buf3[0], sizeof (buf3));
+  memmove (x, &buf4[0], sizeof (buf4));
+  memmove (y, &y3, sizeof (y3));
+  memmove (y, (char *) &y3, sizeof (y3));
+  memmove (x, w, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  memmove (x, (void *) y, sizeof (y));
+  memmove (x, (char *) y1, sizeof (y2));
+  memmove (x, y, sizeof (y) + 0);
+  memmove (x, y1, 0 + sizeof (y2));
+  memmove (x, (void *) &c, sizeof (&c));
+  memmove (x, (signed char *) &c, sizeof (&c));
+  memmove (x, &c, sizeof (&c) + 0);
+  memmove (x, &c, 0 + sizeof (&c));
+}
+
+void
+f4 (char *x, char **y, int z, char w[64])
+{
+  const char *s1 = "foobarbaz";
+  const char *s2 = "abcde12345678";
+  strncpy (x, s1, sizeof (s1));                    /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  strncat (x, s2, sizeof (s2));                    /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  stpncpy (x, s1, sizeof (s1));                    /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+
+  strncpy (w, s1, sizeof (w));             /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  strncat (w, s2, sizeof (w));             /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  stpncpy (w, s1, sizeof (w));             /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+
+  /* These are correct, no warning.  */
+  const char s3[] = "foobarbaz";
+  const char s4[] = "abcde12345678";
+  strncpy (x, s3, sizeof (s3));
+  strncat (x, s4, sizeof (s4));
+  stpncpy (x, s3, sizeof (s3));
+}
+
+/* { dg-prune-output "\[\n\r\]*will always overflow\[\n\r\]*" } */
index c57096cc063dde1806dd3f10eb440fbe8761b1a6..6cb39809d6ce5c4e74c8f9d5c74eaa2bb2128a53 100644 (file)
@@ -14,6 +14,7 @@ extern void *memmove (void *__restrict, const void *__restrict, size_t);
 extern int memcmp (const void *, const void *, size_t);
 extern char *strncpy (char *__restrict, const char *__restrict, size_t);
 extern char *strncat (char *__restrict, const char *__restrict, size_t);
+extern char *stpncpy (char *__restrict, const char *__restrict, size_t);
 extern char *strndup (const char *, size_t);
 extern int strncmp (const char *, const char *, size_t);
 extern int strncasecmp (const char *, const char *, size_t);
@@ -56,6 +57,13 @@ strncat (char *dest, const char *src, size_t len)
 {
   return __builtin___strncat_chk (dest, src, len, bos (dest));
 }
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+stpncpy (char *__restrict dest, const char *__restrict src, size_t len)
+{
+  return __builtin___stpncpy_chk (dest, src, len, bos (dest));
+}
 #endif
 
 }
@@ -127,23 +135,23 @@ f1 (void *x, int z)
   memmove (x, pa3, sizeof (PA));           // { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
   memmove (x, pa4, sizeof (__typeof (pa4)));// { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
 
-  z += memcmp (&a, x, sizeof (&a));        // { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" }
-  z += memcmp (pa1, x, sizeof (pa1));      // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pa2, x, sizeof pa2);        // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pa3, x, sizeof (pa3));      // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pa4, x, sizeof pa4);        // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pa1, x, sizeof (struct A *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (pa2, x, sizeof (PTA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (pa3, x, sizeof (PA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" }
-
-  z += memcmp (x, &a, sizeof (&a));        // { dg-warning "call is the same expression as the source; did you mean to remove the addressof" }
-  z += memcmp (x, pa1, sizeof (pa1));      // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pa2, sizeof pa2);        // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pa3, sizeof (pa3));      // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pa4, sizeof pa4);        // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pa1, sizeof (struct A *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (x, pa2, sizeof (PTA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (x, pa3, sizeof (PA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (&a, x, sizeof (&a));        // { dg-warning "call is the same expression as the first source; did you mean to remove the addressof" }
+  z += memcmp (pa1, x, sizeof (pa1));      // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pa2, x, sizeof pa2);        // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pa3, x, sizeof (pa3));      // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pa4, x, sizeof pa4);        // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pa1, x, sizeof (struct A *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (pa2, x, sizeof (PTA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (pa3, x, sizeof (PA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" }
+
+  z += memcmp (x, &a, sizeof (&a));        // { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" }
+  z += memcmp (x, pa1, sizeof (pa1));      // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pa2, sizeof pa2);        // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pa3, sizeof (pa3));      // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pa4, sizeof pa4);        // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pa1, sizeof (struct A *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (x, pa2, sizeof (PTA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (x, pa3, sizeof (PA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" }
 
   // These are correct, no warning. 
   memset (&a, 0, sizeof a);
@@ -331,23 +339,23 @@ f2 (void *x, int z)
   memmove (x, pb3, sizeof (PB));           // { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
   memmove (x, pb4, sizeof (__typeof (pb4)));// { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
 
-  z += memcmp (&b, x, sizeof (&b));        // { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" }
-  z += memcmp (pb1, x, sizeof (pb1));      // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pb2, x, sizeof pb2);        // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pb3, x, sizeof (pb3));      // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pb4, x, sizeof pb4);        // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pb1, x, sizeof (struct B *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (pb2, x, sizeof (PTB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (pb3, x, sizeof (PB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" }
-
-  z += memcmp (x, &b, sizeof (&b));        // { dg-warning "call is the same expression as the source; did you mean to remove the addressof" }
-  z += memcmp (x, pb1, sizeof (pb1));      // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pb2, sizeof pb2);        // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pb3, sizeof (pb3));      // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pb4, sizeof pb4);        // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pb1, sizeof (struct B *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (x, pb2, sizeof (PTB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (x, pb3, sizeof (PB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (&b, x, sizeof (&b));        // { dg-warning "call is the same expression as the first source; did you mean to remove the addressof" }
+  z += memcmp (pb1, x, sizeof (pb1));      // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pb2, x, sizeof pb2);        // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pb3, x, sizeof (pb3));      // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pb4, x, sizeof pb4);        // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pb1, x, sizeof (struct B *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (pb2, x, sizeof (PTB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (pb3, x, sizeof (PB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" }
+
+  z += memcmp (x, &b, sizeof (&b));        // { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" }
+  z += memcmp (x, pb1, sizeof (pb1));      // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pb2, sizeof pb2);        // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pb3, sizeof (pb3));      // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pb4, sizeof pb4);        // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pb1, sizeof (struct B *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (x, pb2, sizeof (PTB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (x, pb3, sizeof (PB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" }
 
   // These are correct, no warning. 
   memset (&b, 0, sizeof b);
@@ -519,17 +527,17 @@ f3 (void *x, char *y, int z, X w)
   memmove (x, &c, sizeof (&c));                    // { dg-warning "call is the same expression as the source; did you mean to remove the addressof" }
   memmove (x, w, sizeof w);                // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
 
-  z += memcmp (y, x, sizeof (y));          // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
-  z += memcmp (y1, x, sizeof (y1));        // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
-  z += memcmp (y2, x, sizeof (y2));        // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
-  z += memcmp (&c, x, sizeof (&c));        // { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" }
-  z += memcmp (w, x, sizeof w);                    // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
+  z += memcmp (y, x, sizeof (y));          // { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" }
+  z += memcmp (y1, x, sizeof (y1));        // { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" }
+  z += memcmp (y2, x, sizeof (y2));        // { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" }
+  z += memcmp (&c, x, sizeof (&c));        // { dg-warning "call is the same expression as the first source; did you mean to remove the addressof" }
+  z += memcmp (w, x, sizeof w);                    // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
 
-  z += memcmp (x, y, sizeof (y));          // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
-  z += memcmp (x, y1, sizeof (y1));        // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
-  z += memcmp (x, y2, sizeof (y2));        // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
-  z += memcmp (x, &c, sizeof (&c));        // { dg-warning "call is the same expression as the source; did you mean to remove the addressof" }
-  z += memcmp (x, w, sizeof w);                    // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
+  z += memcmp (x, y, sizeof (y));          // { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" }
+  z += memcmp (x, y1, sizeof (y1));        // { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" }
+  z += memcmp (x, y2, sizeof (y2));        // { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" }
+  z += memcmp (x, &c, sizeof (&c));        // { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" }
+  z += memcmp (x, w, sizeof w);                    // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
 
   // These are correct, no warning. 
   memset (y, 0, sizeof (*y));
@@ -673,23 +681,29 @@ f3 (void *x, char *y, int z, X w)
 }
 
 int
-f4 (char *x, char **y, int z)
+f4 (char *x, char **y, int z, char w[64])
 {
   const char *s1 = "foobarbaz";
   const char *s2 = "abcde12345678";
   strncpy (x, s1, sizeof (s1));                    // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
   strncat (x, s2, sizeof (s2));                    // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
+  stpncpy (x, s1, sizeof (s1));                    // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
   y[0] = strndup (s1, sizeof (s1));        // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
-  z += strncmp (s1, s2, sizeof (s1));      // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
-  z += strncmp (s1, s2, sizeof (s2));      // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
-  z += strncasecmp (s1, s2, sizeof (s1));   // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
-  z += strncasecmp (s1, s2, sizeof (s2));   // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
+  z += strncmp (s1, s2, sizeof (s1));      // { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" }
+  z += strncmp (s1, s2, sizeof (s2));      // { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" }
+  z += strncasecmp (s1, s2, sizeof (s1));   // { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" }
+  z += strncasecmp (s1, s2, sizeof (s2));   // { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" }
+
+  strncpy (w, s1, sizeof (w));             // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
+  strncat (w, s2, sizeof (w));             // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
+  stpncpy (w, s1, sizeof (w));             // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
 
   // These are correct, no warning. 
   const char s3[] = "foobarbaz";
   const char s4[] = "abcde12345678";
   strncpy (x, s3, sizeof (s3));
   strncat (x, s4, sizeof (s4));
+  stpncpy (x, s3, sizeof (s3));
   y[1] = strndup (s3, sizeof (s3));
   z += strncmp (s3, s4, sizeof (s3));
   z += strncmp (s3, s4, sizeof (s4));
index d5a29d8f582f0686779916dd2ce07e85f02693be..9e2805d2b7466369ad571cb7a1fd549338571d87 100644 (file)
@@ -14,6 +14,7 @@ extern void *memmove (void *__restrict, const void *__restrict, size_t);
 extern int memcmp (const void *, const void *, size_t);
 extern char *strncpy (char *__restrict, const char *__restrict, size_t);
 extern char *strncat (char *__restrict, const char *__restrict, size_t);
+extern char *stpncpy (char *__restrict, const char *__restrict, size_t);
 extern char *strndup (const char *, size_t);
 extern int strncmp (const char *, const char *, size_t);
 extern int strncasecmp (const char *, const char *, size_t);
@@ -56,6 +57,13 @@ strncat (char *dest, const char *src, size_t len)
 {
   return __builtin___strncat_chk (dest, src, len, bos (dest));
 }
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+stpncpy (char *__restrict dest, const char *__restrict src, size_t len)
+{
+  return __builtin___stpncpy_chk (dest, src, len, bos (dest));
+}
 #endif
 
 }
@@ -128,23 +136,23 @@ f1 (void *x, int z)
   memmove (x, pa3, sizeof (PA));           // { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
   memmove (x, pa4, sizeof (__typeof (pa4)));// { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
 
-  z += memcmp (&a, x, sizeof (&a));        // { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" }
-  z += memcmp (pa1, x, sizeof (pa1));      // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pa2, x, sizeof pa2);        // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pa3, x, sizeof (pa3));      // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pa4, x, sizeof pa4);        // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pa1, x, sizeof (struct A *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (pa2, x, sizeof (PTA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (pa3, x, sizeof (PA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" }
-
-  z += memcmp (x, &a, sizeof (&a));        // { dg-warning "call is the same expression as the source; did you mean to remove the addressof" }
-  z += memcmp (x, pa1, sizeof (pa1));      // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pa2, sizeof pa2);        // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pa3, sizeof (pa3));      // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pa4, sizeof pa4);        // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pa1, sizeof (struct A *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (x, pa2, sizeof (PTA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (x, pa3, sizeof (PA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (&a, x, sizeof (&a));        // { dg-warning "call is the same expression as the first source; did you mean to remove the addressof" }
+  z += memcmp (pa1, x, sizeof (pa1));      // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pa2, x, sizeof pa2);        // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pa3, x, sizeof (pa3));      // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pa4, x, sizeof pa4);        // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pa1, x, sizeof (struct A *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (pa2, x, sizeof (PTA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (pa3, x, sizeof (PA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" }
+
+  z += memcmp (x, &a, sizeof (&a));        // { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" }
+  z += memcmp (x, pa1, sizeof (pa1));      // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pa2, sizeof pa2);        // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pa3, sizeof (pa3));      // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pa4, sizeof pa4);        // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pa1, sizeof (struct A *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (x, pa2, sizeof (PTA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (x, pa3, sizeof (PA));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" }
 
   // These are correct, no warning. 
   memset (&a, 0, sizeof a);
@@ -333,23 +341,23 @@ f2 (void *x, int z)
   memmove (x, pb3, sizeof (PB));           // { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
   memmove (x, pb4, sizeof (__typeof (pb4)));// { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
 
-  z += memcmp (&b, x, sizeof (&b));        // { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" }
-  z += memcmp (pb1, x, sizeof (pb1));      // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pb2, x, sizeof pb2);        // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pb3, x, sizeof (pb3));      // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pb4, x, sizeof pb4);        // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
-  z += memcmp (pb1, x, sizeof (struct B *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (pb2, x, sizeof (PTB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (pb3, x, sizeof (PB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" }
-
-  z += memcmp (x, &b, sizeof (&b));        // { dg-warning "call is the same expression as the source; did you mean to remove the addressof" }
-  z += memcmp (x, pb1, sizeof (pb1));      // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pb2, sizeof pb2);        // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pb3, sizeof (pb3));      // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pb4, sizeof pb4);        // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
-  z += memcmp (x, pb1, sizeof (struct B *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (x, pb2, sizeof (PTB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
-  z += memcmp (x, pb3, sizeof (PB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (&b, x, sizeof (&b));        // { dg-warning "call is the same expression as the first source; did you mean to remove the addressof" }
+  z += memcmp (pb1, x, sizeof (pb1));      // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pb2, x, sizeof pb2);        // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pb3, x, sizeof (pb3));      // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pb4, x, sizeof pb4);        // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
+  z += memcmp (pb1, x, sizeof (struct B *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (pb2, x, sizeof (PTB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (pb3, x, sizeof (PB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" }
+
+  z += memcmp (x, &b, sizeof (&b));        // { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" }
+  z += memcmp (x, pb1, sizeof (pb1));      // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pb2, sizeof pb2);        // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pb3, sizeof (pb3));      // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pb4, sizeof pb4);        // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
+  z += memcmp (x, pb1, sizeof (struct B *));// { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (x, pb2, sizeof (PTB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" }
+  z += memcmp (x, pb3, sizeof (PB));       // { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" }
 
   // These are correct, no warning. 
   memset (&b, 0, sizeof b);
@@ -522,17 +530,17 @@ f3 (void *x, char *y, int z, X w)
   memmove (x, &c, sizeof (&c));                    // { dg-warning "call is the same expression as the source; did you mean to remove the addressof" }
   memmove (x, w, sizeof w);                // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
 
-  z += memcmp (y, x, sizeof (y));          // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
-  z += memcmp (y1, x, sizeof (y1));        // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
-  z += memcmp (y2, x, sizeof (y2));        // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
-  z += memcmp (&c, x, sizeof (&c));        // { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" }
-  z += memcmp (w, x, sizeof w);                    // { dg-warning "call is the same expression as the destination; did you mean to dereference it" }
+  z += memcmp (y, x, sizeof (y));          // { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" }
+  z += memcmp (y1, x, sizeof (y1));        // { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" }
+  z += memcmp (y2, x, sizeof (y2));        // { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" }
+  z += memcmp (&c, x, sizeof (&c));        // { dg-warning "call is the same expression as the first source; did you mean to remove the addressof" }
+  z += memcmp (w, x, sizeof w);                    // { dg-warning "call is the same expression as the first source; did you mean to dereference it" }
 
-  z += memcmp (x, y, sizeof (y));          // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
-  z += memcmp (x, y1, sizeof (y1));        // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
-  z += memcmp (x, y2, sizeof (y2));        // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
-  z += memcmp (x, &c, sizeof (&c));        // { dg-warning "call is the same expression as the source; did you mean to remove the addressof" }
-  z += memcmp (x, w, sizeof w);                    // { dg-warning "call is the same expression as the source; did you mean to dereference it" }
+  z += memcmp (x, y, sizeof (y));          // { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" }
+  z += memcmp (x, y1, sizeof (y1));        // { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" }
+  z += memcmp (x, y2, sizeof (y2));        // { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" }
+  z += memcmp (x, &c, sizeof (&c));        // { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" }
+  z += memcmp (x, w, sizeof w);                    // { dg-warning "call is the same expression as the second source; did you mean to dereference it" }
 
   // These are correct, no warning. 
   memset (y, 0, sizeof (*y));
@@ -677,23 +685,29 @@ f3 (void *x, char *y, int z, X w)
 
 template <int N>
 int
-f4 (char *x, char **y, int z)
+f4 (char *x, char **y, int z, char w[64])
 {
   const char *s1 = "foobarbaz";
   const char *s2 = "abcde12345678";
   strncpy (x, s1, sizeof (s1));                    // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
   strncat (x, s2, sizeof (s2));                    // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
+  stpncpy (x, s1, sizeof (s1));                    // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
   y[0] = strndup (s1, sizeof (s1));        // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
-  z += strncmp (s1, s2, sizeof (s1));      // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
-  z += strncmp (s1, s2, sizeof (s2));      // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
-  z += strncasecmp (s1, s2, sizeof (s1));   // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
-  z += strncasecmp (s1, s2, sizeof (s2));   // { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" }
+  z += strncmp (s1, s2, sizeof (s1));      // { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" }
+  z += strncmp (s1, s2, sizeof (s2));      // { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" }
+  z += strncasecmp (s1, s2, sizeof (s1));   // { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" }
+  z += strncasecmp (s1, s2, sizeof (s2));   // { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" }
+
+  strncpy (w, s1, sizeof (w));             // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
+  strncat (w, s2, sizeof (w));             // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
+  stpncpy (w, s1, sizeof (w));             // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" }
 
   // These are correct, no warning. 
   const char s3[] = "foobarbaz";
   const char s4[] = "abcde12345678";
   strncpy (x, s3, sizeof (s3));
   strncat (x, s4, sizeof (s4));
+  stpncpy (x, s3, sizeof (s3));
   y[1] = strndup (s3, sizeof (s3));
   z += strncmp (s3, s4, sizeof (s3));
   z += strncmp (s3, s4, sizeof (s4));
@@ -704,12 +718,12 @@ f4 (char *x, char **y, int z)
 }
 
 int
-f (void *x, char *y, int z, X w, char **u)
+f (void *x, char *y, int z, X w, char **u, char v[64])
 {
   z += f1<0> (x, z);
   z += f2<0> (x, z);
   z += f3<0> (x, y, z, w);
-  z += f4<0> (y, u, z);
+  z += f4<0> (y, u, z, v);
   return z;
 }
 
diff --git a/gcc/testsuite/gcc.dg/Wsizeof-pointer-memaccess1.c b/gcc/testsuite/gcc.dg/Wsizeof-pointer-memaccess1.c
new file mode 100644 (file)
index 0000000..b683be7
--- /dev/null
@@ -0,0 +1,456 @@
+/* Test -Wsizeof-pointer-memaccess warnings.  */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+extern void bzero (void *, size_t);
+extern void bcopy (void *, const void *, size_t);
+extern int bcmp (const void *, const void *, size_t);
+
+struct A { short a, b; int c, d; long e, f; };
+typedef struct A TA;
+typedef struct A *PA;
+typedef TA *PTA;
+struct B {};
+typedef struct B TB;
+typedef struct B *PB;
+typedef TB *PTB;
+typedef int X[3][3][3];
+
+int
+f1 (void *x, int z)
+{
+  struct A a, *pa1 = &a;
+  TA *pa2 = &a;
+  PA pa3 = &a;
+  PTA pa4 = &a;
+  bzero (&a, sizeof (&a));                 /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  bzero (pa1, sizeof (pa1));               /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bzero (pa2, sizeof pa2);                 /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bzero (pa3, sizeof (pa3));               /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bzero (pa4, sizeof pa4);                 /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bzero (pa1, sizeof (struct A *));        /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  bzero (pa2, sizeof (PTA));               /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  bzero (pa3, sizeof (PA));                /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  bzero (pa4, sizeof (__typeof (pa4)));            /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+
+  bcopy (x, &a, sizeof (&a));              /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  bcopy (x, pa1, sizeof (pa1));                    /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bcopy (x, pa2, sizeof pa2);              /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bcopy (x, pa3, sizeof (pa3));                    /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bcopy (x, pa4, sizeof pa4);              /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bcopy (x, pa1, sizeof (struct A *));     /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  bcopy (x, pa2, sizeof (PTA));                    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  bcopy (x, pa3, sizeof (PA));             /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  bcopy (x, pa4, sizeof (__typeof (pa4)));  /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+
+  bcopy (&a, x, sizeof (&a));              /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
+  bcopy (pa1, x, sizeof (pa1));                    /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  bcopy (pa2, x, sizeof pa2);              /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  bcopy (pa3, x, sizeof (pa3));                    /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  bcopy (pa4, x, sizeof pa4);              /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  bcopy (pa1, x, sizeof (struct A *));     /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  bcopy (pa2, x, sizeof (PTA));                    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  bcopy (pa3, x, sizeof (PA));             /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  bcopy (pa4, x, sizeof (__typeof (pa4)));  /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+
+  z += bcmp (&a, x, sizeof (&a));          /* { dg-warning "call is the same expression as the first source; did you mean to remove the addressof" } */
+  z += bcmp (pa1, x, sizeof (pa1));        /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += bcmp (pa2, x, sizeof pa2);          /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += bcmp (pa3, x, sizeof (pa3));        /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += bcmp (pa4, x, sizeof pa4);          /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += bcmp (pa1, x, sizeof (struct A *));  /* { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" } */
+  z += bcmp (pa2, x, sizeof (PTA));        /* { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" } */
+  z += bcmp (pa3, x, sizeof (PA));         /* { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" } */
+
+  z += bcmp (x, &a, sizeof (&a));          /* { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" } */
+  z += bcmp (x, pa1, sizeof (pa1));        /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += bcmp (x, pa2, sizeof pa2);          /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += bcmp (x, pa3, sizeof (pa3));        /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += bcmp (x, pa4, sizeof pa4);          /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += bcmp (x, pa1, sizeof (struct A *));  /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+  z += bcmp (x, pa2, sizeof (PTA));        /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+  z += bcmp (x, pa3, sizeof (PA));         /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+
+  /* These are correct, no warning.  */
+  bzero (&a, sizeof a);
+  bzero (&a, sizeof (a));
+  bzero (&a, sizeof (struct A));
+  bzero (&a, sizeof (const struct A));
+  bzero (&a, sizeof (volatile struct A));
+  bzero (&a, sizeof (volatile const struct A));
+  bzero (&a, sizeof (TA));
+  bzero (&a, sizeof (__typeof (*&a)));
+  bzero (pa1, sizeof (*pa1));
+  bzero (pa2, sizeof (*pa3));
+  bzero (pa3, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  bzero ((void *) &a, sizeof (&a));
+  bzero ((char *) &a, sizeof (&a));
+  bzero (&a, sizeof (&a) + 0);
+  bzero (&a, 0 + sizeof (&a));
+
+  /* These are correct, no warning.  */
+  bcopy (x, &a, sizeof a);
+  bcopy (x, &a, sizeof (a));
+  bcopy (x, &a, sizeof (struct A));
+  bcopy (x, &a, sizeof (const struct A));
+  bcopy (x, &a, sizeof (volatile struct A));
+  bcopy (x, &a, sizeof (volatile const struct A));
+  bcopy (x, &a, sizeof (TA));
+  bcopy (x, &a, sizeof (__typeof (*&a)));
+  bcopy (x, pa1, sizeof (*pa1));
+  bcopy (x, pa2, sizeof (*pa3));
+  bcopy (x, pa3, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  bcopy (x, (void *) &a, sizeof (&a));
+  bcopy (x, (char *) &a, sizeof (&a));
+  bcopy (x, &a, sizeof (&a) + 0);
+  bcopy (x, &a, 0 + sizeof (&a));
+
+  /* These are correct, no warning.  */
+  bcopy (&a, x, sizeof a);
+  bcopy (&a, x, sizeof (a));
+  bcopy (&a, x, sizeof (struct A));
+  bcopy (&a, x, sizeof (const struct A));
+  bcopy (&a, x, sizeof (volatile struct A));
+  bcopy (&a, x, sizeof (volatile const struct A));
+  bcopy (&a, x, sizeof (TA));
+  bcopy (&a, x, sizeof (__typeof (*&a)));
+  bcopy (pa1, x, sizeof (*pa1));
+  bcopy (pa2, x, sizeof (*pa3));
+  bcopy (pa3, x, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  bcopy ((void *) &a, x, sizeof (&a));
+  bcopy ((char *) &a, x, sizeof (&a));
+  bcopy (&a, x, sizeof (&a) + 0);
+  bcopy (&a, x, 0 + sizeof (&a));
+
+  /* These are correct, no warning.  */
+  z += bcmp (&a, x, sizeof a);
+  z += bcmp (&a, x, sizeof (a));
+  z += bcmp (&a, x, sizeof (struct A));
+  z += bcmp (&a, x, sizeof (const struct A));
+  z += bcmp (&a, x, sizeof (volatile struct A));
+  z += bcmp (&a, x, sizeof (volatile const struct A));
+  z += bcmp (&a, x, sizeof (TA));
+  z += bcmp (&a, x, sizeof (__typeof (*&a)));
+  z += bcmp (pa1, x, sizeof (*pa1));
+  z += bcmp (pa2, x, sizeof (*pa3));
+  z += bcmp (pa3, x, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  z += bcmp ((void *) &a, x, sizeof (&a));
+  z += bcmp ((char *) &a, x, sizeof (&a));
+  z += bcmp (&a, x, sizeof (&a) + 0);
+  z += bcmp (&a, x, 0 + sizeof (&a));
+
+  /* These are correct, no warning.  */
+  z += bcmp (x, &a, sizeof a);
+  z += bcmp (x, &a, sizeof (a));
+  z += bcmp (x, &a, sizeof (struct A));
+  z += bcmp (x, &a, sizeof (const struct A));
+  z += bcmp (x, &a, sizeof (volatile struct A));
+  z += bcmp (x, &a, sizeof (volatile const struct A));
+  z += bcmp (x, &a, sizeof (TA));
+  z += bcmp (x, &a, sizeof (__typeof (*&a)));
+  z += bcmp (x, pa1, sizeof (*pa1));
+  z += bcmp (x, pa2, sizeof (*pa3));
+  z += bcmp (x, pa3, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  z += bcmp (x, (void *) &a, sizeof (&a));
+  z += bcmp (x, (char *) &a, sizeof (&a));
+  z += bcmp (x, &a, sizeof (&a) + 0);
+  z += bcmp (x, &a, 0 + sizeof (&a));
+
+  return z;
+}
+
+int
+f2 (void *x, int z)
+{
+  struct B b, *pb1 = &b;
+  TB *pb2 = &b;
+  PB pb3 = &b;
+  PTB pb4 = &b;
+  bzero (&b, sizeof (&b));                 /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  bzero (pb1, sizeof (pb1));               /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bzero (pb2, sizeof pb2);                 /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bzero (pb3, sizeof (pb3));               /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bzero (pb4, sizeof pb4);                 /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bzero (pb1, sizeof (struct B *));        /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  bzero (pb2, sizeof (PTB));               /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  bzero (pb3, sizeof (PB));                /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  bzero (pb4, sizeof (__typeof (pb4)));            /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+
+  bcopy (x, &b, sizeof (&b));              /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  bcopy (x, pb1, sizeof (pb1));                    /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bcopy (x, pb2, sizeof pb2);              /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bcopy (x, pb3, sizeof (pb3));                    /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bcopy (x, pb4, sizeof pb4);              /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  bcopy (x, pb1, sizeof (struct B *));     /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  bcopy (x, pb2, sizeof (PTB));                    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  bcopy (x, pb3, sizeof (PB));             /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+  bcopy (x, pb4, sizeof (__typeof (pb4)));  /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
+
+  bcopy (&b, x, sizeof (&b));              /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
+  bcopy (pb1, x, sizeof (pb1));                    /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  bcopy (pb2, x, sizeof pb2);              /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  bcopy (pb3, x, sizeof (pb3));                    /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  bcopy (pb4, x, sizeof pb4);              /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  bcopy (pb1, x, sizeof (struct B *));     /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  bcopy (pb2, x, sizeof (PTB));                    /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  bcopy (pb3, x, sizeof (PB));             /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  bcopy (pb4, x, sizeof (__typeof (pb4)));  /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+
+  z += bcmp (&b, x, sizeof (&b));          /* { dg-warning "call is the same expression as the first source; did you mean to remove the addressof" } */
+  z += bcmp (pb1, x, sizeof (pb1));        /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += bcmp (pb2, x, sizeof pb2);          /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += bcmp (pb3, x, sizeof (pb3));        /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += bcmp (pb4, x, sizeof pb4);          /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += bcmp (pb1, x, sizeof (struct B *));  /* { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" } */
+  z += bcmp (pb2, x, sizeof (PTB));        /* { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" } */
+  z += bcmp (pb3, x, sizeof (PB));         /* { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" } */
+
+  z += bcmp (x, &b, sizeof (&b));          /* { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" } */
+  z += bcmp (x, pb1, sizeof (pb1));        /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += bcmp (x, pb2, sizeof pb2);          /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += bcmp (x, pb3, sizeof (pb3));        /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += bcmp (x, pb4, sizeof pb4);          /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += bcmp (x, pb1, sizeof (struct B *));  /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+  z += bcmp (x, pb2, sizeof (PTB));        /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+  z += bcmp (x, pb3, sizeof (PB));         /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+
+  /* These are correct, no warning.  */
+  bzero (&b, sizeof b);
+  bzero (&b, sizeof (b));
+  bzero (&b, sizeof (struct B));
+  bzero (&b, sizeof (const struct B));
+  bzero (&b, sizeof (volatile struct B));
+  bzero (&b, sizeof (volatile const struct B));
+  bzero (&b, sizeof (TB));
+  bzero (&b, sizeof (__typeof (*&b)));
+  bzero (pb1, sizeof (*pb1));
+  bzero (pb2, sizeof (*pb3));
+  bzero (pb3, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  bzero ((void *) &b, sizeof (&b));
+  bzero ((char *) &b, sizeof (&b));
+  bzero (&b, sizeof (&b) + 0);
+  bzero (&b, 0 + sizeof (&b));
+
+  /* These are correct, no warning.  */
+  bcopy (x, &b, sizeof b);
+  bcopy (x, &b, sizeof (b));
+  bcopy (x, &b, sizeof (struct B));
+  bcopy (x, &b, sizeof (const struct B));
+  bcopy (x, &b, sizeof (volatile struct B));
+  bcopy (x, &b, sizeof (volatile const struct B));
+  bcopy (x, &b, sizeof (TB));
+  bcopy (x, &b, sizeof (__typeof (*&b)));
+  bcopy (x, pb1, sizeof (*pb1));
+  bcopy (x, pb2, sizeof (*pb3));
+  bcopy (x, pb3, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  bcopy (x, (void *) &b, sizeof (&b));
+  bcopy (x, (char *) &b, sizeof (&b));
+  bcopy (x, &b, sizeof (&b) + 0);
+  bcopy (x, &b, 0 + sizeof (&b));
+
+  /* These are correct, no warning.  */
+  bcopy (&b, x, sizeof b);
+  bcopy (&b, x, sizeof (b));
+  bcopy (&b, x, sizeof (struct B));
+  bcopy (&b, x, sizeof (const struct B));
+  bcopy (&b, x, sizeof (volatile struct B));
+  bcopy (&b, x, sizeof (volatile const struct B));
+  bcopy (&b, x, sizeof (TB));
+  bcopy (&b, x, sizeof (__typeof (*&b)));
+  bcopy (pb1, x, sizeof (*pb1));
+  bcopy (pb2, x, sizeof (*pb3));
+  bcopy (pb3, x, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  bcopy ((void *) &b, x, sizeof (&b));
+  bcopy ((char *) &b, x, sizeof (&b));
+  bcopy (&b, x, sizeof (&b) + 0);
+  bcopy (&b, x, 0 + sizeof (&b));
+
+  /* These are correct, no warning.  */
+  z += bcmp (&b, x, sizeof b);
+  z += bcmp (&b, x, sizeof (b));
+  z += bcmp (&b, x, sizeof (struct B));
+  z += bcmp (&b, x, sizeof (const struct B));
+  z += bcmp (&b, x, sizeof (volatile struct B));
+  z += bcmp (&b, x, sizeof (volatile const struct B));
+  z += bcmp (&b, x, sizeof (TB));
+  z += bcmp (&b, x, sizeof (__typeof (*&b)));
+  z += bcmp (pb1, x, sizeof (*pb1));
+  z += bcmp (pb2, x, sizeof (*pb3));
+  z += bcmp (pb3, x, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  z += bcmp ((void *) &b, x, sizeof (&b));
+  z += bcmp ((char *) &b, x, sizeof (&b));
+  z += bcmp (&b, x, sizeof (&b) + 0);
+  z += bcmp (&b, x, 0 + sizeof (&b));
+
+  /* These are correct, no warning.  */
+  z += bcmp (x, &b, sizeof b);
+  z += bcmp (x, &b, sizeof (b));
+  z += bcmp (x, &b, sizeof (struct B));
+  z += bcmp (x, &b, sizeof (const struct B));
+  z += bcmp (x, &b, sizeof (volatile struct B));
+  z += bcmp (x, &b, sizeof (volatile const struct B));
+  z += bcmp (x, &b, sizeof (TB));
+  z += bcmp (x, &b, sizeof (__typeof (*&b)));
+  z += bcmp (x, pb1, sizeof (*pb1));
+  z += bcmp (x, pb2, sizeof (*pb3));
+  z += bcmp (x, pb3, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  z += bcmp (x, (void *) &b, sizeof (&b));
+  z += bcmp (x, (char *) &b, sizeof (&b));
+  z += bcmp (x, &b, sizeof (&b) + 0);
+  z += bcmp (x, &b, 0 + sizeof (&b));
+
+  return z;
+}
+
+int
+f3 (void *x, char *y, int z, X w)
+{
+  unsigned char *y1 = (unsigned char *) __builtin_alloca (z + 16);
+  char buf1[7];
+  signed char buf2[z + 32];
+  long buf3[17];
+  int *buf4[9];
+  signed char *y2 = buf2;
+  char c;
+  char *y3;
+  bzero (y, sizeof (y));                   /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  bzero (y1, sizeof (y1));                 /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  bzero (y2, sizeof (y2));                 /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  bzero (&c, sizeof (&c));                 /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  bzero (w, sizeof w);                     /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+
+  bcopy (x, y, sizeof (y));                /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  bcopy (x, y1, sizeof (y1));              /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  bcopy (x, y2, sizeof (y2));              /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  bcopy (x, &c, sizeof (&c));              /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
+  bcopy (x, w, sizeof w);                  /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+
+  bcopy (y, x, sizeof (y));                /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  bcopy (y1, x, sizeof (y1));              /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  bcopy (y2, x, sizeof (y2));              /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  bcopy (&c, x, sizeof (&c));              /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
+  bcopy (w, x, sizeof w);                  /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+
+  z += bcmp (y, x, sizeof (y));                    /* { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" } */
+  z += bcmp (y1, x, sizeof (y1));          /* { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" } */
+  z += bcmp (y2, x, sizeof (y2));          /* { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" } */
+  z += bcmp (&c, x, sizeof (&c));          /* { dg-warning "call is the same expression as the first source; did you mean to remove the addressof" } */
+  z += bcmp (w, x, sizeof w);              /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+
+  z += bcmp (x, y, sizeof (y));                    /* { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" } */
+  z += bcmp (x, y1, sizeof (y1));          /* { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" } */
+  z += bcmp (x, y2, sizeof (y2));          /* { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" } */
+  z += bcmp (x, &c, sizeof (&c));          /* { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" } */
+  z += bcmp (x, w, sizeof w);              /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+
+  /* These are correct, no warning.  */
+  bzero (y, sizeof (*y));
+  bzero (y1, sizeof (*y2));
+  bzero (buf1, sizeof buf1);
+  bzero (buf3, sizeof (buf3));
+  bzero (&buf3[0], sizeof (buf3));
+  bzero (&buf4[0], sizeof (buf4));
+  bzero (w, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  bzero ((void *) y, sizeof (y));
+  bzero ((char *) y1, sizeof (y2));
+  bzero (y, sizeof (y) + 0);
+  bzero (y1, 0 + sizeof (y2));
+  bzero ((void *) &c, sizeof (&c));
+  bzero ((signed char *) &c, sizeof (&c));
+  bzero (&c, sizeof (&c) + 0);
+  bzero (&c, 0 + sizeof (&c));
+
+  /* These are correct, no warning.  */
+  bcopy (x, y, sizeof (*y));
+  bcopy (x, y1, sizeof (*y2));
+  bcopy (x, buf1, sizeof buf1);
+  bcopy (x, buf3, sizeof (buf3));
+  bcopy (x, &buf3[0], sizeof (buf3));
+  bcopy (x, &buf4[0], sizeof (buf4));
+  bcopy (y, &y3, sizeof (y3));
+  bcopy (y, (char *) &y3, sizeof (y3));
+  bcopy (x, w, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  bcopy (x, (void *) y, sizeof (y));
+  bcopy (x, (char *) y1, sizeof (y2));
+  bcopy (x, y, sizeof (y) + 0);
+  bcopy (x, y1, 0 + sizeof (y2));
+  bcopy (x, (void *) &c, sizeof (&c));
+  bcopy (x, (signed char *) &c, sizeof (&c));
+  bcopy (x, &c, sizeof (&c) + 0);
+  bcopy (x, &c, 0 + sizeof (&c));
+
+  /* These are correct, no warning.  */
+  bcopy (y, x, sizeof (*y));
+  bcopy (y1, x, sizeof (*y2));
+  bcopy (buf1, x, sizeof buf1);
+  bcopy (buf3, x, sizeof (buf3));
+  bcopy (&buf3[0], x, sizeof (buf3));
+  bcopy (&buf4[0], x, sizeof (buf4));
+  bcopy (&y3, y, sizeof (y3));
+  bcopy ((char *) &y3, y, sizeof (y3));
+  bcopy (w, x, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  bcopy ((void *) y, x, sizeof (y));
+  bcopy ((char *) y1, x, sizeof (y2));
+  bcopy (y, x, sizeof (y) + 0);
+  bcopy (y1, x, 0 + sizeof (y2));
+  bcopy ((void *) &c, x, sizeof (&c));
+  bcopy ((signed char *) &c, x, sizeof (&c));
+  bcopy (&c, x, sizeof (&c) + 0);
+  bcopy (&c, x, 0 + sizeof (&c));
+
+  /* These are correct, no warning.  */
+  z += bcmp (y, x, sizeof (*y));
+  z += bcmp (y1, x, sizeof (*y2));
+  z += bcmp (buf1, x, sizeof buf1);
+  z += bcmp (buf3, x, sizeof (buf3));
+  z += bcmp (&buf3[0], x, sizeof (buf3));
+  z += bcmp (&buf4[0], x, sizeof (buf4));
+  z += bcmp (&y3, y, sizeof (y3));
+  z += bcmp ((char *) &y3, y, sizeof (y3));
+  z += bcmp (w, x, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  z += bcmp ((void *) y, x, sizeof (y));
+  z += bcmp ((char *) y1, x, sizeof (y2));
+  z += bcmp (y, x, sizeof (y) + 0);
+  z += bcmp (y1, x, 0 + sizeof (y2));
+  z += bcmp ((void *) &c, x, sizeof (&c));
+  z += bcmp ((signed char *) &c, x, sizeof (&c));
+  z += bcmp (&c, x, sizeof (&c) + 0);
+  z += bcmp (&c, x, 0 + sizeof (&c));
+
+  /* These are correct, no warning.  */
+  z += bcmp (x, y, sizeof (*y));
+  z += bcmp (x, y1, sizeof (*y2));
+  z += bcmp (x, buf1, sizeof buf1);
+  z += bcmp (x, buf3, sizeof (buf3));
+  z += bcmp (x, &buf3[0], sizeof (buf3));
+  z += bcmp (x, &buf4[0], sizeof (buf4));
+  z += bcmp (y, &y3, sizeof (y3));
+  z += bcmp (y, (char *) &y3, sizeof (y3));
+  z += bcmp (x, w, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  z += bcmp (x, (void *) y, sizeof (y));
+  z += bcmp (x, (char *) y1, sizeof (y2));
+  z += bcmp (x, y, sizeof (y) + 0);
+  z += bcmp (x, y1, 0 + sizeof (y2));
+  z += bcmp (x, (void *) &c, sizeof (&c));
+  z += bcmp (x, (signed char *) &c, sizeof (&c));
+  z += bcmp (x, &c, sizeof (&c) + 0);
+  z += bcmp (x, &c, 0 + sizeof (&c));
+
+  return z;
+}
index 3897518de63814078b02143a30a4c4981e2f4a73..8d01bc616a77bc0a012227cb879c777558bb7995 100644 (file)
@@ -12,6 +12,7 @@ extern void *memmove (void *__restrict, const void *__restrict, size_t);
 extern int memcmp (const void *, const void *, size_t);
 extern char *strncpy (char *__restrict, const char *__restrict, size_t);
 extern char *strncat (char *__restrict, const char *__restrict, size_t);
+extern char *stpncpy (char *__restrict, const char *__restrict, size_t);
 extern char *strndup (const char *, size_t);
 extern int strncmp (const char *, const char *, size_t);
 extern int strncasecmp (const char *, const char *, size_t);
@@ -54,6 +55,13 @@ strncat (char *dest, const char *src, size_t len)
 {
   return __builtin___strncat_chk (dest, src, len, bos (dest));
 }
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+stpncpy (char *__restrict dest, const char *__restrict src, size_t len)
+{
+  return __builtin___stpncpy_chk (dest, src, len, bos (dest));
+}
 #endif
 
 struct A { short a, b; int c, d; long e, f; };
@@ -123,23 +131,23 @@ f1 (void *x, int z)
   memmove (x, pa3, sizeof (PA));           /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
   memmove (x, pa4, sizeof (__typeof (pa4)));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
 
-  z += memcmp (&a, x, sizeof (&a));        /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
-  z += memcmp (pa1, x, sizeof (pa1));      /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
-  z += memcmp (pa2, x, sizeof pa2);        /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
-  z += memcmp (pa3, x, sizeof (pa3));      /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
-  z += memcmp (pa4, x, sizeof pa4);        /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
-  z += memcmp (pa1, x, sizeof (struct A *));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
-  z += memcmp (pa2, x, sizeof (PTA));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
-  z += memcmp (pa3, x, sizeof (PA));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
-
-  z += memcmp (x, &a, sizeof (&a));        /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
-  z += memcmp (x, pa1, sizeof (pa1));      /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
-  z += memcmp (x, pa2, sizeof pa2);        /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
-  z += memcmp (x, pa3, sizeof (pa3));      /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
-  z += memcmp (x, pa4, sizeof pa4);        /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
-  z += memcmp (x, pa1, sizeof (struct A *));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
-  z += memcmp (x, pa2, sizeof (PTA));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
-  z += memcmp (x, pa3, sizeof (PA));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  z += memcmp (&a, x, sizeof (&a));        /* { dg-warning "call is the same expression as the first source; did you mean to remove the addressof" } */
+  z += memcmp (pa1, x, sizeof (pa1));      /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += memcmp (pa2, x, sizeof pa2);        /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += memcmp (pa3, x, sizeof (pa3));      /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += memcmp (pa4, x, sizeof pa4);        /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += memcmp (pa1, x, sizeof (struct A *));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" } */
+  z += memcmp (pa2, x, sizeof (PTA));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" } */
+  z += memcmp (pa3, x, sizeof (PA));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" } */
+
+  z += memcmp (x, &a, sizeof (&a));        /* { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" } */
+  z += memcmp (x, pa1, sizeof (pa1));      /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += memcmp (x, pa2, sizeof pa2);        /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += memcmp (x, pa3, sizeof (pa3));      /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += memcmp (x, pa4, sizeof pa4);        /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += memcmp (x, pa1, sizeof (struct A *));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+  z += memcmp (x, pa2, sizeof (PTA));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+  z += memcmp (x, pa3, sizeof (PA));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
 
   /* These are correct, no warning.  */
   memset (&a, 0, sizeof a);
@@ -327,23 +335,23 @@ f2 (void *x, int z)
   memmove (x, pb3, sizeof (PB));           /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
   memmove (x, pb4, sizeof (__typeof (pb4)));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
 
-  z += memcmp (&b, x, sizeof (&b));        /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
-  z += memcmp (pb1, x, sizeof (pb1));      /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
-  z += memcmp (pb2, x, sizeof pb2);        /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
-  z += memcmp (pb3, x, sizeof (pb3));      /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
-  z += memcmp (pb4, x, sizeof pb4);        /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
-  z += memcmp (pb1, x, sizeof (struct B *));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
-  z += memcmp (pb2, x, sizeof (PTB));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
-  z += memcmp (pb3, x, sizeof (PB));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the destination; expected \[^\n\r\]* or an explicit length" } */
-
-  z += memcmp (x, &b, sizeof (&b));        /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
-  z += memcmp (x, pb1, sizeof (pb1));      /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
-  z += memcmp (x, pb2, sizeof pb2);        /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
-  z += memcmp (x, pb3, sizeof (pb3));      /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
-  z += memcmp (x, pb4, sizeof pb4);        /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
-  z += memcmp (x, pb1, sizeof (struct B *));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
-  z += memcmp (x, pb2, sizeof (PTB));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
-  z += memcmp (x, pb3, sizeof (PB));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the source; expected \[^\n\r\]* or an explicit length" } */
+  z += memcmp (&b, x, sizeof (&b));        /* { dg-warning "call is the same expression as the first source; did you mean to remove the addressof" } */
+  z += memcmp (pb1, x, sizeof (pb1));      /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += memcmp (pb2, x, sizeof pb2);        /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += memcmp (pb3, x, sizeof (pb3));      /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += memcmp (pb4, x, sizeof pb4);        /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
+  z += memcmp (pb1, x, sizeof (struct B *));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" } */
+  z += memcmp (pb2, x, sizeof (PTB));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" } */
+  z += memcmp (pb3, x, sizeof (PB));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the first source; expected \[^\n\r\]* or an explicit length" } */
+
+  z += memcmp (x, &b, sizeof (&b));        /* { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" } */
+  z += memcmp (x, pb1, sizeof (pb1));      /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += memcmp (x, pb2, sizeof pb2);        /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += memcmp (x, pb3, sizeof (pb3));      /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += memcmp (x, pb4, sizeof pb4);        /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
+  z += memcmp (x, pb1, sizeof (struct B *));/* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+  z += memcmp (x, pb2, sizeof (PTB));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
+  z += memcmp (x, pb3, sizeof (PB));       /* { dg-warning "call is the same pointer type \[^\n\r\]* as the second source; expected \[^\n\r\]* or an explicit length" } */
 
   /* These are correct, no warning.  */
   memset (&b, 0, sizeof b);
@@ -515,17 +523,17 @@ f3 (void *x, char *y, int z, X w)
   memmove (x, &c, sizeof (&c));                    /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
   memmove (x, w, sizeof w);                /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
 
-  z += memcmp (y, x, sizeof (y));          /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
-  z += memcmp (y1, x, sizeof (y1));        /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
-  z += memcmp (y2, x, sizeof (y2));        /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
-  z += memcmp (&c, x, sizeof (&c));        /* { dg-warning "call is the same expression as the destination; did you mean to remove the addressof" } */
-  z += memcmp (w, x, sizeof w);                    /* { dg-warning "call is the same expression as the destination; did you mean to dereference it" } */
+  z += memcmp (y, x, sizeof (y));          /* { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" } */
+  z += memcmp (y1, x, sizeof (y1));        /* { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" } */
+  z += memcmp (y2, x, sizeof (y2));        /* { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" } */
+  z += memcmp (&c, x, sizeof (&c));        /* { dg-warning "call is the same expression as the first source; did you mean to remove the addressof" } */
+  z += memcmp (w, x, sizeof w);                    /* { dg-warning "call is the same expression as the first source; did you mean to dereference it" } */
 
-  z += memcmp (x, y, sizeof (y));          /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
-  z += memcmp (x, y1, sizeof (y1));        /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
-  z += memcmp (x, y2, sizeof (y2));        /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
-  z += memcmp (x, &c, sizeof (&c));        /* { dg-warning "call is the same expression as the source; did you mean to remove the addressof" } */
-  z += memcmp (x, w, sizeof w);                    /* { dg-warning "call is the same expression as the source; did you mean to dereference it" } */
+  z += memcmp (x, y, sizeof (y));          /* { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" } */
+  z += memcmp (x, y1, sizeof (y1));        /* { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" } */
+  z += memcmp (x, y2, sizeof (y2));        /* { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" } */
+  z += memcmp (x, &c, sizeof (&c));        /* { dg-warning "call is the same expression as the second source; did you mean to remove the addressof" } */
+  z += memcmp (x, w, sizeof w);                    /* { dg-warning "call is the same expression as the second source; did you mean to dereference it" } */
 
   /* These are correct, no warning.  */
   memset (y, 0, sizeof (*y));
@@ -669,23 +677,29 @@ f3 (void *x, char *y, int z, X w)
 }
 
 int
-f4 (char *x, char **y, int z)
+f4 (char *x, char **y, int z, char w[64])
 {
   const char *s1 = "foobarbaz";
   const char *s2 = "abcde12345678";
   strncpy (x, s1, sizeof (s1));                    /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
   strncat (x, s2, sizeof (s2));                    /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  stpncpy (x, s1, sizeof (s1));                    /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
   y[0] = strndup (s1, sizeof (s1));        /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
-  z += strncmp (s1, s2, sizeof (s1));      /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
-  z += strncmp (s1, s2, sizeof (s2));      /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
-  z += strncasecmp (s1, s2, sizeof (s1));   /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
-  z += strncasecmp (s1, s2, sizeof (s2));   /* { dg-warning "call is the same expression as the source; did you mean to provide an explicit length" } */
+  z += strncmp (s1, s2, sizeof (s1));      /* { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" } */
+  z += strncmp (s1, s2, sizeof (s2));      /* { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" } */
+  z += strncasecmp (s1, s2, sizeof (s1));   /* { dg-warning "call is the same expression as the first source; did you mean to provide an explicit length" } */
+  z += strncasecmp (s1, s2, sizeof (s2));   /* { dg-warning "call is the same expression as the second source; did you mean to provide an explicit length" } */
+
+  strncpy (w, s1, sizeof (w));             /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  strncat (w, s2, sizeof (w));             /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
+  stpncpy (w, s1, sizeof (w));             /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */
 
   /* These are correct, no warning.  */
   const char s3[] = "foobarbaz";
   const char s4[] = "abcde12345678";
   strncpy (x, s3, sizeof (s3));
   strncat (x, s4, sizeof (s4));
+  stpncpy (x, s3, sizeof (s3));
   y[1] = strndup (s3, sizeof (s3));
   z += strncmp (s3, s4, sizeof (s3));
   z += strncmp (s3, s4, sizeof (s4));