This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] For -Wformat purposes use ellipsis args before class to pointer to class conversion (PR c++/84076)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Jason Merrill <jason at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Thu, 8 Mar 2018 19:08:11 +0100
- Subject: [C++ PATCH] For -Wformat purposes use ellipsis args before class to pointer to class conversion (PR c++/84076)
- Authentication-results: sourceware.org; auth=none
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
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 <jakub@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