[C++ PATCH] -Wsizeof-pointer-memaccess warning

Jakub Jelinek jakub@redhat.com
Thu Aug 16 19:20:00 GMT 2012


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



More information about the Gcc-patches mailing list