Bug 64867

Summary: split warning for passing non-POD to varargs function from -Wconditionally-supported into new warning flag, -Wnon-pod-varargs
Product: gcc Reporter: Tom Tromey <tromey>
Component: c++Assignee: Not yet assigned to anyone <unassigned>
Status: NEW ---    
Severity: enhancement CC: bisqwit, dcb314, egallager, gerald, jakub, jason, msebor, rsandifo, toojays, vz-gcc, webrown.cpp
Priority: P3 Keywords: diagnostic, easyhack
Version: unknown   
Target Milestone: ---   
See Also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84076
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90005
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37907
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2017-09-05 00:00:00
Bug Depends on:    
Bug Blocks: 87403    

Description Tom Tromey 2015-01-29 17:38:15 UTC
Currently gcc does not warn if I pass a non-POD to a
varargs function.  It would have been useful recently
if there was an option to make gcc warn about this.
Comment 1 Andrew Pinski 2015-01-29 18:27:56 UTC
From https://gcc.gnu.org/gcc-4.5/changes.html:
Diagnostics that used to complain about passing non-POD types to ... or jumping past the declaration of a non-POD variable now check for triviality rather than PODness, as per C++0x.


See PR 37907.

And having an example would be useful too.  Because of the change between C++98 and C++11.
Comment 2 Jonathan Wakely 2015-01-29 18:30:46 UTC
Jason informs me it's now a warning enabled by -Wconditionally-supported
Comment 3 Jason Merrill 2015-01-29 18:31:07 UTC
Passing a non-POD to a varargs function is conditionally-supported, with implementation-defined semantics.  In GCC 5 it's supported and treated like normal pass-by-value.  You can get a diagnostic about it with -Wconditionally-supported.
Comment 4 Tom Tromey 2015-01-29 20:45:43 UTC
Thanks, I'll give it a try.

Here's my test case FWIW and a short demo showing what clang does:

pokyo. cat q.cc
#include <stdarg.h>

class ConstUTF8CharsZ
{
    const char *mData;

  public:
    ConstUTF8CharsZ() : mData(0)
    {
    }

    explicit ConstUTF8CharsZ(const char *aBytes)
      : mData(aBytes)
    {
    }

    const void *get() const { return mData; }

    const char *c_str() const { return mData; }

    operator bool() const { return mData != 0; }
};


void zzz(const char *x, ...) {
}

void m(const char *m) {
  ConstUTF8CharsZ cu(m);
  zzz(m, cu);
}
pokyo. clang++ q.cc
q.cc:30:10: error: cannot pass object of non-POD type 'ConstUTF8CharsZ' through
      variadic function; call will abort at runtime [-Wnon-pod-varargs]
  zzz(m, cu);
         ^
1 error generated.
Comment 5 Tom Tromey 2015-01-30 17:04:22 UTC
(In reply to Jason Merrill from comment #3)
> Passing a non-POD to a varargs function is conditionally-supported, with
> implementation-defined semantics.  In GCC 5 it's supported and treated like
> normal pass-by-value.  You can get a diagnostic about it with
> -Wconditionally-supported.

I tried this today and it does not work with the test case in comment #4.

pokyo. gcc --version
gcc (GCC) 5.0.0 20150129 (experimental)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

pokyo. g++ --std=c++11 --syntax-only -Wall -Wconditionally-supported q.cc
pokyo.
Comment 6 Tom Tromey 2015-01-30 17:11:53 UTC
Also, -Wconditionally-supported triggers other warning as well.
It would be more convenient if different warnings were individually
controllable; and then something like -Wconditionally-supported
would act as if I'd specified all the sub-options.
Comment 7 Andrew Pinski 2015-01-30 17:22:58 UTC
(In reply to Tom Tromey from comment #5)
> (In reply to Jason Merrill from comment #3)
> > Passing a non-POD to a varargs function is conditionally-supported, with
> > implementation-defined semantics.  In GCC 5 it's supported and treated like
> > normal pass-by-value.  You can get a diagnostic about it with
> > -Wconditionally-supported.
> 
> I tried this today and it does not work with the test case in comment #4.
> 
> pokyo. gcc --version
> gcc (GCC) 5.0.0 20150129 (experimental)
> Copyright (C) 2015 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions.  There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
> 
> pokyo. g++ --std=c++11 --syntax-only -Wall -Wconditionally-supported q.cc
> pokyo.

Are you sure that class is not trivial which is why gcc is not warning about it?  C++11 does not really have pod and non-pod any more but rather trivial and non-trivial and the rules has chnaged with respect of constructures.
Comment 8 Andrew Pinski 2015-01-30 17:26:34 UTC
See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm . It does look like gcc is implementing the correct new pod rules and clang is not.
Comment 9 Tom Tromey 2015-01-30 17:40:23 UTC
> Are you sure that class is not trivial which is why gcc is not warning about
> it?  C++11 does not really have pod and non-pod any more but rather trivial
> and non-trivial and the rules has chnaged with respect of constructures.

I hesitate to say I'm sure :)

However my belief is that because this class has a user-provided
default constructor, it is not trivial.

I tested this by adding "#include <type_traits>" and then

static_assert(!std::is_trivial<ConstUTF8CharsZ>::value, "whoops");


Trivial or not, I'd like to get a warning here.  In firefox varargs
is really only used for printf-like things; but for various reasons
there are some custom implementations which can't be marked
with the "printf" attribute.  So while doing a refactoring it turned
out I inadvertently changed code to pass objects rather than char*
to one of these ... but finding the problem locations is proving
to be rather difficult.
Comment 10 Jakub Jelinek 2015-01-30 18:49:52 UTC
FYI, g++ stopped warning on #c4 with r149721.
Comment 11 Jonathan Wakely 2015-01-31 02:37:20 UTC
(In reply to Tom Tromey from comment #9)
> However my belief is that because this class has a user-provided
> default constructor, it is not trivial.

True, but ...
 
> I tested this by adding "#include <type_traits>" and then
> 
> static_assert(!std::is_trivial<ConstUTF8CharsZ>::value, "whoops");

That's the wrong thing to assert:

  Passing a potentially-evaluated argument of class type (Clause 9)
  having a non-trivial copy constructor, a non-trivial move constructor,
  or a non-trivial destructor, with no corresponding parameter, is
  conditionally-supported with implementation-defined semantics.

Your type has a trivial copy constructor and trivial move constructor and trivial destructor, so passing it to a varargs function is well-defined.

Give it a non-trivial destructor and you get a warning:

cs.cc: In function ‘void m(const char*)’:
cs.cc:33:12: warning: passing objects of non-trivially-copyable type ‘class ConstUTF8CharsZ’ through ‘...’ is conditionally supported [-Wconditionally-supported]
   zzz(m, cu);
            ^
Comment 12 Jonathan Wakely 2015-01-31 02:39:11 UTC
N.B. trivially-copyable is not the same as trivial (and there are separate type traits for testing those two properties).
Comment 13 Tom Tromey 2015-02-02 19:37:57 UTC
(In reply to Jonathan Wakely from comment #11)

> That's the wrong thing to assert:

Aha, thank you very much.  I obviously did not realize the difference :)

Unfortunately I think even if I made this change I probably wouldn't
want to enable -Wconditionally-supported here, as it enables some
other warning that IIRC isn't desirable here.

I ended up writing a gcc plugin to find places passing an aggregate
to a varargs function.  But I still think some simpler way to get
a warning here would be nice.
Comment 14 John Steele Scott 2017-07-13 02:34:04 UTC
FWIW Clang has this warning via -Wnon-pod-varargs.
Comment 15 Eric Gallager 2017-09-05 10:55:33 UTC
*** Bug 67559 has been marked as a duplicate of this bug. ***
Comment 16 Eric Gallager 2017-09-05 11:02:15 UTC
(In reply to John Steele Scott from comment #14)
> FWIW Clang has this warning via -Wnon-pod-varargs.

Confirmed, gcc having this warning would help avoid: http://gcc.gnu.org/ml/gcc-patches/2017-09/msg00126.html
Comment 17 Jonathan Wakely 2017-09-05 11:41:35 UTC
This adds -Wnon-pod-varargs, enabled by -Wconditionally-supported, allowing e.g.
-Wconditionally-supported -Werror=non-pod-varargs

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 3435fe90cca..b6ac29cda64 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -714,6 +714,10 @@ Wnamespaces
 C++ ObjC++ Var(warn_namespaces) Warning
 Warn on namespace definition.
 
+Wnon-pod-varargs
+C++ ObjC++ Var(warn_non_pod_varargs) Warning LangEnabledBy(C++ ObjC++,Wconditionally-supported)
+Warn if passing a non-POD object through the \"...\" of a varargs function.
+
 Wpacked-not-aligned
 C ObjC C++ ObjC++ Var(warn_packed_not_aligned) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn when fields in a struct with the packed attribute are misaligned.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 9e4a5c1b9ae..fc9f74f5968 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7164,10 +7164,12 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
              || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (arg_type)))
        {
          if (complain & tf_warning)
-           warning (OPT_Wconditionally_supported,
-                    "passing objects of non-trivially-copyable "
-                    "type %q#T through %<...%> is conditionally supported",
-                    arg_type);
+           {
+             warning (OPT_Wnon_pod_varargs,
+                      "passing objects of non-trivially-copyable "
+                      "type %q#T through %<...%> is conditionally supported",
+                      arg_type);
+           }
          return cp_build_addr_expr (arg, complain);
        }
     }
Comment 18 Richard Sandiford 2017-09-05 14:11:29 UTC
(In reply to Eric Gallager from comment #16)
> (In reply to John Steele Scott from comment #14)
> > FWIW Clang has this warning via -Wnon-pod-varargs.
> 
> Confirmed, gcc having this warning would help avoid:
> http://gcc.gnu.org/ml/gcc-patches/2017-09/msg00126.html

Yeah.  The situation is similar to the code in comment #4,
which as Jakub says in comment #10 no longer produces a warning
with g++ -Wconditionally-supported.  I had to add a dummy
destructor to get one.
Comment 19 Jonathan Wakely 2017-09-05 15:37:00 UTC
Whether Clang warns or not depends on the -std mode active, as that decides the definition of a POD it uses. GCC always uses the C++11 rule, which I quoted in comment 9.
Comment 20 Eric Gallager 2017-12-06 15:49:06 UTC
(In reply to Jonathan Wakely from comment #17)
> This adds -Wnon-pod-varargs, enabled by -Wconditionally-supported, allowing
> e.g.
> -Wconditionally-supported -Werror=non-pod-varargs
> 
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 3435fe90cca..b6ac29cda64 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -714,6 +714,10 @@ Wnamespaces
>  C++ ObjC++ Var(warn_namespaces) Warning
>  Warn on namespace definition.
>  
> +Wnon-pod-varargs
> +C++ ObjC++ Var(warn_non_pod_varargs) Warning LangEnabledBy(C++
> ObjC++,Wconditionally-supported)
> +Warn if passing a non-POD object through the \"...\" of a varargs function.
> +
>  Wpacked-not-aligned
>  C ObjC C++ ObjC++ Var(warn_packed_not_aligned) Warning LangEnabledBy(C ObjC
> C++ ObjC++,Wall)
>  Warn when fields in a struct with the packed attribute are misaligned.
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index 9e4a5c1b9ae..fc9f74f5968 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -7164,10 +7164,12 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t
> complain)
>               || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (arg_type)))
>         {
>           if (complain & tf_warning)
> -           warning (OPT_Wconditionally_supported,
> -                    "passing objects of non-trivially-copyable "
> -                    "type %q#T through %<...%> is conditionally supported",
> -                    arg_type);
> +           {
> +             warning (OPT_Wnon_pod_varargs,
> +                      "passing objects of non-trivially-copyable "
> +                      "type %q#T through %<...%> is conditionally
> supported",
> +                      arg_type);
> +           }
>           return cp_build_addr_expr (arg, complain);
>         }
>      }

Has this patch been posted to the gcc-patches mailing list yet?
Comment 21 Jonathan Wakely 2017-12-06 16:32:18 UTC
No, because it doesn't have any tests.

It should probably adjust:

../gcc/testsuite/g++.dg/overload/ellipsis1.C
../gcc/testsuite/g++.dg/overload/ellipsis2.C
../gcc/testsuite/g++.old-deja/g++.pt/vaarg3.C

to use the new flag, and add a test that the new flag is enabled by -Wconditionally-supported
Comment 22 Eric Gallager 2017-12-07 15:54:47 UTC
(In reply to Jonathan Wakely from comment #21)
> No, because it doesn't have any tests.
> 
> It should probably adjust:
> 
> ../gcc/testsuite/g++.dg/overload/ellipsis1.C
> ../gcc/testsuite/g++.dg/overload/ellipsis2.C
> ../gcc/testsuite/g++.old-deja/g++.pt/vaarg3.C
> 
> to use the new flag, and add a test that the new flag is enabled by
> -Wconditionally-supported

OK, I think I can do this.
Comment 23 Eric Gallager 2017-12-12 14:49:50 UTC
(In reply to Eric Gallager from comment #22)
> (In reply to Jonathan Wakely from comment #21)
> > No, because it doesn't have any tests.
> > 
> > It should probably adjust:
> > 
> > ../gcc/testsuite/g++.dg/overload/ellipsis1.C
> > ../gcc/testsuite/g++.dg/overload/ellipsis2.C
> > ../gcc/testsuite/g++.old-deja/g++.pt/vaarg3.C
> > 
> > to use the new flag, and add a test that the new flag is enabled by
> > -Wconditionally-supported
> 
> OK, I think I can do this.

Actually never mind; I can't test because I'm blocked from bootstrapping by bug 83284; unassigning...
Comment 24 Eric Gallager 2018-07-18 13:54:30 UTC
*** Bug 86562 has been marked as a duplicate of this bug. ***
Comment 25 Eric Gallager 2019-04-09 15:12:31 UTC
retitling
Comment 26 Eric Gallager 2019-07-09 04:15:37 UTC
Martin Sebor has been doing stuff related to warnings about POD-ness lately; cc-ing him
Comment 27 Trass3r 2020-01-25 11:19:06 UTC
This should really be enabled by -Wall or -Wextra as it generates code that may easily crash or corrupt something.
Clang even turns it into an error by default and inserts a trap to abort at runtime: https://godbolt.org/z/8DAUAr
Comment 28 Andrew Pinski 2020-01-25 11:25:58 UTC
(In reply to Trass3r from comment #27)
> This should really be enabled by -Wall or -Wextra as it generates code that
> may easily crash or corrupt something.

But GCC supports this fully.  That is why it is/was part of -Wconditionally-supported .  The code if used correctly does not cause crashes or corrupts anything. 

In fact GCC documents this behavior:
https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/Conditionally-supported-behavior.html#Conditionally-supported-behavior
:)

> Clang even turns it into an error by default and inserts a trap to abort at
> runtime: https://godbolt.org/z/8DAUAr
But clang does not support this.  Both compilers are correct; in that this feature is considered as conditionally supported with implementation defined behavior.  So both compilers are prefectly ok in having their own choices.
Comment 29 Trass3r 2020-01-25 12:52:24 UTC
Ah I see, ok.
Comment 30 David Binderman 2021-09-03 18:17:11 UTC
(In reply to Trass3r from comment #27)
> This should really be enabled by -Wall or -Wextra as it generates code that
> may easily crash or corrupt something.

+1.

Clang errors, intel warns and for gcc you have to enable the somewhat
obscure flag -Wconditionally-supported to see anything at all.

gcc looks to be a trailer on this issue. It's not about standards conformance,
its about making it easy for users to find bugs.

Source code I used is:

struct S
{
	S();
	S( const S &);
	~S();

	char * p;
};

void f( int, ...);

void g()
{
	S s1;

	f( 3, s1);
};

$ /home/dcb/llvm/results/bin/clang++   sep3f.cc
sep3f.cc:19:8: error: cannot pass object of non-trivial type 'S' through variadic function; call will abort at runtime [-Wnon-pod-varargs]
        f( 3, s1);
              ^
1 error generated.

$ /home/dcb34/intel/oneapi/compiler/2021.3.0/linux/bin/intel64/icpc  sep3f.cc
sep3f.cc(19): warning #1595: a class type that is not trivially copyable passed through ellipsis
  	f( 3, s1);
  	      ^

$ /home/dcb/gcc/results/bin/g++ -c -g -O2 -Wall -Wextra  sep3f.cc
$ /home/dcb/gcc/results/bin/g++ -c -g -O2 -Wall -Wextra -Wconditionally-supported sep3f.cc
sep3f.cc: In function ‘void g()’:
sep3f.cc:19:10: warning: passing objects of non-trivially-copyable type ‘struct S’ through ‘...’ is conditionally supported [-Wconditionally-supported]
   19 |         f( 3, s1);
      |         ~^~~~~~~~


I'll add flag -Wconditionally-supported to a build of Fedora and see
what happens.
Comment 31 Jason Merrill 2022-12-05 15:05:16 UTC
(In reply to David Binderman from comment #30)
> gcc looks to be a trailer on this issue. It's not about standards conformance,
> its about making it easy for users to find bugs.

But under GCC it's not a bug, it just works.  Clang is welcome to adopt the same semantics.  But I'm also happy to accept the patch in comment #17 once it includes testing.

And GCC should build with -Wconditionally-supported so we support bootstrapping with compilers that make different choices.
Comment 32 GCC Commits 2022-12-19 15:56:44 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:263c22a95bc9a0d80c4873c0291b0f938cea7310

commit r13-4795-g263c22a95bc9a0d80c4873c0291b0f938cea7310
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Dec 5 10:00:31 2022 -0500

    build: add -Wconditionally-supported to strict_warn [PR64867]
    
    The PR (which isn't resolved by this commit) pointed out to me that GCC
    should build with -Wconditionally-supported to support bootstrapping with a
    C++11 compiler that makes different choices.
    
            PR c++/64867
    
    gcc/ChangeLog:
    
            * configure.ac (strict_warn): Add -Wconditionally-supported.
            * configure: Regenerate.