public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH] -Wsizeof-pointer-memaccess warning
@ 2012-08-16 19:20 Jakub Jelinek
  2012-09-19 13:58 ` Jason Merrill
  0 siblings, 1 reply; 16+ messages in thread
From: Jakub Jelinek @ 2012-08-16 19:20 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Hi!

And here is the C++ FE part of the patch.  There were two issues
I didn't know about when starting the patch, one is that
for say the <string.h> _FORTIFY_SOURCE gnu_inline extern inline
memset etc. wrappers the C++ FE dropped BUILT_IN_NORMAL class,
so it stopped acting as builtin and therefore e.g. even the warning couldn't
find out it is a builtin (fixed by the decl.c change), and also for
templates, while sizeof (expr) always results with processing_template_decl
into SIZEOF_EXPR with original sizeof argument, for non-dependent types
it was folded immediately into a constant.  I hope that for calls in
templates it is not a big deal if even that stays in the SIZEOF_EXPR form
(folded immediately, but changed back to SIZEOF_EXPR form before calling
finish_call_expr).

Bootstrapped/regtested on x68_64-linux and i686-linux on top of the
C -Wsizeof-pointer-memaccess patch (and as mentioned in that patch,
this actually found a bug in GCC itself already).  Ok for trunk?

2012-08-16  Jakub Jelinek  <jakub@redhat.com>

cp/
	* cp-tree.h (struct cp_tree_loc_pair): New type.
	(finish_call_expr): Adjust prototype.
	* parser.c (cp_parser_parenthesized_expression_list): Add
	sizeof_arg argument, fill it in.
	(cp_parser_userdef_char_literal, cp_parser_userdef_numeric_literal,
	cp_parser_userdef_string_literal, cp_parser_perform_range_for_lookup,
	cp_parser_range_for_member_function): Adjust finish_call_expr
	callers.
	(cp_parser_postfix_expression): Adjust finish_call_expr and
	cp_parser_parenthesized_expression_list callers.  Pass sizeof_arg
	through.
	(cp_last_sizeof_arg): New variable.
	(cp_parser_unary_expression): Fill it in for RID_SIZEOF.
	(cp_parser_new_placement, cp_parser_new_initializer,
	cp_parser_mem_initializer, cp_parser_initializer,
	cp_parser_attribute_list, cp_parser_functional_cast): Adjust
	cp_parser_parenthesized_expression_list callers.
	* pt.c (tsubst_copy_and_build): Adjust finish_call_expr callers,
	pass through sizeof_arg.
	* semantics.c (finish_call_expr): Add sizeof_arg argument.
	Call sizeof_pointer_memaccess_warning if needed.
	(finish_omp_barrier, finish_omp_flush, finish_omp_taskwait,
	finish_omp_taskyield): Adjust finish_call_expr callers.
	* decl.c (duplicate_decls): When redeclaring a builtin function,
        keep the merged decl builtin also if newdecl is a gnu_inline
	inline definition.
testsuite/
	* g++.dg/torture/Wsizeof-pointer-memaccess1.C: New test.
	* g++.dg/torture/Wsizeof-pointer-memaccess2.C: New test.
	* g++.dg/ext/builtin30.C: New test.
	* gcc.dg/builtins-85.c: New test.

--- gcc/cp/parser.c.jj	2012-08-15 10:55:24.000000000 +0200
+++ gcc/cp/parser.c	2012-08-16 16:47:56.439684336 +0200
@@ -1803,7 +1803,7 @@ static tree cp_parser_postfix_open_squar
 static tree cp_parser_postfix_dot_deref_expression
   (cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *, location_t);
 static VEC(tree,gc) *cp_parser_parenthesized_expression_list
-  (cp_parser *, int, bool, bool, bool *);
+  (cp_parser *, int, bool, bool, bool *, struct cp_tree_loc_pair *);
 /* Values for the second parameter of cp_parser_parenthesized_expression_list.  */
 enum { non_attr = 0, normal_attr = 1, id_attr = 2 };
 static void cp_parser_pseudo_destructor_name
@@ -3583,7 +3583,8 @@ cp_parser_userdef_char_literal (cp_parse
       release_tree_vector (args);
       return error_mark_node;
     }
-  result = finish_call_expr (decl, &args, false, true, tf_warning_or_error);
+  result = finish_call_expr (decl, &args, false, true, NULL,
+			     tf_warning_or_error);
   release_tree_vector (args);
   if (result != error_mark_node)
     return result;
@@ -3641,7 +3642,7 @@ cp_parser_userdef_numeric_literal (cp_pa
   decl = lookup_literal_operator (name, args);
   if (decl && decl != error_mark_node)
     {
-      result = finish_call_expr (decl, &args, false, true, tf_none);
+      result = finish_call_expr (decl, &args, false, true, NULL, tf_none);
       if (result != error_mark_node)
 	{
 	  release_tree_vector (args);
@@ -3658,7 +3659,7 @@ cp_parser_userdef_numeric_literal (cp_pa
   decl = lookup_literal_operator (name, args);
   if (decl && decl != error_mark_node)
     {
-      result = finish_call_expr (decl, &args, false, true, tf_none);
+      result = finish_call_expr (decl, &args, false, true, NULL, tf_none);
       if (result != error_mark_node)
 	{
 	  release_tree_vector (args);
@@ -3676,7 +3677,7 @@ cp_parser_userdef_numeric_literal (cp_pa
     {
       tree tmpl_args = make_char_string_pack (num_string);
       decl = lookup_template_function (decl, tmpl_args);
-      result = finish_call_expr (decl, &args, false, true, tf_none);
+      result = finish_call_expr (decl, &args, false, true, NULL, tf_none);
       if (result != error_mark_node)
 	{
 	  release_tree_vector (args);
@@ -3716,7 +3717,7 @@ cp_parser_userdef_string_literal (cp_tok
       release_tree_vector (args);
       return error_mark_node;
     }
-  result = finish_call_expr (decl, &args, false, true, tf_none);
+  result = finish_call_expr (decl, &args, false, true, NULL, tf_none);
   release_tree_vector (args);
   if (result != error_mark_node)
     return result;
@@ -5468,7 +5469,7 @@ cp_parser_postfix_expression (cp_parser
 	cp_lexer_consume_token (parser->lexer);
 	vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 		    /*cast_p=*/false, /*allow_expansion_p=*/true,
-		    /*non_constant_p=*/NULL);
+		    /*non_constant_p=*/NULL, /*sizeof_arg=*/NULL);
 	if (vec == NULL)
 	  return error_mark_node;
 
@@ -5624,6 +5625,7 @@ cp_parser_postfix_expression (cp_parser
 	    bool saved_integral_constant_expression_p = false;
 	    bool saved_non_integral_constant_expression_p = false;
 	    VEC(tree,gc) *args;
+	    struct cp_tree_loc_pair sizeof_arg;
 
             is_member_access = false;
 
@@ -5642,7 +5644,7 @@ cp_parser_postfix_expression (cp_parser
 	    args = (cp_parser_parenthesized_expression_list
 		    (parser, non_attr,
 		     /*cast_p=*/false, /*allow_expansion_p=*/true,
-		     /*non_constant_p=*/NULL));
+		     /*non_constant_p=*/NULL, &sizeof_arg));
 	    if (is_builtin_constant_p)
 	      {
 		parser->integral_constant_expression_p
@@ -5746,6 +5748,7 @@ cp_parser_postfix_expression (cp_parser
 		    = finish_call_expr (postfix_expression, &args,
 					/*disallow_virtual=*/false,
 					/*koenig_p=*/false,
+					/*sizeof_arg=*/NULL,
 					tf_warning_or_error);
 	      }
 	    else if (TREE_CODE (postfix_expression) == OFFSET_REF
@@ -5753,21 +5756,43 @@ cp_parser_postfix_expression (cp_parser
 		     || TREE_CODE (postfix_expression) == DOTSTAR_EXPR)
 	      postfix_expression = (build_offset_ref_call_from_tree
 				    (postfix_expression, &args));
-	    else if (idk == CP_ID_KIND_QUALIFIED)
-	      /* A call to a static class member, or a namespace-scope
-		 function.  */
-	      postfix_expression
-		= finish_call_expr (postfix_expression, &args,
-				    /*disallow_virtual=*/true,
-				    koenig_p,
-				    tf_warning_or_error);
 	    else
-	      /* All other function calls.  */
-	      postfix_expression
-		= finish_call_expr (postfix_expression, &args,
-				    /*disallow_virtual=*/false,
-				    koenig_p,
-				    tf_warning_or_error);
+	      {
+		/* In templates, for expressions SIZEOF_EXPR is always
+		   created, but for types it is sometimes already folded.
+		   Force use of SIZEOF_EXPR in that case anyway, so that
+		   -Wsizeof-pointer-memaccess warning can work during
+		   instantiation.  */
+		if (processing_template_decl
+		    && sizeof_arg.expr != NULL_TREE
+		    && TYPE_P (sizeof_arg.expr)
+		    && !VEC_empty (tree, args)
+		    && TREE_CODE (VEC_last (tree, args)) == INTEGER_CST)
+		  {
+		    tree se = build_min (SIZEOF_EXPR, size_type_node,
+					 sizeof_arg.expr);
+		    TREE_SIDE_EFFECTS (se) = 0;
+		    TREE_READONLY (se) = 1;
+		    SET_EXPR_LOCATION (se, sizeof_arg.first_loc);
+		    VEC_replace (tree, args, VEC_length (tree, args) - 1, se);
+		  }
+
+		if (idk == CP_ID_KIND_QUALIFIED)
+		  /* A call to a static class member, or a namespace-scope
+		     function.  */
+		  postfix_expression
+		    = finish_call_expr (postfix_expression, &args,
+					/*disallow_virtual=*/true,
+					koenig_p, &sizeof_arg,
+					tf_warning_or_error);
+		else
+		  /* All other function calls.  */
+		  postfix_expression
+		    = finish_call_expr (postfix_expression, &args,
+					/*disallow_virtual=*/false,
+					koenig_p, &sizeof_arg,
+					tf_warning_or_error);
+	      }
 
 	    /* The POSTFIX_EXPRESSION is certainly no longer an id.  */
 	    idk = CP_ID_KIND_NONE;
@@ -6084,6 +6109,10 @@ cp_parser_postfix_dot_deref_expression (
   return postfix_expression;
 }
 
+/* Argument of last sizeof expression, used for -Wsizeof-pointer-memaccess
+   warning.  */
+static struct cp_tree_loc_pair cp_last_sizeof_arg;
+
 /* Parse a parenthesized expression-list.
 
    expression-list:
@@ -6115,17 +6144,26 @@ cp_parser_parenthesized_expression_list
 					 int is_attribute_list,
 					 bool cast_p,
                                          bool allow_expansion_p,
-					 bool *non_constant_p)
+					 bool *non_constant_p,
+					 struct cp_tree_loc_pair *sizeof_arg)
 {
   VEC(tree,gc) *expression_list;
   bool fold_expr_p = is_attribute_list != non_attr;
   tree identifier = NULL_TREE;
   bool saved_greater_than_is_operator_p;
+  location_t sizeof_arg_loc = UNKNOWN_LOCATION;
 
   /* Assume all the expressions will be constant.  */
   if (non_constant_p)
     *non_constant_p = false;
 
+  if (sizeof_arg != NULL)
+    {
+      sizeof_arg->expr = NULL_TREE;
+      sizeof_arg->first_loc = UNKNOWN_LOCATION;
+      sizeof_arg->last_loc = UNKNOWN_LOCATION;
+    }
+
   if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
     return NULL;
 
@@ -6143,6 +6181,8 @@ cp_parser_parenthesized_expression_list
       {
 	tree expr;
 
+	sizeof_arg_loc = UNKNOWN_LOCATION;
+
 	/* At the beginning of attribute lists, check to see if the
 	   next token is an identifier.  */
 	if (is_attribute_list == id_attr
@@ -6177,7 +6217,14 @@ cp_parser_parenthesized_expression_list
 		  *non_constant_p = true;
 	      }
 	    else
-	      expr = cp_parser_assignment_expression (parser, cast_p, NULL);
+	      {
+		if (sizeof_arg != NULL
+		    && cp_lexer_next_token_is_keyword (parser->lexer,
+						       RID_SIZEOF))
+		  sizeof_arg_loc
+		    = cp_lexer_peek_nth_token (parser->lexer, 2)->location;
+		expr = cp_parser_assignment_expression (parser, cast_p, NULL);
+	      }
 
 	    if (fold_expr_p)
 	      expr = fold_non_dependent_expr (expr);
@@ -6217,6 +6264,14 @@ cp_parser_parenthesized_expression_list
 	cp_lexer_consume_token (parser->lexer);
       }
 
+  if (sizeof_arg != NULL
+      && sizeof_arg_loc != UNKNOWN_LOCATION
+      && cp_last_sizeof_arg.expr != NULL_TREE
+      && sizeof_arg_loc == cp_last_sizeof_arg.first_loc
+      && cp_lexer_peek_token (parser->lexer)->location
+	 == cp_last_sizeof_arg.last_loc)
+    *sizeof_arg = cp_last_sizeof_arg;
+
   if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
     {
       int ending;
@@ -6385,17 +6440,26 @@ cp_parser_unary_expression (cp_parser *p
 	case RID_ALIGNOF:
 	case RID_SIZEOF:
 	  {
-	    tree operand;
+	    tree operand, result;
 	    enum tree_code op;
+	    location_t first_loc;
 
 	    op = keyword == RID_ALIGNOF ? ALIGNOF_EXPR : SIZEOF_EXPR;
 	    /* Consume the token.  */
 	    cp_lexer_consume_token (parser->lexer);
+	    first_loc = cp_lexer_peek_token (parser->lexer)->location;
 	    /* Parse the operand.  */
 	    operand = cp_parser_sizeof_operand (parser, keyword);
+	    if (keyword == RID_SIZEOF)
+	      {
+		cp_last_sizeof_arg.expr = operand;
+		cp_last_sizeof_arg.first_loc = first_loc;
+		cp_last_sizeof_arg.last_loc
+		  = cp_lexer_peek_token (parser->lexer)->location;
+	      }
 
 	    if (TYPE_P (operand))
-	      return cxx_sizeof_or_alignof_type (operand, op, true);
+	      result = cxx_sizeof_or_alignof_type (operand, op, true);
 	    else
 	      {
 		/* ISO C++ defines alignof only with types, not with
@@ -6406,8 +6470,14 @@ cp_parser_unary_expression (cp_parser *p
 			   "ISO C++ does not allow %<alignof%> "
 			   "with a non-type");
 
-		return cxx_sizeof_or_alignof_expr (operand, op, true);
+		result = cxx_sizeof_or_alignof_expr (operand, op, true);
 	      }
+
+	    if (processing_template_decl
+		&& TREE_CODE (result) == SIZEOF_EXPR)
+	      SET_EXPR_LOCATION (result, first_loc);
+
+	    return result;
 	  }
 
 	case RID_NEW:
@@ -6761,7 +6831,7 @@ cp_parser_new_placement (cp_parser* pars
   expression_list = (cp_parser_parenthesized_expression_list
 		     (parser, non_attr, /*cast_p=*/false,
 		      /*allow_expansion_p=*/true,
-		      /*non_constant_p=*/NULL));
+		      /*non_constant_p=*/NULL, /*sizeof_arg=*/NULL));
 
   return expression_list;
 }
@@ -6963,7 +7033,7 @@ cp_parser_new_initializer (cp_parser* pa
     expression_list = (cp_parser_parenthesized_expression_list
 		       (parser, non_attr, /*cast_p=*/false,
 			/*allow_expansion_p=*/true,
-			/*non_constant_p=*/NULL));
+			/*non_constant_p=*/NULL, /*sizeof_arg=*/NULL));
 
   return expression_list;
 }
@@ -9608,12 +9678,12 @@ cp_parser_perform_range_for_lookup (tree
 	  member_begin = perform_koenig_lookup (id_begin, vec,
 						/*include_std=*/true,
 						tf_warning_or_error);
-	  *begin = finish_call_expr (member_begin, &vec, false, true,
+	  *begin = finish_call_expr (member_begin, &vec, false, true, NULL,
 				     tf_warning_or_error);
 	  member_end = perform_koenig_lookup (id_end, vec,
 					      /*include_std=*/true,
 					      tf_warning_or_error);
-	  *end = finish_call_expr (member_end, &vec, false, true,
+	  *end = finish_call_expr (member_end, &vec, false, true, NULL,
 				   tf_warning_or_error);
 
 	  release_tree_vector (vec);
@@ -9657,7 +9727,7 @@ cp_parser_range_for_member_function (tre
   vec = make_tree_vector ();
   res = finish_call_expr (member, &vec,
 			  /*disallow_virtual=*/false,
-			  /*koenig_p=*/false,
+			  /*koenig_p=*/false, /*sizeof_arg=*/NULL,
 			  tf_warning_or_error);
   release_tree_vector (vec);
   return res;
@@ -11513,7 +11583,8 @@ cp_parser_mem_initializer (cp_parser* pa
       vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 						     /*cast_p=*/false,
 						     /*allow_expansion_p=*/true,
-						     /*non_constant_p=*/NULL);
+						     /*non_constant_p=*/NULL,
+						     /*sizeof_arg=*/NULL);
       if (vec == NULL)
 	return error_mark_node;
       expression_list = build_tree_list_vec (vec);
@@ -17548,7 +17619,8 @@ cp_parser_initializer (cp_parser* parser
       vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 						     /*cast_p=*/false,
 						     /*allow_expansion_p=*/true,
-						     non_constant_p);
+						     non_constant_p,
+						     /*sizeof_arg=*/NULL);
       if (vec == NULL)
 	return error_mark_node;
       init = build_tree_list_vec (vec);
@@ -20223,7 +20295,7 @@ cp_parser_attribute_list (cp_parser* par
 	      vec = cp_parser_parenthesized_expression_list
 		    (parser, attr_flag, /*cast_p=*/false,
 		     /*allow_expansion_p=*/false,
-		     /*non_constant_p=*/NULL);
+		     /*non_constant_p=*/NULL, /*sizeof_arg=*/NULL);
 	      if (vec == NULL)
 		arguments = error_mark_node;
 	      else
@@ -21484,7 +21556,8 @@ cp_parser_functional_cast (cp_parser* pa
   vec = cp_parser_parenthesized_expression_list (parser, non_attr,
 						 /*cast_p=*/true,
 						 /*allow_expansion_p=*/true,
-						 /*non_constant_p=*/NULL);
+						 /*non_constant_p=*/NULL,
+						 /*sizeof_arg=*/NULL);
   if (vec == NULL)
     expression_list = error_mark_node;
   else
--- gcc/cp/pt.c.jj	2012-08-10 12:57:26.000000000 +0200
+++ gcc/cp/pt.c	2012-08-16 16:02:12.230154801 +0200
@@ -13500,7 +13500,11 @@ tsubst_copy_and_build (tree t,
 	bool qualified_p;
 	bool koenig_p;
 	tree ret;
+	struct cp_tree_loc_pair sizeof_arg;
 
+	sizeof_arg.expr = NULL_TREE;
+	sizeof_arg.first_loc = UNKNOWN_LOCATION;
+	sizeof_arg.last_loc = UNKNOWN_LOCATION;
 	function = CALL_EXPR_FN (t);
 	/* When we parsed the expression,  we determined whether or
 	   not Koenig lookup should be performed.  */
@@ -13555,8 +13559,18 @@ tsubst_copy_and_build (tree t,
 	    tree arg = CALL_EXPR_ARG (t, i);
 
 	    if (!PACK_EXPANSION_P (arg))
-	      VEC_safe_push (tree, gc, call_args,
-			     RECUR (CALL_EXPR_ARG (t, i)));
+	      {
+		VEC_safe_push (tree, gc, call_args,
+			       RECUR (CALL_EXPR_ARG (t, i)));
+		if (i == nargs - 1
+		    && TREE_CODE (CALL_EXPR_ARG (t, i)) == SIZEOF_EXPR)
+		  {
+		    sizeof_arg.expr
+		      = RECUR (TREE_OPERAND (CALL_EXPR_ARG (t, i), 0));
+		    sizeof_arg.first_loc
+		      = EXPR_LOCATION (CALL_EXPR_ARG (t, i));
+		  }
+	      }
 	    else
 	      {
 		/* Expand the pack expansion and push each entry onto
@@ -13678,9 +13692,9 @@ tsubst_copy_and_build (tree t,
 	      ret = build_nt_call_vec (function, call_args);
 	    else if (!BASELINK_P (fn))
 	      ret = finish_call_expr (function, &call_args,
-				       /*disallow_virtual=*/false,
-				       /*koenig_p=*/false,
-				       complain);
+				      /*disallow_virtual=*/false,
+				      /*koenig_p=*/false, /*sizeof_arg=*/NULL,
+				      complain);
 	    else
 	      ret = (build_new_method_call
 		      (instance, fn,
@@ -13692,7 +13706,7 @@ tsubst_copy_and_build (tree t,
 	else
 	  ret = finish_call_expr (function, &call_args,
 				  /*disallow_virtual=*/qualified_p,
-				  koenig_p,
+				  koenig_p, &sizeof_arg,
 				  complain);
 
 	release_tree_vector (call_args);
--- gcc/cp/semantics.c.jj	2012-08-15 10:55:24.000000000 +0200
+++ gcc/cp/semantics.c	2012-08-16 15:27:45.791077750 +0200
@@ -2030,7 +2030,8 @@ perform_koenig_lookup (tree fn, VEC(tree
 
 tree
 finish_call_expr (tree fn, VEC(tree,gc) **args, bool disallow_virtual,
-		  bool koenig_p, tsubst_flags_t complain)
+		  bool koenig_p, struct cp_tree_loc_pair *sizeof_arg,
+		  tsubst_flags_t complain)
 {
   tree result;
   tree orig_fn;
@@ -2160,8 +2161,18 @@ finish_call_expr (tree fn, VEC(tree,gc)
 	result = resolve_overloaded_builtin (input_location, fn, *args);
 
       if (!result)
-	/* A call to a namespace-scope function.  */
-	result = build_new_function_call (fn, args, koenig_p, complain);
+	{
+	  if (warn_sizeof_pointer_memaccess
+	      && sizeof_arg != NULL
+	      && !processing_template_decl
+	      && sizeof_arg->expr != NULL_TREE)
+	    sizeof_pointer_memaccess_warning
+	      (sizeof_arg->first_loc, fn, *args, sizeof_arg->expr,
+	       same_type_ignoring_top_level_qualifiers_p);
+
+	  /* A call to a namespace-scope function.  */
+	  result = build_new_function_call (fn, args, koenig_p, complain);
+	}
     }
   else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
     {
@@ -4973,7 +4984,8 @@ finish_omp_barrier (void)
 {
   tree fn = builtin_decl_explicit (BUILT_IN_GOMP_BARRIER);
   VEC(tree,gc) *vec = make_tree_vector ();
-  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+  tree stmt = finish_call_expr (fn, &vec, false, false, NULL,
+				tf_warning_or_error);
   release_tree_vector (vec);
   finish_expr_stmt (stmt);
 }
@@ -4983,7 +4995,8 @@ finish_omp_flush (void)
 {
   tree fn = builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE);
   VEC(tree,gc) *vec = make_tree_vector ();
-  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+  tree stmt = finish_call_expr (fn, &vec, false, false, NULL,
+				tf_warning_or_error);
   release_tree_vector (vec);
   finish_expr_stmt (stmt);
 }
@@ -4993,7 +5006,8 @@ finish_omp_taskwait (void)
 {
   tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKWAIT);
   VEC(tree,gc) *vec = make_tree_vector ();
-  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+  tree stmt = finish_call_expr (fn, &vec, false, false, NULL,
+				tf_warning_or_error);
   release_tree_vector (vec);
   finish_expr_stmt (stmt);
 }
@@ -5003,7 +5017,8 @@ finish_omp_taskyield (void)
 {
   tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKYIELD);
   VEC(tree,gc) *vec = make_tree_vector ();
-  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+  tree stmt = finish_call_expr (fn, &vec, false, false, NULL,
+				tf_warning_or_error);
   release_tree_vector (vec);
   finish_expr_stmt (stmt);
 }
--- gcc/cp/decl.c.jj	2012-08-15 10:55:24.044296935 +0200
+++ gcc/cp/decl.c	2012-08-16 15:40:25.729437019 +0200
@@ -2154,39 +2154,40 @@ duplicate_decls (tree newdecl, tree oldd
 	  DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl);
 	  DECL_RESULT (olddecl) = DECL_RESULT (newdecl);
 	}
+      /* If redeclaring a builtin function, it stays built in
+	 if newdecl is a gnu_inline definition, or if newdecl is just
+	 a declaration.  */
+      if (DECL_BUILT_IN (olddecl)
+	  && (new_defines_function ? GNU_INLINE_P (newdecl) : types_match))
+	{
+	  DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
+	  DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+	  /* If we're keeping the built-in definition, keep the rtl,
+	     regardless of declaration matches.  */
+	  COPY_DECL_RTL (olddecl, newdecl);
+	  if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
+	    {
+	      enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl);
+	      switch (fncode)
+		{
+		  /* If a compatible prototype of these builtin functions
+		     is seen, assume the runtime implements it with the
+		     expected semantics.  */
+		case BUILT_IN_STPCPY:
+		  if (builtin_decl_explicit_p (fncode))
+		    set_builtin_decl_implicit_p (fncode, true);
+		  break;
+		default:
+		  break;
+		}
+	    }
+	}
       if (new_defines_function)
 	/* If defining a function declared with other language
 	   linkage, use the previously declared language linkage.  */
 	SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl));
       else if (types_match)
 	{
-	  /* If redeclaring a builtin function, and not a definition,
-	     it stays built in.  */
-	  if (DECL_BUILT_IN (olddecl))
-	    {
-	      DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
-	      DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
-	      /* If we're keeping the built-in definition, keep the rtl,
-		 regardless of declaration matches.  */
-	      COPY_DECL_RTL (olddecl, newdecl);
-	      if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
-		{
-		  enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl);
-		  switch (fncode)
-		    {
-		      /* If a compatible prototype of these builtin functions
-			 is seen, assume the runtime implements it with the
-			 expected semantics.  */
-		    case BUILT_IN_STPCPY:
-		      if (builtin_decl_explicit_p (fncode))
-			set_builtin_decl_implicit_p (fncode, true);
-		      break;
-		    default:
-		      break;
-		    }
-		}
-	    }
-
 	  DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
 	  /* Don't clear out the arguments if we're just redeclaring a
 	     function.  */
--- gcc/cp/cp-tree.h.jj	2012-08-10 12:57:26.000000000 +0200
+++ gcc/cp/cp-tree.h	2012-08-16 12:28:29.062398331 +0200
@@ -5496,6 +5496,12 @@ typedef struct GTY(()) deferred_access_c
 DEF_VEC_O(deferred_access_check);
 DEF_VEC_ALLOC_O(deferred_access_check,gc);
 
+/* Used for -Wsizeof-pointer-memaccess diagnostics.  */
+struct cp_tree_loc_pair {
+  tree expr;
+  location_t first_loc, last_loc;
+};
+
 /* in semantics.c */
 extern void push_deferring_access_checks	(deferring_kind);
 extern void resume_deferring_access_checks	(void);
@@ -5591,7 +5597,8 @@ bool empty_expr_stmt_p				(tree);
 extern tree perform_koenig_lookup		(tree, VEC(tree,gc) *, bool,
 						 tsubst_flags_t);
 extern tree finish_call_expr			(tree, VEC(tree,gc) **, bool,
-						 bool, tsubst_flags_t);
+						 bool, struct cp_tree_loc_pair *,
+						 tsubst_flags_t);
 extern tree finish_increment_expr		(tree, enum tree_code);
 extern tree finish_this_expr			(void);
 extern tree finish_pseudo_destructor_expr       (tree, tree, tree);
--- gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C.jj	2012-08-16 15:41:25.594150006 +0200
+++ gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C	2012-08-16 15:51:04.199374022 +0200
@@ -0,0 +1,716 @@
+// Test -Wsizeof-pointer-memaccess warnings.
+// { dg-do compile }
+// { dg-options "-Wall" }
+// Test just twice, once with -O0 non-fortified, once with -O2 fortified.
+// { dg-skip-if "" { *-*-* }  { "*" } { "-O0" "-O2" } }
+// { dg-skip-if "" { *-*-* }  { "-flto" } { "" } }
+
+extern "C" {
+
+typedef __SIZE_TYPE__ size_t;
+extern void *memset (void *, int, size_t);
+extern void *memcpy (void *__restrict, const void *__restrict, size_t);
+extern void *memmove (void *__restrict, const void *__restrict, size_t);
+extern int memcmp (const void *, const void *, size_t);
+extern char *strncpy (char *__restrict, const char *__restrict, size_t);
+extern char *strncat (char *__restrict, const char *__restrict, size_t);
+extern char *strndup (const char *, size_t);
+extern int strncmp (const char *, const char *, size_t);
+extern int strncasecmp (const char *, const char *, size_t);
+
+#ifdef __OPTIMIZE__
+# define bos(ptr) __builtin_object_size (ptr, 1)
+# define bos0(ptr) __builtin_object_size (ptr, 0)
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memset (void *dest, int c, size_t len)
+{
+  return __builtin___memset_chk (dest, c, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memcpy (void *__restrict dest, const void *__restrict src, size_t len)
+{
+  return __builtin___memcpy_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memmove (void *dest, const void *src, size_t len)
+{
+  return __builtin___memmove_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncpy (char *__restrict dest, const char *__restrict src, size_t len)
+{
+  return __builtin___strncpy_chk (dest, src, len, bos (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncat (char *dest, const char *src, size_t len)
+{
+  return __builtin___strncat_chk (dest, src, len, bos (dest));
+}
+#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];
+
+template <int N>
+int
+f1 (void *x, int z)
+{
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (&a, x, sizeof a);
+  z += memcmp (&a, x, sizeof (a));
+  z += memcmp (&a, x, sizeof (struct A));
+  z += memcmp (&a, x, sizeof (const struct A));
+  z += memcmp (&a, x, sizeof (volatile struct A));
+  z += memcmp (&a, x, sizeof (volatile const struct A));
+  z += memcmp (&a, x, sizeof (TA));
+  z += memcmp (&a, x, sizeof (__typeof (*&a)));
+  z += memcmp (pa1, x, sizeof (*pa1));
+  z += memcmp (pa2, x, sizeof (*pa3));
+  z += memcmp (pa3, x, sizeof (__typeof (*pa3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) &a, x, sizeof (&a));
+  z += memcmp ((char *) &a, x, sizeof (&a));
+  z += memcmp (&a, x, sizeof (&a) + 0);
+  z += memcmp (&a, x, 0 + sizeof (&a));
+
+  // These are correct, no warning. 
+  z += memcmp (x, &a, sizeof a);
+  z += memcmp (x, &a, sizeof (a));
+  z += memcmp (x, &a, sizeof (struct A));
+  z += memcmp (x, &a, sizeof (const struct A));
+  z += memcmp (x, &a, sizeof (volatile struct A));
+  z += memcmp (x, &a, sizeof (volatile const struct A));
+  z += memcmp (x, &a, sizeof (TA));
+  z += memcmp (x, &a, sizeof (__typeof (*&a)));
+  z += memcmp (x, pa1, sizeof (*pa1));
+  z += memcmp (x, pa2, sizeof (*pa3));
+  z += memcmp (x, pa3, sizeof (__typeof (*pa3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) &a, sizeof (&a));
+  z += memcmp (x, (char *) &a, sizeof (&a));
+  z += memcmp (x, &a, sizeof (&a) + 0);
+  z += memcmp (x, &a, 0 + sizeof (&a));
+
+  return z;
+}
+
+template <int N>
+int
+f2 (void *x, int z)
+{
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (&b, x, sizeof b);
+  z += memcmp (&b, x, sizeof (b));
+  z += memcmp (&b, x, sizeof (struct B));
+  z += memcmp (&b, x, sizeof (const struct B));
+  z += memcmp (&b, x, sizeof (volatile struct B));
+  z += memcmp (&b, x, sizeof (volatile const struct B));
+  z += memcmp (&b, x, sizeof (TB));
+  z += memcmp (&b, x, sizeof (__typeof (*&b)));
+  z += memcmp (pb1, x, sizeof (*pb1));
+  z += memcmp (pb2, x, sizeof (*pb3));
+  z += memcmp (pb3, x, sizeof (__typeof (*pb3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) &b, x, sizeof (&b));
+  z += memcmp ((char *) &b, x, sizeof (&b));
+  z += memcmp (&b, x, sizeof (&b) + 0);
+  z += memcmp (&b, x, 0 + sizeof (&b));
+
+  // These are correct, no warning. 
+  z += memcmp (x, &b, sizeof b);
+  z += memcmp (x, &b, sizeof (b));
+  z += memcmp (x, &b, sizeof (struct B));
+  z += memcmp (x, &b, sizeof (const struct B));
+  z += memcmp (x, &b, sizeof (volatile struct B));
+  z += memcmp (x, &b, sizeof (volatile const struct B));
+  z += memcmp (x, &b, sizeof (TB));
+  z += memcmp (x, &b, sizeof (__typeof (*&b)));
+  z += memcmp (x, pb1, sizeof (*pb1));
+  z += memcmp (x, pb2, sizeof (*pb3));
+  z += memcmp (x, pb3, sizeof (__typeof (*pb3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) &b, sizeof (&b));
+  z += memcmp (x, (char *) &b, sizeof (&b));
+  z += memcmp (x, &b, sizeof (&b) + 0);
+  z += memcmp (x, &b, 0 + sizeof (&b));
+
+  return z;
+}
+
+template <int N>
+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;
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (y, x, sizeof (*y));
+  z += memcmp (y1, x, sizeof (*y2));
+  z += memcmp (buf1, x, sizeof buf1);
+  z += memcmp (buf3, x, sizeof (buf3));
+  z += memcmp (&buf3[0], x, sizeof (buf3));
+  z += memcmp (&buf4[0], x, sizeof (buf4));
+  z += memcmp (&y3, y, sizeof (y3));
+  z += memcmp ((char *) &y3, y, sizeof (y3));
+  z += memcmp (w, x, sizeof (X));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) y, x, sizeof (y));
+  z += memcmp ((char *) y1, x, sizeof (y2));
+  z += memcmp (y, x, sizeof (y) + 0);
+  z += memcmp (y1, x, 0 + sizeof (y2));
+  z += memcmp ((void *) &c, x, sizeof (&c));
+  z += memcmp ((signed char *) &c, x, sizeof (&c));
+  z += memcmp (&c, x, sizeof (&c) + 0);
+  z += memcmp (&c, x, 0 + sizeof (&c));
+
+  // These are correct, no warning. 
+  z += memcmp (x, y, sizeof (*y));
+  z += memcmp (x, y1, sizeof (*y2));
+  z += memcmp (x, buf1, sizeof buf1);
+  z += memcmp (x, buf3, sizeof (buf3));
+  z += memcmp (x, &buf3[0], sizeof (buf3));
+  z += memcmp (x, &buf4[0], sizeof (buf4));
+  z += memcmp (y, &y3, sizeof (y3));
+  z += memcmp (y, (char *) &y3, sizeof (y3));
+  z += memcmp (x, w, sizeof (X));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) y, sizeof (y));
+  z += memcmp (x, (char *) y1, sizeof (y2));
+  z += memcmp (x, y, sizeof (y) + 0);
+  z += memcmp (x, y1, 0 + sizeof (y2));
+  z += memcmp (x, (void *) &c, sizeof (&c));
+  z += memcmp (x, (signed char *) &c, sizeof (&c));
+  z += memcmp (x, &c, sizeof (&c) + 0);
+  z += memcmp (x, &c, 0 + sizeof (&c));
+
+  return z;
+}
+
+template <int N>
+int
+f4 (char *x, char **y, int z)
+{
+  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" }
+  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" }
+
+  // These are correct, no warning. 
+  const char s3[] = "foobarbaz";
+  const char s4[] = "abcde12345678";
+  strncpy (x, s3, sizeof (s3));
+  strncat (x, s4, sizeof (s4));
+  y[1] = strndup (s3, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s4));
+  z += strncasecmp (s3, s4, sizeof (s3));
+  z += strncasecmp (s3, s4, sizeof (s4));
+
+  return z;
+}
+
+int
+f (void *x, char *y, int z, X w, char **u)
+{
+  z += f1<0> (x, z);
+  z += f2<0> (x, z);
+  z += f3<0> (x, y, z, w);
+  z += f4<0> (y, u, z);
+  return z;
+}
+
+// { dg-prune-output "\[\n\r\]*will always overflow\[\n\r\]*" }
--- gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C.jj	2012-08-16 14:00:00.843157082 +0200
+++ gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C	2012-08-16 13:59:44.000000000 +0200
@@ -0,0 +1,702 @@
+// Test -Wsizeof-pointer-memaccess warnings.
+// { dg-do compile }
+// { dg-options "-Wall" }
+// Test just twice, once with -O0 non-fortified, once with -O2 fortified.
+// { dg-skip-if "" { *-*-* }  { "*" } { "-O0" "-O2" } }
+// { dg-skip-if "" { *-*-* }  { "-flto" } { "" } }
+
+extern "C" {
+
+typedef __SIZE_TYPE__ size_t;
+extern void *memset (void *, int, size_t);
+extern void *memcpy (void *__restrict, const void *__restrict, size_t);
+extern void *memmove (void *__restrict, const void *__restrict, size_t);
+extern int memcmp (const void *, const void *, size_t);
+extern char *strncpy (char *__restrict, const char *__restrict, size_t);
+extern char *strncat (char *__restrict, const char *__restrict, size_t);
+extern char *strndup (const char *, size_t);
+extern int strncmp (const char *, const char *, size_t);
+extern int strncasecmp (const char *, const char *, size_t);
+
+#ifdef __OPTIMIZE__
+# define bos(ptr) __builtin_object_size (ptr, 1)
+# define bos0(ptr) __builtin_object_size (ptr, 0)
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memset (void *dest, int c, size_t len)
+{
+  return __builtin___memset_chk (dest, c, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memcpy (void *__restrict dest, const void *__restrict src, size_t len)
+{
+  return __builtin___memcpy_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memmove (void *dest, const void *src, size_t len)
+{
+  return __builtin___memmove_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncpy (char *__restrict dest, const char *__restrict src, size_t len)
+{
+  return __builtin___strncpy_chk (dest, src, len, bos (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncat (char *dest, const char *src, size_t len)
+{
+  return __builtin___strncat_chk (dest, src, len, bos (dest));
+}
+#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];
+
+int
+f1 (void *x, int z)
+{
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (&a, x, sizeof a);
+  z += memcmp (&a, x, sizeof (a));
+  z += memcmp (&a, x, sizeof (struct A));
+  z += memcmp (&a, x, sizeof (const struct A));
+  z += memcmp (&a, x, sizeof (volatile struct A));
+  z += memcmp (&a, x, sizeof (volatile const struct A));
+  z += memcmp (&a, x, sizeof (TA));
+  z += memcmp (&a, x, sizeof (__typeof (*&a)));
+  z += memcmp (pa1, x, sizeof (*pa1));
+  z += memcmp (pa2, x, sizeof (*pa3));
+  z += memcmp (pa3, x, sizeof (__typeof (*pa3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) &a, x, sizeof (&a));
+  z += memcmp ((char *) &a, x, sizeof (&a));
+  z += memcmp (&a, x, sizeof (&a) + 0);
+  z += memcmp (&a, x, 0 + sizeof (&a));
+
+  // These are correct, no warning. 
+  z += memcmp (x, &a, sizeof a);
+  z += memcmp (x, &a, sizeof (a));
+  z += memcmp (x, &a, sizeof (struct A));
+  z += memcmp (x, &a, sizeof (const struct A));
+  z += memcmp (x, &a, sizeof (volatile struct A));
+  z += memcmp (x, &a, sizeof (volatile const struct A));
+  z += memcmp (x, &a, sizeof (TA));
+  z += memcmp (x, &a, sizeof (__typeof (*&a)));
+  z += memcmp (x, pa1, sizeof (*pa1));
+  z += memcmp (x, pa2, sizeof (*pa3));
+  z += memcmp (x, pa3, sizeof (__typeof (*pa3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) &a, sizeof (&a));
+  z += memcmp (x, (char *) &a, sizeof (&a));
+  z += memcmp (x, &a, sizeof (&a) + 0);
+  z += memcmp (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;
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (&b, x, sizeof b);
+  z += memcmp (&b, x, sizeof (b));
+  z += memcmp (&b, x, sizeof (struct B));
+  z += memcmp (&b, x, sizeof (const struct B));
+  z += memcmp (&b, x, sizeof (volatile struct B));
+  z += memcmp (&b, x, sizeof (volatile const struct B));
+  z += memcmp (&b, x, sizeof (TB));
+  z += memcmp (&b, x, sizeof (__typeof (*&b)));
+  z += memcmp (pb1, x, sizeof (*pb1));
+  z += memcmp (pb2, x, sizeof (*pb3));
+  z += memcmp (pb3, x, sizeof (__typeof (*pb3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) &b, x, sizeof (&b));
+  z += memcmp ((char *) &b, x, sizeof (&b));
+  z += memcmp (&b, x, sizeof (&b) + 0);
+  z += memcmp (&b, x, 0 + sizeof (&b));
+
+  // These are correct, no warning. 
+  z += memcmp (x, &b, sizeof b);
+  z += memcmp (x, &b, sizeof (b));
+  z += memcmp (x, &b, sizeof (struct B));
+  z += memcmp (x, &b, sizeof (const struct B));
+  z += memcmp (x, &b, sizeof (volatile struct B));
+  z += memcmp (x, &b, sizeof (volatile const struct B));
+  z += memcmp (x, &b, sizeof (TB));
+  z += memcmp (x, &b, sizeof (__typeof (*&b)));
+  z += memcmp (x, pb1, sizeof (*pb1));
+  z += memcmp (x, pb2, sizeof (*pb3));
+  z += memcmp (x, pb3, sizeof (__typeof (*pb3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) &b, sizeof (&b));
+  z += memcmp (x, (char *) &b, sizeof (&b));
+  z += memcmp (x, &b, sizeof (&b) + 0);
+  z += memcmp (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;
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (y, x, sizeof (*y));
+  z += memcmp (y1, x, sizeof (*y2));
+  z += memcmp (buf1, x, sizeof buf1);
+  z += memcmp (buf3, x, sizeof (buf3));
+  z += memcmp (&buf3[0], x, sizeof (buf3));
+  z += memcmp (&buf4[0], x, sizeof (buf4));
+  z += memcmp (&y3, y, sizeof (y3));
+  z += memcmp ((char *) &y3, y, sizeof (y3));
+  z += memcmp (w, x, sizeof (X));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) y, x, sizeof (y));
+  z += memcmp ((char *) y1, x, sizeof (y2));
+  z += memcmp (y, x, sizeof (y) + 0);
+  z += memcmp (y1, x, 0 + sizeof (y2));
+  z += memcmp ((void *) &c, x, sizeof (&c));
+  z += memcmp ((signed char *) &c, x, sizeof (&c));
+  z += memcmp (&c, x, sizeof (&c) + 0);
+  z += memcmp (&c, x, 0 + sizeof (&c));
+
+  // These are correct, no warning. 
+  z += memcmp (x, y, sizeof (*y));
+  z += memcmp (x, y1, sizeof (*y2));
+  z += memcmp (x, buf1, sizeof buf1);
+  z += memcmp (x, buf3, sizeof (buf3));
+  z += memcmp (x, &buf3[0], sizeof (buf3));
+  z += memcmp (x, &buf4[0], sizeof (buf4));
+  z += memcmp (y, &y3, sizeof (y3));
+  z += memcmp (y, (char *) &y3, sizeof (y3));
+  z += memcmp (x, w, sizeof (X));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) y, sizeof (y));
+  z += memcmp (x, (char *) y1, sizeof (y2));
+  z += memcmp (x, y, sizeof (y) + 0);
+  z += memcmp (x, y1, 0 + sizeof (y2));
+  z += memcmp (x, (void *) &c, sizeof (&c));
+  z += memcmp (x, (signed char *) &c, sizeof (&c));
+  z += memcmp (x, &c, sizeof (&c) + 0);
+  z += memcmp (x, &c, 0 + sizeof (&c));
+
+  return z;
+}
+
+int
+f4 (char *x, char **y, int z)
+{
+  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" }
+  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" }
+
+  // These are correct, no warning. 
+  const char s3[] = "foobarbaz";
+  const char s4[] = "abcde12345678";
+  strncpy (x, s3, sizeof (s3));
+  strncat (x, s4, sizeof (s4));
+  y[1] = strndup (s3, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s4));
+  z += strncasecmp (s3, s4, sizeof (s3));
+  z += strncasecmp (s3, s4, sizeof (s4));
+
+  return z;
+}
+
+// { dg-prune-output "\[\n\r\]*will always overflow\[\n\r\]*" }
--- gcc/testsuite/g++.dg/ext/builtin30.C.jj	2012-08-16 15:35:44.573784210 +0200
+++ gcc/testsuite/g++.dg/ext/builtin30.C	2012-08-16 15:35:44.573784210 +0200
@@ -0,0 +1,27 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+
+typedef __SIZE_TYPE__ size_t;
+extern "C" {
+extern void __chk_fail (void);
+extern int snprintf (char *, size_t, const char *, ...);
+extern inline __attribute__((gnu_inline, always_inline)) int snprintf (char *a, size_t b, const char *fmt, ...)
+{
+  if (__builtin_object_size (a, 0) != -1UL && __builtin_object_size (a, 0) < b)
+    __chk_fail ();
+  return __builtin_snprintf (a, b, fmt, __builtin_va_arg_pack ());
+}
+extern int snprintf (char *, size_t, const char *, ...) __asm ("mysnprintf");
+}
+
+char buf[10];
+
+int
+main (void)
+{
+  snprintf (buf, 10, "%d%d\n", 10, 10);
+  return 0;
+}
+
+// { dg-final { scan-assembler "mysnprintf" } }
+// { dg-final { scan-assembler-not "__chk_fail" } }
--- gcc/testsuite/gcc.dg/builtins-85.c.jj	2012-08-16 15:35:44.568784234 +0200
+++ gcc/testsuite/gcc.dg/builtins-85.c	2012-08-16 15:35:44.568784234 +0200
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+extern void __chk_fail (void);
+extern int snprintf (char *, size_t, const char *, ...);
+extern inline __attribute__((gnu_inline, always_inline)) int snprintf (char *a, size_t b, const char *fmt, ...)
+{
+  if (__builtin_object_size (a, 0) != -1UL && __builtin_object_size (a, 0) < b)
+    __chk_fail ();
+  return __builtin_snprintf (a, b, fmt, __builtin_va_arg_pack ());
+}
+extern int snprintf (char *, size_t, const char *, ...) __asm ("mysnprintf");
+
+char buf[10];
+
+int
+main (void)
+{
+  snprintf (buf, 10, "%d%d\n", 10, 10);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mysnprintf" } } */
+/* { dg-final { scan-assembler-not "__chk_fail" } } */

	Jakub

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [C++ PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-16 19:20 [C++ PATCH] -Wsizeof-pointer-memaccess warning Jakub Jelinek
@ 2012-09-19 13:58 ` Jason Merrill
  2012-09-25 16:28   ` Jakub Jelinek
  0 siblings, 1 reply; 16+ messages in thread
From: Jason Merrill @ 2012-09-19 13:58 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

Hmm.  This is a rather intrusive change to work around the problem of 
early folding, which we'd like to move away from anyway.  How does it 
work to always keep SIZEOF_EXPR unfolded until cxx_eval_constant_expression?

Jason

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [C++ PATCH] -Wsizeof-pointer-memaccess warning
  2012-09-19 13:58 ` Jason Merrill
@ 2012-09-25 16:28   ` Jakub Jelinek
  2012-10-02 12:57     ` [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2) Jakub Jelinek
  0 siblings, 1 reply; 16+ messages in thread
From: Jakub Jelinek @ 2012-09-25 16:28 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Wed, Sep 19, 2012 at 09:57:51AM -0400, Jason Merrill wrote:
> Hmm.  This is a rather intrusive change to work around the problem
> of early folding, which we'd like to move away from anyway.  How
> does it work to always keep SIZEOF_EXPR unfolded until
> cxx_eval_constant_expression?

Ok, I've tried that, but it is getting uglier and uglier.

Here is the current patch.  One issue already mentioned on IRC is
that generic code like contains_placeholder_p, save_expr etc.
got confused by SIZEOF_EXPR having type as argument instead of expression.
So for !processing_template_decl this patch uses instead NOP_EXPR with
error_mark_node operand and type on the NOP_EXPR, plus SIZEOF_EXPR_TYPE_P
bit set on the SIZEOF_EXPR (we need location on the sizeof expression, so
it should be expression).  The patch solves that thing.

The remaining unsolved issues are two regressions, one is error
FAIL: g++.dg/warn/Wnull-conversion-1.C -std=gnu++98 (test for excess errors)
FAIL: g++.dg/warn/Wnull-conversion-1.C -std=gnu++11 (test for excess errors)
on the
  int* r = sizeof(char) / 2;
line.  Is that even valid C++11?  C++03?  The thing is that we previously
immediately folded sizeof(char) to 1, and 1/2 into 0 and considered that as
null_ptr_cst_p.  With the patch we don't fold it anymore right away, we
have:
558	      /* Core issue 903 says only literal 0 is a null pointer constant.  */
559	      if (cxx_dialect < cxx0x)
560		t = integral_constant_value (t);
in null_ptr_cst_p but guess we'd need to perform maybe_constant_value to
actually fold any SIZEOF_EXPRs in it into 0.  Or use
fold_sizeof_expr_r (? if !TREE_SIDE_EFFECTS) like in
compute_array_index_type.

The other issue is Obj-C++ ICE, in cp_build_binary_op I've added
+         tree oop0 = maybe_constant_value (orig_op0);
+         tree oop1 = maybe_constant_value (orig_op1);
calls to make bootstrap possible (otherwise g++ would start warning about
  if (read (...., sizeof (something)) != sizeof (something))
because one expression is signed while the other is unsigned (but we disable
that warning for small constants that fit into the other type, if
SIZEOF_EXPR isn't folded, we don't).  Unfortunately, for Obj-C++, sometimes
orig_op0/orig_op1 contains ObjC specific tree codes like PROPERTY_REF, on
which cxx_eval_constant_expression ICEs:
7938	    default:
7939	      internal_error ("unexpected expression %qE of kind %s", t,
7940			      tree_code_name[TREE_CODE (t)]);
7941	      *non_constant_p = true;
No idea what to do about that unfortunately, we don't have any handy macro
to tell us the ObjC tree code range, we'd need to enumerate the Obj-C++ tree
codes which we don't want to ICE on (and just set *non_constant_p on them
instead).  We have objc_is_property_ref predicate, but not sure about the
other ObjC trees.
Perhaps I should just revert that cp_build_binary_op change, but what to
replace it with?

2012-09-25  Jakub Jelinek  <jakub@redhat.com>

cp/
	* cp-tree.h (SIZEOF_EXPR_TYPE_P): Define.
	* tree.c (cp_tree_equal): Handle SIZEOF_EXPR with
	SIZEOF_EXPR_TYPE_P.
	* mangle.c (write_expression): Likewise.
	* cxx-pretty-print.c (pp_cxx_unary_expression): Likewise.
	* error.c (dump_expr): Likewise.
	* parser.c (cp_parser_unary_expression): For sizeof call
	cxx_sizeof_or_alignof_{type,expr} just for diagnostics and
	return SIZEOF_EXPR with the operand.
	* pt.c (tsubst_copy, tsubst_copy_and_build): For SIZEOF_EXPR,
	call cxx_sizeof_or_alignof_{type,expr} for diagnostics, but
	return SIZEOF_EXPR with tsubsted operand.
	(value_dependent_expression_p): Handle SIZEOF_EXPR with
	SIZEOF_EXPR_TYPE_P.
	(instantiation_dependent_r): Likewise.
	* semantics.c (finish_call_expr): Call
	sizeof_pointer_memaccess_warning if needed.
	(cxx_eval_constant_expression): For SIZEOF_EXPR.
	* decl.c (duplicate_decls): When redeclaring a builtin function,
        keep the merged decl builtin also if newdecl is a gnu_inline
	inline definition.
	(fold_sizeof_expr_r): New function.
	(compute_array_index_type): Fold SIZEOF_EXPRs in itype.
	* cp-gimplify.c (cp_genericize_r): Fold SIZEOF_EXPR.
	* typeck.c (cp_build_binary_op): For warn_for_sign_compare
	try harder using maybe_constant_value to get INTEGER_CSTs.

	* decl.c (stabilize_vla_size): Call pointer_set_destroy
	at the end.
testsuite/
	* g++.dg/torture/Wsizeof-pointer-memaccess1.C: New test.
	* g++.dg/torture/Wsizeof-pointer-memaccess2.C: New test.
	* g++.dg/warn/Wsign-compare-5.C: New test.
	* g++.dg/warn/Wsizeof-pointer-memaccess-1.C: New test.
	* g++.dg/ext/builtin30.C: New test.
	* g++.dg/ext/vla12.C: New test.
	* gcc.dg/builtins-85.c: New test.
libstdc++-v3/
	* testsuite/20_util/shared_ptr/cons/43820_neg.cc: Adjust line
	numbers.

--- gcc/cp/cp-tree.h.jj	2012-09-12 10:57:01.000000000 +0200
+++ gcc/cp/cp-tree.h	2012-09-24 19:36:27.946331084 +0200
@@ -79,6 +79,7 @@ c-common.h, not after.
       OVL_ARG_DEPENDENT (in OVERLOAD)
       PACK_EXPANSION_LOCAL_P (in *_PACK_EXPANSION)
       TINFO_RECHECK_ACCESS_P (in TEMPLATE_INFO)
+      SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR)
    1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
       TI_PENDING_TEMPLATE_FLAG.
       TEMPLATE_PARMS_FOR_INLINE.
@@ -4044,6 +4045,10 @@ more_aggr_init_expr_args_p (const aggr_i
 #define CONVERT_EXPR_VBASE_PATH(NODE) \
   TREE_LANG_FLAG_0 (CONVERT_EXPR_CHECK (NODE))
 
+/* True if SIZEOF_EXPR argument is type.  */
+#define SIZEOF_EXPR_TYPE_P(NODE) \
+  TREE_LANG_FLAG_0 (SIZEOF_EXPR_CHECK (NODE))
+
 /* An enumeration of the kind of tags that C++ accepts.  */
 enum tag_types {
   none_type = 0, /* Not a tag type.  */
--- gcc/cp/cp-gimplify.c.jj	2012-09-14 14:20:55.000000000 +0200
+++ gcc/cp/cp-gimplify.c	2012-09-25 09:51:09.947883720 +0200
@@ -1119,6 +1119,22 @@ cp_genericize_r (tree *stmt_p, int *walk
     genericize_break_stmt (stmt_p);
   else if (TREE_CODE (stmt) == OMP_FOR)
     genericize_omp_for_stmt (stmt_p, walk_subtrees, data);
+  else if (TREE_CODE (stmt) == SIZEOF_EXPR)
+    {
+      if (SIZEOF_EXPR_TYPE_P (stmt))
+	*stmt_p
+	  = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (stmt, 0)),
+					SIZEOF_EXPR, false);
+      else if (TYPE_P (TREE_OPERAND (stmt, 0)))
+	*stmt_p = cxx_sizeof_or_alignof_type (TREE_OPERAND (stmt, 0),
+					      SIZEOF_EXPR, false);
+      else
+	*stmt_p = cxx_sizeof_or_alignof_expr (TREE_OPERAND (stmt, 0),
+					      SIZEOF_EXPR, false);
+      if (*stmt_p == error_mark_node)
+	*stmt_p = size_one_node;
+      return NULL;
+    }    
 
   pointer_set_insert (p_set, *stmt_p);
 
--- gcc/cp/semantics.c.jj	2012-09-20 13:40:38.063143375 +0200
+++ gcc/cp/semantics.c	2012-09-25 09:52:26.125474643 +0200
@@ -2170,8 +2170,25 @@ finish_call_expr (tree fn, VEC(tree,gc)
 	result = resolve_overloaded_builtin (input_location, fn, *args);
 
       if (!result)
-	/* A call to a namespace-scope function.  */
-	result = build_new_function_call (fn, args, koenig_p, complain);
+	{
+	  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);
+	      sizeof_pointer_memaccess_warning
+		(EXPR_LOCATION (VEC_last(tree, *args)), fn, *args,
+		 sizeof_arg, same_type_ignoring_top_level_qualifiers_p);
+	    }
+
+	  /* A call to a namespace-scope function.  */
+	  result = build_new_function_call (fn, args, koenig_p, complain);
+	}
     }
   else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
     {
@@ -7723,6 +7740,21 @@ cxx_eval_constant_expression (const cons
 				     non_constant_p);
       break;
 
+    case SIZEOF_EXPR:
+      if (SIZEOF_EXPR_TYPE_P (t))
+	r = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (t, 0)),
+					SIZEOF_EXPR, false);
+      else if (TYPE_P (TREE_OPERAND (t, 0)))
+	r = cxx_sizeof_or_alignof_type (TREE_OPERAND (t, 0), SIZEOF_EXPR,
+					false);
+      else
+	r = cxx_sizeof_or_alignof_expr (TREE_OPERAND (t, 0), SIZEOF_EXPR,
+					false);
+      if (r == error_mark_node)
+	r = size_one_node;
+      VERIFY_CONSTANT (r);
+      break;
+
     case COMPOUND_EXPR:
       {
 	/* check_return_expr sometimes wraps a TARGET_EXPR in a
--- gcc/cp/tree.c.jj	2012-09-14 14:20:55.000000000 +0200
+++ gcc/cp/tree.c	2012-09-25 09:23:31.339552861 +0200
@@ -2602,6 +2602,10 @@ cp_tree_equal (tree t1, tree t2)
 	tree o1 = TREE_OPERAND (t1, 0);
 	tree o2 = TREE_OPERAND (t2, 0);
 
+	if (SIZEOF_EXPR_TYPE_P (t1))
+	  o1 = TREE_TYPE (o1);
+	if (SIZEOF_EXPR_TYPE_P (t2))
+	  o2 = TREE_TYPE (o2);
 	if (TREE_CODE (o1) != TREE_CODE (o2))
 	  return false;
 	if (TYPE_P (o1))
--- gcc/cp/mangle.c.jj	2012-09-14 14:20:55.000000000 +0200
+++ gcc/cp/mangle.c	2012-09-25 09:26:58.019501621 +0200
@@ -2581,6 +2581,12 @@ write_expression (tree expr)
       write_char ('E');
     }
   else if (TREE_CODE (expr) == SIZEOF_EXPR
+	   && SIZEOF_EXPR_TYPE_P (expr))
+    {
+      write_string ("st");
+      write_type (TREE_TYPE (TREE_OPERAND (expr, 0)));
+    }
+  else if (TREE_CODE (expr) == SIZEOF_EXPR
 	   && TYPE_P (TREE_OPERAND (expr, 0)))
     {
       write_string ("st");
--- gcc/cp/decl.c.jj	2012-09-20 13:40:38.055143423 +0200
+++ gcc/cp/decl.c	2012-09-25 10:45:15.627068660 +0200
@@ -2154,39 +2154,40 @@ duplicate_decls (tree newdecl, tree oldd
 	  DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl);
 	  DECL_RESULT (olddecl) = DECL_RESULT (newdecl);
 	}
+      /* If redeclaring a builtin function, it stays built in
+	 if newdecl is a gnu_inline definition, or if newdecl is just
+	 a declaration.  */
+      if (DECL_BUILT_IN (olddecl)
+	  && (new_defines_function ? GNU_INLINE_P (newdecl) : types_match))
+	{
+	  DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
+	  DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+	  /* If we're keeping the built-in definition, keep the rtl,
+	     regardless of declaration matches.  */
+	  COPY_DECL_RTL (olddecl, newdecl);
+	  if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
+	    {
+	      enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl);
+	      switch (fncode)
+		{
+		  /* If a compatible prototype of these builtin functions
+		     is seen, assume the runtime implements it with the
+		     expected semantics.  */
+		case BUILT_IN_STPCPY:
+		  if (builtin_decl_explicit_p (fncode))
+		    set_builtin_decl_implicit_p (fncode, true);
+		  break;
+		default:
+		  break;
+		}
+	    }
+	}
       if (new_defines_function)
 	/* If defining a function declared with other language
 	   linkage, use the previously declared language linkage.  */
 	SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl));
       else if (types_match)
 	{
-	  /* If redeclaring a builtin function, and not a definition,
-	     it stays built in.  */
-	  if (DECL_BUILT_IN (olddecl))
-	    {
-	      DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
-	      DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
-	      /* If we're keeping the built-in definition, keep the rtl,
-		 regardless of declaration matches.  */
-	      COPY_DECL_RTL (olddecl, newdecl);
-	      if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
-		{
-		  enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl);
-		  switch (fncode)
-		    {
-		      /* If a compatible prototype of these builtin functions
-			 is seen, assume the runtime implements it with the
-			 expected semantics.  */
-		    case BUILT_IN_STPCPY:
-		      if (builtin_decl_explicit_p (fncode))
-			set_builtin_decl_implicit_p (fncode, true);
-		      break;
-		    default:
-		      break;
-		    }
-		}
-	    }
-
 	  DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
 	  /* Don't clear out the arguments if we're just redeclaring a
 	     function.  */
@@ -7921,6 +7922,36 @@ stabilize_vla_size (tree size)
   struct pointer_set_t *pset = pointer_set_create ();
   /* Break out any function calls into temporary variables.  */
   cp_walk_tree (&size, stabilize_save_expr_r, pset, pset);
+  pointer_set_destroy (pset);
+}
+
+/* Helper function for compute_array_index_type.  Look for SIZEOF_EXPR
+   not inside of SAVE_EXPR and fold them.  */
+
+static tree
+fold_sizeof_expr_r (tree *expr_p, int *walk_subtrees, void *data)
+{
+  tree expr = *expr_p;
+  if (TREE_CODE (expr) == SAVE_EXPR || TYPE_P (expr))
+    *walk_subtrees = 0;
+  else if (TREE_CODE (expr) == SIZEOF_EXPR)
+    {
+      *(bool *)data = true;
+      if (SIZEOF_EXPR_TYPE_P (expr))
+	expr = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (expr, 0)),
+					   SIZEOF_EXPR, false);
+      else if (TYPE_P (TREE_OPERAND (expr, 0)))
+	expr = cxx_sizeof_or_alignof_type (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
+					   false);
+      else
+        expr = cxx_sizeof_or_alignof_expr (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
+					   false);
+      if (expr == error_mark_node)
+        expr = size_one_node;
+      *expr_p = expr;
+      *walk_subtrees = 0;
+    }
+  return NULL;
 }
 
 /* Given the SIZE (i.e., number of elements) in an array, compute an
@@ -8116,8 +8147,21 @@ compute_array_index_type (tree name, tre
       processing_template_decl = saved_processing_template_decl;
 
       if (!TREE_CONSTANT (itype))
-	/* A variable sized array.  */
-	itype = variable_size (itype);
+	{
+	  /* A variable sized array.  */
+	  itype = variable_size (itype);
+	  if (TREE_CODE (itype) != SAVE_EXPR)
+	    {
+	      /* Look for SIZEOF_EXPRs in itype and fold them, otherwise
+		 they might survive till gimplification.  */
+	      tree newitype = itype;
+	      bool found = false;
+	      cp_walk_tree_without_duplicates (&newitype,
+					       fold_sizeof_expr_r, &found);
+	      if (found)
+		itype = variable_size (fold (newitype));
+	    }
+	}
       /* Make sure that there was no overflow when creating to a signed
 	 index type.  (For example, on a 32-bit machine, an array with
 	 size 2^32 - 1 is too big.)  */
--- gcc/cp/cxx-pretty-print.c.jj	2012-08-10 12:57:26.000000000 +0200
+++ gcc/cp/cxx-pretty-print.c	2012-09-24 19:20:59.846433758 +0200
@@ -798,7 +798,13 @@ pp_cxx_unary_expression (cxx_pretty_prin
     case ALIGNOF_EXPR:
       pp_cxx_ws_string (pp, code == SIZEOF_EXPR ? "sizeof" : "__alignof__");
       pp_cxx_whitespace (pp);
-      if (TYPE_P (TREE_OPERAND (t, 0)))
+      if (TREE_CODE (t) == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (t))
+	{
+	  pp_cxx_left_paren (pp);
+	  pp_cxx_type_id (pp, TREE_TYPE (TREE_OPERAND (t, 0)));
+	  pp_cxx_right_paren (pp);
+	}
+      else if (TYPE_P (TREE_OPERAND (t, 0)))
 	{
 	  pp_cxx_left_paren (pp);
 	  pp_cxx_type_id (pp, TREE_OPERAND (t, 0));
--- gcc/cp/typeck.c.jj	2012-09-17 11:13:13.241074760 +0200
+++ gcc/cp/typeck.c	2012-09-25 09:22:16.334988243 +0200
@@ -4619,7 +4619,14 @@ cp_build_binary_op (location_t location,
 	  && !enum_cast_to_int (orig_op0)
 	  && !enum_cast_to_int (orig_op1))
 	{
-	  warn_for_sign_compare (location, orig_op0, orig_op1, op0, op1, 
+	  tree oop0 = maybe_constant_value (orig_op0);
+	  tree oop1 = maybe_constant_value (orig_op1);
+
+	  if (TREE_CODE (oop0) != INTEGER_CST)
+	    oop0 = orig_op0;
+	  if (TREE_CODE (oop1) != INTEGER_CST)
+	    oop1 = orig_op1;
+	  warn_for_sign_compare (location, oop0, oop1, op0, op1, 
 				 result_type, resultcode);
 	}
     }
--- gcc/cp/parser.c.jj	2012-09-20 13:40:38.044143486 +0200
+++ gcc/cp/parser.c	2012-09-25 09:21:16.881333051 +0200
@@ -6382,17 +6382,19 @@ cp_parser_unary_expression (cp_parser *p
 	case RID_ALIGNOF:
 	case RID_SIZEOF:
 	  {
-	    tree operand;
+	    tree operand, ret;
 	    enum tree_code op;
+	    location_t first_loc;
 
 	    op = keyword == RID_ALIGNOF ? ALIGNOF_EXPR : SIZEOF_EXPR;
 	    /* Consume the token.  */
 	    cp_lexer_consume_token (parser->lexer);
+	    first_loc = cp_lexer_peek_token (parser->lexer)->location;
 	    /* Parse the operand.  */
 	    operand = cp_parser_sizeof_operand (parser, keyword);
 
 	    if (TYPE_P (operand))
-	      return cxx_sizeof_or_alignof_type (operand, op, true);
+	      ret = cxx_sizeof_or_alignof_type (operand, op, true);
 	    else
 	      {
 		/* ISO C++ defines alignof only with types, not with
@@ -6403,8 +6405,29 @@ cp_parser_unary_expression (cp_parser *p
 			   "ISO C++ does not allow %<alignof%> "
 			   "with a non-type");
 
-		return cxx_sizeof_or_alignof_expr (operand, op, true);
+		ret = cxx_sizeof_or_alignof_expr (operand, op, true);
 	      }
+	    /* For SIZEOF_EXPR, just issue diagnostics, but keep
+	       SIZEOF_EXPR with the original operand.  */
+	    if (op == SIZEOF_EXPR && ret != error_mark_node)
+	      {
+		if (TREE_CODE (ret) != SIZEOF_EXPR || TYPE_P (operand))
+		  {
+		    if (!processing_template_decl && TYPE_P (operand))
+		      {
+			ret = build_min (SIZEOF_EXPR, size_type_node,
+					 build1 (NOP_EXPR, operand,
+						 error_mark_node));
+			SIZEOF_EXPR_TYPE_P (ret) = 1;
+		      }
+		    else
+		      ret = build_min (SIZEOF_EXPR, size_type_node, operand);
+		    TREE_SIDE_EFFECTS (ret) = 0;
+		    TREE_READONLY (ret) = 1;
+		  }
+		SET_EXPR_LOCATION (ret, first_loc);
+	      }
+	    return ret;
 	  }
 
 	case RID_NEW:
--- gcc/cp/pt.c.jj	2012-09-20 16:22:28.000000000 +0200
+++ gcc/cp/pt.c	2012-09-25 09:28:34.661048655 +0200
@@ -12031,14 +12031,16 @@ tsubst_copy (tree t, tree args, tsubst_f
       if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
         {
 
-          tree expanded;
+          tree expanded, op = TREE_OPERAND (t, 0);
 	  int len = 0;
 
+	  if (SIZEOF_EXPR_TYPE_P (t))
+	    op = TREE_TYPE (op);
+
 	  ++cp_unevaluated_operand;
 	  ++c_inhibit_evaluation_warnings;
 	  /* We only want to compute the number of arguments.  */
-	  expanded = tsubst_pack_expansion (TREE_OPERAND (t, 0), args,
-					    complain, in_decl);
+	  expanded = tsubst_pack_expansion (op, args, complain, in_decl);
 	  --cp_unevaluated_operand;
 	  --c_inhibit_evaluation_warnings;
 
@@ -12065,6 +12067,16 @@ tsubst_copy (tree t, tree args, tsubst_f
 	  else
 	    return build_int_cst (size_type_node, len);
         }
+      if (SIZEOF_EXPR_TYPE_P (t))
+	{
+	  r = tsubst_copy (TREE_TYPE (TREE_OPERAND (t, 0)),
+			   args, complain, in_decl);
+	  r = build1 (NOP_EXPR, r, error_mark_node);
+	  r = build1 (SIZEOF_EXPR,
+		      tsubst (TREE_TYPE (t), args, complain, in_decl), r);
+	  SIZEOF_EXPR_TYPE_P (r) = 1;
+	  return r;
+	}
       /* Fall through */
 
     case INDIRECT_REF:
@@ -13468,31 +13480,56 @@ tsubst_copy_and_build (tree t,
       /* Fall through */
       
     case ALIGNOF_EXPR:
-      op1 = TREE_OPERAND (t, 0);
-      if (!args)
-	{
-	  /* When there are no ARGS, we are trying to evaluate a
-	     non-dependent expression from the parser.  Trying to do
-	     the substitutions may not work.  */
-	  if (!TYPE_P (op1))
-	    op1 = TREE_TYPE (op1);
-	}
-      else
-	{
-	  ++cp_unevaluated_operand;
-	  ++c_inhibit_evaluation_warnings;
-	  op1 = tsubst_copy_and_build (op1, args, complain, in_decl,
-				       /*function_p=*/false,
-				       /*integral_constant_expression_p=*/false);
-	  --cp_unevaluated_operand;
-	  --c_inhibit_evaluation_warnings;
-	}
-      if (TYPE_P (op1))
-	RETURN (cxx_sizeof_or_alignof_type (op1, TREE_CODE (t),
-                                           complain & tf_error));
-      else
-	RETURN (cxx_sizeof_or_alignof_expr (op1, TREE_CODE (t),
-                                           complain & tf_error));
+      {
+	tree r;
+
+	op1 = TREE_OPERAND (t, 0);
+	if (TREE_CODE (t) == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (t))
+	  op1 = TREE_TYPE (op1);
+        if (!args)
+	  {
+	    /* When there are no ARGS, we are trying to evaluate a
+	       non-dependent expression from the parser.  Trying to do
+	       the substitutions may not work.  */
+	    if (!TYPE_P (op1))
+	      op1 = TREE_TYPE (op1);
+	  }
+	else
+	  {
+	    ++cp_unevaluated_operand;
+	    ++c_inhibit_evaluation_warnings;
+	    op1 = tsubst_copy_and_build (op1, args, complain, in_decl,
+					 /*function_p=*/false,
+					 /*integral_constant_expression_p=*/
+					 false);
+	    --cp_unevaluated_operand;
+	    --c_inhibit_evaluation_warnings;
+	  }
+        if (TYPE_P (op1))
+	  r = cxx_sizeof_or_alignof_type (op1, TREE_CODE (t),
+					  complain & tf_error);
+	else
+	  r = cxx_sizeof_or_alignof_expr (op1, TREE_CODE (t),
+					  complain & tf_error);
+	if (TREE_CODE (t) == SIZEOF_EXPR && r != error_mark_node)
+	  {
+	    if (TREE_CODE (r) != SIZEOF_EXPR || TYPE_P (op1))
+	      {
+		if (TYPE_P (op1))
+		  {
+		    r = build_min (SIZEOF_EXPR, size_type_node,
+				   build1 (NOP_EXPR, op1, error_mark_node));
+		    SIZEOF_EXPR_TYPE_P (r) = 1;
+		  }
+		else
+		  r = build_min (SIZEOF_EXPR, size_type_node, op1);
+		TREE_SIDE_EFFECTS (r) = 0;
+		TREE_READONLY (r) = 1;
+	      }
+	    SET_EXPR_LOCATION (r, EXPR_LOCATION (t));
+	  }
+	RETURN (r);
+      }
 
     case AT_ENCODE_EXPR:
       {
@@ -19287,6 +19324,9 @@ value_dependent_expression_p (tree expre
       }
 
     case SIZEOF_EXPR:
+      if (SIZEOF_EXPR_TYPE_P (expression))
+	return dependent_type_p (TREE_TYPE (TREE_OPERAND (expression, 0)));
+      /* FALLTHRU */
     case ALIGNOF_EXPR:
     case TYPEID_EXPR:
       /* A `sizeof' expression is value-dependent if the operand is
@@ -19626,6 +19666,8 @@ instantiation_dependent_r (tree *tp, int
     case TRAIT_EXPR:
       {
 	tree op = TREE_OPERAND (*tp, 0);
+	if (code == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (*tp))
+	  op = TREE_TYPE (op);
 	if (TYPE_P (op))
 	  {
 	    if (dependent_type_p (op)
--- gcc/cp/error.c.jj	2012-09-14 14:20:55.000000000 +0200
+++ gcc/cp/error.c	2012-09-24 19:19:34.742901173 +0200
@@ -2312,7 +2312,9 @@ dump_expr (tree t, int flags)
 	}
       pp_cxx_whitespace (cxx_pp);
       pp_cxx_left_paren (cxx_pp);
-      if (TYPE_P (TREE_OPERAND (t, 0)))
+      if (TREE_CODE (t) == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (t))
+	dump_type (TREE_TYPE (TREE_OPERAND (t, 0)), flags);
+      else if (TYPE_P (TREE_OPERAND (t, 0)))
 	dump_type (TREE_OPERAND (t, 0), flags);
       else
 	dump_expr (TREE_OPERAND (t, 0), flags);
--- gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C.jj	2012-09-21 15:48:05.367214310 +0200
+++ gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C	2012-09-21 15:48:05.367214310 +0200
@@ -0,0 +1,716 @@
+// Test -Wsizeof-pointer-memaccess warnings.
+// { dg-do compile }
+// { dg-options "-Wall" }
+// Test just twice, once with -O0 non-fortified, once with -O2 fortified.
+// { dg-skip-if "" { *-*-* }  { "*" } { "-O0" "-O2" } }
+// { dg-skip-if "" { *-*-* }  { "-flto" } { "" } }
+
+extern "C" {
+
+typedef __SIZE_TYPE__ size_t;
+extern void *memset (void *, int, size_t);
+extern void *memcpy (void *__restrict, const void *__restrict, size_t);
+extern void *memmove (void *__restrict, const void *__restrict, size_t);
+extern int memcmp (const void *, const void *, size_t);
+extern char *strncpy (char *__restrict, const char *__restrict, size_t);
+extern char *strncat (char *__restrict, const char *__restrict, size_t);
+extern char *strndup (const char *, size_t);
+extern int strncmp (const char *, const char *, size_t);
+extern int strncasecmp (const char *, const char *, size_t);
+
+#ifdef __OPTIMIZE__
+# define bos(ptr) __builtin_object_size (ptr, 1)
+# define bos0(ptr) __builtin_object_size (ptr, 0)
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memset (void *dest, int c, size_t len)
+{
+  return __builtin___memset_chk (dest, c, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memcpy (void *__restrict dest, const void *__restrict src, size_t len)
+{
+  return __builtin___memcpy_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memmove (void *dest, const void *src, size_t len)
+{
+  return __builtin___memmove_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncpy (char *__restrict dest, const char *__restrict src, size_t len)
+{
+  return __builtin___strncpy_chk (dest, src, len, bos (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncat (char *dest, const char *src, size_t len)
+{
+  return __builtin___strncat_chk (dest, src, len, bos (dest));
+}
+#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];
+
+template <int N>
+int
+f1 (void *x, int z)
+{
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (&a, x, sizeof a);
+  z += memcmp (&a, x, sizeof (a));
+  z += memcmp (&a, x, sizeof (struct A));
+  z += memcmp (&a, x, sizeof (const struct A));
+  z += memcmp (&a, x, sizeof (volatile struct A));
+  z += memcmp (&a, x, sizeof (volatile const struct A));
+  z += memcmp (&a, x, sizeof (TA));
+  z += memcmp (&a, x, sizeof (__typeof (*&a)));
+  z += memcmp (pa1, x, sizeof (*pa1));
+  z += memcmp (pa2, x, sizeof (*pa3));
+  z += memcmp (pa3, x, sizeof (__typeof (*pa3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) &a, x, sizeof (&a));
+  z += memcmp ((char *) &a, x, sizeof (&a));
+  z += memcmp (&a, x, sizeof (&a) + 0);
+  z += memcmp (&a, x, 0 + sizeof (&a));
+
+  // These are correct, no warning. 
+  z += memcmp (x, &a, sizeof a);
+  z += memcmp (x, &a, sizeof (a));
+  z += memcmp (x, &a, sizeof (struct A));
+  z += memcmp (x, &a, sizeof (const struct A));
+  z += memcmp (x, &a, sizeof (volatile struct A));
+  z += memcmp (x, &a, sizeof (volatile const struct A));
+  z += memcmp (x, &a, sizeof (TA));
+  z += memcmp (x, &a, sizeof (__typeof (*&a)));
+  z += memcmp (x, pa1, sizeof (*pa1));
+  z += memcmp (x, pa2, sizeof (*pa3));
+  z += memcmp (x, pa3, sizeof (__typeof (*pa3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) &a, sizeof (&a));
+  z += memcmp (x, (char *) &a, sizeof (&a));
+  z += memcmp (x, &a, sizeof (&a) + 0);
+  z += memcmp (x, &a, 0 + sizeof (&a));
+
+  return z;
+}
+
+template <int N>
+int
+f2 (void *x, int z)
+{
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (&b, x, sizeof b);
+  z += memcmp (&b, x, sizeof (b));
+  z += memcmp (&b, x, sizeof (struct B));
+  z += memcmp (&b, x, sizeof (const struct B));
+  z += memcmp (&b, x, sizeof (volatile struct B));
+  z += memcmp (&b, x, sizeof (volatile const struct B));
+  z += memcmp (&b, x, sizeof (TB));
+  z += memcmp (&b, x, sizeof (__typeof (*&b)));
+  z += memcmp (pb1, x, sizeof (*pb1));
+  z += memcmp (pb2, x, sizeof (*pb3));
+  z += memcmp (pb3, x, sizeof (__typeof (*pb3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) &b, x, sizeof (&b));
+  z += memcmp ((char *) &b, x, sizeof (&b));
+  z += memcmp (&b, x, sizeof (&b) + 0);
+  z += memcmp (&b, x, 0 + sizeof (&b));
+
+  // These are correct, no warning. 
+  z += memcmp (x, &b, sizeof b);
+  z += memcmp (x, &b, sizeof (b));
+  z += memcmp (x, &b, sizeof (struct B));
+  z += memcmp (x, &b, sizeof (const struct B));
+  z += memcmp (x, &b, sizeof (volatile struct B));
+  z += memcmp (x, &b, sizeof (volatile const struct B));
+  z += memcmp (x, &b, sizeof (TB));
+  z += memcmp (x, &b, sizeof (__typeof (*&b)));
+  z += memcmp (x, pb1, sizeof (*pb1));
+  z += memcmp (x, pb2, sizeof (*pb3));
+  z += memcmp (x, pb3, sizeof (__typeof (*pb3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) &b, sizeof (&b));
+  z += memcmp (x, (char *) &b, sizeof (&b));
+  z += memcmp (x, &b, sizeof (&b) + 0);
+  z += memcmp (x, &b, 0 + sizeof (&b));
+
+  return z;
+}
+
+template <int N>
+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;
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (y, x, sizeof (*y));
+  z += memcmp (y1, x, sizeof (*y2));
+  z += memcmp (buf1, x, sizeof buf1);
+  z += memcmp (buf3, x, sizeof (buf3));
+  z += memcmp (&buf3[0], x, sizeof (buf3));
+  z += memcmp (&buf4[0], x, sizeof (buf4));
+  z += memcmp (&y3, y, sizeof (y3));
+  z += memcmp ((char *) &y3, y, sizeof (y3));
+  z += memcmp (w, x, sizeof (X));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) y, x, sizeof (y));
+  z += memcmp ((char *) y1, x, sizeof (y2));
+  z += memcmp (y, x, sizeof (y) + 0);
+  z += memcmp (y1, x, 0 + sizeof (y2));
+  z += memcmp ((void *) &c, x, sizeof (&c));
+  z += memcmp ((signed char *) &c, x, sizeof (&c));
+  z += memcmp (&c, x, sizeof (&c) + 0);
+  z += memcmp (&c, x, 0 + sizeof (&c));
+
+  // These are correct, no warning. 
+  z += memcmp (x, y, sizeof (*y));
+  z += memcmp (x, y1, sizeof (*y2));
+  z += memcmp (x, buf1, sizeof buf1);
+  z += memcmp (x, buf3, sizeof (buf3));
+  z += memcmp (x, &buf3[0], sizeof (buf3));
+  z += memcmp (x, &buf4[0], sizeof (buf4));
+  z += memcmp (y, &y3, sizeof (y3));
+  z += memcmp (y, (char *) &y3, sizeof (y3));
+  z += memcmp (x, w, sizeof (X));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) y, sizeof (y));
+  z += memcmp (x, (char *) y1, sizeof (y2));
+  z += memcmp (x, y, sizeof (y) + 0);
+  z += memcmp (x, y1, 0 + sizeof (y2));
+  z += memcmp (x, (void *) &c, sizeof (&c));
+  z += memcmp (x, (signed char *) &c, sizeof (&c));
+  z += memcmp (x, &c, sizeof (&c) + 0);
+  z += memcmp (x, &c, 0 + sizeof (&c));
+
+  return z;
+}
+
+template <int N>
+int
+f4 (char *x, char **y, int z)
+{
+  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" }
+  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" }
+
+  // These are correct, no warning. 
+  const char s3[] = "foobarbaz";
+  const char s4[] = "abcde12345678";
+  strncpy (x, s3, sizeof (s3));
+  strncat (x, s4, sizeof (s4));
+  y[1] = strndup (s3, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s4));
+  z += strncasecmp (s3, s4, sizeof (s3));
+  z += strncasecmp (s3, s4, sizeof (s4));
+
+  return z;
+}
+
+int
+f (void *x, char *y, int z, X w, char **u)
+{
+  z += f1<0> (x, z);
+  z += f2<0> (x, z);
+  z += f3<0> (x, y, z, w);
+  z += f4<0> (y, u, z);
+  return z;
+}
+
+// { dg-prune-output "\[\n\r\]*will always overflow\[\n\r\]*" }
--- gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C.jj	2012-09-21 15:48:05.368214305 +0200
+++ gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C	2012-09-21 15:48:05.368214305 +0200
@@ -0,0 +1,702 @@
+// Test -Wsizeof-pointer-memaccess warnings.
+// { dg-do compile }
+// { dg-options "-Wall" }
+// Test just twice, once with -O0 non-fortified, once with -O2 fortified.
+// { dg-skip-if "" { *-*-* }  { "*" } { "-O0" "-O2" } }
+// { dg-skip-if "" { *-*-* }  { "-flto" } { "" } }
+
+extern "C" {
+
+typedef __SIZE_TYPE__ size_t;
+extern void *memset (void *, int, size_t);
+extern void *memcpy (void *__restrict, const void *__restrict, size_t);
+extern void *memmove (void *__restrict, const void *__restrict, size_t);
+extern int memcmp (const void *, const void *, size_t);
+extern char *strncpy (char *__restrict, const char *__restrict, size_t);
+extern char *strncat (char *__restrict, const char *__restrict, size_t);
+extern char *strndup (const char *, size_t);
+extern int strncmp (const char *, const char *, size_t);
+extern int strncasecmp (const char *, const char *, size_t);
+
+#ifdef __OPTIMIZE__
+# define bos(ptr) __builtin_object_size (ptr, 1)
+# define bos0(ptr) __builtin_object_size (ptr, 0)
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memset (void *dest, int c, size_t len)
+{
+  return __builtin___memset_chk (dest, c, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memcpy (void *__restrict dest, const void *__restrict src, size_t len)
+{
+  return __builtin___memcpy_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memmove (void *dest, const void *src, size_t len)
+{
+  return __builtin___memmove_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncpy (char *__restrict dest, const char *__restrict src, size_t len)
+{
+  return __builtin___strncpy_chk (dest, src, len, bos (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncat (char *dest, const char *src, size_t len)
+{
+  return __builtin___strncat_chk (dest, src, len, bos (dest));
+}
+#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];
+
+int
+f1 (void *x, int z)
+{
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (&a, x, sizeof a);
+  z += memcmp (&a, x, sizeof (a));
+  z += memcmp (&a, x, sizeof (struct A));
+  z += memcmp (&a, x, sizeof (const struct A));
+  z += memcmp (&a, x, sizeof (volatile struct A));
+  z += memcmp (&a, x, sizeof (volatile const struct A));
+  z += memcmp (&a, x, sizeof (TA));
+  z += memcmp (&a, x, sizeof (__typeof (*&a)));
+  z += memcmp (pa1, x, sizeof (*pa1));
+  z += memcmp (pa2, x, sizeof (*pa3));
+  z += memcmp (pa3, x, sizeof (__typeof (*pa3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) &a, x, sizeof (&a));
+  z += memcmp ((char *) &a, x, sizeof (&a));
+  z += memcmp (&a, x, sizeof (&a) + 0);
+  z += memcmp (&a, x, 0 + sizeof (&a));
+
+  // These are correct, no warning. 
+  z += memcmp (x, &a, sizeof a);
+  z += memcmp (x, &a, sizeof (a));
+  z += memcmp (x, &a, sizeof (struct A));
+  z += memcmp (x, &a, sizeof (const struct A));
+  z += memcmp (x, &a, sizeof (volatile struct A));
+  z += memcmp (x, &a, sizeof (volatile const struct A));
+  z += memcmp (x, &a, sizeof (TA));
+  z += memcmp (x, &a, sizeof (__typeof (*&a)));
+  z += memcmp (x, pa1, sizeof (*pa1));
+  z += memcmp (x, pa2, sizeof (*pa3));
+  z += memcmp (x, pa3, sizeof (__typeof (*pa3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) &a, sizeof (&a));
+  z += memcmp (x, (char *) &a, sizeof (&a));
+  z += memcmp (x, &a, sizeof (&a) + 0);
+  z += memcmp (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;
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (&b, x, sizeof b);
+  z += memcmp (&b, x, sizeof (b));
+  z += memcmp (&b, x, sizeof (struct B));
+  z += memcmp (&b, x, sizeof (const struct B));
+  z += memcmp (&b, x, sizeof (volatile struct B));
+  z += memcmp (&b, x, sizeof (volatile const struct B));
+  z += memcmp (&b, x, sizeof (TB));
+  z += memcmp (&b, x, sizeof (__typeof (*&b)));
+  z += memcmp (pb1, x, sizeof (*pb1));
+  z += memcmp (pb2, x, sizeof (*pb3));
+  z += memcmp (pb3, x, sizeof (__typeof (*pb3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) &b, x, sizeof (&b));
+  z += memcmp ((char *) &b, x, sizeof (&b));
+  z += memcmp (&b, x, sizeof (&b) + 0);
+  z += memcmp (&b, x, 0 + sizeof (&b));
+
+  // These are correct, no warning. 
+  z += memcmp (x, &b, sizeof b);
+  z += memcmp (x, &b, sizeof (b));
+  z += memcmp (x, &b, sizeof (struct B));
+  z += memcmp (x, &b, sizeof (const struct B));
+  z += memcmp (x, &b, sizeof (volatile struct B));
+  z += memcmp (x, &b, sizeof (volatile const struct B));
+  z += memcmp (x, &b, sizeof (TB));
+  z += memcmp (x, &b, sizeof (__typeof (*&b)));
+  z += memcmp (x, pb1, sizeof (*pb1));
+  z += memcmp (x, pb2, sizeof (*pb3));
+  z += memcmp (x, pb3, sizeof (__typeof (*pb3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) &b, sizeof (&b));
+  z += memcmp (x, (char *) &b, sizeof (&b));
+  z += memcmp (x, &b, sizeof (&b) + 0);
+  z += memcmp (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;
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (y, x, sizeof (*y));
+  z += memcmp (y1, x, sizeof (*y2));
+  z += memcmp (buf1, x, sizeof buf1);
+  z += memcmp (buf3, x, sizeof (buf3));
+  z += memcmp (&buf3[0], x, sizeof (buf3));
+  z += memcmp (&buf4[0], x, sizeof (buf4));
+  z += memcmp (&y3, y, sizeof (y3));
+  z += memcmp ((char *) &y3, y, sizeof (y3));
+  z += memcmp (w, x, sizeof (X));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) y, x, sizeof (y));
+  z += memcmp ((char *) y1, x, sizeof (y2));
+  z += memcmp (y, x, sizeof (y) + 0);
+  z += memcmp (y1, x, 0 + sizeof (y2));
+  z += memcmp ((void *) &c, x, sizeof (&c));
+  z += memcmp ((signed char *) &c, x, sizeof (&c));
+  z += memcmp (&c, x, sizeof (&c) + 0);
+  z += memcmp (&c, x, 0 + sizeof (&c));
+
+  // These are correct, no warning. 
+  z += memcmp (x, y, sizeof (*y));
+  z += memcmp (x, y1, sizeof (*y2));
+  z += memcmp (x, buf1, sizeof buf1);
+  z += memcmp (x, buf3, sizeof (buf3));
+  z += memcmp (x, &buf3[0], sizeof (buf3));
+  z += memcmp (x, &buf4[0], sizeof (buf4));
+  z += memcmp (y, &y3, sizeof (y3));
+  z += memcmp (y, (char *) &y3, sizeof (y3));
+  z += memcmp (x, w, sizeof (X));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) y, sizeof (y));
+  z += memcmp (x, (char *) y1, sizeof (y2));
+  z += memcmp (x, y, sizeof (y) + 0);
+  z += memcmp (x, y1, 0 + sizeof (y2));
+  z += memcmp (x, (void *) &c, sizeof (&c));
+  z += memcmp (x, (signed char *) &c, sizeof (&c));
+  z += memcmp (x, &c, sizeof (&c) + 0);
+  z += memcmp (x, &c, 0 + sizeof (&c));
+
+  return z;
+}
+
+int
+f4 (char *x, char **y, int z)
+{
+  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" }
+  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" }
+
+  // These are correct, no warning. 
+  const char s3[] = "foobarbaz";
+  const char s4[] = "abcde12345678";
+  strncpy (x, s3, sizeof (s3));
+  strncat (x, s4, sizeof (s4));
+  y[1] = strndup (s3, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s4));
+  z += strncasecmp (s3, s4, sizeof (s3));
+  z += strncasecmp (s3, s4, sizeof (s4));
+
+  return z;
+}
+
+// { dg-prune-output "\[\n\r\]*will always overflow\[\n\r\]*" }
--- gcc/testsuite/g++.dg/warn/Wsizeof-pointer-memaccess-1.C.jj	2012-09-25 11:25:38.593933892 +0200
+++ gcc/testsuite/g++.dg/warn/Wsizeof-pointer-memaccess-1.C	2012-09-25 11:25:04.000000000 +0200
@@ -0,0 +1,13 @@
+// Test -Wsizeof-pointer-memaccess warnings.
+// { dg-do compile }
+// { dg-options "-Wall" }
+
+typedef __SIZE_TYPE__ size_t;
+extern "C" void *memset (void *, int, size_t);
+
+int
+foo (int x, char b[10])
+{
+  long a[memset (b, 0, sizeof (b)) ? x + 10 : x];	// { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length?" }
+  return a[0];
+}
--- gcc/testsuite/g++.dg/warn/Wsign-compare-5.C.jj	2012-09-24 17:07:26.190435596 +0200
+++ gcc/testsuite/g++.dg/warn/Wsign-compare-5.C	2012-09-24 17:07:17.000000000 +0200
@@ -0,0 +1,20 @@
+// Test that -Wsign-compare doesn't warn about
+// equality/non-equality comparisons with sizeof.
+// { dg-do compile }
+// { dg-options "-Wsign-compare" }
+
+int
+foo (int x)
+{
+  if (x != sizeof (sizeof (x)))		// { dg-bogus "comparison between signed and unsigned integer expressions" }
+    return 1;
+  return 0;
+}
+
+int
+bar (int x)
+{
+  if (x == sizeof (sizeof (x)) + 1)	// { dg-bogus "comparison between signed and unsigned integer expressions" }
+    return 1;
+  return 0;
+}
--- gcc/testsuite/g++.dg/ext/vla12.C.jj	2012-09-25 10:44:41.659254943 +0200
+++ gcc/testsuite/g++.dg/ext/vla12.C	2012-09-25 10:44:33.000000000 +0200
@@ -0,0 +1,28 @@
+// VLA sizeof test
+// { dg-do compile }
+// { dg-options "" }
+
+int
+f1 (int i)
+{
+  char a[sizeof (i) + 6 + i];
+  char b[sizeof (a) + 1];
+  return sizeof (b);
+}
+
+int
+f2 (int i)
+{
+  char a[sizeof (i) + 6 + i];
+  char b[sizeof (a)];
+  return sizeof (b);
+}
+
+int
+f3 (int i)
+{
+  char a[sizeof (i) + 6 + i];
+  char b[sizeof (i) + i];
+  char c[sizeof (a) + sizeof (b) + 7];
+  return sizeof (c);
+}
--- gcc/testsuite/g++.dg/ext/builtin30.C.jj	2012-09-21 15:48:05.375214264 +0200
+++ gcc/testsuite/g++.dg/ext/builtin30.C	2012-09-21 15:48:05.375214264 +0200
@@ -0,0 +1,27 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+
+typedef __SIZE_TYPE__ size_t;
+extern "C" {
+extern void __chk_fail (void);
+extern int snprintf (char *, size_t, const char *, ...);
+extern inline __attribute__((gnu_inline, always_inline)) int snprintf (char *a, size_t b, const char *fmt, ...)
+{
+  if (__builtin_object_size (a, 0) != -1UL && __builtin_object_size (a, 0) < b)
+    __chk_fail ();
+  return __builtin_snprintf (a, b, fmt, __builtin_va_arg_pack ());
+}
+extern int snprintf (char *, size_t, const char *, ...) __asm ("mysnprintf");
+}
+
+char buf[10];
+
+int
+main (void)
+{
+  snprintf (buf, 10, "%d%d\n", 10, 10);
+  return 0;
+}
+
+// { dg-final { scan-assembler "mysnprintf" } }
+// { dg-final { scan-assembler-not "__chk_fail" } }
--- gcc/testsuite/gcc.dg/builtins-85.c.jj	2012-09-21 15:48:05.375214264 +0200
+++ gcc/testsuite/gcc.dg/builtins-85.c	2012-09-21 15:48:05.375214264 +0200
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+extern void __chk_fail (void);
+extern int snprintf (char *, size_t, const char *, ...);
+extern inline __attribute__((gnu_inline, always_inline)) int snprintf (char *a, size_t b, const char *fmt, ...)
+{
+  if (__builtin_object_size (a, 0) != -1UL && __builtin_object_size (a, 0) < b)
+    __chk_fail ();
+  return __builtin_snprintf (a, b, fmt, __builtin_va_arg_pack ());
+}
+extern int snprintf (char *, size_t, const char *, ...) __asm ("mysnprintf");
+
+char buf[10];
+
+int
+main (void)
+{
+  snprintf (buf, 10, "%d%d\n", 10, 10);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mysnprintf" } } */
+/* { dg-final { scan-assembler-not "__chk_fail" } } */
--- libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc.jj	2012-08-10 12:57:16.000000000 +0200
+++ libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc	2012-09-25 15:28:16.902924472 +0200
@@ -32,9 +32,9 @@ void test01()
 {
   X* px = 0;
   std::shared_ptr<X> p1(px);   // { dg-error "here" }
-  // { dg-error "incomplete" "" { target *-*-* } 776 }
+  // { dg-error "incomplete" "" { target *-*-* } 775 }
 
   std::shared_ptr<X> p9(ap());  // { dg-error "here" }
-  // { dg-error "incomplete" "" { target *-*-* } 310 }
+  // { dg-error "incomplete" "" { target *-*-* } 307 }
 
 }


	Jakub

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2)
  2012-09-25 16:28   ` Jakub Jelinek
@ 2012-10-02 12:57     ` Jakub Jelinek
  2012-10-03  9:14       ` Dodji Seketeli
                         ` (3 more replies)
  0 siblings, 4 replies; 16+ messages in thread
From: Jakub Jelinek @ 2012-10-02 12:57 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Tue, Sep 25, 2012 at 05:36:40PM +0200, Jakub Jelinek wrote:
> Here is the current patch.  One issue already mentioned on IRC is
> that generic code like contains_placeholder_p, save_expr etc.
> got confused by SIZEOF_EXPR having type as argument instead of expression.
> So for !processing_template_decl this patch uses instead NOP_EXPR with
> error_mark_node operand and type on the NOP_EXPR, plus SIZEOF_EXPR_TYPE_P
> bit set on the SIZEOF_EXPR (we need location on the sizeof expression, so
> it should be expression).  The patch solves that thing.
> 
> The remaining unsolved issues are two regressions, one is error
> FAIL: g++.dg/warn/Wnull-conversion-1.C -std=gnu++98 (test for excess errors)
> FAIL: g++.dg/warn/Wnull-conversion-1.C -std=gnu++11 (test for excess errors)
> on the
>   int* r = sizeof(char) / 2;
> line.  Is that even valid C++11?  C++03?  The thing is that we previously
> immediately folded sizeof(char) to 1, and 1/2 into 0 and considered that as
> null_ptr_cst_p.  With the patch we don't fold it anymore right away, we

This patch uses maybe_constant_value for C++98/03, and makes the above an
error for C++11 (where the standard says that only literal 0 is null pointer
constant?).

> The other issue is Obj-C++ ICE, in cp_build_binary_op I've added
...
> No idea what to do about that unfortunately, we don't have any handy macro
> to tell us the ObjC tree code range, we'd need to enumerate the Obj-C++ tree
> codes which we don't want to ICE on (and just set *non_constant_p on them
> instead).  We have objc_is_property_ref predicate, but not sure about the
> other ObjC trees.

And this is solved by saying objc_is_property_ref is not a
potential_constant_expression and removing the early return for C++98/03.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2012-10-02  Jakub Jelinek  <jakub@redhat.com>

cp/
	* cp-tree.h (SIZEOF_EXPR_TYPE_P): Define.
	* tree.c (cp_tree_equal): Handle SIZEOF_EXPR with
	SIZEOF_EXPR_TYPE_P.
	* mangle.c (write_expression): Likewise.
	* cxx-pretty-print.c (pp_cxx_unary_expression): Likewise.
	* error.c (dump_expr): Likewise.
	* parser.c (cp_parser_unary_expression): For sizeof call
	cxx_sizeof_or_alignof_{type,expr} just for diagnostics and
	return SIZEOF_EXPR with the operand.
	* pt.c (tsubst_copy, tsubst_copy_and_build): For SIZEOF_EXPR,
	call cxx_sizeof_or_alignof_{type,expr} for diagnostics, but
	return SIZEOF_EXPR with tsubsted operand.
	(value_dependent_expression_p): Handle SIZEOF_EXPR with
	SIZEOF_EXPR_TYPE_P.
	(instantiation_dependent_r): Likewise.
	* call.c (null_ptr_cst_p): Call maybe_constant_value for C++98.
	* semantics.c (finish_call_expr): Call
	sizeof_pointer_memaccess_warning if needed.
	(cxx_eval_constant_expression): Handle SIZEOF_EXPR.
	(potential_constant_expression_1): Remove early exit for
	C++98.  Handle PROPERTY_REF.
	* decl.c (duplicate_decls): When redeclaring a builtin function,
	keep the merged decl builtin also if newdecl is a gnu_inline
	inline definition.
	(fold_sizeof_expr_r): New function.
	(compute_array_index_type): Fold SIZEOF_EXPRs in itype.
	* cp-gimplify.c (cp_genericize_r): Fold SIZEOF_EXPR.
	* typeck.c (cp_build_binary_op): For warn_for_sign_compare
	try harder using maybe_constant_value to get INTEGER_CSTs.

	* decl.c (stabilize_vla_size): Call pointer_set_destroy
	at the end.
testsuite/
	* g++.dg/torture/Wsizeof-pointer-memaccess1.C: New test.
	* g++.dg/torture/Wsizeof-pointer-memaccess2.C: New test.
	* g++.dg/warn/Wsign-compare-5.C: New test.
	* g++.dg/warn/Wsizeof-pointer-memaccess-1.C: New test.
	* g++.dg/warn/Wnull-conversion-1.C: For c++11 add dg-error.
	* g++.dg/ext/builtin30.C: New test.
	* g++.dg/ext/vla12.C: New test.
	* gcc.dg/builtins-85.c: New test.
libstdc++-v3/
	* testsuite/20_util/shared_ptr/cons/43820_neg.cc: Adjust line
	numbers.

--- gcc/cp/cp-tree.h.jj	2012-10-01 10:08:40.447237104 +0200
+++ gcc/cp/cp-tree.h	2012-10-01 17:38:18.506576783 +0200
@@ -79,6 +79,7 @@ c-common.h, not after.
       OVL_ARG_DEPENDENT (in OVERLOAD)
       PACK_EXPANSION_LOCAL_P (in *_PACK_EXPANSION)
       TINFO_RECHECK_ACCESS_P (in TEMPLATE_INFO)
+      SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR)
    1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
       TI_PENDING_TEMPLATE_FLAG.
       TEMPLATE_PARMS_FOR_INLINE.
@@ -4044,6 +4045,10 @@ more_aggr_init_expr_args_p (const aggr_i
 #define CONVERT_EXPR_VBASE_PATH(NODE) \
   TREE_LANG_FLAG_0 (CONVERT_EXPR_CHECK (NODE))
 
+/* True if SIZEOF_EXPR argument is type.  */
+#define SIZEOF_EXPR_TYPE_P(NODE) \
+  TREE_LANG_FLAG_0 (SIZEOF_EXPR_CHECK (NODE))
+
 /* An enumeration of the kind of tags that C++ accepts.  */
 enum tag_types {
   none_type = 0, /* Not a tag type.  */
--- gcc/cp/cp-gimplify.c.jj	2012-09-27 12:45:49.060392494 +0200
+++ gcc/cp/cp-gimplify.c	2012-10-01 17:38:18.507576775 +0200
@@ -1119,6 +1119,22 @@ cp_genericize_r (tree *stmt_p, int *walk
     genericize_break_stmt (stmt_p);
   else if (TREE_CODE (stmt) == OMP_FOR)
     genericize_omp_for_stmt (stmt_p, walk_subtrees, data);
+  else if (TREE_CODE (stmt) == SIZEOF_EXPR)
+    {
+      if (SIZEOF_EXPR_TYPE_P (stmt))
+	*stmt_p
+	  = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (stmt, 0)),
+					SIZEOF_EXPR, false);
+      else if (TYPE_P (TREE_OPERAND (stmt, 0)))
+	*stmt_p = cxx_sizeof_or_alignof_type (TREE_OPERAND (stmt, 0),
+					      SIZEOF_EXPR, false);
+      else
+	*stmt_p = cxx_sizeof_or_alignof_expr (TREE_OPERAND (stmt, 0),
+					      SIZEOF_EXPR, false);
+      if (*stmt_p == error_mark_node)
+	*stmt_p = size_one_node;
+      return NULL;
+    }    
 
   pointer_set_insert (p_set, *stmt_p);
 
--- gcc/cp/call.c.jj	2012-09-27 12:45:49.000000000 +0200
+++ gcc/cp/call.c	2012-10-01 17:53:17.594609236 +0200
@@ -557,7 +557,10 @@ null_ptr_cst_p (tree t)
     {
       /* Core issue 903 says only literal 0 is a null pointer constant.  */
       if (cxx_dialect < cxx0x)
-	t = integral_constant_value (t);
+	{
+	  t = integral_constant_value (t);
+	  t = maybe_constant_value (t);
+	}
       STRIP_NOPS (t);
       if (integer_zerop (t) && !TREE_OVERFLOW (t))
 	return true;
--- gcc/cp/semantics.c.jj	2012-09-27 12:45:49.296391214 +0200
+++ gcc/cp/semantics.c	2012-10-01 17:50:27.088550744 +0200
@@ -2170,8 +2170,25 @@ finish_call_expr (tree fn, VEC(tree,gc)
 	result = resolve_overloaded_builtin (input_location, fn, *args);
 
       if (!result)
-	/* A call to a namespace-scope function.  */
-	result = build_new_function_call (fn, args, koenig_p, complain);
+	{
+	  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);
+	      sizeof_pointer_memaccess_warning
+		(EXPR_LOCATION (VEC_last(tree, *args)), fn, *args,
+		 sizeof_arg, same_type_ignoring_top_level_qualifiers_p);
+	    }
+
+	  /* A call to a namespace-scope function.  */
+	  result = build_new_function_call (fn, args, koenig_p, complain);
+	}
     }
   else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
     {
@@ -7723,6 +7740,21 @@ cxx_eval_constant_expression (const cons
 				     non_constant_p);
       break;
 
+    case SIZEOF_EXPR:
+      if (SIZEOF_EXPR_TYPE_P (t))
+	r = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (t, 0)),
+					SIZEOF_EXPR, false);
+      else if (TYPE_P (TREE_OPERAND (t, 0)))
+	r = cxx_sizeof_or_alignof_type (TREE_OPERAND (t, 0), SIZEOF_EXPR,
+					false);
+      else
+	r = cxx_sizeof_or_alignof_expr (TREE_OPERAND (t, 0), SIZEOF_EXPR,
+					false);
+      if (r == error_mark_node)
+	r = size_one_node;
+      VERIFY_CONSTANT (r);
+      break;
+
     case COMPOUND_EXPR:
       {
 	/* check_return_expr sometimes wraps a TARGET_EXPR in a
@@ -8106,12 +8138,6 @@ potential_constant_expression_1 (tree t,
   int i;
   tree tmp;
 
-  /* C++98 has different rules for the form of a constant expression that
-     are enforced in the parser, so we can assume that anything that gets
-     this far is suitable.  */
-  if (cxx_dialect < cxx0x)
-    return true;
-
   if (t == error_mark_node)
     return false;
   if (t == NULL_TREE)
@@ -8632,6 +8658,9 @@ potential_constant_expression_1 (tree t,
       return false;
 
     default:
+      if (objc_is_property_ref (t))
+	return false;
+
       sorry ("unexpected AST of kind %s", tree_code_name[TREE_CODE (t)]);
       gcc_unreachable();
       return false;
--- gcc/cp/tree.c.jj	2012-09-27 12:45:49.083392369 +0200
+++ gcc/cp/tree.c	2012-10-01 17:38:18.512576744 +0200
@@ -2602,6 +2602,10 @@ cp_tree_equal (tree t1, tree t2)
 	tree o1 = TREE_OPERAND (t1, 0);
 	tree o2 = TREE_OPERAND (t2, 0);
 
+	if (SIZEOF_EXPR_TYPE_P (t1))
+	  o1 = TREE_TYPE (o1);
+	if (SIZEOF_EXPR_TYPE_P (t2))
+	  o2 = TREE_TYPE (o2);
 	if (TREE_CODE (o1) != TREE_CODE (o2))
 	  return false;
 	if (TYPE_P (o1))
--- gcc/cp/mangle.c.jj	2012-09-27 12:45:49.111392217 +0200
+++ gcc/cp/mangle.c	2012-10-01 17:38:18.513576740 +0200
@@ -2581,6 +2581,12 @@ write_expression (tree expr)
       write_char ('E');
     }
   else if (TREE_CODE (expr) == SIZEOF_EXPR
+	   && SIZEOF_EXPR_TYPE_P (expr))
+    {
+      write_string ("st");
+      write_type (TREE_TYPE (TREE_OPERAND (expr, 0)));
+    }
+  else if (TREE_CODE (expr) == SIZEOF_EXPR
 	   && TYPE_P (TREE_OPERAND (expr, 0)))
     {
       write_string ("st");
--- gcc/cp/decl.c.jj	2012-10-01 10:08:40.429237206 +0200
+++ gcc/cp/decl.c	2012-10-01 17:38:18.516576724 +0200
@@ -2160,39 +2160,40 @@ duplicate_decls (tree newdecl, tree oldd
 	  DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl);
 	  DECL_RESULT (olddecl) = DECL_RESULT (newdecl);
 	}
+      /* If redeclaring a builtin function, it stays built in
+	 if newdecl is a gnu_inline definition, or if newdecl is just
+	 a declaration.  */
+      if (DECL_BUILT_IN (olddecl)
+	  && (new_defines_function ? GNU_INLINE_P (newdecl) : types_match))
+	{
+	  DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
+	  DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+	  /* If we're keeping the built-in definition, keep the rtl,
+	     regardless of declaration matches.  */
+	  COPY_DECL_RTL (olddecl, newdecl);
+	  if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
+	    {
+	      enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl);
+	      switch (fncode)
+		{
+		  /* If a compatible prototype of these builtin functions
+		     is seen, assume the runtime implements it with the
+		     expected semantics.  */
+		case BUILT_IN_STPCPY:
+		  if (builtin_decl_explicit_p (fncode))
+		    set_builtin_decl_implicit_p (fncode, true);
+		  break;
+		default:
+		  break;
+		}
+	    }
+	}
       if (new_defines_function)
 	/* If defining a function declared with other language
 	   linkage, use the previously declared language linkage.  */
 	SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl));
       else if (types_match)
 	{
-	  /* If redeclaring a builtin function, and not a definition,
-	     it stays built in.  */
-	  if (DECL_BUILT_IN (olddecl))
-	    {
-	      DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
-	      DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
-	      /* If we're keeping the built-in definition, keep the rtl,
-		 regardless of declaration matches.  */
-	      COPY_DECL_RTL (olddecl, newdecl);
-	      if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
-		{
-		  enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl);
-		  switch (fncode)
-		    {
-		      /* If a compatible prototype of these builtin functions
-			 is seen, assume the runtime implements it with the
-			 expected semantics.  */
-		    case BUILT_IN_STPCPY:
-		      if (builtin_decl_explicit_p (fncode))
-			set_builtin_decl_implicit_p (fncode, true);
-		      break;
-		    default:
-		      break;
-		    }
-		}
-	    }
-
 	  DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
 	  /* Don't clear out the arguments if we're just redeclaring a
 	     function.  */
@@ -7928,6 +7929,36 @@ stabilize_vla_size (tree size)
   struct pointer_set_t *pset = pointer_set_create ();
   /* Break out any function calls into temporary variables.  */
   cp_walk_tree (&size, stabilize_save_expr_r, pset, pset);
+  pointer_set_destroy (pset);
+}
+
+/* Helper function for compute_array_index_type.  Look for SIZEOF_EXPR
+   not inside of SAVE_EXPR and fold them.  */
+
+static tree
+fold_sizeof_expr_r (tree *expr_p, int *walk_subtrees, void *data)
+{
+  tree expr = *expr_p;
+  if (TREE_CODE (expr) == SAVE_EXPR || TYPE_P (expr))
+    *walk_subtrees = 0;
+  else if (TREE_CODE (expr) == SIZEOF_EXPR)
+    {
+      *(bool *)data = true;
+      if (SIZEOF_EXPR_TYPE_P (expr))
+	expr = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (expr, 0)),
+					   SIZEOF_EXPR, false);
+      else if (TYPE_P (TREE_OPERAND (expr, 0)))
+	expr = cxx_sizeof_or_alignof_type (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
+					   false);
+      else
+        expr = cxx_sizeof_or_alignof_expr (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
+					   false);
+      if (expr == error_mark_node)
+        expr = size_one_node;
+      *expr_p = expr;
+      *walk_subtrees = 0;
+    }
+  return NULL;
 }
 
 /* Given the SIZE (i.e., number of elements) in an array, compute an
@@ -8123,8 +8154,21 @@ compute_array_index_type (tree name, tre
       processing_template_decl = saved_processing_template_decl;
 
       if (!TREE_CONSTANT (itype))
-	/* A variable sized array.  */
-	itype = variable_size (itype);
+	{
+	  /* A variable sized array.  */
+	  itype = variable_size (itype);
+	  if (TREE_CODE (itype) != SAVE_EXPR)
+	    {
+	      /* Look for SIZEOF_EXPRs in itype and fold them, otherwise
+		 they might survive till gimplification.  */
+	      tree newitype = itype;
+	      bool found = false;
+	      cp_walk_tree_without_duplicates (&newitype,
+					       fold_sizeof_expr_r, &found);
+	      if (found)
+		itype = variable_size (fold (newitype));
+	    }
+	}
       /* Make sure that there was no overflow when creating to a signed
 	 index type.  (For example, on a 32-bit machine, an array with
 	 size 2^32 - 1 is too big.)  */
--- gcc/cp/cxx-pretty-print.c.jj	2012-09-27 12:45:49.118392179 +0200
+++ gcc/cp/cxx-pretty-print.c	2012-10-01 17:38:18.518576711 +0200
@@ -798,7 +798,13 @@ pp_cxx_unary_expression (cxx_pretty_prin
     case ALIGNOF_EXPR:
       pp_cxx_ws_string (pp, code == SIZEOF_EXPR ? "sizeof" : "__alignof__");
       pp_cxx_whitespace (pp);
-      if (TYPE_P (TREE_OPERAND (t, 0)))
+      if (TREE_CODE (t) == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (t))
+	{
+	  pp_cxx_left_paren (pp);
+	  pp_cxx_type_id (pp, TREE_TYPE (TREE_OPERAND (t, 0)));
+	  pp_cxx_right_paren (pp);
+	}
+      else if (TYPE_P (TREE_OPERAND (t, 0)))
 	{
 	  pp_cxx_left_paren (pp);
 	  pp_cxx_type_id (pp, TREE_OPERAND (t, 0));
--- gcc/cp/typeck.c.jj	2012-09-27 12:45:49.208391691 +0200
+++ gcc/cp/typeck.c	2012-10-01 17:38:18.519576704 +0200
@@ -4624,7 +4624,14 @@ cp_build_binary_op (location_t location,
 	  && !enum_cast_to_int (orig_op0)
 	  && !enum_cast_to_int (orig_op1))
 	{
-	  warn_for_sign_compare (location, orig_op0, orig_op1, op0, op1, 
+	  tree oop0 = maybe_constant_value (orig_op0);
+	  tree oop1 = maybe_constant_value (orig_op1);
+
+	  if (TREE_CODE (oop0) != INTEGER_CST)
+	    oop0 = orig_op0;
+	  if (TREE_CODE (oop1) != INTEGER_CST)
+	    oop1 = orig_op1;
+	  warn_for_sign_compare (location, oop0, oop1, op0, op1, 
 				 result_type, resultcode);
 	}
     }
--- gcc/cp/parser.c.jj	2012-10-01 10:08:40.447237104 +0200
+++ gcc/cp/parser.c	2012-10-01 17:38:18.524576680 +0200
@@ -6383,17 +6383,19 @@ cp_parser_unary_expression (cp_parser *p
 	case RID_ALIGNOF:
 	case RID_SIZEOF:
 	  {
-	    tree operand;
+	    tree operand, ret;
 	    enum tree_code op;
+	    location_t first_loc;
 
 	    op = keyword == RID_ALIGNOF ? ALIGNOF_EXPR : SIZEOF_EXPR;
 	    /* Consume the token.  */
 	    cp_lexer_consume_token (parser->lexer);
+	    first_loc = cp_lexer_peek_token (parser->lexer)->location;
 	    /* Parse the operand.  */
 	    operand = cp_parser_sizeof_operand (parser, keyword);
 
 	    if (TYPE_P (operand))
-	      return cxx_sizeof_or_alignof_type (operand, op, true);
+	      ret = cxx_sizeof_or_alignof_type (operand, op, true);
 	    else
 	      {
 		/* ISO C++ defines alignof only with types, not with
@@ -6404,8 +6406,29 @@ cp_parser_unary_expression (cp_parser *p
 			   "ISO C++ does not allow %<alignof%> "
 			   "with a non-type");
 
-		return cxx_sizeof_or_alignof_expr (operand, op, true);
+		ret = cxx_sizeof_or_alignof_expr (operand, op, true);
 	      }
+	    /* For SIZEOF_EXPR, just issue diagnostics, but keep
+	       SIZEOF_EXPR with the original operand.  */
+	    if (op == SIZEOF_EXPR && ret != error_mark_node)
+	      {
+		if (TREE_CODE (ret) != SIZEOF_EXPR || TYPE_P (operand))
+		  {
+		    if (!processing_template_decl && TYPE_P (operand))
+		      {
+			ret = build_min (SIZEOF_EXPR, size_type_node,
+					 build1 (NOP_EXPR, operand,
+						 error_mark_node));
+			SIZEOF_EXPR_TYPE_P (ret) = 1;
+		      }
+		    else
+		      ret = build_min (SIZEOF_EXPR, size_type_node, operand);
+		    TREE_SIDE_EFFECTS (ret) = 0;
+		    TREE_READONLY (ret) = 1;
+		  }
+		SET_EXPR_LOCATION (ret, first_loc);
+	      }
+	    return ret;
 	  }
 
 	case RID_NEW:
--- gcc/cp/pt.c.jj	2012-10-01 10:08:40.445237116 +0200
+++ gcc/cp/pt.c	2012-10-01 17:38:18.529576651 +0200
@@ -12031,14 +12031,16 @@ tsubst_copy (tree t, tree args, tsubst_f
       if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
         {
 
-          tree expanded;
+          tree expanded, op = TREE_OPERAND (t, 0);
 	  int len = 0;
 
+	  if (SIZEOF_EXPR_TYPE_P (t))
+	    op = TREE_TYPE (op);
+
 	  ++cp_unevaluated_operand;
 	  ++c_inhibit_evaluation_warnings;
 	  /* We only want to compute the number of arguments.  */
-	  expanded = tsubst_pack_expansion (TREE_OPERAND (t, 0), args,
-					    complain, in_decl);
+	  expanded = tsubst_pack_expansion (op, args, complain, in_decl);
 	  --cp_unevaluated_operand;
 	  --c_inhibit_evaluation_warnings;
 
@@ -12065,6 +12067,16 @@ tsubst_copy (tree t, tree args, tsubst_f
 	  else
 	    return build_int_cst (size_type_node, len);
         }
+      if (SIZEOF_EXPR_TYPE_P (t))
+	{
+	  r = tsubst_copy (TREE_TYPE (TREE_OPERAND (t, 0)),
+			   args, complain, in_decl);
+	  r = build1 (NOP_EXPR, r, error_mark_node);
+	  r = build1 (SIZEOF_EXPR,
+		      tsubst (TREE_TYPE (t), args, complain, in_decl), r);
+	  SIZEOF_EXPR_TYPE_P (r) = 1;
+	  return r;
+	}
       /* Fall through */
 
     case INDIRECT_REF:
@@ -13468,31 +13480,56 @@ tsubst_copy_and_build (tree t,
       /* Fall through */
       
     case ALIGNOF_EXPR:
-      op1 = TREE_OPERAND (t, 0);
-      if (!args)
-	{
-	  /* When there are no ARGS, we are trying to evaluate a
-	     non-dependent expression from the parser.  Trying to do
-	     the substitutions may not work.  */
-	  if (!TYPE_P (op1))
-	    op1 = TREE_TYPE (op1);
-	}
-      else
-	{
-	  ++cp_unevaluated_operand;
-	  ++c_inhibit_evaluation_warnings;
-	  op1 = tsubst_copy_and_build (op1, args, complain, in_decl,
-				       /*function_p=*/false,
-				       /*integral_constant_expression_p=*/false);
-	  --cp_unevaluated_operand;
-	  --c_inhibit_evaluation_warnings;
-	}
-      if (TYPE_P (op1))
-	RETURN (cxx_sizeof_or_alignof_type (op1, TREE_CODE (t),
-                                           complain & tf_error));
-      else
-	RETURN (cxx_sizeof_or_alignof_expr (op1, TREE_CODE (t),
-                                           complain & tf_error));
+      {
+	tree r;
+
+	op1 = TREE_OPERAND (t, 0);
+	if (TREE_CODE (t) == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (t))
+	  op1 = TREE_TYPE (op1);
+        if (!args)
+	  {
+	    /* When there are no ARGS, we are trying to evaluate a
+	       non-dependent expression from the parser.  Trying to do
+	       the substitutions may not work.  */
+	    if (!TYPE_P (op1))
+	      op1 = TREE_TYPE (op1);
+	  }
+	else
+	  {
+	    ++cp_unevaluated_operand;
+	    ++c_inhibit_evaluation_warnings;
+	    op1 = tsubst_copy_and_build (op1, args, complain, in_decl,
+					 /*function_p=*/false,
+					 /*integral_constant_expression_p=*/
+					 false);
+	    --cp_unevaluated_operand;
+	    --c_inhibit_evaluation_warnings;
+	  }
+        if (TYPE_P (op1))
+	  r = cxx_sizeof_or_alignof_type (op1, TREE_CODE (t),
+					  complain & tf_error);
+	else
+	  r = cxx_sizeof_or_alignof_expr (op1, TREE_CODE (t),
+					  complain & tf_error);
+	if (TREE_CODE (t) == SIZEOF_EXPR && r != error_mark_node)
+	  {
+	    if (TREE_CODE (r) != SIZEOF_EXPR || TYPE_P (op1))
+	      {
+		if (TYPE_P (op1))
+		  {
+		    r = build_min (SIZEOF_EXPR, size_type_node,
+				   build1 (NOP_EXPR, op1, error_mark_node));
+		    SIZEOF_EXPR_TYPE_P (r) = 1;
+		  }
+		else
+		  r = build_min (SIZEOF_EXPR, size_type_node, op1);
+		TREE_SIDE_EFFECTS (r) = 0;
+		TREE_READONLY (r) = 1;
+	      }
+	    SET_EXPR_LOCATION (r, EXPR_LOCATION (t));
+	  }
+	RETURN (r);
+      }
 
     case AT_ENCODE_EXPR:
       {
@@ -19288,6 +19325,9 @@ value_dependent_expression_p (tree expre
       }
 
     case SIZEOF_EXPR:
+      if (SIZEOF_EXPR_TYPE_P (expression))
+	return dependent_type_p (TREE_TYPE (TREE_OPERAND (expression, 0)));
+      /* FALLTHRU */
     case ALIGNOF_EXPR:
     case TYPEID_EXPR:
       /* A `sizeof' expression is value-dependent if the operand is
@@ -19627,6 +19667,8 @@ instantiation_dependent_r (tree *tp, int
     case TRAIT_EXPR:
       {
 	tree op = TREE_OPERAND (*tp, 0);
+	if (code == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (*tp))
+	  op = TREE_TYPE (op);
 	if (TYPE_P (op))
 	  {
 	    if (dependent_type_p (op)
--- gcc/cp/error.c.jj	2012-09-27 12:45:49.151391999 +0200
+++ gcc/cp/error.c	2012-10-01 17:38:18.532576635 +0200
@@ -2312,7 +2312,9 @@ dump_expr (tree t, int flags)
 	}
       pp_cxx_whitespace (cxx_pp);
       pp_cxx_left_paren (cxx_pp);
-      if (TYPE_P (TREE_OPERAND (t, 0)))
+      if (TREE_CODE (t) == SIZEOF_EXPR && SIZEOF_EXPR_TYPE_P (t))
+	dump_type (TREE_TYPE (TREE_OPERAND (t, 0)), flags);
+      else if (TYPE_P (TREE_OPERAND (t, 0)))
 	dump_type (TREE_OPERAND (t, 0), flags);
       else
 	dump_expr (TREE_OPERAND (t, 0), flags);
--- gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C.jj	2012-10-01 17:38:18.549576540 +0200
+++ gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C	2012-10-01 17:38:18.549576540 +0200
@@ -0,0 +1,716 @@
+// Test -Wsizeof-pointer-memaccess warnings.
+// { dg-do compile }
+// { dg-options "-Wall" }
+// Test just twice, once with -O0 non-fortified, once with -O2 fortified.
+// { dg-skip-if "" { *-*-* }  { "*" } { "-O0" "-O2" } }
+// { dg-skip-if "" { *-*-* }  { "-flto" } { "" } }
+
+extern "C" {
+
+typedef __SIZE_TYPE__ size_t;
+extern void *memset (void *, int, size_t);
+extern void *memcpy (void *__restrict, const void *__restrict, size_t);
+extern void *memmove (void *__restrict, const void *__restrict, size_t);
+extern int memcmp (const void *, const void *, size_t);
+extern char *strncpy (char *__restrict, const char *__restrict, size_t);
+extern char *strncat (char *__restrict, const char *__restrict, size_t);
+extern char *strndup (const char *, size_t);
+extern int strncmp (const char *, const char *, size_t);
+extern int strncasecmp (const char *, const char *, size_t);
+
+#ifdef __OPTIMIZE__
+# define bos(ptr) __builtin_object_size (ptr, 1)
+# define bos0(ptr) __builtin_object_size (ptr, 0)
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memset (void *dest, int c, size_t len)
+{
+  return __builtin___memset_chk (dest, c, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memcpy (void *__restrict dest, const void *__restrict src, size_t len)
+{
+  return __builtin___memcpy_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memmove (void *dest, const void *src, size_t len)
+{
+  return __builtin___memmove_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncpy (char *__restrict dest, const char *__restrict src, size_t len)
+{
+  return __builtin___strncpy_chk (dest, src, len, bos (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncat (char *dest, const char *src, size_t len)
+{
+  return __builtin___strncat_chk (dest, src, len, bos (dest));
+}
+#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];
+
+template <int N>
+int
+f1 (void *x, int z)
+{
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (&a, x, sizeof a);
+  z += memcmp (&a, x, sizeof (a));
+  z += memcmp (&a, x, sizeof (struct A));
+  z += memcmp (&a, x, sizeof (const struct A));
+  z += memcmp (&a, x, sizeof (volatile struct A));
+  z += memcmp (&a, x, sizeof (volatile const struct A));
+  z += memcmp (&a, x, sizeof (TA));
+  z += memcmp (&a, x, sizeof (__typeof (*&a)));
+  z += memcmp (pa1, x, sizeof (*pa1));
+  z += memcmp (pa2, x, sizeof (*pa3));
+  z += memcmp (pa3, x, sizeof (__typeof (*pa3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) &a, x, sizeof (&a));
+  z += memcmp ((char *) &a, x, sizeof (&a));
+  z += memcmp (&a, x, sizeof (&a) + 0);
+  z += memcmp (&a, x, 0 + sizeof (&a));
+
+  // These are correct, no warning. 
+  z += memcmp (x, &a, sizeof a);
+  z += memcmp (x, &a, sizeof (a));
+  z += memcmp (x, &a, sizeof (struct A));
+  z += memcmp (x, &a, sizeof (const struct A));
+  z += memcmp (x, &a, sizeof (volatile struct A));
+  z += memcmp (x, &a, sizeof (volatile const struct A));
+  z += memcmp (x, &a, sizeof (TA));
+  z += memcmp (x, &a, sizeof (__typeof (*&a)));
+  z += memcmp (x, pa1, sizeof (*pa1));
+  z += memcmp (x, pa2, sizeof (*pa3));
+  z += memcmp (x, pa3, sizeof (__typeof (*pa3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) &a, sizeof (&a));
+  z += memcmp (x, (char *) &a, sizeof (&a));
+  z += memcmp (x, &a, sizeof (&a) + 0);
+  z += memcmp (x, &a, 0 + sizeof (&a));
+
+  return z;
+}
+
+template <int N>
+int
+f2 (void *x, int z)
+{
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (&b, x, sizeof b);
+  z += memcmp (&b, x, sizeof (b));
+  z += memcmp (&b, x, sizeof (struct B));
+  z += memcmp (&b, x, sizeof (const struct B));
+  z += memcmp (&b, x, sizeof (volatile struct B));
+  z += memcmp (&b, x, sizeof (volatile const struct B));
+  z += memcmp (&b, x, sizeof (TB));
+  z += memcmp (&b, x, sizeof (__typeof (*&b)));
+  z += memcmp (pb1, x, sizeof (*pb1));
+  z += memcmp (pb2, x, sizeof (*pb3));
+  z += memcmp (pb3, x, sizeof (__typeof (*pb3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) &b, x, sizeof (&b));
+  z += memcmp ((char *) &b, x, sizeof (&b));
+  z += memcmp (&b, x, sizeof (&b) + 0);
+  z += memcmp (&b, x, 0 + sizeof (&b));
+
+  // These are correct, no warning. 
+  z += memcmp (x, &b, sizeof b);
+  z += memcmp (x, &b, sizeof (b));
+  z += memcmp (x, &b, sizeof (struct B));
+  z += memcmp (x, &b, sizeof (const struct B));
+  z += memcmp (x, &b, sizeof (volatile struct B));
+  z += memcmp (x, &b, sizeof (volatile const struct B));
+  z += memcmp (x, &b, sizeof (TB));
+  z += memcmp (x, &b, sizeof (__typeof (*&b)));
+  z += memcmp (x, pb1, sizeof (*pb1));
+  z += memcmp (x, pb2, sizeof (*pb3));
+  z += memcmp (x, pb3, sizeof (__typeof (*pb3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) &b, sizeof (&b));
+  z += memcmp (x, (char *) &b, sizeof (&b));
+  z += memcmp (x, &b, sizeof (&b) + 0);
+  z += memcmp (x, &b, 0 + sizeof (&b));
+
+  return z;
+}
+
+template <int N>
+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;
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (y, x, sizeof (*y));
+  z += memcmp (y1, x, sizeof (*y2));
+  z += memcmp (buf1, x, sizeof buf1);
+  z += memcmp (buf3, x, sizeof (buf3));
+  z += memcmp (&buf3[0], x, sizeof (buf3));
+  z += memcmp (&buf4[0], x, sizeof (buf4));
+  z += memcmp (&y3, y, sizeof (y3));
+  z += memcmp ((char *) &y3, y, sizeof (y3));
+  z += memcmp (w, x, sizeof (X));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) y, x, sizeof (y));
+  z += memcmp ((char *) y1, x, sizeof (y2));
+  z += memcmp (y, x, sizeof (y) + 0);
+  z += memcmp (y1, x, 0 + sizeof (y2));
+  z += memcmp ((void *) &c, x, sizeof (&c));
+  z += memcmp ((signed char *) &c, x, sizeof (&c));
+  z += memcmp (&c, x, sizeof (&c) + 0);
+  z += memcmp (&c, x, 0 + sizeof (&c));
+
+  // These are correct, no warning. 
+  z += memcmp (x, y, sizeof (*y));
+  z += memcmp (x, y1, sizeof (*y2));
+  z += memcmp (x, buf1, sizeof buf1);
+  z += memcmp (x, buf3, sizeof (buf3));
+  z += memcmp (x, &buf3[0], sizeof (buf3));
+  z += memcmp (x, &buf4[0], sizeof (buf4));
+  z += memcmp (y, &y3, sizeof (y3));
+  z += memcmp (y, (char *) &y3, sizeof (y3));
+  z += memcmp (x, w, sizeof (X));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) y, sizeof (y));
+  z += memcmp (x, (char *) y1, sizeof (y2));
+  z += memcmp (x, y, sizeof (y) + 0);
+  z += memcmp (x, y1, 0 + sizeof (y2));
+  z += memcmp (x, (void *) &c, sizeof (&c));
+  z += memcmp (x, (signed char *) &c, sizeof (&c));
+  z += memcmp (x, &c, sizeof (&c) + 0);
+  z += memcmp (x, &c, 0 + sizeof (&c));
+
+  return z;
+}
+
+template <int N>
+int
+f4 (char *x, char **y, int z)
+{
+  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" }
+  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" }
+
+  // These are correct, no warning. 
+  const char s3[] = "foobarbaz";
+  const char s4[] = "abcde12345678";
+  strncpy (x, s3, sizeof (s3));
+  strncat (x, s4, sizeof (s4));
+  y[1] = strndup (s3, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s4));
+  z += strncasecmp (s3, s4, sizeof (s3));
+  z += strncasecmp (s3, s4, sizeof (s4));
+
+  return z;
+}
+
+int
+f (void *x, char *y, int z, X w, char **u)
+{
+  z += f1<0> (x, z);
+  z += f2<0> (x, z);
+  z += f3<0> (x, y, z, w);
+  z += f4<0> (y, u, z);
+  return z;
+}
+
+// { dg-prune-output "\[\n\r\]*will always overflow\[\n\r\]*" }
--- gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C.jj	2012-10-01 17:38:18.549576540 +0200
+++ gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C	2012-10-01 17:38:18.549576540 +0200
@@ -0,0 +1,702 @@
+// Test -Wsizeof-pointer-memaccess warnings.
+// { dg-do compile }
+// { dg-options "-Wall" }
+// Test just twice, once with -O0 non-fortified, once with -O2 fortified.
+// { dg-skip-if "" { *-*-* }  { "*" } { "-O0" "-O2" } }
+// { dg-skip-if "" { *-*-* }  { "-flto" } { "" } }
+
+extern "C" {
+
+typedef __SIZE_TYPE__ size_t;
+extern void *memset (void *, int, size_t);
+extern void *memcpy (void *__restrict, const void *__restrict, size_t);
+extern void *memmove (void *__restrict, const void *__restrict, size_t);
+extern int memcmp (const void *, const void *, size_t);
+extern char *strncpy (char *__restrict, const char *__restrict, size_t);
+extern char *strncat (char *__restrict, const char *__restrict, size_t);
+extern char *strndup (const char *, size_t);
+extern int strncmp (const char *, const char *, size_t);
+extern int strncasecmp (const char *, const char *, size_t);
+
+#ifdef __OPTIMIZE__
+# define bos(ptr) __builtin_object_size (ptr, 1)
+# define bos0(ptr) __builtin_object_size (ptr, 0)
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memset (void *dest, int c, size_t len)
+{
+  return __builtin___memset_chk (dest, c, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memcpy (void *__restrict dest, const void *__restrict src, size_t len)
+{
+  return __builtin___memcpy_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memmove (void *dest, const void *src, size_t len)
+{
+  return __builtin___memmove_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncpy (char *__restrict dest, const char *__restrict src, size_t len)
+{
+  return __builtin___strncpy_chk (dest, src, len, bos (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncat (char *dest, const char *src, size_t len)
+{
+  return __builtin___strncat_chk (dest, src, len, bos (dest));
+}
+#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];
+
+int
+f1 (void *x, int z)
+{
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (&a, x, sizeof a);
+  z += memcmp (&a, x, sizeof (a));
+  z += memcmp (&a, x, sizeof (struct A));
+  z += memcmp (&a, x, sizeof (const struct A));
+  z += memcmp (&a, x, sizeof (volatile struct A));
+  z += memcmp (&a, x, sizeof (volatile const struct A));
+  z += memcmp (&a, x, sizeof (TA));
+  z += memcmp (&a, x, sizeof (__typeof (*&a)));
+  z += memcmp (pa1, x, sizeof (*pa1));
+  z += memcmp (pa2, x, sizeof (*pa3));
+  z += memcmp (pa3, x, sizeof (__typeof (*pa3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) &a, x, sizeof (&a));
+  z += memcmp ((char *) &a, x, sizeof (&a));
+  z += memcmp (&a, x, sizeof (&a) + 0);
+  z += memcmp (&a, x, 0 + sizeof (&a));
+
+  // These are correct, no warning. 
+  z += memcmp (x, &a, sizeof a);
+  z += memcmp (x, &a, sizeof (a));
+  z += memcmp (x, &a, sizeof (struct A));
+  z += memcmp (x, &a, sizeof (const struct A));
+  z += memcmp (x, &a, sizeof (volatile struct A));
+  z += memcmp (x, &a, sizeof (volatile const struct A));
+  z += memcmp (x, &a, sizeof (TA));
+  z += memcmp (x, &a, sizeof (__typeof (*&a)));
+  z += memcmp (x, pa1, sizeof (*pa1));
+  z += memcmp (x, pa2, sizeof (*pa3));
+  z += memcmp (x, pa3, sizeof (__typeof (*pa3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) &a, sizeof (&a));
+  z += memcmp (x, (char *) &a, sizeof (&a));
+  z += memcmp (x, &a, sizeof (&a) + 0);
+  z += memcmp (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;
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (&b, x, sizeof b);
+  z += memcmp (&b, x, sizeof (b));
+  z += memcmp (&b, x, sizeof (struct B));
+  z += memcmp (&b, x, sizeof (const struct B));
+  z += memcmp (&b, x, sizeof (volatile struct B));
+  z += memcmp (&b, x, sizeof (volatile const struct B));
+  z += memcmp (&b, x, sizeof (TB));
+  z += memcmp (&b, x, sizeof (__typeof (*&b)));
+  z += memcmp (pb1, x, sizeof (*pb1));
+  z += memcmp (pb2, x, sizeof (*pb3));
+  z += memcmp (pb3, x, sizeof (__typeof (*pb3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) &b, x, sizeof (&b));
+  z += memcmp ((char *) &b, x, sizeof (&b));
+  z += memcmp (&b, x, sizeof (&b) + 0);
+  z += memcmp (&b, x, 0 + sizeof (&b));
+
+  // These are correct, no warning. 
+  z += memcmp (x, &b, sizeof b);
+  z += memcmp (x, &b, sizeof (b));
+  z += memcmp (x, &b, sizeof (struct B));
+  z += memcmp (x, &b, sizeof (const struct B));
+  z += memcmp (x, &b, sizeof (volatile struct B));
+  z += memcmp (x, &b, sizeof (volatile const struct B));
+  z += memcmp (x, &b, sizeof (TB));
+  z += memcmp (x, &b, sizeof (__typeof (*&b)));
+  z += memcmp (x, pb1, sizeof (*pb1));
+  z += memcmp (x, pb2, sizeof (*pb3));
+  z += memcmp (x, pb3, sizeof (__typeof (*pb3)));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) &b, sizeof (&b));
+  z += memcmp (x, (char *) &b, sizeof (&b));
+  z += memcmp (x, &b, sizeof (&b) + 0);
+  z += memcmp (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;
+  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" }
+
+  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" }
+
+  // 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));
+
+  // These are correct, no warning. 
+  z += memcmp (y, x, sizeof (*y));
+  z += memcmp (y1, x, sizeof (*y2));
+  z += memcmp (buf1, x, sizeof buf1);
+  z += memcmp (buf3, x, sizeof (buf3));
+  z += memcmp (&buf3[0], x, sizeof (buf3));
+  z += memcmp (&buf4[0], x, sizeof (buf4));
+  z += memcmp (&y3, y, sizeof (y3));
+  z += memcmp ((char *) &y3, y, sizeof (y3));
+  z += memcmp (w, x, sizeof (X));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp ((void *) y, x, sizeof (y));
+  z += memcmp ((char *) y1, x, sizeof (y2));
+  z += memcmp (y, x, sizeof (y) + 0);
+  z += memcmp (y1, x, 0 + sizeof (y2));
+  z += memcmp ((void *) &c, x, sizeof (&c));
+  z += memcmp ((signed char *) &c, x, sizeof (&c));
+  z += memcmp (&c, x, sizeof (&c) + 0);
+  z += memcmp (&c, x, 0 + sizeof (&c));
+
+  // These are correct, no warning. 
+  z += memcmp (x, y, sizeof (*y));
+  z += memcmp (x, y1, sizeof (*y2));
+  z += memcmp (x, buf1, sizeof buf1);
+  z += memcmp (x, buf3, sizeof (buf3));
+  z += memcmp (x, &buf3[0], sizeof (buf3));
+  z += memcmp (x, &buf4[0], sizeof (buf4));
+  z += memcmp (y, &y3, sizeof (y3));
+  z += memcmp (y, (char *) &y3, sizeof (y3));
+  z += memcmp (x, w, sizeof (X));
+  // These are probably broken, but obfuscated, no warning. 
+  z += memcmp (x, (void *) y, sizeof (y));
+  z += memcmp (x, (char *) y1, sizeof (y2));
+  z += memcmp (x, y, sizeof (y) + 0);
+  z += memcmp (x, y1, 0 + sizeof (y2));
+  z += memcmp (x, (void *) &c, sizeof (&c));
+  z += memcmp (x, (signed char *) &c, sizeof (&c));
+  z += memcmp (x, &c, sizeof (&c) + 0);
+  z += memcmp (x, &c, 0 + sizeof (&c));
+
+  return z;
+}
+
+int
+f4 (char *x, char **y, int z)
+{
+  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" }
+  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" }
+
+  // These are correct, no warning. 
+  const char s3[] = "foobarbaz";
+  const char s4[] = "abcde12345678";
+  strncpy (x, s3, sizeof (s3));
+  strncat (x, s4, sizeof (s4));
+  y[1] = strndup (s3, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s4));
+  z += strncasecmp (s3, s4, sizeof (s3));
+  z += strncasecmp (s3, s4, sizeof (s4));
+
+  return z;
+}
+
+// { dg-prune-output "\[\n\r\]*will always overflow\[\n\r\]*" }
--- gcc/testsuite/g++.dg/warn/Wsizeof-pointer-memaccess-1.C.jj	2012-10-01 17:38:18.556576500 +0200
+++ gcc/testsuite/g++.dg/warn/Wsizeof-pointer-memaccess-1.C	2012-10-01 17:38:18.556576500 +0200
@@ -0,0 +1,13 @@
+// Test -Wsizeof-pointer-memaccess warnings.
+// { dg-do compile }
+// { dg-options "-Wall" }
+
+typedef __SIZE_TYPE__ size_t;
+extern "C" void *memset (void *, int, size_t);
+
+int
+foo (int x, char b[10])
+{
+  long a[memset (b, 0, sizeof (b)) ? x + 10 : x];	// { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length?" }
+  return a[0];
+}
--- gcc/testsuite/g++.dg/warn/Wsign-compare-5.C.jj	2012-10-01 17:38:18.556576500 +0200
+++ gcc/testsuite/g++.dg/warn/Wsign-compare-5.C	2012-10-01 17:38:18.556576500 +0200
@@ -0,0 +1,20 @@
+// Test that -Wsign-compare doesn't warn about
+// equality/non-equality comparisons with sizeof.
+// { dg-do compile }
+// { dg-options "-Wsign-compare" }
+
+int
+foo (int x)
+{
+  if (x != sizeof (sizeof (x)))		// { dg-bogus "comparison between signed and unsigned integer expressions" }
+    return 1;
+  return 0;
+}
+
+int
+bar (int x)
+{
+  if (x == sizeof (sizeof (x)) + 1)	// { dg-bogus "comparison between signed and unsigned integer expressions" }
+    return 1;
+  return 0;
+}
--- gcc/testsuite/g++.dg/warn/Wnull-conversion-1.C.jj	2011-05-02 18:39:10.000000000 +0200
+++ gcc/testsuite/g++.dg/warn/Wnull-conversion-1.C	2012-10-02 10:32:08.764195850 +0200
@@ -9,7 +9,7 @@ void func2() {
   int* t = false;             // { dg-warning "converting 'false' to pointer" }
   int* p;
   p = false;                  // { dg-warning "converting 'false' to pointer" }
-  int* r = sizeof(char) / 2;
+  int* r = sizeof(char) / 2;  // { dg-error "invalid conversion from" "" { target c++11 } }
   func1(false);               // { dg-warning "converting 'false' to pointer" }
   int i = NULL;               // { dg-warning "converting to non-pointer" }
 }
--- gcc/testsuite/g++.dg/ext/vla12.C.jj	2012-10-01 17:38:18.556576500 +0200
+++ gcc/testsuite/g++.dg/ext/vla12.C	2012-10-01 17:38:18.557576495 +0200
@@ -0,0 +1,28 @@
+// VLA sizeof test
+// { dg-do compile }
+// { dg-options "" }
+
+int
+f1 (int i)
+{
+  char a[sizeof (i) + 6 + i];
+  char b[sizeof (a) + 1];
+  return sizeof (b);
+}
+
+int
+f2 (int i)
+{
+  char a[sizeof (i) + 6 + i];
+  char b[sizeof (a)];
+  return sizeof (b);
+}
+
+int
+f3 (int i)
+{
+  char a[sizeof (i) + 6 + i];
+  char b[sizeof (i) + i];
+  char c[sizeof (a) + sizeof (b) + 7];
+  return sizeof (c);
+}
--- gcc/testsuite/g++.dg/ext/builtin30.C.jj	2012-10-01 17:38:18.557576495 +0200
+++ gcc/testsuite/g++.dg/ext/builtin30.C	2012-10-01 17:38:18.557576495 +0200
@@ -0,0 +1,27 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+
+typedef __SIZE_TYPE__ size_t;
+extern "C" {
+extern void __chk_fail (void);
+extern int snprintf (char *, size_t, const char *, ...);
+extern inline __attribute__((gnu_inline, always_inline)) int snprintf (char *a, size_t b, const char *fmt, ...)
+{
+  if (__builtin_object_size (a, 0) != -1UL && __builtin_object_size (a, 0) < b)
+    __chk_fail ();
+  return __builtin_snprintf (a, b, fmt, __builtin_va_arg_pack ());
+}
+extern int snprintf (char *, size_t, const char *, ...) __asm ("mysnprintf");
+}
+
+char buf[10];
+
+int
+main (void)
+{
+  snprintf (buf, 10, "%d%d\n", 10, 10);
+  return 0;
+}
+
+// { dg-final { scan-assembler "mysnprintf" } }
+// { dg-final { scan-assembler-not "__chk_fail" } }
--- gcc/testsuite/gcc.dg/builtins-85.c.jj	2012-10-01 17:38:18.557576495 +0200
+++ gcc/testsuite/gcc.dg/builtins-85.c	2012-10-01 17:38:18.557576495 +0200
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+extern void __chk_fail (void);
+extern int snprintf (char *, size_t, const char *, ...);
+extern inline __attribute__((gnu_inline, always_inline)) int snprintf (char *a, size_t b, const char *fmt, ...)
+{
+  if (__builtin_object_size (a, 0) != -1UL && __builtin_object_size (a, 0) < b)
+    __chk_fail ();
+  return __builtin_snprintf (a, b, fmt, __builtin_va_arg_pack ());
+}
+extern int snprintf (char *, size_t, const char *, ...) __asm ("mysnprintf");
+
+char buf[10];
+
+int
+main (void)
+{
+  snprintf (buf, 10, "%d%d\n", 10, 10);
+  return 0;
+}
+
+/* { dg-final { scan-assembler "mysnprintf" } } */
+/* { dg-final { scan-assembler-not "__chk_fail" } } */
--- libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc.jj	2012-08-10 12:57:16.000000000 +0200
+++ libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc	2012-09-25 15:28:16.902924472 +0200
@@ -32,9 +32,9 @@ void test01()
 {
   X* px = 0;
   std::shared_ptr<X> p1(px);   // { dg-error "here" }
-  // { dg-error "incomplete" "" { target *-*-* } 776 }
+  // { dg-error "incomplete" "" { target *-*-* } 775 }
 
   std::shared_ptr<X> p9(ap());  // { dg-error "here" }
-  // { dg-error "incomplete" "" { target *-*-* } 310 }
+  // { dg-error "incomplete" "" { target *-*-* } 307 }
 
 }

	Jakub

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2)
  2012-10-02 12:57     ` [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2) Jakub Jelinek
@ 2012-10-03  9:14       ` Dodji Seketeli
  2012-10-03  9:43         ` Jakub Jelinek
  2012-10-05 13:45       ` Jason Merrill
                         ` (2 subsequent siblings)
  3 siblings, 1 reply; 16+ messages in thread
From: Dodji Seketeli @ 2012-10-03  9:14 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, gcc-patches

Jakub Jelinek <jakub@redhat.com> a écrit:

> --- gcc/cp/call.c.jj	2012-09-27 12:45:49.000000000 +0200
> +++ gcc/cp/call.c	2012-10-01 17:53:17.594609236 +0200
> @@ -557,7 +557,10 @@ null_ptr_cst_p (tree t)
>      {
>        /* Core issue 903 says only literal 0 is a null pointer constant.  */
>        if (cxx_dialect < cxx0x)
> -	t = integral_constant_value (t);
> +	{
> +	  t = integral_constant_value (t);
> +	  t = maybe_constant_value (t);
> +	}

Just for my education, why couldn't maybe_constant_value just call
integral_constant_value, so that we just use maybe_constant_value here?

Even after reading the comments of these two functions, /having/ to use
them like this seems confusing to the casual reader in me.

-- 
		Dodji

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2)
  2012-10-03  9:14       ` Dodji Seketeli
@ 2012-10-03  9:43         ` Jakub Jelinek
  0 siblings, 0 replies; 16+ messages in thread
From: Jakub Jelinek @ 2012-10-03  9:43 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Jason Merrill, gcc-patches

On Wed, Oct 03, 2012 at 11:14:37AM +0200, Dodji Seketeli wrote:
> Jakub Jelinek <jakub@redhat.com> a écrit:
> 
> > --- gcc/cp/call.c.jj	2012-09-27 12:45:49.000000000 +0200
> > +++ gcc/cp/call.c	2012-10-01 17:53:17.594609236 +0200
> > @@ -557,7 +557,10 @@ null_ptr_cst_p (tree t)
> >      {
> >        /* Core issue 903 says only literal 0 is a null pointer constant.  */
> >        if (cxx_dialect < cxx0x)
> > -	t = integral_constant_value (t);
> > +	{
> > +	  t = integral_constant_value (t);
> > +	  t = maybe_constant_value (t);
> > +	}
> 
> Just for my education, why couldn't maybe_constant_value just call
> integral_constant_value, so that we just use maybe_constant_value here?

Perhaps maybe_constant_value already does all that integral_constant_value
does, but I'm not sure about it.  maybe_constant_value starts with a lot of
conditions where it doesn't do anything if they are true,
integral_constant_value doesn't have any such conditions, on the other side
performs far less - just loops through DECL_INITIAL values looking for a
const.  As I said earlier, while the initial hacks around early folding
of SIZEOF_EXPR were quite ugly, the amount of changes to allow late folding
of SIZEOF_EXPR was huge, with user visible changes etc.

	Jakub

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2)
  2012-10-02 12:57     ` [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2) Jakub Jelinek
  2012-10-03  9:14       ` Dodji Seketeli
@ 2012-10-05 13:45       ` Jason Merrill
  2012-10-11  0:41       ` Hans-Peter Nilsson
  2012-10-26 13:36       ` [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2) Roman Zhuykov
  3 siblings, 0 replies; 16+ messages in thread
From: Jason Merrill @ 2012-10-05 13:45 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

On 10/02/2012 08:56 AM, Jakub Jelinek wrote:
> Perhaps maybe_constant_value already does all that integral_constant_value
> does, but I'm not sure about it.

It does, you can remove that call.

OK with that change.

Jason

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2)
  2012-10-02 12:57     ` [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2) Jakub Jelinek
  2012-10-03  9:14       ` Dodji Seketeli
  2012-10-05 13:45       ` Jason Merrill
@ 2012-10-11  0:41       ` Hans-Peter Nilsson
  2012-10-11 11:54         ` Committed, PR54897 (was: [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2)) Hans-Peter Nilsson
  2012-10-26 13:36       ` [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2) Roman Zhuykov
  3 siblings, 1 reply; 16+ messages in thread
From: Hans-Peter Nilsson @ 2012-10-11  0:41 UTC (permalink / raw)
  To: jakub; +Cc: jason, gcc-patches

> From: Jakub Jelinek <jakub@redhat.com>
> Date: Tue, 2 Oct 2012 14:56:29 +0200

> 2012-10-02  Jakub Jelinek  <jakub@redhat.com>
> 
> cp/
>         * cp-tree.h (SIZEOF_EXPR_TYPE_P): Define.
>         * tree.c (cp_tree_equal): Handle SIZEOF_EXPR with
>         SIZEOF_EXPR_TYPE_P.
...etc.

Looks like this caused a regression; PR54897, where the error
message seems to indicate an ABI change.

There's now an "excess error":

x/libstdc++-v3/testsuite/23_containers/bitset/45713.cc:24:55:
error: size of array 'test' is not an integral constant-expression
 int test[sizeof(std::bitset<0xffffffff>) != 1 ? 1 : -1];

Or is the error message in error and just "missing" before?
Please have a look.

brgds, H-P

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Committed, PR54897 (was: [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2))
  2012-10-11  0:41       ` Hans-Peter Nilsson
@ 2012-10-11 11:54         ` Hans-Peter Nilsson
  0 siblings, 0 replies; 16+ messages in thread
From: Hans-Peter Nilsson @ 2012-10-11 11:54 UTC (permalink / raw)
  To: gcc-patches, libstdc++

> From: Hans-Peter Nilsson <hp@axis.com>
> Date: Thu, 11 Oct 2012 02:13:32 +0200

> There's now an "excess error":
> 
> x/libstdc++-v3/testsuite/23_containers/bitset/45713.cc:24:55:
> error: size of array 'test' is not an integral constant-expression
>  int test[sizeof(std::bitset<0xffffffff>) != 1 ? 1 : -1];
> 
> Or is the error message in error and just "missing" before?
> Please have a look.

As per discussion in PR54897, I committed the following, after
correcting the target syntax in the cutnpasted patch there.
(The target parser is picky about matching *-*-*, which I guess is
appropriate since it has to handle effective-targets as well.)

	PR testsuite/54897
	* testsuite/23_containers/bitset/45713.cc: Skip for avr*-*-*
	cris*-*-* h8300*-*-* mcore*-*-* moxie*-*-*.


Index: libstdc++-v3/testsuite/23_containers/bitset/45713.cc
===================================================================
--- libstdc++-v3/testsuite/23_containers/bitset/45713.cc	(revision 192353)
+++ libstdc++-v3/testsuite/23_containers/bitset/45713.cc	(working copy)
@@ -1,4 +1,4 @@
-// Copyright (C) 2010 Free Software Foundation, Inc.
+// Copyright (C) 2010, 2012 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
@@ -15,7 +15,10 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-do compile }
+// The testcase requires bitsizetype to be wider than sizetype,
+// otherwise types/vars with 0x20000000 bytes or larger can't be used.
+// See http://gcc.gnu.org/PR54897
+// { dg-do compile { target { ! { avr*-*-* cris*-*-* h8300*-*-* mcore*-*-* moxie*-*-* } } } }
 
 #include <bitset>
 
brgds, H-P

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2)
  2012-10-02 12:57     ` [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2) Jakub Jelinek
                         ` (2 preceding siblings ...)
  2012-10-11  0:41       ` Hans-Peter Nilsson
@ 2012-10-26 13:36       ` Roman Zhuykov
  3 siblings, 0 replies; 16+ messages in thread
From: Roman Zhuykov @ 2012-10-26 13:36 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, gcc-patches

This caused
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55081

--
Roman Zhuykov

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [C PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-17 13:27             ` Florian Weimer
@ 2012-08-17 13:34               ` Jakub Jelinek
  0 siblings, 0 replies; 16+ messages in thread
From: Jakub Jelinek @ 2012-08-17 13:34 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Joseph S. Myers, gcc-patches, Jason Merrill, Paolo Carlini

On Fri, Aug 17, 2012 at 03:26:34PM +0200, Florian Weimer wrote:
> On 08/17/2012 03:09 PM, Jakub Jelinek wrote:
> 
> >s/stpncopy/stpncpy/, yeah, I guess, we could do that for those too,
> >but 1) I'd prefer to wait for the C++ FE change to go in first
> >2) {,v}snprintf would be much harder than the rest, as the size
> >argument then isn't the last argument to the function, and the FEs
> >only provide the last one right now.
> 
> Could you pick the second argument for varargs functions?
> Incredibly hacky, but would do the trick for those two.  Or does the
> FE not know at this point it is processing a varargs function?

Yeah, it doesn't know that.
What could perhaps work for all the builtins that makes sense to warn for is
to record the third argument if it is a sizeof, or, if that one isn't a
sizeof, record the second argument if it is a sizeof.

	Jakub

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [C PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-17 13:14           ` Jakub Jelinek
@ 2012-08-17 13:27             ` Florian Weimer
  2012-08-17 13:34               ` Jakub Jelinek
  0 siblings, 1 reply; 16+ messages in thread
From: Florian Weimer @ 2012-08-17 13:27 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Joseph S. Myers, gcc-patches, Jason Merrill, Paolo Carlini

On 08/17/2012 03:09 PM, Jakub Jelinek wrote:

> s/stpncopy/stpncpy/, yeah, I guess, we could do that for those too,
> but 1) I'd prefer to wait for the C++ FE change to go in first
> 2) {,v}snprintf would be much harder than the rest, as the size
> argument then isn't the last argument to the function, and the FEs
> only provide the last one right now.

Could you pick the second argument for varargs functions?  Incredibly 
hacky, but would do the trick for those two.  Or does the FE not know at 
this point it is processing a varargs function?

-- 
Florian Weimer / Red Hat Product Security Team

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [C PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-17 12:53         ` Florian Weimer
@ 2012-08-17 13:14           ` Jakub Jelinek
  2012-08-17 13:27             ` Florian Weimer
  0 siblings, 1 reply; 16+ messages in thread
From: Jakub Jelinek @ 2012-08-17 13:14 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Joseph S. Myers, gcc-patches, Jason Merrill, Paolo Carlini

On Fri, Aug 17, 2012 at 02:52:34PM +0200, Florian Weimer wrote:
> >+    {
> >+    case BUILT_IN_STRNCMP:
> >+    case BUILT_IN_STRNCASECMP:
> >+    case BUILT_IN_STRNCPY:
> >+    case BUILT_IN_STRNCAT:
> >+      strop = true;
> >+      /* FALLTHRU */
> >+    case BUILT_IN_MEMCPY:
> >+    case BUILT_IN_MEMMOVE:
> >+    case BUILT_IN_MEMCMP:
> >+      if (VEC_length (tree, params) < 3)
> >+	return;
> >+      src = VEC_index (tree, params, 1);
> >+      dest = VEC_index (tree, params, 0);
> >+      break;
> >+    case BUILT_IN_MEMSET:
> >+      if (VEC_length (tree, params) < 3)
> >+	return;
> >+      dest = VEC_index (tree, params, 0);
> >+      break;
> >+    case BUILT_IN_STRNDUP:
> >+      src = VEC_index (tree, params, 0);
> >+      strop = true;
> >+      break;
> >+    default:
> >+      break;
> >+    }
> 
> I think this would apply to memchr, snprintf, vsnprintf, stpncopy,
> bzero, bcopy, bcmp as well.  Or are some of them already lowered at
> this point?

s/stpncopy/stpncpy/, yeah, I guess, we could do that for those too,
but 1) I'd prefer to wait for the C++ FE change to go in first
2) {,v}snprintf would be much harder than the rest, as the size
argument then isn't the last argument to the function, and the FEs
only provide the last one right now.  The parser routine which parses
arguments doesn't know which fn it will be for, recording sizeof_arg
(including location_t) for all arguments would be an overkill,
perhaps we could record instead the first sizeof argument + its position in
the argument list.  That would not catch say
memset (ptr, sizeof (int), sizeof (ptr));
(as it would record 2nd argument, expr int and locus), but perhaps it is so
rare to use sizeof on second argument of memset that it doesn't matter.
On the other side it would help if somebody calls __builtin___memset_chk
and similar explicitly (sizeof in that case isn't the last argument, but
3rd), the above switch then could handle also BUILT_IN_*CHK.
That said, usually -D_FORTIFY_SOURCE is done through the string.h
wrapper inlines and that is handled already (and tested in the testcases).

	Jakub

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [C PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-16 19:14       ` [C " Jakub Jelinek
  2012-08-16 21:32         ` Joseph S. Myers
@ 2012-08-17 12:53         ` Florian Weimer
  2012-08-17 13:14           ` Jakub Jelinek
  1 sibling, 1 reply; 16+ messages in thread
From: Florian Weimer @ 2012-08-17 12:53 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Joseph S. Myers, gcc-patches, Jason Merrill, Paolo Carlini

On 08/16/2012 09:10 PM, Jakub Jelinek wrote:

> +  switch (DECL_FUNCTION_CODE (callee))
> +    {
> +    case BUILT_IN_STRNCMP:
> +    case BUILT_IN_STRNCASECMP:
> +    case BUILT_IN_STRNCPY:
> +    case BUILT_IN_STRNCAT:
> +      strop = true;
> +      /* FALLTHRU */
> +    case BUILT_IN_MEMCPY:
> +    case BUILT_IN_MEMMOVE:
> +    case BUILT_IN_MEMCMP:
> +      if (VEC_length (tree, params) < 3)
> +	return;
> +      src = VEC_index (tree, params, 1);
> +      dest = VEC_index (tree, params, 0);
> +      break;
> +    case BUILT_IN_MEMSET:
> +      if (VEC_length (tree, params) < 3)
> +	return;
> +      dest = VEC_index (tree, params, 0);
> +      break;
> +    case BUILT_IN_STRNDUP:
> +      src = VEC_index (tree, params, 0);
> +      strop = true;
> +      break;
> +    default:
> +      break;
> +    }

I think this would apply to memchr, snprintf, vsnprintf, stpncopy, 
bzero, bcopy, bcmp as well.  Or are some of them already lowered at this 
point?

-- 
Florian Weimer / Red Hat Product Security Team

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [C PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-16 19:14       ` [C " Jakub Jelinek
@ 2012-08-16 21:32         ` Joseph S. Myers
  2012-08-17 12:53         ` Florian Weimer
  1 sibling, 0 replies; 16+ messages in thread
From: Joseph S. Myers @ 2012-08-16 21:32 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Jason Merrill, Paolo Carlini

On Thu, 16 Aug 2012, Jakub Jelinek wrote:

> Hi!
> 
> On Wed, Aug 15, 2012 at 04:29:55PM +0000, Joseph S. Myers wrote:
> > On Wed, 15 Aug 2012, Jakub Jelinek wrote:
> > 
> > > I was mainly interested in whether such an approach is acceptable, or
> > > whether I need to stop evaluating sizeof right away, create SIZEOF_EXPR
> > > and only fold it during fully_fold*.  I've briefly looked at that today,
> > 
> > The approach is fine.  Delaying evaluating sizeof is hard simply because 
> > of the expectation that integer constant expressions in general are 
> > evaluated early.
> 
> Ok, thanks.  Here is an updated patch, which gets away just with one global
> variable (location_t computed from token after sizeof keyword in the
> caller).  Bootstrapped/regtested on x86_64-linux and i686-linux, ok for
> trunk?

This version is OK.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [C PATCH] -Wsizeof-pointer-memaccess warning
  2012-08-15 16:30     ` Joseph S. Myers
@ 2012-08-16 19:14       ` Jakub Jelinek
  2012-08-16 21:32         ` Joseph S. Myers
  2012-08-17 12:53         ` Florian Weimer
  0 siblings, 2 replies; 16+ messages in thread
From: Jakub Jelinek @ 2012-08-16 19:14 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gcc-patches, Jason Merrill, Paolo Carlini

Hi!

On Wed, Aug 15, 2012 at 04:29:55PM +0000, Joseph S. Myers wrote:
> On Wed, 15 Aug 2012, Jakub Jelinek wrote:
> 
> > I was mainly interested in whether such an approach is acceptable, or
> > whether I need to stop evaluating sizeof right away, create SIZEOF_EXPR
> > and only fold it during fully_fold*.  I've briefly looked at that today,
> 
> The approach is fine.  Delaying evaluating sizeof is hard simply because 
> of the expectation that integer constant expressions in general are 
> evaluated early.

Ok, thanks.  Here is an updated patch, which gets away just with one global
variable (location_t computed from token after sizeof keyword in the
caller).  Bootstrapped/regtested on x86_64-linux and i686-linux, ok for
trunk?

The fortran/ change is a bug that the patch discovered in the gcc
sources (well, as we now bootstrap with C++ it was actually the C++ patch
I'm going to post momentarily).

2012-08-16  Jakub Jelinek  <jakub@redhat.com>

	* doc/invoke.texi (-Wsizeof-pointer-memaccess): Document.
c/
	* c-tree.h (c_last_sizeof_arg): Declare.
	* c-parser.c (struct c_tree_loc_pair): New type.
	(c_parser_expr_list): Add sizeof_arg argument.  Fill it in if
	non-NULL.
	(c_parser_attributes, c_parser_objc_keywordexpr): Adjust callers.
	(c_parser_postfix_expression_after_primary): Likewise.  Call
	sizeof_pointer_memaccess_warning if needed.
	(sizeof_ptr_memacc_comptypes): New function.
	* c-typeck.c (c_last_sizeof_arg): New global variable.
	(c_expr_sizeof_expr, c_expr_sizeof_type): Initialize it.
cp/
	* cp-tree.def (SIZEOF_EXPR): Move to c-common.def.
c-family/
	* c-common.c (sizeof_pointer_memaccess_warning): New function.
	* c.opt (-Wsizeof-pointer-memaccess): Add new option.
	* c-opts.c (c_common_handle_option): Enable it for -Wall.
	* c-common.h (sizeof_pointer_memaccess_warning): Add prototype.
	* c-common.def (SIZEOF_EXPR): Moved here from cp-tree.def.
fortran/
	* array.c (gfc_match_array_ref): Fix up memset arguments.
testsuite/
	* gcc.dg/torture/Wsizeof-pointer-memaccess1.c: New test.

--- gcc/c/c-tree.h.jj	2012-08-15 11:30:33.045649950 +0200
+++ gcc/c/c-tree.h	2012-08-16 10:28:05.423879815 +0200
@@ -573,6 +573,8 @@ extern int in_alignof;
 extern int in_sizeof;
 extern int in_typeof;
 
+extern tree c_last_sizeof_arg;
+
 extern struct c_switch *c_switch_stack;
 
 extern tree c_objc_common_truthvalue_conversion (location_t, tree);
--- gcc/c/c-parser.c.jj	2012-08-15 11:30:32.987650235 +0200
+++ gcc/c/c-parser.c	2012-08-16 10:41:10.820017698 +0200
@@ -1111,6 +1111,12 @@ 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,
@@ -1179,7 +1185,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) **);
+					 VEC(tree,gc) **,
+					 struct c_tree_loc_pair *);
 static void c_parser_omp_construct (c_parser *);
 static void c_parser_omp_threadprivate (c_parser *);
 static void c_parser_omp_barrier (c_parser *);
@@ -3578,7 +3585,8 @@ c_parser_attributes (c_parser *parser)
 		{
 		  tree tree_list;
 		  c_parser_consume_token (parser);
-		  expr_list = c_parser_expr_list (parser, false, true, NULL);
+		  expr_list = c_parser_expr_list (parser, false, true,
+						  NULL, NULL);
 		  tree_list = build_tree_list_vec (expr_list);
 		  attr_args = tree_cons (NULL_TREE, arg1, tree_list);
 		  release_tree_vector (expr_list);
@@ -3590,7 +3598,8 @@ c_parser_attributes (c_parser *parser)
 		attr_args = NULL_TREE;
 	      else
 		{
-		  expr_list = c_parser_expr_list (parser, false, true, NULL);
+		  expr_list = c_parser_expr_list (parser, false, true,
+						  NULL, NULL);
 		  attr_args = build_tree_list_vec (expr_list);
 		  release_tree_vector (expr_list);
 		}
@@ -6845,6 +6854,15 @@ c_parser_postfix_expression_after_paren_
   return c_parser_postfix_expression_after_primary (parser, start_loc, expr);
 }
 
+/* Callback function for sizeof_pointer_memaccess_warning to compare
+   types.  */
+
+static bool
+sizeof_ptr_memacc_comptypes (tree type1, tree type2)
+{
+  return comptypes (type1, type2) == 1;
+}
+
 /* Parse a postfix expression after the initial primary or compound
    literal; that is, parse a series of postfix operators.
 
@@ -6857,6 +6875,7 @@ c_parser_postfix_expression_after_primar
 {
   struct c_expr orig_expr;
   tree ident, idx;
+  struct c_tree_loc_pair sizeof_arg;
   VEC(tree,gc) *exprlist;
   VEC(tree,gc) *origtypes;
   while (true)
@@ -6877,14 +6896,22 @@ c_parser_postfix_expression_after_primar
 	case CPP_OPEN_PAREN:
 	  /* Function call.  */
 	  c_parser_consume_token (parser);
+	  sizeof_arg.expr = NULL_TREE;
 	  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
 	    exprlist = NULL;
 	  else
-	    exprlist = c_parser_expr_list (parser, true, false, &origtypes);
+	    exprlist = c_parser_expr_list (parser, true, false, &origtypes,
+					   &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,
+					      expr.value, exprlist,
+					      sizeof_arg.expr,
+					      sizeof_ptr_memacc_comptypes);
 	  /* FIXME diagnostics: Ideally we want the FUNCNAME, not the
 	     "(" after the FUNCNAME, which is what we have now.    */
 	  expr.value = build_function_call_vec (op_loc, expr.value, exprlist,
@@ -7045,12 +7072,14 @@ 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)
+		    VEC(tree,gc) **p_orig_types,
+		    struct c_tree_loc_pair *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;
 
   ret = make_tree_vector ();
   if (p_orig_types == NULL)
@@ -7058,6 +7087,9 @@ c_parser_expr_list (c_parser *parser, bo
   else
     orig_types = make_tree_vector ();
 
+  if (sizeof_arg != NULL
+      && c_parser_next_token_is_keyword (parser, RID_SIZEOF))
+    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);
@@ -7070,6 +7102,11 @@ c_parser_expr_list (c_parser *parser, bo
     {
       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;
+      else
+	sizeof_arg_loc = UNKNOWN_LOCATION;
       expr = c_parser_expr_no_commas (parser, NULL);
       if (convert_p)
 	expr = default_function_array_read_conversion (loc, expr);
@@ -7079,6 +7116,20 @@ c_parser_expr_list (c_parser *parser, bo
       if (orig_types != NULL)
 	VEC_safe_push (tree, gc, orig_types, expr.original_type);
     }
+  if (sizeof_arg != NULL)
+    {
+      if (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;
+	}
+    }
   if (orig_types != NULL)
     *p_orig_types = orig_types;
   return ret;
@@ -8157,7 +8208,8 @@ static tree
 c_parser_objc_keywordexpr (c_parser *parser)
 {
   tree ret;
-  VEC(tree,gc) *expr_list = c_parser_expr_list (parser, true, true, NULL);
+  VEC(tree,gc) *expr_list = c_parser_expr_list (parser, true, true,
+						NULL, NULL);
   if (VEC_length (tree, expr_list) == 1)
     {
       /* Just return the expression, remove a level of
--- gcc/c/c-typeck.c.jj	2012-08-15 11:30:33.002650161 +0200
+++ gcc/c/c-typeck.c	2012-08-16 10:28:21.134802412 +0200
@@ -67,6 +67,10 @@ int in_sizeof;
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
+/* The argument of last parsed sizeof expression, only to be tested
+   if expr.original_code == SIZEOF_EXPR.  */
+tree c_last_sizeof_arg;
+
 /* Nonzero if we've already printed a "missing braces around initializer"
    message within this initializer.  */
 static int missing_braces_mentioned;
@@ -2603,7 +2607,8 @@ c_expr_sizeof_expr (location_t loc, stru
       tree folded_expr = c_fully_fold (expr.value, require_constant_value,
 				       &expr_const_operands);
       ret.value = c_sizeof (loc, TREE_TYPE (folded_expr));
-      ret.original_code = ERROR_MARK;
+      c_last_sizeof_arg = expr.value;
+      ret.original_code = SIZEOF_EXPR;
       ret.original_type = NULL;
       if (c_vla_type_p (TREE_TYPE (folded_expr)))
 	{
@@ -2631,7 +2636,8 @@ c_expr_sizeof_type (location_t loc, stru
   bool type_expr_const = true;
   type = groktypename (t, &type_expr, &type_expr_const);
   ret.value = c_sizeof (loc, type);
-  ret.original_code = ERROR_MARK;
+  c_last_sizeof_arg = type;
+  ret.original_code = SIZEOF_EXPR;
   ret.original_type = NULL;
   if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
       && c_vla_type_p (type))
--- gcc/cp/cp-tree.def.jj	2012-08-15 11:30:32.241653899 +0200
+++ gcc/cp/cp-tree.def	2012-08-16 10:16:11.064380908 +0200
@@ -2,7 +2,7 @@
    additional tree codes used in the GNU C++ compiler (see tree.def
    for the standard codes).
    Copyright (C) 1987, 1988, 1990, 1993, 1997, 1998, 2003, 2004, 2005,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2010, 2011
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2010, 2011, 2012
    Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
@@ -333,9 +333,6 @@ DEFTREECODE (TAG_DEFN, "tag_defn", tcc_e
 /* Represents an 'offsetof' expression during template expansion.  */
 DEFTREECODE (OFFSETOF_EXPR, "offsetof_expr", tcc_expression, 1)
 
-/* Represents a 'sizeof' expression during template expansion.  */
-DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
-
 /* Represents the -> operator during template expansion.  */
 DEFTREECODE (ARROW_EXPR, "arrow_expr", tcc_expression, 1)
 
--- gcc/doc/invoke.texi.jj	2012-08-16 10:15:36.297550048 +0200
+++ gcc/doc/invoke.texi	2012-08-16 10:16:11.070380880 +0200
@@ -263,9 +263,9 @@ Objective-C and Objective-C++ Dialects}.
 -Wpointer-arith  -Wno-pointer-to-int-cast @gol
 -Wredundant-decls @gol
 -Wreturn-type  -Wsequence-point  -Wshadow @gol
--Wsign-compare  -Wsign-conversion  -Wstack-protector @gol
--Wstack-usage=@var{len} -Wstrict-aliasing -Wstrict-aliasing=n @gol
--Wstrict-overflow -Wstrict-overflow=@var{n} @gol
+-Wsign-compare  -Wsign-conversion  -Wsizeof-pointer-memaccess @gol
+-Wstack-protector -Wstack-usage=@var{len} -Wstrict-aliasing @gol
+-Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol
 -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{]} @gol
 -Wmissing-format-attribute @gol
 -Wswitch  -Wswitch-default  -Wswitch-enum -Wsync-nand @gol
@@ -4327,6 +4327,16 @@ value, like assigning a signed integer e
 integer variable. An explicit cast silences the warning. In C, this
 option is enabled also by @option{-Wconversion}.
 
+@item -Wsizeof-pointer-memaccess
+@opindex Wsizeof-pointer-memaccess
+@opindex Wno-sizeof-pointer-memaccess
+Warn for suspicious length parameters to certain string and memory built-in
+functions if the argument uses @code{sizeof}.  This warning warns e.g.@:
+about @code{memset (ptr, 0, sizeof (ptr));} if @code{ptr} is not an array,
+but a pointer, and suggests a possible fix, or about
+@code{memcpy (&foo, ptr, sizeof (&foo));}.  This warning is enabled by
+@option{-Wall}.
+
 @item -Waddress
 @opindex Waddress
 @opindex Wno-address
--- gcc/c-family/c-common.c.jj	2012-08-15 11:30:31.961655279 +0200
+++ gcc/c-family/c-common.c	2012-08-16 10:16:11.074380858 +0200
@@ -1841,6 +1841,149 @@ strict_aliasing_warning (tree otype, tre
   return false;
 }
 
+/* Warn about memset (&a, 0, sizeof (&a)); and similar mistakes with
+   sizeof as last operand of certain builtins.  */
+
+void
+sizeof_pointer_memaccess_warning (location_t 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;
+
+  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:
+    case BUILT_IN_STRNCPY:
+    case BUILT_IN_STRNCAT:
+      strop = true;
+      /* FALLTHRU */
+    case BUILT_IN_MEMCPY:
+    case BUILT_IN_MEMMOVE:
+    case BUILT_IN_MEMCMP:
+      if (VEC_length (tree, params) < 3)
+	return;
+      src = VEC_index (tree, params, 1);
+      dest = VEC_index (tree, params, 0);
+      break;
+    case BUILT_IN_MEMSET:
+      if (VEC_length (tree, params) < 3)
+	return;
+      dest = VEC_index (tree, params, 0);
+      break;
+    case BUILT_IN_STRNDUP:
+      src = VEC_index (tree, params, 0);
+      strop = true;
+      break;
+    default:
+      break;
+    }
+
+  if (dest
+      && (tem = tree_strip_nop_conversions (dest))
+      && POINTER_TYPE_P (TREE_TYPE (tem))
+      && comp_types (TREE_TYPE (TREE_TYPE (tem)), type))
+    return;
+
+  if (src
+      && (tem = tree_strip_nop_conversions (src))
+      && POINTER_TYPE_P (TREE_TYPE (tem))
+      && comp_types (TREE_TYPE (TREE_TYPE (tem)), type))
+    return;
+
+  if (dest)
+    {
+      if (!TYPE_P (sizeof_arg)
+	  && operand_equal_p (dest, sizeof_arg, 0)
+	  && comp_types (TREE_TYPE (dest), type))
+	{
+	  if (TREE_CODE (sizeof_arg) == 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 "
+			"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 destination; 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 destination; 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 destination; expected %qT "
+		      "or an explicit length", callee, TREE_TYPE (dest),
+		      TREE_TYPE (TREE_TYPE (dest)));
+	  return;
+	}
+    }
+
+  if (src)
+    {
+      if (!TYPE_P (sizeof_arg)
+	  && operand_equal_p (src, sizeof_arg, 0)
+	  && comp_types (TREE_TYPE (src), type))
+	{
+	  if (TREE_CODE (sizeof_arg) == 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 "
+			"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 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 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 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
    of `main'.  */
 
--- gcc/c-family/c.opt.jj	2012-08-15 11:30:32.079654704 +0200
+++ gcc/c-family/c.opt	2012-08-16 10:16:11.076380847 +0200
@@ -474,6 +474,9 @@ Wmissing-field-initializers
 C ObjC C++ ObjC++ Var(warn_missing_field_initializers) Warning EnabledBy(Wextra)
 Warn about missing fields in struct initializers
 
+Wsizeof-pointer-memaccess
+C ObjC C++ ObjC++ Var(warn_sizeof_pointer_memaccess) Warning
+
 Wsuggest-attribute=format
 C ObjC C++ ObjC++ Var(warn_suggest_attribute_format) Warning
 Warn about functions which might be candidates for format attributes
--- gcc/c-family/c-opts.c.jj	2012-08-15 11:30:31.923655462 +0200
+++ gcc/c-family/c-opts.c	2012-08-16 10:16:11.076380847 +0200
@@ -374,6 +374,7 @@ c_common_handle_option (size_t scode, co
       warn_return_type = value;
       warn_sequence_point = value;	/* Was C only.  */
       warn_switch = value;
+      warn_sizeof_pointer_memaccess = value;
       if (warn_strict_aliasing == -1)
 	set_Wstrict_aliasing (&global_options, value);
       warn_address = value;
--- gcc/c-family/c-common.h.jj	2012-08-15 11:30:31.986655156 +0200
+++ gcc/c-family/c-common.h	2012-08-16 10:16:11.077380843 +0200
@@ -1,6 +1,6 @@
 /* Definitions for c-common.c.
-   Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
+   Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002,
+   2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -768,6 +768,9 @@ 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,
+					      bool (*) (tree, tree));
 extern void warnings_for_convert_and_check (tree, tree, tree);
 extern tree convert_and_check (tree, tree);
 extern void overflow_warning (location_t, tree);
--- gcc/c-family/c-common.def.jj	2012-08-15 11:30:32.033654924 +0200
+++ gcc/c-family/c-common.def	2012-08-16 10:16:11.077380843 +0200
@@ -53,6 +53,10 @@ DEFTREECODE (EXCESS_PRECISION_EXPR, "exc
    number.  */
 DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3)
 
+/* Represents a 'sizeof' expression during C++ template expansion,
+   or for the purpose of -Wsizeof-pointer-memaccess warning.  */
+DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
+
 /*
 Local variables:
 mode:c
--- gcc/fortran/array.c.jj	2012-08-10 15:49:17.000000000 +0200
+++ gcc/fortran/array.c	2012-08-16 17:59:38.941821058 +0200
@@ -159,7 +159,7 @@ gfc_match_array_ref (gfc_array_ref *ar,
   match m;
   bool matched_bracket = false;
 
-  memset (ar, '\0', sizeof (ar));
+  memset (ar, '\0', sizeof (*ar));
 
   ar->where = gfc_current_locus;
   ar->as = as;
--- gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c.jj	2012-08-16 10:16:11.078380839 +0200
+++ gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c	2012-08-16 10:16:11.078380839 +0200
@@ -0,0 +1,698 @@
+/* Test -Wsizeof-pointer-memaccess warnings.  */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+/* Test just twice, once with -O0 non-fortified, once with -O2 fortified.  */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0" "-O2" } } */
+/* { dg-skip-if "" { *-*-* }  { "-flto" } { "" } } */
+
+typedef __SIZE_TYPE__ size_t;
+extern void *memset (void *, int, size_t);
+extern void *memcpy (void *__restrict, const void *__restrict, size_t);
+extern void *memmove (void *__restrict, const void *__restrict, size_t);
+extern int memcmp (const void *, const void *, size_t);
+extern char *strncpy (char *__restrict, const char *__restrict, size_t);
+extern char *strncat (char *__restrict, const char *__restrict, size_t);
+extern char *strndup (const char *, size_t);
+extern int strncmp (const char *, const char *, size_t);
+extern int strncasecmp (const char *, const char *, size_t);
+
+#ifdef __OPTIMIZE__
+# define bos(ptr) __builtin_object_size (ptr, 1)
+# define bos0(ptr) __builtin_object_size (ptr, 0)
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memset (void *dest, int c, size_t len)
+{
+  return __builtin___memset_chk (dest, c, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memcpy (void *__restrict dest, const void *__restrict src, size_t len)
+{
+  return __builtin___memcpy_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline void *
+memmove (void *dest, const void *src, size_t len)
+{
+  return __builtin___memmove_chk (dest, src, len, bos0 (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncpy (char *__restrict dest, const char *__restrict src, size_t len)
+{
+  return __builtin___strncpy_chk (dest, src, len, bos (dest));
+}
+
+__attribute__((__always_inline__, __gnu_inline__, __artificial__))
+extern inline char *
+strncat (char *dest, const char *src, size_t len)
+{
+  return __builtin___strncat_chk (dest, src, len, bos (dest));
+}
+#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];
+
+int
+f1 (void *x, int z)
+{
+  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" } */
+
+  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" } */
+
+  /* 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));
+
+  /* These are correct, no warning.  */
+  z += memcmp (&a, x, sizeof a);
+  z += memcmp (&a, x, sizeof (a));
+  z += memcmp (&a, x, sizeof (struct A));
+  z += memcmp (&a, x, sizeof (const struct A));
+  z += memcmp (&a, x, sizeof (volatile struct A));
+  z += memcmp (&a, x, sizeof (volatile const struct A));
+  z += memcmp (&a, x, sizeof (TA));
+  z += memcmp (&a, x, sizeof (__typeof (*&a)));
+  z += memcmp (pa1, x, sizeof (*pa1));
+  z += memcmp (pa2, x, sizeof (*pa3));
+  z += memcmp (pa3, x, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  z += memcmp ((void *) &a, x, sizeof (&a));
+  z += memcmp ((char *) &a, x, sizeof (&a));
+  z += memcmp (&a, x, sizeof (&a) + 0);
+  z += memcmp (&a, x, 0 + sizeof (&a));
+
+  /* These are correct, no warning.  */
+  z += memcmp (x, &a, sizeof a);
+  z += memcmp (x, &a, sizeof (a));
+  z += memcmp (x, &a, sizeof (struct A));
+  z += memcmp (x, &a, sizeof (const struct A));
+  z += memcmp (x, &a, sizeof (volatile struct A));
+  z += memcmp (x, &a, sizeof (volatile const struct A));
+  z += memcmp (x, &a, sizeof (TA));
+  z += memcmp (x, &a, sizeof (__typeof (*&a)));
+  z += memcmp (x, pa1, sizeof (*pa1));
+  z += memcmp (x, pa2, sizeof (*pa3));
+  z += memcmp (x, pa3, sizeof (__typeof (*pa3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  z += memcmp (x, (void *) &a, sizeof (&a));
+  z += memcmp (x, (char *) &a, sizeof (&a));
+  z += memcmp (x, &a, sizeof (&a) + 0);
+  z += memcmp (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;
+  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" } */
+
+  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" } */
+
+  /* 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));
+
+  /* These are correct, no warning.  */
+  z += memcmp (&b, x, sizeof b);
+  z += memcmp (&b, x, sizeof (b));
+  z += memcmp (&b, x, sizeof (struct B));
+  z += memcmp (&b, x, sizeof (const struct B));
+  z += memcmp (&b, x, sizeof (volatile struct B));
+  z += memcmp (&b, x, sizeof (volatile const struct B));
+  z += memcmp (&b, x, sizeof (TB));
+  z += memcmp (&b, x, sizeof (__typeof (*&b)));
+  z += memcmp (pb1, x, sizeof (*pb1));
+  z += memcmp (pb2, x, sizeof (*pb3));
+  z += memcmp (pb3, x, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  z += memcmp ((void *) &b, x, sizeof (&b));
+  z += memcmp ((char *) &b, x, sizeof (&b));
+  z += memcmp (&b, x, sizeof (&b) + 0);
+  z += memcmp (&b, x, 0 + sizeof (&b));
+
+  /* These are correct, no warning.  */
+  z += memcmp (x, &b, sizeof b);
+  z += memcmp (x, &b, sizeof (b));
+  z += memcmp (x, &b, sizeof (struct B));
+  z += memcmp (x, &b, sizeof (const struct B));
+  z += memcmp (x, &b, sizeof (volatile struct B));
+  z += memcmp (x, &b, sizeof (volatile const struct B));
+  z += memcmp (x, &b, sizeof (TB));
+  z += memcmp (x, &b, sizeof (__typeof (*&b)));
+  z += memcmp (x, pb1, sizeof (*pb1));
+  z += memcmp (x, pb2, sizeof (*pb3));
+  z += memcmp (x, pb3, sizeof (__typeof (*pb3)));
+  /* These are probably broken, but obfuscated, no warning.  */
+  z += memcmp (x, (void *) &b, sizeof (&b));
+  z += memcmp (x, (char *) &b, sizeof (&b));
+  z += memcmp (x, &b, sizeof (&b) + 0);
+  z += memcmp (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;
+  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" } */
+
+  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" } */
+
+  /* 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));
+
+  /* These are correct, no warning.  */
+  z += memcmp (y, x, sizeof (*y));
+  z += memcmp (y1, x, sizeof (*y2));
+  z += memcmp (buf1, x, sizeof buf1);
+  z += memcmp (buf3, x, sizeof (buf3));
+  z += memcmp (&buf3[0], x, sizeof (buf3));
+  z += memcmp (&buf4[0], x, sizeof (buf4));
+  z += memcmp (&y3, y, sizeof (y3));
+  z += memcmp ((char *) &y3, y, sizeof (y3));
+  z += memcmp (w, x, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  z += memcmp ((void *) y, x, sizeof (y));
+  z += memcmp ((char *) y1, x, sizeof (y2));
+  z += memcmp (y, x, sizeof (y) + 0);
+  z += memcmp (y1, x, 0 + sizeof (y2));
+  z += memcmp ((void *) &c, x, sizeof (&c));
+  z += memcmp ((signed char *) &c, x, sizeof (&c));
+  z += memcmp (&c, x, sizeof (&c) + 0);
+  z += memcmp (&c, x, 0 + sizeof (&c));
+
+  /* These are correct, no warning.  */
+  z += memcmp (x, y, sizeof (*y));
+  z += memcmp (x, y1, sizeof (*y2));
+  z += memcmp (x, buf1, sizeof buf1);
+  z += memcmp (x, buf3, sizeof (buf3));
+  z += memcmp (x, &buf3[0], sizeof (buf3));
+  z += memcmp (x, &buf4[0], sizeof (buf4));
+  z += memcmp (y, &y3, sizeof (y3));
+  z += memcmp (y, (char *) &y3, sizeof (y3));
+  z += memcmp (x, w, sizeof (X));
+  /* These are probably broken, but obfuscated, no warning.  */
+  z += memcmp (x, (void *) y, sizeof (y));
+  z += memcmp (x, (char *) y1, sizeof (y2));
+  z += memcmp (x, y, sizeof (y) + 0);
+  z += memcmp (x, y1, 0 + sizeof (y2));
+  z += memcmp (x, (void *) &c, sizeof (&c));
+  z += memcmp (x, (signed char *) &c, sizeof (&c));
+  z += memcmp (x, &c, sizeof (&c) + 0);
+  z += memcmp (x, &c, 0 + sizeof (&c));
+
+  return z;
+}
+
+int
+f4 (char *x, char **y, int z)
+{
+  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" } */
+  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" } */
+
+  /* These are correct, no warning.  */
+  const char s3[] = "foobarbaz";
+  const char s4[] = "abcde12345678";
+  strncpy (x, s3, sizeof (s3));
+  strncat (x, s4, sizeof (s4));
+  y[1] = strndup (s3, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s3));
+  z += strncmp (s3, s4, sizeof (s4));
+  z += strncasecmp (s3, s4, sizeof (s3));
+  z += strncasecmp (s3, s4, sizeof (s4));
+
+  return z;
+}
+
+/* { dg-prune-output "\[\n\r\]*will always overflow\[\n\r\]*" } */


	Jakub

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2012-10-26 13:21 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-16 19:20 [C++ PATCH] -Wsizeof-pointer-memaccess warning Jakub Jelinek
2012-09-19 13:58 ` Jason Merrill
2012-09-25 16:28   ` Jakub Jelinek
2012-10-02 12:57     ` [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2) Jakub Jelinek
2012-10-03  9:14       ` Dodji Seketeli
2012-10-03  9:43         ` Jakub Jelinek
2012-10-05 13:45       ` Jason Merrill
2012-10-11  0:41       ` Hans-Peter Nilsson
2012-10-11 11:54         ` Committed, PR54897 (was: [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2)) Hans-Peter Nilsson
2012-10-26 13:36       ` [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2) Roman Zhuykov
  -- strict thread matches above, loose matches on Subject: below --
2012-07-18 12:40 [RFC PATCH] -Wsizeof-pointer-memaccess warning Jakub Jelinek
2012-08-15 15:39 ` Joseph S. Myers
2012-08-15 15:54   ` Jakub Jelinek
2012-08-15 16:30     ` Joseph S. Myers
2012-08-16 19:14       ` [C " Jakub Jelinek
2012-08-16 21:32         ` Joseph S. Myers
2012-08-17 12:53         ` Florian Weimer
2012-08-17 13:14           ` Jakub Jelinek
2012-08-17 13:27             ` Florian Weimer
2012-08-17 13:34               ` Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).