Mailing List Archive

Can we get rid of '-Wc++-compat' build-time warnings?
When we build Perl 5 blead using 'gcc' version 9 or later, we get 240
instances of the '-Wc++-compat' warning. When we build with 'gcc'
version 8, we do not get this build-time warning at all.

A typical '-Wc++-compat' warning will look like this:
#####
gcc12 -c -I./Encode -I../Encode -DHAS_FPSETMASK -DHAS_FLOATINGPOINT_H
-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong
-I/usr/local/include -D_FORTIFY_SOURCE=2 -Wall -Werror=pointer-arith
-Werror=vla -Wextra -Wc++-compat -Wwrite-strings
-Werror=declaration-after-statement -O2 -DVERSION=\"2.04\"
-DXS_VERSION=\"2.04\" -DPIC -fPIC "-I../../.." byte_t.c
byte_t.c:12:24: warning: uninitialized 'const
utf8_AdobeStandardEncoding' is invalid in C++ [-Wc++-compat]
12 | static const encpage_t utf8_AdobeStandardEncoding[];
| ^~~~~~~~~~~~~~~~~~~~~~~~~~

#####
... or like this:
#####
gcc9 -c -I./Encode -I../Encode -DHAS_FPSETMASK -DHAS_FLOATINGPOINT_H
-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong
-I/usr/local/include -D_FORTIFY_SOURCE=2 -Wall -Werror=pointer-arith
-Werror=vla -Wextra -Wc++-compat -Wwrite-strings
-Werror=declaration-after-statement -O2 -DVERSION=\"2.03\"
-DXS_VERSION=\"2.03\" -DPIC -fPIC "-I../../.." cp_00_t.c
cp_00_t.c:12:24: warning: uninitialized const 'cp949_utf8' is invalid in
C++ [-Wc++-compat]
12 | static const encpage_t cp949_utf8[];
| ^~~~~~~~~~
cp_00_t.c:17:24: warning: uninitialized const 'utf8_cp949' is invalid in
C++ [-Wc++-compat]
17 | static const encpage_t utf8_cp949[];
| ^~~~~~~~~~
cp_00_t.c:5583:24: warning: duplicate declaration of 'cp949_utf8' is
invalid in C++ [-Wc++-compat]
5583 | static const encpage_t cp949_utf8[129] = {
| ^~~~~~~~~~
cp_00_t.c:12:24: note: previous declaration of 'cp949_utf8' was here
12 | static const encpage_t cp949_utf8[];
| ^~~~~~~~~~
cp_00_t.c:13928:24: warning: duplicate declaration of 'utf8_cp949' is
invalid in C++ [-Wc++-compat]
13928 | static const encpage_t utf8_cp949[26] = {
| ^~~~~~~~~~
cp_00_t.c:17:24: note: previous declaration of 'utf8_cp949' was here
17 | static const encpage_t utf8_cp949[];
| ^~~~~~~~~~

#####
AFAICT, all 240 instances of these warnings occur while compiling '*.c'
files generated underneath the 'cpan/Encode/' directory as 'make' runs.
The Encode library is maintained upstream on CPAN.

According to the GNU docs
(https://gcc.gnu.org/onlinedocs/gcc-11.2.0/gcc/Warning-Options.html#Warning-Options),
the purpose of this warning is: "Warn about ISO C constructs that are
outside of the common subset of ISO C and ISO C++, e.g. request for
implicit conversion from void * to a pointer to non-void type."

Now, you might think that, what with all these warnings about
incompatibility with C++, our builds would gag when building with 'g++'
version 9 as opposed to gcc-9. But that's not the case. On both Linux
and FreeBSD, g++-9 sails right through the Encode compilation without
losing its breath or its lunch. Neither does the (presumably)
equivalent version of 'clang' have a problem with Encode compilation.

So it appears that these 240 '-Wc++-compat' warnings are effectively
false positives. That's really annoying because they constitute more
than 97% of all the build-time warnings emitted by 'gcc'. This
distracts us from other warnings, most of which originate in code
committed fairly recently. For that reason, they are a nuisance that we
should address. I can think of a number of possible approaches to
remediation:

* We can simply remove '-Wcc++-compat' entirely. I took a first stab at
this in the 'smoke-me/jkeenan/compat-exploration' branch, wherein I
removed the string '-Wc++-compat' in exactly one location.
#####
commit 0b8cd7e46f95b6afc88ed2830ca01b753f13e233 (HEAD -> compat-exploration)
Author: James E Keenan <jkeenan@cpan.org>
AuthorDate: Tue Sep 14 22:03:05 2021 +0000
Commit: James E Keenan <jkeenan@cpan.org>
CommitDate: Wed Sep 15 20:32:06 2021 +0000

Suppose we don't warn about cc compatibility

diff --git a/cflags.SH b/cflags.SH
index 162538583d..6da6ed48a7 100755
--- a/cflags.SH
+++ b/cflags.SH
@@ -182,7 +182,7 @@ Intel*) ;; # # Is that you, Intel C++?
-Werror=pointer-arith \
-Werror=vla \
-Wextra -W \
- -Wc++-compat -Wwrite-strings"
+ -Wwrite-strings"
# declaration after statement is normal in C++ rather than an
# extension and compilers complain if we try to warn about it
case "$d_cplusplus" in
#####
This silenced the 240 build-time warnings when compiling with 'gcc'
version 9 or later and appears to have had no harmful results in [smoke
testing](http://perl.develop-help.com/?b=smoke-me%2Fjkeenan%2Fcompat-exploration)
or [CI](https://github.com/Perl/perl5/actions/runs/1237882207). We
would presumably purge that string from the remaining locations in the
core distribution.

* We could explicitly compile with '-Wno-c++-compat' (or however it's
spelled). I've tried this locally; it eliminates the 240 warnings --
but I haven't smoke-tested it with other compilers.

* We could work with the Encode maintainer to revise the upstream code
such that, when compiled in Perl 5 with gcc 9 or later, it does not
warn. We would then continue to build with '-Wc++-compat'. (This may
be difficult, as the files being warned about are not source code but
'*.c' files generated by 'cpan/Encode/bin/enc2xs'.)

How should we proceed?

Thank you very much.
Jim Keenan
Re: Can we get rid of '-Wc++-compat' build-time warnings? [ In reply to ]
James E Keenan <jkeenan@pobox.com> wrote:
:When we build Perl 5 blead using 'gcc' version 9 or later, we get 240
:instances of the '-Wc++-compat' warning. When we build with 'gcc'
:version 8, we do not get this build-time warning at all.
[...]
:* We can simply remove '-Wcc++-compat' entirely.

The issue is a combination of a) we support compiling with a C++ compiler;
b) in various places we enable that by providing different code for C++
v. C compilers.

For code that is _not_ guarded by "for C compilers only" macros, it is
really useful to have these warnings. For code that is, they are useless.

So I think we need to come up with a way to ensure that -Wc++-compat is
disabled by the macros marking "for C compilers only", but keep them
enabled the rest of the time.

I had started trying to work with @dankogai to resolve this in
https://github.com/Perl/perl5/issues/18842, but that petered out.
If we can come up with a workable way to do it, this would be the
preferable solution.

Hugo
Re: Can we get rid of '-Wc++-compat' build-time warnings? [ In reply to ]
On 9/16/21 3:31 PM, hv@crypt.org wrote:
> James E Keenan <jkeenan@pobox.com> wrote:
> :When we build Perl 5 blead using 'gcc' version 9 or later, we get 240
> :instances of the '-Wc++-compat' warning. When we build with 'gcc'
> :version 8, we do not get this build-time warning at all.
> [...]
> :* We can simply remove '-Wcc++-compat' entirely.
>
> The issue is a combination of a) we support compiling with a C++ compiler;
> b) in various places we enable that by providing different code for C++
> v. C compilers.
>
> For code that is _not_ guarded by "for C compilers only" macros, it is
> really useful to have these warnings. For code that is, they are useless.
>
> So I think we need to come up with a way to ensure that -Wc++-compat is
> disabled by the macros marking "for C compilers only", but keep them
> enabled the rest of the time.
>
> I had started trying to work with @dankogai to resolve this in
> https://github.com/Perl/perl5/issues/18842, but that petered out.
> If we can come up with a workable way to do it, this would be the
> preferable solution.

When compiling Perl 5 blead with gcc9 (threaded build, FreeBSD-12), the
portion of make's output dealing with Encode totals 1326 lines. As
previously reported, we get 240 '-Wc++-compat' build-time warnings in
this build. Of these, slightly more than half -- 126, to be exact --
are associated with the generated file 'cpan/Encode/Byte/byte_t.c'. If
we can understand how to suppress the warning in this file (of > 10K
lines), then we can probably figure out how to suppress the warnings
entirely.

Fortunately, the compilation for Byte is located early in those 1326
lines of Encode compilation.
#####
1 ./miniperl -Ilib make_ext.pl lib/auto/Encode/Encode.so
MAKE="make" LIBPERL_A=libperl.a LINKTYPE=dynamic
2 Generating a Unix-style Makefile
3 Writing Makefile for Encode
4 Running Mkbootstrap for Byte ()
5 chmod 644 "Byte.bs"
6 /usr/home/jkeenan/gitwork/perl2/cpan/Encode/Byte/../../../miniperl
"-I../../../lib" -MExtUtils::Command::MM -e 'cp_nonempty' --
Byte.bs ../../../lib/auto/Encode/Byte/Byte.bs 644
7 "../../../miniperl" "-I../../../lib" ../bin/enc2xs -"Q" -"O" -o
byte_t.c -f byte_t.fnm
8 Reading iso-8859-2 (iso-8859-2)
9 Reading iso-8859-3 (iso-8859-3)
...
70 Reading nextstep (nextstep)
71 Reading viscii (viscii)
72 "../../../miniperl" "-I../../../lib"
"../../../lib/ExtUtils/xsubpp" -nolinenumbers -typemap
'/usr/home/jkeenan
/gitwork/perl2/cpan/Encode/Byte/../../../lib/ExtUtils/typemap' Byte.xs
> Byte.xsc
73 mv Byte.xsc Byte.c
74 gcc9 -c -I./Encode -I../Encode -DHAS_FPSETMASK
-DHAS_FLOATINGPOINT_H -fwrapv -fno-strict-aliasing -pipe -fsta
ck-protector-strong -I/usr/local/include -D_FORTIFY_SOURCE=2 -Wall
-Werror=pointer-arith -Werror=vla -Wextra -W c++-compat
-Wwrite-strings -Werror=declaration-after-statement -O2
-DVERSION=\"2.04\" -DXS_VERSION=\"2.04\" -DPIC -fPIC "-I../../.."
Byte.c
75 gcc9 -c -I./Encode -I../Encode -DHAS_FPSETMASK
-DHAS_FLOATINGPOINT_H -fwrapv -fno-strict-aliasing -pipe -fsta
ck-protector-strong -I/usr/local/include -D_FORTIFY_SOURCE=2 -Wall
-Werror=pointer-arith -Werror=vla -Wextra -W c++-compat
-Wwrite-strings -Werror=declaration-after-statement -O2
-DVERSION=\"2.04\" -DXS_VERSION=\"2.04\" -DPIC -fPIC "-I../../.."
byte_t.c
#####

And here's where the warnings begin:

#####
76 byte_t.c:12:24: warning: uninitialized const
'utf8_AdobeStandardEncoding' is invalid in C++ [-Wc++-compat]
77 12 | static const encpage_t utf8_AdobeStandardEncoding[];
78 | ^~~~~~~~~~~~~~~~~~~~~~~~~~
79 byte_t.c:17:24: warning: uninitialized const 'utf8_MacArabic' is
invalid in C++ [-Wc++-compat]
80 17 | static const encpage_t utf8_MacArabic[];
81 | ^~~~~~~~~~~~~~
...
262 byte_t.c:322:24: warning: uninitialized const 'utf8_viscii' is
invalid in C++ [-Wc++-compat]
263 322 | static const encpage_t utf8_viscii[];
264 | ^~~~~~~~~~~
#####

63 instances of "warning: uninitialized const '[some encoding]' is
invalid in C++", each of which occupies 2 lines of output.

Then ...

#####
265 byte_t.c:1144:24: warning: duplicate declaration of
'utf8_AdobeStandardEncoding' is invalid in C++ [-Wc++-compat]
266 1144 | static const encpage_t utf8_AdobeStandardEncoding[10] = {
267 | ^~~~~~~~~~~~~~~~~~~~~~~~~~
268 byte_t.c:12:24: note: previous declaration of
'utf8_AdobeStandardEncoding' was here
269 12 | static const encpage_t utf8_AdobeStandardEncoding[];
270 | ^~~~~~~~~~~~~~~~~~~~~~~~~~
271 byte_t.c:1294:24: warning: duplicate declaration of
'utf8_MacArabic' is invalid in C++ [-Wc++-compat]
272 1294 | static const encpage_t utf8_MacArabic[9] = {
273 | ^~~~~~~~~~~~~~
274 byte_t.c:17:24: note: previous declaration of 'utf8_MacArabic' was
here
275 17 | static const encpage_t utf8_MacArabic[];
276 | ^~~~~~~~~~~~~~
...
637 byte_t.c:10394:24: warning: duplicate declaration of 'utf8_viscii'
is invalid in C++ [-Wc++-compat]
638 10394 | static const encpage_t utf8_viscii[12] = {
639 | ^~~~~~~~~~~
640 byte_t.c:322:24: note: previous declaration of 'utf8_viscii' was here
641 322 | static const encpage_t utf8_viscii[];
642 | ^~~~~~~~~~~
#####

63 instances of "warning: duplicate declaration of '[some encoding]' is
invalid in C++", each accompanied by a "note: previous declaration of
'some encoding' was here", totaling 6 lines of output each.

Let's look at the first of these encodings, utf8_AdobeStandardEncoding,
as it appears in cpan/Encode/Byte/byte_t.c -- which, remember, is a
generated file. Based on the information in the warnings excerpted
above, we'll be looking at the contexts of lines 12 and 1144

#####
9 #ifdef __cplusplus
10 extern encpage_t utf8_AdobeStandardEncoding[];
11 #else
12 static const encpage_t utf8_AdobeStandardEncoding[];
13 #endif
...
1141 #ifdef __cplusplus
1142 encpage_t utf8_AdobeStandardEncoding[10] = {
1143 #else
1144 static const encpage_t utf8_AdobeStandardEncoding[10] = {
1145 #endif
1146 {enctable + 3735,utf8_AdobeStandardEncoding,0x00,0x7e,1,1},
1147 {0,utf8_AdobeStandardEncoding_c2,0xc2,0xc2,0,2},
1148 {0,utf8_AdobeStandardEncoding_c3,0xc3,0xc3,0,2},
1149 {0,utf8_AdobeStandardEncoding_c4,0xc4,0xc4,0,2},
1150 {0,utf8_AdobeStandardEncoding_c5,0xc5,0xc5,0,2},
1151 {0,utf8_AdobeStandardEncoding_c6,0xc6,0xc6,0,2},
1152 {0,utf8_AdobeStandardEncoding_cb,0xcb,0xcb,0,2},
1153 {0,utf8_AdobeStandardEncoding_e2,0xe2,0xe2,0,3},
1154 {0,utf8_AdobeStandardEncoding_ef,0xef,0xef,0,3},
1155 {0,utf8_AdobeStandardEncoding,0xf0,0xff,0,0},
1156 };
#####

Note that at lines 12 and 1144 of byte_t.c, we are *not* within the
scope of "#ifdef __cpluplus". That's as we would expect, because we're
compiling with gcc9 rather than g++9. The problem is that while gcc
makes a claim that the code at lines 12 and 1144 won't fly *if we were
to compile with g++*, it's not smart enough to understand that we have
already anticipated g++'s needs in the "#ifdef __cplusplus" blocks at
lines 9 thru 11 and 1141 thru 1143, respectively.

So our first challenge will be to figure out what C code would silence
the warnings right after the start of the "#else" blocks at lines 11 and
1143, respectively.

Once we've done that, our next challenge will be to think backwards to
what we have to do in the cpan/Encode source files to generate a
byte_t.c file which does not warn. At the very least, that will involve
some modification of this part of the cpan/Encode source code:

#####
$ cd cpan/Encode
$ ack -B4 -A7 '\b__c(plus){2}\b' .
bin/enc2xs
771- my ($cpp, $static, $sized) = compiler_info(1);
772- my $count = $sized ? scalar(@{$a->{'Entries'}}) : '';
773- if ($static) {
774- # we cannot ask Config for d_plusplus since we can override
CC=g++-6 on the cmdline
775: print $fh "#ifdef __cplusplus\n"; # -fpermissive since g++-6
776- print $fh "extern encpage_t $name\[$count];\n";
777- print $fh "#else\n";
778- print $fh "static const encpage_t $name\[$count];\n";
779- print $fh "#endif\n";
780- } else {
781- print $fh "extern encpage_t $name\[$count];\n";
782- }
--
871- }
872- my ($cpp, $static) = compiler_info(0);
873- my $count = scalar(@{$a->{'Entries'}});
874- if ($static) {
875: print $fh "#ifdef __cplusplus\n"; # -fpermissive since g++-6
876- print $fh "encpage_t $name\[$count] = {\n";
877- print $fh "#else\n";
878- print $fh "static const encpage_t $name\[$count] = {\n";
879- print $fh "#endif\n";
880- } else {
881- print $fh "\nencpage_t $name\[$count] = {\n";
882- }
#####

Is this line of approach okay so far?

Thank you very much.
Jim Keenan