--- gcc/c-family/c-common.h.jj	2012-10-09 13:42:29.000000000 +0200
+++ gcc/c-family/c-common.h	2012-10-09 16:55:57.028290378 +0200
@@ -767,8 +767,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);
--- gcc/c-family/c-common.c.jj	2012-10-09 13:42:29.000000000 +0200
+++ gcc/c-family/c-common.c	2012-10-09 20:03:04.651155693 +0200
@@ -1847,52 +1847,105 @@ strict_aliasing_warning (tree otype, tre
    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 (locati
       && 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 (locati
 	}
     }
 
-  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 (locati
 	  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
--- gcc/c/c-parser.c.jj	2012-08-24 23:44:41.000000000 +0200
+++ gcc/c/c-parser.c	2012-10-09 18:23:48.513110416 +0200
@@ -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
 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_primar
 {
   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_primar
 	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 *pars
 
 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, bo
 
   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, bo
   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, bo
       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 *par
 {
   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
--- gcc/cp/semantics.c.jj	2012-10-08 21:37:27.000000000 +0200
+++ gcc/cp/semantics.c	2012-10-09 18:18:53.813767352 +0200
@@ -2172,16 +2172,30 @@ finish_call_expr (tree fn, VEC(tree,gc)
 	{
 	  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);
 	    }
 
--- gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c.jj	2012-10-09 18:39:27.000000000 +0200
+++ gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess1.c	2012-10-10 09:31:02.547488042 +0200
@@ -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);
+}
--- gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c.jj	2012-10-10 09:37:31.302144406 +0200
+++ gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c	2012-10-10 10:20:50.296348095 +0200
@@ -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\]*" } */
--- gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c.jj	2012-08-17 09:11:47.000000000 +0200
+++ gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c	2012-10-10 11:00:44.877016535 +0200
@@ -12,6 +12,7 @@ extern void *memmove (void *__restrict,
 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, si
 {
   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 (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 (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 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));
--- gcc/testsuite/gcc.dg/Wsizeof-pointer-memaccess1.c.jj	2012-10-09 18:39:27.506921645 +0200
+++ gcc/testsuite/gcc.dg/Wsizeof-pointer-memaccess1.c	2012-10-09 19:19:22.152706730 +0200
@@ -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;
+}
--- gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C.jj	2012-10-05 21:26:54.000000000 +0200
+++ gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C	2012-10-10 10:59:10.585543713 +0200
@@ -14,6 +14,7 @@ extern void *memmove (void *__restrict,
 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, si
 {
   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 (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 (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 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));
--- gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C.jj	2012-10-05 21:26:54.000000000 +0200
+++ gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C	2012-10-10 11:00:22.183143646 +0200
@@ -14,6 +14,7 @@ extern void *memmove (void *__restrict,
 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, si
 {
   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 (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 (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 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;
 }
 
