Bug 84076 - [6/7 Regression] Warning about objects through POD mistakenly claims the object is a pointer
Summary: [6/7 Regression] Warning about objects through POD mistakenly claims the obje...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 7.3.0
: P3 normal
Target Milestone: 6.5
Assignee: Jakub Jelinek
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2018-01-27 13:11 UTC by Steinar H. Gunderson
Modified: 2018-06-25 18:12 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2018-03-09 00:00:00


Attachments
gcc8-pr84076.patch (1.02 KB, patch)
2018-03-08 10:13 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Steinar H. Gunderson 2018-01-27 13:11:10 UTC
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.
Comment 1 Jakub Jelinek 2018-01-29 08:16:52 UTC
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.
Comment 2 Jakub Jelinek 2018-01-29 08:26:06 UTC
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.
Comment 3 Steinar H. Gunderson 2018-01-30 09:46:21 UTC
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.)
Comment 4 Eric Gallager 2018-01-30 16:44:18 UTC
(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
Comment 5 Steinar H. Gunderson 2018-01-30 18:16:12 UTC
Ah, so it's allowed to send structs and classes, just not non-PODs. So that's why the conversion to a pointer happens.
Comment 6 Jakub Jelinek 2018-03-08 10:13:02 UTC
Created attachment 43596 [details]
gcc8-pr84076.patch

Untested fix.
Comment 7 Jakub Jelinek 2018-03-09 20:39:45 UTC
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
Comment 8 Jakub Jelinek 2018-03-09 20:40:28 UTC
Fixed on the trunk so far.
Comment 9 Jakub Jelinek 2018-06-22 20:35:05 UTC
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
Comment 10 Jakub Jelinek 2018-06-25 17:30:43 UTC
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
Comment 11 Jakub Jelinek 2018-06-25 18:12:39 UTC
Fixed for 6.5 and 7.4+ too.