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

Hi!

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

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

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

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

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

	Jakub

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

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

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

Jason

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

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

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

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

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

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

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

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

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

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

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


	Jakub

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

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

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

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

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

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

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

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

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

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

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

	Jakub

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

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

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

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

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

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

-- 
		Dodji

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

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

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

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

	Jakub

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

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

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

It does, you can remove that call.

OK with that change.

Jason

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

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

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

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

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

There's now an "excess error":

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

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

brgds, H-P

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

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

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

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

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

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


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

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

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

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

--
Roman Zhuykov

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

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

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-16 19:20 [C++ PATCH] -Wsizeof-pointer-memaccess warning Jakub Jelinek
2012-09-19 13:58 ` Jason Merrill
2012-09-25 16:28   ` Jakub Jelinek
2012-10-02 12:57     ` [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2) Jakub Jelinek
2012-10-03  9:14       ` Dodji Seketeli
2012-10-03  9:43         ` Jakub Jelinek
2012-10-05 13:45       ` Jason Merrill
2012-10-11  0:41       ` Hans-Peter Nilsson
2012-10-11 11:54         ` Committed, PR54897 (was: [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2)) Hans-Peter Nilsson
2012-10-26 13:36       ` [C++ PATCH] -Wsizeof-pointer-memaccess warning (take 2) Roman Zhuykov

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