blob: aece89619e77cddf08ef3fd44331f264808161f4 [file] [log] [blame]
/* Functions to enable and disable individual warnings on an expression
and statement basis.
Copyright (C) 2021-2022 Free Software Foundation, Inc.
Contributed by Martin Sebor <msebor@redhat.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "bitmap.h"
#include "tree.h"
#include "cgraph.h"
#include "hash-map.h"
#include "diagnostic-spec.h"
#include "pretty-print.h"
#include "options.h"
/* Initialize *THIS from warning option OPT. */
nowarn_spec_t::nowarn_spec_t (opt_code opt)
{
/* Create a very simple mapping based on testing and experience.
It should become more refined with time. */
switch (opt)
{
case no_warning:
m_bits = 0;
break;
case all_warnings:
m_bits = -1;
break;
/* Flow-sensitive warnings about pointer problems issued by both
front ends and the middle end. */
case OPT_Waddress:
case OPT_Wnonnull:
m_bits = NW_NONNULL;
break;
/* Flow-sensitive warnings about arithmetic overflow issued by both
front ends and the middle end. */
case OPT_Woverflow:
case OPT_Wshift_count_negative:
case OPT_Wshift_count_overflow:
case OPT_Wstrict_overflow:
m_bits = NW_VFLOW;
break;
/* Lexical warnings issued by front ends. */
case OPT_Wabi:
case OPT_Wlogical_op:
case OPT_Wparentheses:
case OPT_Wreturn_type:
case OPT_Wsizeof_array_div:
case OPT_Wstrict_aliasing:
case OPT_Wunused:
case OPT_Wunused_function:
case OPT_Wunused_but_set_variable:
case OPT_Wunused_variable:
case OPT_Wunused_but_set_parameter:
m_bits = NW_LEXICAL;
break;
/* Access warning group. */
case OPT_Warray_bounds:
case OPT_Warray_bounds_:
case OPT_Wformat_overflow_:
case OPT_Wformat_truncation_:
case OPT_Wrestrict:
case OPT_Wsizeof_pointer_memaccess:
case OPT_Wstrict_aliasing_:
case OPT_Wstringop_overflow_:
case OPT_Wstringop_overread:
case OPT_Wstringop_truncation:
m_bits = NW_ACCESS;
break;
/* Initialization warning group. */
case OPT_Winit_self:
case OPT_Wuninitialized:
case OPT_Wmaybe_uninitialized:
m_bits = NW_UNINIT;
break;
case OPT_Wdangling_pointer_:
case OPT_Wreturn_local_addr:
case OPT_Wuse_after_free_:
m_bits = NW_DANGLING;
break;
case OPT_Wpessimizing_move:
case OPT_Wredundant_move:
m_bits = NW_REDUNDANT;
break;
default:
/* A catchall group for everything else. */
m_bits = NW_OTHER;
}
}
/* A mapping from a 'location_t' to the warning spec set for it. */
GTY(()) nowarn_map_t *nowarn_map;
/* Return the no-warning disposition for location LOC and option OPT
or for all/any otions by default. */
bool
warning_suppressed_at (location_t loc, opt_code opt /* = all_warnings */)
{
gcc_checking_assert (!RESERVED_LOCATION_P (loc));
if (!nowarn_map)
return false;
if (const nowarn_spec_t* const pspec = nowarn_map->get (loc))
{
const nowarn_spec_t optspec (opt);
return *pspec & optspec;
}
return false;
}
/* Change the supression of warnings for location LOC.
OPT controls which warnings are affected.
The wildcard OPT of -1 controls all warnings.
If SUPP is true (the default), enable the suppression of the warnings.
If SUPP is false, disable the suppression of the warnings. */
bool
suppress_warning_at (location_t loc, opt_code opt /* = all_warnings */,
bool supp /* = true */)
{
gcc_checking_assert (!RESERVED_LOCATION_P (loc));
const nowarn_spec_t optspec (supp ? opt : opt_code ());
if (nowarn_spec_t *pspec = nowarn_map ? nowarn_map->get (loc) : NULL)
{
if (supp)
{
*pspec |= optspec;
return true;
}
*pspec &= optspec;
if (*pspec)
return true;
nowarn_map->remove (loc);
return false;
}
if (!supp || opt == no_warning)
return false;
if (!nowarn_map)
nowarn_map = nowarn_map_t::create_ggc (32);
nowarn_map->put (loc, optspec);
return true;
}
/* Copy the no-warning disposition from one location to another. */
void
copy_warning (location_t to, location_t from)
{
if (!nowarn_map)
return;
nowarn_spec_t *from_spec;
if (RESERVED_LOCATION_P (from))
from_spec = NULL;
else
from_spec = nowarn_map->get (from);
if (RESERVED_LOCATION_P (to))
/* We cannot set no-warning dispositions for 'to', so we have no chance but
lose those potentially set for 'from'. */
;
else
{
if (from_spec)
{
nowarn_spec_t tem = *from_spec;
nowarn_map->put (to, tem);
}
else
nowarn_map->remove (to);
}
}