Add support for per-location warning groups. gcc/ChangeLog: * Makefile.in (OBJS-libcommon): Add diagnostic-spec.o. * gengtype.c (open_base_files): Add diagnostic-spec.h. * diagnostic-spec.c: New file. * diagnostic-spec.h: New file. * warning-control.cc: New file. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 1164554e6d6..b7bbcb60051 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1696,6 +1696,7 @@ OBJS = \ vmsdbgout.o \ vr-values.o \ vtable-verify.o \ + warning-control.o \ web.o \ wide-int.o \ wide-int-print.o \ @@ -1707,8 +1708,8 @@ OBJS = \ # Objects in libcommon.a, potentially used by all host binaries and with # no target dependencies. -OBJS-libcommon = diagnostic.o diagnostic-color.o diagnostic-show-locus.o \ - diagnostic-format-json.o json.o \ +OBJS-libcommon = diagnostic-spec.o diagnostic.o diagnostic-color.o \ + diagnostic-show-locus.o diagnostic-format-json.o json.o \ edit-context.o \ pretty-print.o intl.o \ sbitmap.o \ @@ -2648,6 +2649,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/ipa-modref.h $(srcdir)/ipa-modref.c \ $(srcdir)/ipa-modref-tree.h \ $(srcdir)/signop.h \ + $(srcdir)/diagnostic-spec.h $(srcdir)/diagnostic-spec.c \ $(srcdir)/dwarf2out.h \ $(srcdir)/dwarf2asm.c \ $(srcdir)/dwarf2cfi.c \ diff --git a/gcc/diagnostic-spec.c b/gcc/diagnostic-spec.c new file mode 100644 index 00000000000..582ae3f3fe2 --- /dev/null +++ b/gcc/diagnostic-spec.c @@ -0,0 +1,172 @@ +/* Functions to enable and disable individual warnings on an expression + and statement basis. + Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Martin Sebor + + 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 + . */ + +#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" + +/* Initialize *THIS from warning option OPT. */ + +nowarn_spec_t::nowarn_spec_t (int opt) +{ + /* Create a very simple mapping based on testing and experience. + It should become more refined with time. */ + switch (opt) + { + case 0: + case -1: + bits = opt; + break; + + /* Flow-sensitive warnings about pointer problems issued by both + front ends and the middle end. */ + case OPT_Waddress: + case OPT_Wnonnull: + 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: + 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: + 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_Wstrict_aliasing_: + case OPT_Wstringop_overflow_: + case OPT_Wstringop_overread: + case OPT_Wstringop_truncation: + bits = NW_ACCESS; + break; + + /* Initialization warning group. */ + case OPT_Winit_self: + case OPT_Wuninitialized: + case OPT_Wmaybe_uninitialized: + bits = NW_UNINIT; + break; + + default: + /* A catchall group for everything else. */ + bits = NW_OTHER; + } +} + +/* Map from location to its no-warning disposition. */ + +GTY(()) xint_hash_map_t *nowarn_map; + +/* Return the no-warning disposition for location LOC and option OPT + or for all/any otions by default. */ + +bool +get_no_warning (location_t loc, int opt /* = -1 */) +{ + 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; +} + +/* Set the no-warning disposition for location LOC and option OPT when + DIS is true, or clear it when it's false. Return true if LOC has any + warnings disabled at the end of processing. */ + +bool +set_no_warning (location_t loc, int opt /* = -1 */, bool dis /* = true */) +{ + const nowarn_spec_t optspec (dis ? opt : 0); + + if (nowarn_spec_t *pspec = nowarn_map ? nowarn_map->get (loc) : NULL) + { + if (dis) + { + *pspec |= optspec; + return true; + } + + *pspec &= optspec; + if (*pspec) + return true; + + nowarn_map->remove (loc); + return false; + } + + if (!dis) + return false; + + if (!nowarn_map) + nowarn_map = xint_hash_map_t::create_ggc (32); + + nowarn_map->put (loc, optspec); + return true; +} + +/* Copy the no-warning disposition from one location to another. */ + +void +copy_no_warning (location_t to, location_t from) +{ + if (!nowarn_map) + return; + + if (nowarn_spec_t *pspec = nowarn_map->get (from)) + nowarn_map->put (to, *pspec); + else + nowarn_map->remove (to); +} diff --git a/gcc/diagnostic-spec.h b/gcc/diagnostic-spec.h new file mode 100644 index 00000000000..e0c02753923 --- /dev/null +++ b/gcc/diagnostic-spec.h @@ -0,0 +1,140 @@ +/* Language-independent APIs to enable/disable per-location warnings. + + Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Martin Sebor + + 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 + . */ + +#ifndef DIAGNOSTIC_SPEC_H_INCLUDED +#define DIAGNOSTIC_SPEC_H_INCLUDED + +#include "hash-map.h" + +/* A "bitset" of warning groups. */ + +struct nowarn_spec_t +{ + enum + { + /* Middle end warnings about invalid accesses. */ + NW_ACCESS = 1 << 0, + /* Front end/lexical warnings. */ + NW_LEXICAL = 1 << 1, + /* Warnings about null pointers. */ + NW_NONNULL = 1 << 2, + /* Warnings about uninitialized reads. */ + NW_UNINIT = 1 << 3, + /* Warnings about arithmetic overflow. */ + NW_VFLOW = 1 << 4, + /* All other unclassified warnings. */ + NW_OTHER = 1 << 5, + /* All groups of warnings. */ + NW_ALL = (NW_ACCESS | NW_LEXICAL | NW_NONNULL + | NW_UNINIT | NW_VFLOW | NW_OTHER) + }; + + nowarn_spec_t (): bits () { } + + nowarn_spec_t (int); + + /* Return the raw bitset. */ + operator unsigned() const + { + return bits; + } + + /* Return true if the bitset is clear. */ + bool operator!() const + { + return !bits; + } + + /* Return the inverse of the bitset. */ + nowarn_spec_t operator~() const + { + nowarn_spec_t res (*this); + res.bits &= ~NW_ALL; + return res; + } + + /* Set *THIS to the bitwise OR of *THIS and RHS. */ + nowarn_spec_t& operator|= (const nowarn_spec_t &rhs) + { + bits |= rhs.bits; + return *this; + } + + /* Set *THIS to the bitwise AND of *THIS and RHS. */ + nowarn_spec_t& operator&= (const nowarn_spec_t &rhs) + { + bits &= rhs.bits; + return *this; + } + + /* Set *THIS to the bitwise exclusive OR of *THIS and RHS. */ + nowarn_spec_t& operator^= (const nowarn_spec_t &rhs) + { + bits ^= rhs.bits; + return *this; + } + +private: + /* Bitset of warning groups. */ + unsigned bits; +}; + +/* Return the bitwise OR of LHS and RHS. */ + +inline nowarn_spec_t +operator| (const nowarn_spec_t &lhs, const nowarn_spec_t &rhs) +{ + return nowarn_spec_t (lhs) |= rhs; +} + +/* Return the bitwise AND of LHS and RHS. */ + +inline nowarn_spec_t +operator& (const nowarn_spec_t &lhs, const nowarn_spec_t &rhs) +{ + return nowarn_spec_t (lhs) &= rhs; +} + +/* Return true if LHS is equal RHS. */ + +inline bool +operator== (const nowarn_spec_t &lhs, const nowarn_spec_t &rhs) +{ + return static_cast(lhs) == static_cast(rhs); +} + +/* Return true if LHS is not equal RHS. */ + +inline bool +operator!= (const nowarn_spec_t &lhs, const nowarn_spec_t &rhs) +{ + return !(lhs == rhs); +} + +typedef location_t key_type_t; +typedef int_hash xint_hash_t; +typedef hash_map xint_hash_map_t; + +/* A mapping from the location of an expression to the warning spec + set for it. */ +extern GTY(()) xint_hash_map_t *nowarn_map; + +#endif // DIAGNOSTIC_SPEC_H_INCLUDED diff --git a/gcc/gengtype.c b/gcc/gengtype.c index b94e2f126ec..c1fa6d35c87 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -1727,7 +1727,7 @@ open_base_files (void) "target-globals.h", "ipa-ref.h", "cgraph.h", "symbol-summary.h", "ipa-prop.h", "ipa-fnsummary.h", "dwarf2out.h", "omp-general.h", "omp-offload.h", "ipa-modref-tree.h", "ipa-modref.h", "symtab-thunks.h", - "symtab-clones.h", + "symtab-clones.h", "diagnostic-spec.h", NULL }; const char *const *ifp; diff --git a/gcc/warning-control.cc b/gcc/warning-control.cc new file mode 100644 index 00000000000..73147b618ad --- /dev/null +++ b/gcc/warning-control.cc @@ -0,0 +1,230 @@ +/* Functions to enable and disable individual warnings on an expression + and statement basis. + + Copyright (C) 2021 Free Software Foundation, Inc. + + 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 + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "bitmap.h" +#include "tree.h" +#include "gimple.h" +#include "cgraph.h" +#include "hash-map.h" +#include "diagnostic-spec.h" + +/* Return the no-warning bit for EXPR. */ + +static inline bool +get_no_warning_bit (const_tree expr) +{ + return expr->base.nowarning_flag; +} + +/* Return the no-warning bit for statement STMT. */ + +static inline bool +get_no_warning_bit (const gimple *stmt) +{ + return stmt->no_warning; +} + +/* Set the no-warning bit for EXPR to VALUE. */ + +static inline void +set_no_warning_bit (tree expr, bool value) +{ + expr->base.nowarning_flag = value; +} + +/* Set the no-warning bit for statement STMT to VALUE. */ + +static inline void +set_no_warning_bit (gimple *stmt, bool value) +{ + stmt->no_warning = value; +} + +/* Return EXPR location of zero. */ + +static inline key_type_t +convert_to_key (const_tree expr) +{ + if (DECL_P (expr)) + return DECL_SOURCE_LOCATION (expr); + if (EXPR_P (expr)) + return EXPR_LOCATION (expr); + return 0; +} + +/* Return STMT location (may be zero). */ + +static inline key_type_t +convert_to_key (const gimple *stmt) +{ + return gimple_location (stmt); +} + +/* Return the no-warning bitmap for decl/expression EXPR. */ + +static nowarn_spec_t* +get_nowarn_spec (const_tree expr) +{ + const key_type_t key = convert_to_key (expr); + + if (!get_no_warning_bit (expr) || !key) + return NULL; + + return nowarn_map ? nowarn_map->get (key) : NULL; +} + +/* Return the no-warning bitmap for stateemt STMT. */ + +static nowarn_spec_t* +get_nowarn_spec (const gimple *stmt) +{ + const key_type_t key = convert_to_key (stmt); + + if (!get_no_warning_bit (stmt)) + return NULL; + + return nowarn_map ? nowarn_map->get (key) : NULL; +} + +/* Return true if warning OPT is enabled for decl/expression EXPR. + The wildcard OPT of -1 tests for all warnings being disabled. */ + +bool +get_no_warning (const_tree expr, int opt /* = -1 */) +{ + const nowarn_spec_t *spec = get_nowarn_spec (expr); + + if (!spec) + return get_no_warning_bit (expr); + + nowarn_spec_t optspec (opt); + bool dis = *spec & optspec; + gcc_assert (get_no_warning_bit (expr) || !dis); + return dis; +} + +/* Return true if warning OPT is enabled for statement STMT. + The wildcard OPT of -1 tests for all warnings being disabled. */ + +bool +get_no_warning (const gimple *stmt, int opt /* = -1 */) +{ + const nowarn_spec_t *spec = get_nowarn_spec (stmt); + + if (!spec) + /* Fall back on the single no-warning bit. */ + return get_no_warning_bit (stmt); + + nowarn_spec_t optspec (opt); + bool dis = *spec & optspec; + gcc_assert (get_no_warning_bit (stmt) || !dis); + return dis; +} + +/* Enable, or by default disable, a warning for the expression. + The wildcard OPT of -1 controls all warnings. */ + +void +set_no_warning (tree expr, int opt /* = -1 */, bool dis /* = true */) +{ + const key_type_t key = convert_to_key (expr); + + dis = set_no_warning (key, opt, dis) || dis; + set_no_warning_bit (expr, dis); +} + +/* Enable, or by default disable, a warning for the statement STMT. + The wildcard OPT of -1 controls all warnings. */ + +void +set_no_warning (gimple *stmt, int opt /* = -1 */, bool dis /* = true */) +{ + const key_type_t key = convert_to_key (stmt); + const nowarn_spec_t optspec (opt); + dis = set_no_warning (key, opt, dis) || dis; + set_no_warning_bit (stmt, dis); +} + +/* Copy the warning disposition mapping between an expression and/or + a statement. */ + +template +void copy_no_warning (ToType to, FromType from) +{ + const key_type_t to_key = convert_to_key (to); + + if (nowarn_spec_t *from_map = get_nowarn_spec (from)) + { + /* If there's an entry in the map the no-warning bit must be set. */ + gcc_assert (get_no_warning_bit (from)); + + if (!nowarn_map) + nowarn_map = xint_hash_map_t::create_ggc (32); + + nowarn_map->put (to_key, *from_map); + set_no_warning_bit (to, true); + } + else + { + if (nowarn_map) + nowarn_map->remove (to_key); + + /* The no-warning bit might be set even if there's no entry + in the map. */ + set_no_warning_bit (to, get_no_warning_bit (from)); + } +} + +/* Copy the warning disposition mapping from one expression to another. */ + +void +copy_no_warning (tree to, const_tree from) +{ + copy_no_warning(to, from); +} + +/* Copy the warning disposition mapping from a statement to an expression. */ + +void +copy_no_warning (tree to, const gimple *from) +{ + copy_no_warning(to, from); +} + +/* Copy the warning disposition mapping from an expression to a statement. */ + +void +copy_no_warning (gimple *to, const_tree from) +{ + copy_no_warning(to, from); +} + +/* Copy the warning disposition mapping from one statement to another. */ + +void +copy_no_warning (gimple *to, const gimple *from) +{ + copy_no_warning(to, from); +}