C++ PATCH for c++/58710, -Wmemset-elt-size in a template

Message ID CADzB+2mW78ED3iF97g=SDeJYs+8z6jE5dAfn7VgpQ9DCXuyGYA@mail.gmail.com
State New
Headers show
Series
  • C++ PATCH for c++/58710, -Wmemset-elt-size in a template
Related show

Commit Message

Jason Merrill June 6, 2018, 3:12 p.m.
In this testcase, -Wmemset-elt-size was crashing because
TYPE_UNIT_SIZE of A<int> was NULL.  The first hunk fixes that.  The
patch also moves the warning into finish_call_expr so that it can be
issued at instantiation time as well, for dependent arguments.  And I
noticed that we were unnecessarily wrapping CONST_DECL in
NON_DEPENDENT_EXPR.

Tested x86_64-pc-linux-gnu, applying to trunk.

Patch

commit 94e6a80b724b3f2f8f83274a4f74ab13915d42f0
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jun 6 11:06:48 2018 +0200

            PR c++/85710 - ICE with -Wmemset-elt-size.
    c-family/
            * c-warn.c (warn_for_memset): Don't crash on incomplete element type.
    cp/
            * semantics.c (finish_call_expr): Call warn_for_memset here.
            * parser.c (cp_parser_postfix_expression): Not here.
            (literal_integer_zerop): No longer static.
            * pt.c (build_non_dependent_expr): Don't wrap CONST_DECL.

diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index e7bcbb18a3c..859d72b3f83 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -1897,7 +1897,8 @@  warn_for_memset (location_t loc, tree arg0, tree arg2,
 	{
 	  tree elt_type = TREE_TYPE (type);
 	  tree domain = TYPE_DOMAIN (type);
-	  if (!integer_onep (TYPE_SIZE_UNIT (elt_type))
+	  if (COMPLETE_TYPE_P (elt_type)
+	      && !integer_onep (TYPE_SIZE_UNIT (elt_type))
 	      && domain != NULL_TREE
 	      && TYPE_MAX_VALUE (domain)
 	      && TYPE_MIN_VALUE (domain)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f2016f173bd..a6d0b431a9d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6548,6 +6548,7 @@  extern bool parsing_default_capturing_generic_lambda_in_template (void);
 extern void inject_this_parameter (tree, cp_cv_quals);
 extern location_t defarg_location (tree);
 extern void maybe_show_extern_c_location (void);
+extern bool literal_integer_zerop (const_tree);
 
 /* in pt.c */
 extern bool check_template_shadow		(tree);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index de090d42d8d..03aea2f1150 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -6614,11 +6614,11 @@  cp_parser_compound_literal_p (cp_parser *parser)
 /* Return true if EXPR is the integer constant zero or a complex constant
    of zero, without any folding, but ignoring location wrappers.  */
 
-static bool
+bool
 literal_integer_zerop (const_tree expr)
 {
-  STRIP_ANY_LOCATION_WRAPPER (expr);
-  return integer_zerop (expr);
+  return (location_wrapper_p (expr)
+	  && integer_zerop (TREE_OPERAND (expr, 0)));
 }
 
 /* Parse a postfix-expression.
@@ -7159,19 +7159,6 @@  cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 		  }
 	      }
 
-	    if (TREE_CODE (postfix_expression) == FUNCTION_DECL
-		&& DECL_BUILT_IN_CLASS (postfix_expression) == BUILT_IN_NORMAL
-		&& DECL_FUNCTION_CODE (postfix_expression) == BUILT_IN_MEMSET
-		&& vec_safe_length (args) == 3)
-	      {
-		tree arg0 = (*args)[0];
-		tree arg1 = (*args)[1];
-		tree arg2 = (*args)[2];
-		int literal_mask = ((literal_integer_zerop (arg1) << 1)
-				    | (literal_integer_zerop (arg2) << 2));
-		warn_for_memset (input_location, arg0, arg2, literal_mask);
-	      }
-
 	    if (TREE_CODE (postfix_expression) == COMPONENT_REF)
 	      {
 		tree instance = TREE_OPERAND (postfix_expression, 0);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index aad68a32643..448cd69b722 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -25837,8 +25837,8 @@  build_non_dependent_expr (tree expr)
   if (is_overloaded_fn (inner_expr)
       || TREE_CODE (inner_expr) == OFFSET_REF)
     return orig_expr;
-  /* There is no need to return a proxy for a variable.  */
-  if (VAR_P (expr))
+  /* There is no need to return a proxy for a variable or enumerator.  */
+  if (VAR_P (expr) || TREE_CODE (expr) == CONST_DECL)
     return orig_expr;
   /* Preserve string constants; conversions from string constants to
      "char *" are allowed, even though normally a "const char *"
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index a3426623385..55791894221 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2350,7 +2350,7 @@  finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 {
   tree result;
   tree orig_fn;
-  vec<tree, va_gc> *orig_args = NULL;
+  vec<tree, va_gc> *orig_args = *args;
 
   if (fn == error_mark_node)
     return error_mark_node;
@@ -2524,6 +2524,22 @@  finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 		 sizeof_arg, same_type_ignoring_top_level_qualifiers_p);
 	    }
 
+	  if ((complain & tf_warning)
+	      && TREE_CODE (fn) == FUNCTION_DECL
+	      && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
+	      && DECL_FUNCTION_CODE (fn) == BUILT_IN_MEMSET
+	      && vec_safe_length (*args) == 3
+	      && !any_type_dependent_arguments_p (*args))
+	    {
+	      tree arg0 = (*orig_args)[0];
+	      tree arg1 = (*orig_args)[1];
+	      tree arg2 = (*orig_args)[2];
+	      int literal_mask = ((literal_integer_zerop (arg1) << 1)
+				  | (literal_integer_zerop (arg2) << 2));
+	      arg2 = instantiate_non_dependent_expr (arg2);
+	      warn_for_memset (input_location, arg0, arg2, literal_mask);
+	    }
+
 	  /* A call to a namespace-scope function.  */
 	  result = build_new_function_call (fn, args, complain);
 	}
diff --git a/gcc/testsuite/g++.dg/warn/Wmemset-elt-size1.C b/gcc/testsuite/g++.dg/warn/Wmemset-elt-size1.C
new file mode 100644
index 00000000000..e4d3232063d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wmemset-elt-size1.C
@@ -0,0 +1,31 @@ 
+// PR c++/85710
+// { dg-additional-options -Wmemset-elt-size }
+
+#include <cstring>
+
+template <typename T> struct A { int a; };
+
+void foo(A<int> (*ap)[2])
+{
+  std::memset (*ap, 0, 2);	// no warning because A<int> is incomplete
+}
+
+template <typename T>
+class E
+{
+public:
+  void Clear();
+private:
+  A<T> mA[2];
+};
+
+template<typename T>
+void E<T>::Clear()
+{
+  std::memset(mA, 0, 2);	// { dg-warning -Wmemset-elt-size }
+}
+
+int main()
+{
+  E<int>().Clear();
+}