Hi!

The reporter complains that -Wformat incorrectly reports std::string* passed
to "%s" format rather than std::string, which is what the user did.

This transformation of non-trivial copy init or dtor classes in ellipsis is
done by convert_arg_to_ellipsis; that function does many changes and all
but this one look desirable for the -Wnonnull/-Wformat/-Wsentinel/-Wrestrict
warnings.  We prepare a special argument vector in any case, so this patch
just arranges to undo what convert_arg_to_ellipsis did for the classes.
I think -Wnonnull shouldn't care, because when passing such a class by
value, it will be non-NULL (and -Wnonnull looks only for literal NULLs
anyway), -Wrestrict only cares about named arguments and -Wsentinel only
cares about NULL arguments passed to ellipsis.

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

2018-03-08  Jakub Jelinek  <ja...@redhat.com>

        PR c++/84076
        * call.c (build_over_call): For purposes of check_function_arguments,
        undo convert_arg_to_ellipsis passing of classes with non-trivial
        copy ctor or dtor by invisible reference.

        * g++.dg/warn/Wformat-2.C: New test.

--- gcc/cp/call.c.jj    2018-03-07 22:51:58.698478669 +0100
+++ gcc/cp/call.c       2018-03-08 10:58:58.157373982 +0100
@@ -7967,6 +7967,8 @@ build_over_call (struct z_candidate *can
     }
 
   /* Ellipsis */
+  int ellipsis_first = j;
+  unsigned ellipsis_bias = arg_index - j;
   int magic = magic_varargs_p (fn);
   for (; arg_index < vec_safe_length (args); ++arg_index)
     {
@@ -8014,7 +8016,22 @@ build_over_call (struct z_candidate *can
       tree *fargs = (!nargs ? argarray
                            : (tree *) alloca (nargs * sizeof (tree)));
       for (j = 0; j < nargs; j++)
-       fargs[j] = maybe_constant_value (argarray[j]);
+       {
+         /* For the purposes of check_function_arguments, undo the implicit
+            passing of classes with non-trivial copy ctor or dtor in ellipsis
+            by invisible reference.  */
+         if (j >= ellipsis_first && POINTER_TYPE_P (TREE_TYPE (argarray[j])))
+           {
+             tree orig_type = TREE_TYPE ((*args)[ellipsis_bias + j]);
+             if (type_has_nontrivial_copy_init (orig_type)
+                 || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (orig_type))
+               {
+                 fargs[j] = (*args)[ellipsis_bias + j];
+                 continue;
+               }
+           }
+         fargs[j] = maybe_constant_value (argarray[j]);
+       }
 
       warned_p = check_function_arguments (input_location, fn, TREE_TYPE (fn),
                                           nargs, fargs, NULL);
--- gcc/testsuite/g++.dg/warn/Wformat-2.C.jj    2018-03-08 11:05:27.269422301 
+0100
+++ gcc/testsuite/g++.dg/warn/Wformat-2.C       2018-03-08 11:04:52.915418031 
+0100
@@ -0,0 +1,17 @@
+// PR c++/84076
+// { dg-do compile }
+// { dg-options "-Wformat" }
+
+struct S { ~S (); };
+struct T { T (); T (const T &); };
+
+void
+foo ()
+{
+  S s;
+  T t;
+  __builtin_printf ("%s\n", s);        // { dg-warning "format '%s' expects 
argument of type 'char\\*', but argument 2 has type 'S'" }
+  __builtin_printf ("%s\n", t);        // { dg-warning "format '%s' expects 
argument of type 'char\\*', but argument 2 has type 'T'" }
+  __builtin_printf ("%s\n", &s);// { dg-warning "format '%s' expects argument 
of type 'char\\*', but argument 2 has type 'S\\*'" }
+  __builtin_printf ("%s\n", &t);// { dg-warning "format '%s' expects argument 
of type 'char\\*', but argument 2 has type 'T\\*'" }
+}

        Jakub

Reply via email to