diff mbox series

[1/11] introduce xxx_no_warning APIs

Message ID 535d1b55-fc0a-63c3-08b5-48a017674d1e@gmail.com
State New
Headers show
Series warning control by group and location (PR 74765) | expand

Commit Message

Martin Sebor May 24, 2021, 10:07 p.m. UTC
The attached patch introduces the get_no_warning(), set_no_warning(),
and copy_no_warning() APIs without making use of them in the rest of
GCC.  They are in three files:

   diagnostic-spec.{h,c}: Location-centric overloads.
   warning-control.cc: Tree- and gimple*-centric overloads.

The location-centric overloads are suitable to use from the diagnostic
subsystem.  The rest can be used from the front ends and the middle end.
diff mbox series

Patch

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 <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"
+
+/* 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 <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/>.  */
+
+#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<unsigned>(lhs) == static_cast<unsigned>(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 <key_type_t, 0, UINT_MAX> xint_hash_t;
+typedef hash_map<xint_hash_t, nowarn_spec_t> 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
+   <http://www.gnu.org/licenses/>.  */
+
+#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 <class ToType, class FromType>
+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<tree, const_tree>(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<tree, const gimple *>(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<gimple *, const_tree>(to, from);
+}
+
+/* Copy the warning disposition mapping from one statement to another.  */
+
+void
+copy_no_warning (gimple *to, const gimple *from)
+{
+  copy_no_warning<gimple *, const gimple *>(to, from);
+}