File Coverage

File:config/auto/warnings.pm
Coverage:81.6%

linestmtbrancondsubcode
1# Copyright (C) 2007-2011, Parrot Foundation.
2
3 - 14
=head1 NAME

config/auto/warnings.pm - Warning flags probing.

=head1 DESCRIPTION

Given a list of potential warnings available for a certain type of
compiler, probe to see which of those are valid for this particular version.

=over 4

=cut
15
16package auto::warnings;
17
18
2
2
2
use strict;
19
2
2
2
use warnings;
20
21
2
2
2
use base qw(Parrot::Configure::Step);
22
23
2
2
2
use Parrot::Configure::Utils ();
24
2
2
2
use Parrot::BuildUtil;
25
26 - 85
=item C<_init>

Declare potential warnings for various compilers.  Note that the compiler
key used here doesn't really exist in a unified way in Configure - would
be nice if it did so we could simplify our checks in runstep().

We create a data structure here that breaks out the warnings by compiler,
using this structure:

warnings:
  gcc:
    basic:
      - -Warning1
      - -Warning2
    cage:
      - -Warning3
      - -Warning4
    only:
      - -Warning5:
        - foo.c
        - bar.c
    never:
      - -Warning6:
        - baz.c
        - frob.c
    todo:
      - -Warning7:
        - cow.c
        - pig.c
  g++:
    ...

'basic' warnings are always used.

'cage' warnings are added only if --cage is specified during
Configure. This can be used to hold warnings that aren't ready to be
added to the default run yet.

'only' should be used as we add new warnings to the build, it will let
us insure that files we know are clean for a new warning stay clean.

'never' should be used when a particular file contains generated code
(e.g. imcc) and we cannot update it to conform to the standards.

'todo' functions just like never does, but it indicates that these
files are expected to eventually be free of this warning.

Note that there is no actual requirement that the 'file' be a full path
to a .c file; the file could be "PMCS" or "OPS" or some other identifier;
whatever the value, it will generate a Config entry prefixed with
C<ccwarn::>, which will probably be used via @@ expansion in a makefile.

It is tempting to put this into a config file, but having it in
perl gives us the ability to dynamically setup certain warnings based
on any criteria already discovered via Config.

Order is important - some warnings are invalid unless they are specified
after other warnings.

=cut
86
87sub _init {
88
4
    my $self = shift;
89
90
4
    my $data = {
91        description => 'Detect supported compiler warnings',
92        result => '',
93        validated => [],
94    };
95
96    # begin gcc/g++
97
4
    my $gcc = {};
98
4
    my $gpp = {};
99
4
    my $icc = {};
100
101
4
    my @gcc_or_gpp_basic = qw(
102        -falign-functions=16
103        -funit-at-a-time
104        -fexcess-precision=standard
105        -maccumulate-outgoing-args
106        -W
107        -Wall
108        -Waggregate-return
109        -Wcast-align
110        -Wcast-qual
111        -Wchar-subscripts
112        -Wcomment
113        -Wdisabled-optimization
114        -Wdiv-by-zero
115        -Wenum-compare
116        -Wendif-labels
117        -Wextra
118        -Wformat
119        -Wformat-extra-args
120        -Wformat-nonliteral
121        -Wformat-security
122        -Wformat-y2k
123        -Wimplicit
124        -Wimport
125        -Winit-self
126        -Winline
127        -Winvalid-pch
128        -Wjump-misses-init
129        -Wlogical-op
130        -Werror=missing-braces
131        -Wmissing-declarations
132        -Wmissing-field-initializers
133        -Wno-missing-format-attribute
134        -Wmissing-include-dirs
135        -Wmultichar
136        -Wpacked
137        -Wparentheses
138        -Wpointer-arith
139        -Wpointer-sign
140        -Wreturn-type
141        -Wsequence-point
142        -Wsign-compare
143        -Wstrict-aliasing
144        -Wstrict-aliasing=2
145        -Wswitch
146        -Wswitch-default
147        -Wtrigraphs
148        -Werror=undef
149        -Wno-unused
150        -Wunknown-pragmas
151        -Wvariadic-macros
152        -Wwrite-strings
153        -Wstack-usage=500
154    );
155
156    # gcc-only warnings that would break g++
157
4
    my @gcc_basic = qw(
158        -Wc++-compat
159        -Werror=declaration-after-statement
160        -Werror=implicit-function-declaration
161        -Wmissing-prototypes
162        -Werror=nested-externs
163        -Werror=old-style-definition
164        -Werror=strict-prototypes
165    );
166
167
4
    $gcc->{'basic'} = [ @gcc_or_gpp_basic, @gcc_basic ];
168
4
    $gpp->{'basic'} = [ @gcc_or_gpp_basic ];
169
170
4
    my @gcc_or_gpp_cage = qw(
171        -std=c89
172        -Wfloat-equal
173        -Wformat=2
174        -Wlarger-than-4096
175        -Wlong-long
176        -Wmissing-format-attribute
177        -Wdeprecated-declarations
178        -Wno-format-extra-args
179        -Wno-import
180        -Wredundant-decls
181        -Wshadow
182        -Wstrict-overflow=5
183        -Wsuggest-attribute=const
184        -Wsuggest-attribute=noreturn
185        -Wsuggest-attribute=pure
186        -Wtrampolines
187        -Wunreachable-code
188        -Wunsafe-loop-optimizations
189        -Wunused
190        -Wunused-function
191        -Wunused-label
192        -Wunused-value
193        -Wunused-variable
194        -Wvolatile-register-var
195    );
196
197
4
    my @gpp_cage = qw(
198        -Weffc++
199        -Wstrict-null-sentinel
200        -Wtraditional
201        -Wuseless-cast
202    );
203
204
4
    $gcc->{'cage'} = [ @gcc_or_gpp_cage ];
205
4
    $gpp->{'cage'} = [ @gcc_or_gpp_cage, @gpp_cage ];
206
207
4
    $gcc->{'todo'} = $gpp->{'todo'} = {
208        '-Wformat-nonliteral' => [ qw(
209            src/spf_render.c
210            compilers/imcc/optimizer.c
211        ) ],
212        '-Wstrict-prototypes' => [ qw(
213            src/nci/extra_thunks.c
214            src/extra_nci_thunks.c
215        ) ],
216    };
217
218
4
    $gcc->{'never'} = $gpp->{'never'} = {
219        '-Wformat-nonliteral' => [ qw(
220            compilers/imcc/imclexer.c
221        ) ],
222        '-Wswitch-default' => [ qw(
223            compilers/imcc/imclexer.c
224        ) ],
225        '-Wcast-qual' => [ qw(
226            compilers/imcc/imcparser.c
227        ) ],
228        '-Wlogical-op' => [ qw(
229            compilers/imcc/imcparser.c
230        ) ],
231    };
232
233    # Warning flags docs
234    # http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/cpp/lin/compiler_c/index.htm
235
236
4
    $icc->{'basic'} = [ qw(
237        -w2
238        -Wabi
239        -Wall
240        -Wcheck
241        -Wcomment
242        -Wdeprecated
243        -Weffc++
244        -Wextra-tokens
245        -Wformat
246        -Wformat-security
247        -Wmain
248        -Wmaybe-uninitialized
249        -Wmissing-declarations
250        -Wmissing-prototypes
251        -Wpointer-arith
252        -Wport
253        -Wreturn-type
254        -Wshadow
255        -Wstrict-prototypes
256        -Wuninitialized
257        -Wunknown-pragmas
258        -Wunused-function
259        -Wunused-variable
260        -Wwrite-strings
261        ),
262        # Disable some warnings and notifications that are overly noisy
263        '-diag-disable 271', # trailing comma is nonstandard
264        '-diag-disable 981', # operands are evaluated in unspecified order
265        '-diag-disable 1572', # floating-point equality and inequality comparisons are unreliable
266        '-diag-disable 2259', # non-pointer conversion from "typeA" to "typeB" may lose significant bits
267    ];
268
4
    $icc->{'cage'} = [
269        # http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/cpp/lin/compiler_c/bldaps_cls/common/bldaps_svover.htm
270        '-diag-enable sc3',
271        '-diag-enable sc-include',
272    ];
273
274
4
    $data->{'warnings'}{'gcc'} = $gcc;
275
4
    $data->{'warnings'}{'g++'} = $gpp;
276
4
    $data->{'warnings'}{'icc'} = $icc;
277
4
    $data->{'warnings'}{'clang'} = $gcc;
278
279    ## end gcc/g++
280
281
4
    return $data;
282}
283
284sub runstep {
285
4
    my ( $self, $conf ) = @_;
286
287
4
    $conf->debug("\n");
288
289
4
    my $compiler = '';
290
4
    if ( defined $conf->data->get('gccversion') ) {
291
2
        $compiler = $conf->data->get('g++') ? 'g++' :
292            $conf->data->get('clang') ? 'clang' : 'gcc';
293    }
294    elsif ( $conf->option_or_data('cc') =~ /icc/ ) {
295
0
        $compiler = 'icc';
296    }
297
298
4
    if ($compiler eq '') {
299
2
        $conf->debug("We do not (yet) probe for warnings for your compiler\n");
300
2
        $self->set_result('skipped');
301
2
        return 1;
302    }
303
304
2
    if (
305        ( $compiler eq 'gcc' or $compiler eq 'g++' ) and
306        ( $conf->data->get('gccversion') >= 4.0 )
307    ) {
308
2
2
        push @{$self->{'warnings'}{$compiler}{'basic'}},
309            '-fvisibility=hidden';
310    };
311    # standard warnings.
312
120
2
    my @warnings = grep {$self->valid_warning($conf, $_)}
313
2
        @{$self->{'warnings'}{$compiler}{'basic'}};
314
315    # --cage?
316
2
    if ($conf->options->get('cage')) {
317
24
1
        push @warnings, grep {$self->valid_warning($conf, $_)}
318
1
            @{$self->{'warnings'}{$compiler}{'cage'}}
319    }
320
321    # -- only?
322
2
    my %per_file;
323
2
    if (exists $self->{'warnings'}{$compiler}{'only'}) {
324
0
0
        my %only = %{$self->{'warnings'}{$compiler}{'only'}};
325
0
        foreach my $warning (keys %only) {
326
0
            next unless $self->valid_warning($conf, $warning);
327
0
0
            foreach my $file (@{$only{$warning}}) {
328
0
                $per_file{$file} = [ @warnings ] unless exists $per_file{$file};
329
0
0
                push @{$per_file{$file}}, $warning;
330            }
331        }
332    }
333
334
2
    foreach my $key (qw/todo never/) {
335
4
        if (exists $self->{'warnings'}{$compiler}{$key}) {
336
4
4
            my %dont = %{$self->{'warnings'}{$compiler}{$key}};
337
4
            foreach my $warning (keys %dont) {
338
12
12
                foreach my $file (@{$dont{$warning}}) {
339
16
                    $per_file{$file} = [ @warnings ] unless exists $per_file{$file};
340
16
16
1052
16
                    @{$per_file{$file}} = grep {$warning ne $_} @{$per_file{$file}};
341                }
342            }
343        }
344    }
345
346
2
    $conf->data->set('ccwarn', join(' ', @warnings));
347
2
    foreach my $file (keys %per_file) {
348
12
12
        $conf->data->set("ccwarn::$file", join(' ', @{$per_file{$file}}));
349    }
350
351
2
    $self->set_result('done');
352
2
    return 1;
353}
354
355 - 368
=item C<valid_warning>

Try a given warning to see if it is supported by the compiler.  The compiler
is determined by the C<cc> value of the C<Parrot::Configure> object passed
in as the first argument to the method (not counting C<$self>.  The warning
to be checked is passed in as the second argument to the method.

Returns true if the warning flag is recognized by the compiler and undef
otherwise.

Use the running set of known valid options, since some options may depend
on previous options.

=cut
369
370sub valid_warning {
371
144
    my ( $self, $conf, $warning ) = @_;
372
373    # This should be using a temp file name.
374
144
    my $output_file = 'test.cco';
375
376
144
    $conf->debug("trying attribute '$warning'\n");
377
378
144
    my $cc = $conf->option_or_data('cc');
379
144
    $conf->cc_gen('config/auto/warnings/test_c.in');
380
381
144
    my $ccflags = $conf->data->get('ccflags');
382
144
144
    my $warnings = join(' ', @{$self->{'validated'}});
383
144
    my $tryflags = "$ccflags $warnings $warning";
384
385
144
    my $command_line = Parrot::Configure::Utils::_build_compile_command( $cc, $tryflags );
386
144
    $conf->debug(" ", $command_line, "\n");
387
388    # Don't use cc_build, because failure is expected.
389
144
    my $exit_code = Parrot::Configure::Utils::_run_command(
390        $command_line, $output_file, $output_file
391    );
392
393    # Cleanup any remnants of the test compilation
394
144
    $conf->cc_clean();
395
396
144
    if ($exit_code) {
397
12
        unlink $output_file or die "Unable to unlink $output_file: $!";
398
12
        return;
399    }
400
401
132
    my $output = Parrot::BuildUtil::slurp_file($output_file);
402
132
    unlink $output_file or die "Unable to unlink $output_file: $!";
403
404
132
    $conf->debug(" output: $output\n");
405
406
132
    if ( $output !~ /\berror|warning|not supported|ignoring (unknown )?option\b/i ) {
407
132
132
        push @{$self->{'validated'}}, $warning;
408
132
        $conf->debug(" valid warning: '$warning'\n");
409
132
        return 1;
410    }
411    else {
412
0
        $conf->debug(" invalid warning: '$warning'\n");
413
0
        return 0;
414    }
415}
416
417=back
418
419=cut
420
4211;
422
423# Local Variables:
424# mode: cperl
425# cperl-indent-level: 4
426# fill-column: 100
427# End:
428# vim: expandtab shiftwidth=4: