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