Test program: #include <stdio.h> #include <string> int main(void) { std::string str; printf("%s\n", str); } GCC 4.9 and older gives: test.cpp: In function ‘int main()’: test.cpp:7:20: error: cannot pass objects of non-trivially-copyable type ‘std::string {aka class std::basic_string<char>}’ through ‘...’ printf("%s\n", str); ^ GCC 5.0 and newer (including 7.3.0) prints: test.cpp: In function ‘int main()’: test.cpp:7:20: warning: format ‘%s’ expects argument of type ‘char*’, but argument 2 has type ‘std::__cxx11::string* {aka std::__cxx11::basic_string<char>*}’ [-Wformat=] printf("%s\n", str); ^ This is a confusing warning, since it claims I'm sending a std::string * when I'm sending a std::string. In particular, in the program I was trying to fix this by adding ->c_str(), but .c_str() was the correct choice.
With -Wconditionally-supported you'd get additional warning: pr84076.C: In function ‘int main()’: pr84076.C:7:27: warning: passing objects of non-trivially-copyable type ‘std::__cxx11::string’ {aka ‘class std::__cxx11::basic_string<char>’} through ‘...’ is conditionally supported [-Wconditionally-supported] printf("%s\n", str); ^ The reason for the std::string * in diagnostics is that is how we actually implement the ... passing of non-trivially-copyable objects, we pass them by invisible reference as they are passed to named arguments, and the -Wformat code can't find anymore whether the user actually passed the std::string object or an address of it.
The convert_arg_to_ellipsis call that converts in this case the non-POD class to its address is done very shortly before calling the -Wformat check, but most of the stuff the function is doing is needed for the following check_format_arguments. So, in order to hide this in diagnostics, we'd either need to somehow mark the tree with the argument that check_format_arguments could determine it is implicitly added, or have another on the side array with the argument types for -Wformat* etc. The question is though if we want or don't want to warn for std::string str; printf ("%p\n", str); where str is passed as reference and thus printing address of it would work just fine.
printf aside, is this thing actually supported in varargs? I thought non-PODs were not allowed in varargs, period. (If it's not allowed, I'm not sure why the compiler even tries.)
(In reply to sgunderson from comment #3) > printf aside, is this thing actually supported in varargs? I thought > non-PODs were not allowed in varargs, period. (If it's not allowed, I'm not > sure why the compiler even tries.) Related: bug 64867
Ah, so it's allowed to send structs and classes, just not non-PODs. So that's why the conversion to a pointer happens.
Created attachment 43596 [details] gcc8-pr84076.patch Untested fix.
Author: jakub Date: Fri Mar 9 20:39:14 2018 New Revision: 258397 URL: https://gcc.gnu.org/viewcvs?rev=258397&root=gcc&view=rev Log: PR c++/84076 * call.c (convert_arg_to_ellipsis): Instead of cp_build_addr_expr build ADDR_EXPR with REFERENCE_TYPE. (build_over_call): For purposes of check_function_arguments, if argarray[j] is ADDR_EXPR with REFERENCE_TYPE created above, use its operand rather than the argument itself. * g++.dg/warn/Wformat-2.C: New test. Added: trunk/gcc/testsuite/g++.dg/warn/Wformat-2.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/call.c trunk/gcc/testsuite/ChangeLog
Fixed on the trunk so far.
Author: jakub Date: Fri Jun 22 20:34:33 2018 New Revision: 261917 URL: https://gcc.gnu.org/viewcvs?rev=261917&root=gcc&view=rev Log: Backported from mainline 2018-03-09 Jason Merrill <jason@redhat.com> Jakub Jelinek <jakub@redhat.com> PR c++/84076 * call.c (convert_arg_to_ellipsis): Instead of cp_build_addr_expr build ADDR_EXPR with REFERENCE_TYPE. (build_over_call): For purposes of check_function_arguments, if argarray[j] is ADDR_EXPR with REFERENCE_TYPE created above, use its operand rather than the argument itself. * g++.dg/warn/Wformat-2.C: New test. Added: branches/gcc-7-branch/gcc/testsuite/g++.dg/warn/Wformat-2.C Modified: branches/gcc-7-branch/gcc/cp/ChangeLog branches/gcc-7-branch/gcc/cp/call.c branches/gcc-7-branch/gcc/testsuite/ChangeLog
Author: jakub Date: Mon Jun 25 17:30:03 2018 New Revision: 262073 URL: https://gcc.gnu.org/viewcvs?rev=262073&root=gcc&view=rev Log: Backported from mainline 2018-03-09 Jason Merrill <jason@redhat.com> Jakub Jelinek <jakub@redhat.com> PR c++/84076 * call.c (convert_arg_to_ellipsis): Instead of cp_build_addr_expr build ADDR_EXPR with REFERENCE_TYPE. (build_over_call): For purposes of check_function_arguments, if argarray[j] is ADDR_EXPR with REFERENCE_TYPE created above, use its operand rather than the argument itself. * g++.dg/warn/Wformat-2.C: New test. Added: branches/gcc-6-branch/gcc/testsuite/g++.dg/warn/Wformat-2.C Modified: branches/gcc-6-branch/gcc/cp/ChangeLog branches/gcc-6-branch/gcc/cp/call.c branches/gcc-6-branch/gcc/testsuite/ChangeLog
Fixed for 6.5 and 7.4+ too.