(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.dg/
plugin/
diagnostic_group_plugin.c
       1  /* { dg-options "-O" } */
       2  
       3  #include "gcc-plugin.h"
       4  #include "config.h"
       5  #include "system.h"
       6  #include "coretypes.h"
       7  #include "tm.h"
       8  #include "tree.h"
       9  #include "stringpool.h"
      10  #include "toplev.h"
      11  #include "basic-block.h"
      12  #include "hash-table.h"
      13  #include "vec.h"
      14  #include "ggc.h"
      15  #include "basic-block.h"
      16  #include "tree-ssa-alias.h"
      17  #include "internal-fn.h"
      18  #include "gimple.h"
      19  #include "gimple-iterator.h"
      20  #include "gimple-fold.h"
      21  #include "tree-eh.h"
      22  #include "gimple-expr.h"
      23  #include "is-a.h"
      24  #include "tree.h"
      25  #include "tree-pass.h"
      26  #include "intl.h"
      27  #include "plugin-version.h"
      28  #include "c-family/c-common.h"
      29  #include "diagnostic.h"
      30  #include "context.h"
      31  
      32  int plugin_is_GPL_compatible;
      33  
      34  /* A custom pass for emitting dummy warnings from the middle-end.  */
      35  
      36  const pass_data pass_data_test_groups =
      37  {
      38    GIMPLE_PASS, /* type */
      39    "test_groups", /* name */
      40    OPTGROUP_NONE, /* optinfo_flags */
      41    TV_NONE, /* tv_id */
      42    PROP_ssa, /* properties_required */
      43    0, /* properties_provided */
      44    0, /* properties_destroyed */
      45    0, /* todo_flags_start */
      46    0, /* todo_flags_finish */
      47  };
      48  
      49  class pass_test_groups : public gimple_opt_pass
      50  {
      51  public:
      52    pass_test_groups(gcc::context *ctxt)
      53      : gimple_opt_pass(pass_data_test_groups, ctxt)
      54    {}
      55  
      56    /* opt_pass methods: */
      57    bool gate (function *) { return true; }
      58    virtual unsigned int execute (function *);
      59  
      60  }; // class pass_test_groups
      61  
      62  /* Determine if STMT is a call with NUM_ARGS arguments to a function
      63     named FUNCNAME.
      64     If so, return STMT as a gcall *.  Otherwise return NULL.  */
      65  
      66  static gcall *
      67  check_for_named_call (gimple *stmt,
      68  		      const char *funcname, unsigned int num_args)
      69  {
      70    gcc_assert (funcname);
      71  
      72    gcall *call = dyn_cast <gcall *> (stmt);
      73    if (!call)
      74      return NULL;
      75  
      76    tree fndecl = gimple_call_fndecl (call);
      77    if (!fndecl)
      78      return NULL;
      79  
      80    if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname))
      81      return NULL;
      82  
      83    if (gimple_call_num_args (call) != num_args)
      84      {
      85        error_at (stmt->location, "expected number of args: %i (got %i)",
      86  		num_args, gimple_call_num_args (call));
      87        return NULL;
      88      }
      89  
      90    return call;
      91  }
      92  
      93  /* Emit a warning at LOC.  */
      94  
      95  static void
      96  emit_warning (location_t loc)
      97  {
      98    source_range src_range = get_range_from_loc (line_table, loc);
      99    warning_at (loc, 0, "range %i:%i-%i:%i",
     100  	      LOCATION_LINE (src_range.m_start),
     101  	      LOCATION_COLUMN (src_range.m_start),
     102  	      LOCATION_LINE (src_range.m_finish),
     103  	      LOCATION_COLUMN (src_range.m_finish));
     104  }
     105  
     106  /* Code for simulating the emission of a warning from the middle-end.
     107     Emit a warning for each call to a function named "__emit_warning".  */
     108  
     109  static void
     110  test_groups (gimple *stmt)
     111  {
     112    gcall *call = check_for_named_call (stmt, "__emit_warning", 1);
     113    if (!call)
     114      return;
     115  
     116    /* We expect an ADDR_EXPR with a STRING_CST inside it for the
     117       initial arg.  */
     118    tree t_addr_string = gimple_call_arg (call, 0);
     119    if (TREE_CODE (t_addr_string) != ADDR_EXPR)
     120      {
     121        error_at (call->location, "string literal required for arg 1");
     122        return;
     123      }
     124  
     125    tree t_string = TREE_OPERAND (t_addr_string, 0);
     126    if (TREE_CODE (t_string) != STRING_CST)
     127      {
     128        error_at (call->location, "string literal required for arg 1");
     129        return;
     130      }
     131  
     132    {
     133      auto_diagnostic_group d;
     134      if (warning_at (call->location, 0, "%s", call,
     135  		    TREE_STRING_POINTER (t_string)))
     136        {
     137  	inform (call->location, "message for note");
     138  	inform (call->location, " some more detail");
     139  	inform (call->location, "  yet more detail");
     140        }
     141    }
     142    inform (call->location, "an unrelated message");
     143  }
     144  
     145  /* Call test_groups on every statement within FUN.  */
     146  
     147  unsigned int
     148  pass_test_groups::execute (function *fun)
     149  {
     150    gimple_stmt_iterator gsi;
     151    basic_block bb;
     152  
     153    FOR_EACH_BB_FN (bb, fun)
     154      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
     155        {
     156  	gimple *stmt = gsi_stmt (gsi);
     157  	test_groups (stmt);
     158        }
     159  
     160    return 0;
     161  }
     162  
     163  /* Custom diagnostic callback, to avoid having the path in the
     164     expected output.  */
     165  
     166  void
     167  test_diagnostic_starter (diagnostic_context *context,
     168  			 diagnostic_info *diagnostic)
     169  {
     170    pp_set_prefix (context->printer, xstrdup ("PREFIX: "));
     171  }
     172  
     173  /* Custom diagnostic callback, to avoid having the path in the
     174     expected output.  */
     175  
     176  void
     177  test_diagnostic_start_span_fn (diagnostic_context *context,
     178  			       expanded_location exploc)
     179  {
     180    pp_string (context->printer, "START_SPAN_FN: ");
     181    pp_newline (context->printer);
     182  }
     183  
     184  /* Custom diagnostic callback: loudly announce a new diagnostic group.  */
     185  
     186  static void
     187  test_begin_group_cb (diagnostic_context * context)
     188  {
     189    pp_string (context->printer,
     190  	     "================================= BEGIN GROUP ==============================");
     191    pp_newline (context->printer);
     192  }
     193  
     194  /* Custom diagnostic callback: loudly announce the end of a
     195     diagnostic group.  */
     196  
     197  static void
     198  test_end_group_cb (diagnostic_context * context)
     199  {
     200    pp_set_prefix (context->printer, NULL);
     201    pp_string (context->printer,
     202  	     "---------------------------------- END GROUP -------------------------------");
     203    pp_newline_and_flush (context->printer);
     204  }
     205  
     206  /* Entrypoint for the plugin.
     207     Install custom callbacks into the global_dc.
     208     Create and register the custom pass.  */
     209  
     210  int
     211  plugin_init (struct plugin_name_args *plugin_info,
     212  	     struct plugin_gcc_version *version)
     213  {
     214    struct register_pass_info pass_info;
     215    const char *plugin_name = plugin_info->base_name;
     216    int argc = plugin_info->argc;
     217    struct plugin_argument *argv = plugin_info->argv;
     218  
     219    if (!plugin_default_version_check (version, &gcc_version))
     220      return 1;
     221  
     222    diagnostic_starter (global_dc) = test_diagnostic_starter;
     223    global_dc->start_span = test_diagnostic_start_span_fn;
     224    global_dc->begin_group_cb = test_begin_group_cb;
     225    global_dc->end_group_cb = test_end_group_cb;
     226  
     227    pass_info.pass = new pass_test_groups (g);
     228    pass_info.reference_pass_name = "*warn_function_noreturn";
     229    pass_info.ref_pass_instance_number = 1;
     230    pass_info.pos_op = PASS_POS_INSERT_AFTER;
     231    register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
     232  		     &pass_info);
     233  
     234    return 0;
     235  }