Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2229945/?format=api
{ "id": 2229945, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2229945/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260428232811.1953975-1-dmalcolm@redhat.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/1.1/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null }, "msgid": "<20260428232811.1953975-1-dmalcolm@redhat.com>", "date": "2026-04-28T23:28:11", "name": "[pushed:,r17-183] analyzer: split out various pending_diagnostic subclasses from region-model.cc", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "7dbeaf92e9e94a99a0ca1ccaebdcec42a2b394c6", "submitter": { "id": 24465, "url": "http://patchwork.ozlabs.org/api/1.1/people/24465/?format=api", "name": "David Malcolm", "email": "dmalcolm@redhat.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260428232811.1953975-1-dmalcolm@redhat.com/mbox/", "series": [ { "id": 501954, "url": "http://patchwork.ozlabs.org/api/1.1/series/501954/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=501954", "date": "2026-04-28T23:28:11", "name": "[pushed:,r17-183] analyzer: split out various pending_diagnostic subclasses from region-model.cc", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/501954/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2229945/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2229945/checks/", "tags": {}, "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=PIZTNeCq;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=PIZTNeCq", "sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com", "sourceware.org; spf=pass smtp.mailfrom=redhat.com", "server2.sourceware.org;\n arc=none smtp.remote-ip=170.10.129.124" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g4xTJ6Dd1z1yHv\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 09:28:52 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id D5B2B4BBCD81\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 23:28:50 +0000 (GMT)", "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by sourceware.org (Postfix) with ESMTP id 5D8864BBC0BB\n for <gcc-patches@gcc.gnu.org>; Tue, 28 Apr 2026 23:28:16 +0000 (GMT)", "from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-553-nBdAHjSzM5igiR0b920N-Q-1; Tue,\n 28 Apr 2026 19:28:14 -0400", "from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id BD26E1956095\n for <gcc-patches@gcc.gnu.org>; Tue, 28 Apr 2026 23:28:13 +0000 (UTC)", "from t14s.localdomain.com (unknown [10.22.65.168])\n by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 1F917180045E; Tue, 28 Apr 2026 23:28:13 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org D5B2B4BBCD81", "OpenDKIM Filter v2.11.0 sourceware.org 5D8864BBC0BB" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 5D8864BBC0BB", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 5D8864BBC0BB", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777418896; cv=none;\n b=h4IJFgN1DYekbAHuThPOy0+rfi56kilg00IgH6odsnY1JY41Y+5c8QedSmESonmoHjy9UWZCpUWSV4J3n8PYIsPG5Xaz5ms7/t4YdFgrTGTOC1gjF/LTa+NA/OegG0WVlATHg+YczXnR+ZyCX7CB9dEE79ozDhHClKVeSrTmQ2I=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777418896; c=relaxed/simple;\n bh=Y0BF3ZS01q+xQffm3cW5Ntd9A14qzROhO38DELE+0fI=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=UysE6cQrl0y4NAwBZOkzoVvtg3Mkv7CWl5XO9SwduKfLsywWoOADJYYASgwNMdSkerx1HLpdbi9f/078jLfj0IXgW3OrDPcNNJXCQv1lKlyIHCR2fFxtThw7vtmnzOGJfB7Q0lFO0+LmhXzgfVYr7lZqt26LTb+k5aryobWKqf8=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1777418895;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding;\n bh=AKOn2N6Ykc3Tfb4hNW9UAjfpVjyH4wG6WVRm/vV1Dvg=;\n b=PIZTNeCqfjO+LuhzybyjEzu6WVz420UeSuW5KG1wW7odC1Gtypu2Ffr/ag2yB9fZ0z1Y4C\n BotLDKkbF9p38OgkyvaU/rDsDgtVe+mGTg3+JuXTqeA1zkOtecsgBduqK1hIfgrdWs1O59\n 2EerjcNSVFYqk2sYzWj9MYAJe619Els=", "X-MC-Unique": "nBdAHjSzM5igiR0b920N-Q-1", "X-Mimecast-MFC-AGG-ID": "nBdAHjSzM5igiR0b920N-Q_1777418893", "From": "David Malcolm <dmalcolm@redhat.com>", "To": "gcc-patches@gcc.gnu.org", "Cc": "David Malcolm <dmalcolm@redhat.com>", "Subject": "[pushed: r17-183] analyzer: split out various pending_diagnostic\n subclasses from region-model.cc", "Date": "Tue, 28 Apr 2026 19:28:11 -0400", "Message-ID": "<20260428232811.1953975-1-dmalcolm@redhat.com>", "MIME-Version": "1.0", "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.111", "X-Mimecast-Spam-Score": "0", "X-Mimecast-MFC-PROC-ID": "WxE-f_HrGcyUJG7IuxaWutLRMVk6BNKmJ9kzGTkeb5A_1777418893", "X-Mimecast-Originator": "redhat.com", "Content-Transfer-Encoding": "8bit", "content-type": "text/plain; charset=\"US-ASCII\"; x-default=true", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "Split up region-model.cc somewhat. No functional change intended.\n\nSuccessfully bootstrapped & regrtested on powerpc64le-unknown-linux-gnu\n(albeit without ada,cobol,d, and possibly missing some optional test dependencies)\nPushed to trunk as r17-183-gd6dbbc97dd44b4.\n\ngcc/ChangeLog:\n\t* Makefile.in (ANALYZER_OBJS): Add\n\tanalyzer/poisoned-value-diagnostic.o,\n\tanalyzer/shift-diagnostics.o, and\n\tanalyzer/write-to-const-diagnostics.o.\n\ngcc/analyzer/ChangeLog:\n\t* poisoned-value-diagnostic.cc: New file, taken from material in\n\tregion-model.cc.\n\t* region-model.cc (class poisoned_value_diagnostic): Move to\n\tpoisoned-value-diagnostic.cc.\n\t(class shift_count_negative_diagnostic): Move to\n\tshift-diagnostics.cc.\n\t(class shift_count_overflow_diagnostic): Likewise.\n\t(region_model::get_gassign_result): Use factory functions when\n\tcreating diagnostics so that the subclasses can be moved to their\n\town source files.\n\t(region_model::check_for_poison): Likewise.\n\t(region_model::deref_rvalue): Likewise.\n\t(class write_to_const_diagnostic): Move to\n\twrite-to-const-diagnostics.cc.\n\t(class write_to_string_literal_diagnostic): Likewise.\n\t(region_model::check_for_writable_region): Use factory functions\n\twhen creating diagnostics so that the subclasses can be moved to\n\ttheir own source files.\n\t* region-model.h (make_poisoned_value_diagnostic): New decl.\n\t(make_shift_count_negative_diagnostic): New decl.\n\t(make_shift_count_overflow_diagnostic): New decl.\n\t(make_write_to_const_diagnostic): New decl.\n\t(make_write_to_string_literal_diagnostic): New decl.\n\t* shift-diagnostics.cc: New file, taken from material in\n\tregion-model.cc.\n\t* write-to-const-diagnostics.cc: Likewise.\n\nSigned-off-by: David Malcolm <dmalcolm@redhat.com>\n---\n gcc/Makefile.in | 5 +-\n gcc/analyzer/poisoned-value-diagnostic.cc | 220 +++++++++++\n gcc/analyzer/region-model.cc | 440 +--------------------\n gcc/analyzer/region-model.h | 22 ++\n gcc/analyzer/shift-diagnostics.cc | 148 +++++++\n gcc/analyzer/write-to-const-diagnostics.cc | 169 ++++++++\n 6 files changed, 577 insertions(+), 427 deletions(-)\n create mode 100644 gcc/analyzer/poisoned-value-diagnostic.cc\n create mode 100644 gcc/analyzer/shift-diagnostics.cc\n create mode 100644 gcc/analyzer/write-to-const-diagnostics.cc", "diff": "diff --git a/gcc/Makefile.in b/gcc/Makefile.in\nindex cbce3188794..0bccfffedc0 100644\n--- a/gcc/Makefile.in\n+++ b/gcc/Makefile.in\n@@ -1363,6 +1363,7 @@ ANALYZER_OBJS = \\\n \tanalyzer/known-function-manager.o \\\n \tanalyzer/ops.o \\\n \tanalyzer/pending-diagnostic.o \\\n+\tanalyzer/poisoned-value-diagnostic.o \\\n \tanalyzer/program-point.o \\\n \tanalyzer/program-state.o \\\n \tanalyzer/ranges.o \\\n@@ -1372,6 +1373,7 @@ ANALYZER_OBJS = \\\n \tanalyzer/region-model-asm.o \\\n \tanalyzer/region-model-manager.o \\\n \tanalyzer/region-model-reachability.o \\\n+\tanalyzer/shift-diagnostics.o \\\n \tanalyzer/sm.o \\\n \tanalyzer/sm-file.o \\\n \tanalyzer/sm-fd.o \\\n@@ -1389,7 +1391,8 @@ ANALYZER_OBJS = \\\n \tanalyzer/svalue.o \\\n \tanalyzer/symbol.o \\\n \tanalyzer/trimmed-graph.o \\\n-\tanalyzer/varargs.o\n+\tanalyzer/varargs.o \\\n+\tanalyzer/write-to-const-diagnostics.o \\\n \n # Language-independent object files.\n # We put the *-match.o and insn-*.o files first so that a parallel make\ndiff --git a/gcc/analyzer/poisoned-value-diagnostic.cc b/gcc/analyzer/poisoned-value-diagnostic.cc\nnew file mode 100644\nindex 00000000000..d29ceeaca63\n--- /dev/null\n+++ b/gcc/analyzer/poisoned-value-diagnostic.cc\n@@ -0,0 +1,220 @@\n+/* Implementation of class ana::poisoned_value_diagnostic.\n+ Copyright (C) 2019-2026 Free Software Foundation, Inc.\n+ Contributed by David Malcolm <dmalcolm@redhat.com>.\n+\n+This file is part of GCC.\n+\n+GCC is free software; you can redistribute it and/or modify it\n+under the terms of the GNU General Public License as published by\n+the Free Software Foundation; either version 3, or (at your option)\n+any later version.\n+\n+GCC is distributed in the hope that it will be useful, but\n+WITHOUT ANY WARRANTY; without even the implied warranty of\n+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+General Public License for more details.\n+\n+You should have received a copy of the GNU General Public License\n+along with GCC; see the file COPYING3. If not see\n+<http://www.gnu.org/licenses/>. */\n+\n+#include \"analyzer/common.h\"\n+\n+#include \"analyzer/region-model.h\"\n+#include \"analyzer/feasible-graph.h\"\n+#include \"diagnostics/sarif-sink.h\"\n+\n+#if ENABLE_ANALYZER\n+\n+namespace ana {\n+\n+/* A subclass of pending_diagnostic for complaining about uses of\n+ poisoned values. */\n+\n+class poisoned_value_diagnostic\n+: public pending_diagnostic_subclass<poisoned_value_diagnostic>\n+{\n+public:\n+ poisoned_value_diagnostic (tree expr, enum poison_kind pkind,\n+\t\t\t const region *src_region,\n+\t\t\t tree check_expr)\n+ : m_expr (expr), m_pkind (pkind),\n+ m_src_region (src_region),\n+ m_check_expr (check_expr)\n+ {}\n+\n+ const char *get_kind () const final override { return \"poisoned_value_diagnostic\"; }\n+\n+ bool use_of_uninit_p () const final override\n+ {\n+ return m_pkind == poison_kind::uninit;\n+ }\n+\n+ bool operator== (const poisoned_value_diagnostic &other) const\n+ {\n+ return (m_expr == other.m_expr\n+\t && m_pkind == other.m_pkind\n+\t && m_src_region == other.m_src_region);\n+ }\n+\n+ int get_controlling_option () const final override\n+ {\n+ switch (m_pkind)\n+ {\n+ default:\n+\tgcc_unreachable ();\n+ case poison_kind::uninit:\n+\treturn OPT_Wanalyzer_use_of_uninitialized_value;\n+ case poison_kind::freed:\n+ case poison_kind::deleted:\n+\treturn OPT_Wanalyzer_use_after_free;\n+ case poison_kind::popped_stack:\n+\treturn OPT_Wanalyzer_use_of_pointer_in_stale_stack_frame;\n+ }\n+ }\n+\n+ bool terminate_path_p () const final override { return true; }\n+\n+ bool emit (diagnostic_emission_context &ctxt) final override\n+ {\n+ switch (m_pkind)\n+ {\n+ default:\n+\tgcc_unreachable ();\n+ case poison_kind::uninit:\n+\t{\n+\t ctxt.add_cwe (457); /* \"CWE-457: Use of Uninitialized Variable\". */\n+\t return ctxt.warn (\"use of uninitialized value %qE\",\n+\t\t\t m_expr);\n+\t}\n+\tbreak;\n+ case poison_kind::freed:\n+\t{\n+\t ctxt.add_cwe (416); /* \"CWE-416: Use After Free\". */\n+\t return ctxt.warn (\"use after %<free%> of %qE\",\n+\t\t\t m_expr);\n+\t}\n+\tbreak;\n+ case poison_kind::deleted:\n+\t{\n+\t ctxt.add_cwe (416); /* \"CWE-416: Use After Free\". */\n+\t return ctxt.warn (\"use after %<delete%> of %qE\",\n+\t\t\t m_expr);\n+\t}\n+\tbreak;\n+ case poison_kind::popped_stack:\n+\t{\n+\t /* TODO: which CWE? */\n+\t return ctxt.warn\n+\t (\"dereferencing pointer %qE to within stale stack frame\",\n+\t m_expr);\n+\t}\n+\tbreak;\n+ }\n+ }\n+\n+ bool\n+ describe_final_event (pretty_printer &pp,\n+\t\t\tconst evdesc::final_event &) final override\n+ {\n+ switch (m_pkind)\n+ {\n+ default:\n+\tgcc_unreachable ();\n+ case poison_kind::uninit:\n+\t{\n+\t pp_printf (&pp,\n+\t\t \"use of uninitialized value %qE here\",\n+\t\t m_expr);\n+\t return true;\n+\t}\n+ case poison_kind::freed:\n+\t{\n+\t pp_printf (&pp,\n+\t\t \"use after %<free%> of %qE here\",\n+\t\t m_expr);\n+\t return true;\n+\t}\n+ case poison_kind::deleted:\n+\t{\n+\t pp_printf (&pp,\n+\t\t \"use after %<delete%> of %qE here\",\n+\t\t m_expr);\n+\t return true;\n+\t}\n+ case poison_kind::popped_stack:\n+\t{\n+\t pp_printf (&pp,\n+\t\t \"dereferencing pointer %qE to within stale stack frame\",\n+\t\t m_expr);\n+\t return true;\n+\t}\n+ }\n+ }\n+\n+ void mark_interesting_stuff (interesting_t *interest) final override\n+ {\n+ if (m_src_region)\n+ interest->add_region_creation (m_src_region);\n+ }\n+\n+ /* Attempt to suppress false positives.\n+ Reject paths where the value of the underlying region isn't poisoned.\n+ This can happen due to state merging when exploring the exploded graph,\n+ where the more precise analysis during feasibility analysis finds that\n+ the region is in fact valid.\n+ To do this we need to get the value from the fgraph. Unfortunately\n+ we can't simply query the state of m_src_region (from the enode),\n+ since it might be a different region in the fnode state (e.g. with\n+ heap-allocated regions, the numbering could be different).\n+ Hence we access m_check_expr, if available. */\n+\n+ bool check_valid_fpath_p (const feasible_node &fnode)\n+ const final override\n+ {\n+ if (!m_check_expr)\n+ return true;\n+ const svalue *fsval = fnode.get_model ().get_rvalue (m_check_expr, nullptr);\n+ /* Check to see if the expr is also poisoned in FNODE (and in the\n+ same way). */\n+ const poisoned_svalue * fspval = fsval->dyn_cast_poisoned_svalue ();\n+ if (!fspval)\n+ return false;\n+ if (fspval->get_poison_kind () != m_pkind)\n+ return false;\n+ return true;\n+ }\n+\n+ void\n+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)\n+ const final override\n+ {\n+ auto &props = result_obj.get_or_create_properties ();\n+#define PROPERTY_PREFIX \"gcc/analyzer/poisoned_value_diagnostic/\"\n+ props.set (PROPERTY_PREFIX \"expr\", tree_to_json (m_expr));\n+ props.set_string (PROPERTY_PREFIX \"kind\", poison_kind_to_str (m_pkind));\n+ if (m_src_region)\n+ props.set (PROPERTY_PREFIX \"src_region\", m_src_region->to_json ());\n+ props.set (PROPERTY_PREFIX \"check_expr\", tree_to_json (m_check_expr));\n+#undef PROPERTY_PREFIX\n+ }\n+\n+private:\n+ tree m_expr;\n+ enum poison_kind m_pkind;\n+ const region *m_src_region;\n+ tree m_check_expr;\n+};\n+\n+std::unique_ptr<pending_diagnostic>\n+make_poisoned_value_diagnostic (tree expr, enum poison_kind pkind,\n+\t\t\t\tconst region *src_region,\n+\t\t\t\ttree check_expr)\n+{\n+ return std::make_unique<poisoned_value_diagnostic> (expr, pkind,\n+\t\t\t\t\t\t src_region, check_expr);\n+}\n+\n+} // namespace ana\n+\n+#endif /* #if ENABLE_ANALYZER */\ndiff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc\nindex 6e25029d9d2..15210f5aa9c 100644\n--- a/gcc/analyzer/region-model.cc\n+++ b/gcc/analyzer/region-model.cc\n@@ -742,284 +742,6 @@ region_model::loop_replay_fixup (const region_model *dst_state)\n m_store.loop_replay_fixup (dst_state->get_store (), m_mgr);\n }\n \n-/* A subclass of pending_diagnostic for complaining about uses of\n- poisoned values. */\n-\n-class poisoned_value_diagnostic\n-: public pending_diagnostic_subclass<poisoned_value_diagnostic>\n-{\n-public:\n- poisoned_value_diagnostic (tree expr, enum poison_kind pkind,\n-\t\t\t const region *src_region,\n-\t\t\t tree check_expr)\n- : m_expr (expr), m_pkind (pkind),\n- m_src_region (src_region),\n- m_check_expr (check_expr)\n- {}\n-\n- const char *get_kind () const final override { return \"poisoned_value_diagnostic\"; }\n-\n- bool use_of_uninit_p () const final override\n- {\n- return m_pkind == poison_kind::uninit;\n- }\n-\n- bool operator== (const poisoned_value_diagnostic &other) const\n- {\n- return (m_expr == other.m_expr\n-\t && m_pkind == other.m_pkind\n-\t && m_src_region == other.m_src_region);\n- }\n-\n- int get_controlling_option () const final override\n- {\n- switch (m_pkind)\n- {\n- default:\n-\tgcc_unreachable ();\n- case poison_kind::uninit:\n-\treturn OPT_Wanalyzer_use_of_uninitialized_value;\n- case poison_kind::freed:\n- case poison_kind::deleted:\n-\treturn OPT_Wanalyzer_use_after_free;\n- case poison_kind::popped_stack:\n-\treturn OPT_Wanalyzer_use_of_pointer_in_stale_stack_frame;\n- }\n- }\n-\n- bool terminate_path_p () const final override { return true; }\n-\n- bool emit (diagnostic_emission_context &ctxt) final override\n- {\n- switch (m_pkind)\n- {\n- default:\n-\tgcc_unreachable ();\n- case poison_kind::uninit:\n-\t{\n-\t ctxt.add_cwe (457); /* \"CWE-457: Use of Uninitialized Variable\". */\n-\t return ctxt.warn (\"use of uninitialized value %qE\",\n-\t\t\t m_expr);\n-\t}\n-\tbreak;\n- case poison_kind::freed:\n-\t{\n-\t ctxt.add_cwe (416); /* \"CWE-416: Use After Free\". */\n-\t return ctxt.warn (\"use after %<free%> of %qE\",\n-\t\t\t m_expr);\n-\t}\n-\tbreak;\n- case poison_kind::deleted:\n-\t{\n-\t ctxt.add_cwe (416); /* \"CWE-416: Use After Free\". */\n-\t return ctxt.warn (\"use after %<delete%> of %qE\",\n-\t\t\t m_expr);\n-\t}\n-\tbreak;\n- case poison_kind::popped_stack:\n-\t{\n-\t /* TODO: which CWE? */\n-\t return ctxt.warn\n-\t (\"dereferencing pointer %qE to within stale stack frame\",\n-\t m_expr);\n-\t}\n-\tbreak;\n- }\n- }\n-\n- bool\n- describe_final_event (pretty_printer &pp,\n-\t\t\tconst evdesc::final_event &) final override\n- {\n- switch (m_pkind)\n- {\n- default:\n-\tgcc_unreachable ();\n- case poison_kind::uninit:\n-\t{\n-\t pp_printf (&pp,\n-\t\t \"use of uninitialized value %qE here\",\n-\t\t m_expr);\n-\t return true;\n-\t}\n- case poison_kind::freed:\n-\t{\n-\t pp_printf (&pp,\n-\t\t \"use after %<free%> of %qE here\",\n-\t\t m_expr);\n-\t return true;\n-\t}\n- case poison_kind::deleted:\n-\t{\n-\t pp_printf (&pp,\n-\t\t \"use after %<delete%> of %qE here\",\n-\t\t m_expr);\n-\t return true;\n-\t}\n- case poison_kind::popped_stack:\n-\t{\n-\t pp_printf (&pp,\n-\t\t \"dereferencing pointer %qE to within stale stack frame\",\n-\t\t m_expr);\n-\t return true;\n-\t}\n- }\n- }\n-\n- void mark_interesting_stuff (interesting_t *interest) final override\n- {\n- if (m_src_region)\n- interest->add_region_creation (m_src_region);\n- }\n-\n- /* Attempt to suppress false positives.\n- Reject paths where the value of the underlying region isn't poisoned.\n- This can happen due to state merging when exploring the exploded graph,\n- where the more precise analysis during feasibility analysis finds that\n- the region is in fact valid.\n- To do this we need to get the value from the fgraph. Unfortunately\n- we can't simply query the state of m_src_region (from the enode),\n- since it might be a different region in the fnode state (e.g. with\n- heap-allocated regions, the numbering could be different).\n- Hence we access m_check_expr, if available. */\n-\n- bool check_valid_fpath_p (const feasible_node &fnode)\n- const final override\n- {\n- if (!m_check_expr)\n- return true;\n- const svalue *fsval = fnode.get_model ().get_rvalue (m_check_expr, nullptr);\n- /* Check to see if the expr is also poisoned in FNODE (and in the\n- same way). */\n- const poisoned_svalue * fspval = fsval->dyn_cast_poisoned_svalue ();\n- if (!fspval)\n- return false;\n- if (fspval->get_poison_kind () != m_pkind)\n- return false;\n- return true;\n- }\n-\n- void\n- maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)\n- const final override\n- {\n- auto &props = result_obj.get_or_create_properties ();\n-#define PROPERTY_PREFIX \"gcc/analyzer/poisoned_value_diagnostic/\"\n- props.set (PROPERTY_PREFIX \"expr\", tree_to_json (m_expr));\n- props.set_string (PROPERTY_PREFIX \"kind\", poison_kind_to_str (m_pkind));\n- if (m_src_region)\n- props.set (PROPERTY_PREFIX \"src_region\", m_src_region->to_json ());\n- props.set (PROPERTY_PREFIX \"check_expr\", tree_to_json (m_check_expr));\n-#undef PROPERTY_PREFIX\n- }\n-\n-private:\n- tree m_expr;\n- enum poison_kind m_pkind;\n- const region *m_src_region;\n- tree m_check_expr;\n-};\n-\n-/* A subclass of pending_diagnostic for complaining about shifts\n- by negative counts. */\n-\n-class shift_count_negative_diagnostic\n-: public pending_diagnostic_subclass<shift_count_negative_diagnostic>\n-{\n-public:\n- shift_count_negative_diagnostic (const gassign *assign, tree count_cst)\n- : m_assign (assign), m_count_cst (count_cst)\n- {}\n-\n- const char *get_kind () const final override\n- {\n- return \"shift_count_negative_diagnostic\";\n- }\n-\n- bool operator== (const shift_count_negative_diagnostic &other) const\n- {\n- return (m_assign == other.m_assign\n-\t && same_tree_p (m_count_cst, other.m_count_cst));\n- }\n-\n- int get_controlling_option () const final override\n- {\n- return OPT_Wanalyzer_shift_count_negative;\n- }\n-\n- bool emit (diagnostic_emission_context &ctxt) final override\n- {\n- return ctxt.warn (\"shift by negative count (%qE)\", m_count_cst);\n- }\n-\n- bool\n- describe_final_event (pretty_printer &pp,\n-\t\t\tconst evdesc::final_event &) final override\n- {\n- pp_printf (&pp,\n-\t \"shift by negative amount here (%qE)\",\n-\t m_count_cst);\n- return true;\n- }\n-\n-private:\n- const gassign *m_assign;\n- tree m_count_cst;\n-};\n-\n-/* A subclass of pending_diagnostic for complaining about shifts\n- by counts >= the width of the operand type. */\n-\n-class shift_count_overflow_diagnostic\n-: public pending_diagnostic_subclass<shift_count_overflow_diagnostic>\n-{\n-public:\n- shift_count_overflow_diagnostic (const gassign *assign,\n-\t\t\t\t int operand_precision,\n-\t\t\t\t tree count_cst)\n- : m_assign (assign), m_operand_precision (operand_precision),\n- m_count_cst (count_cst)\n- {}\n-\n- const char *get_kind () const final override\n- {\n- return \"shift_count_overflow_diagnostic\";\n- }\n-\n- bool operator== (const shift_count_overflow_diagnostic &other) const\n- {\n- return (m_assign == other.m_assign\n-\t && m_operand_precision == other.m_operand_precision\n-\t && same_tree_p (m_count_cst, other.m_count_cst));\n- }\n-\n- int get_controlling_option () const final override\n- {\n- return OPT_Wanalyzer_shift_count_overflow;\n- }\n-\n- bool emit (diagnostic_emission_context &ctxt) final override\n- {\n- return ctxt.warn (\"shift by count (%qE) >= precision of type (%qi)\",\n-\t\t m_count_cst, m_operand_precision);\n- }\n-\n- bool\n- describe_final_event (pretty_printer &pp,\n-\t\t\tconst evdesc::final_event &) final override\n- {\n- pp_printf (&pp,\n-\t \"shift by count %qE here\",\n-\t m_count_cst);\n- return true;\n- }\n-\n-private:\n- const gassign *m_assign;\n- int m_operand_precision;\n- tree m_count_cst;\n-};\n-\n /* A subclass of pending_diagnostic for complaining about pointer\n subtractions involving unrelated buffers. */\n \n@@ -1340,16 +1062,14 @@ region_model::get_gassign_result (const gassign *assign,\n \t\t{\n \t\t if (tree_int_cst_sgn (rhs2_cst) < 0)\n \t\t ctxt->warn\n-\t\t (std::make_unique<shift_count_negative_diagnostic>\n-\t\t\t (assign, rhs2_cst));\n+\t\t (make_shift_count_negative_diagnostic (assign, rhs2_cst));\n \t\t else if (compare_tree_int (rhs2_cst,\n \t\t\t\t\t TYPE_PRECISION (TREE_TYPE (rhs1)))\n \t\t\t >= 0)\n-\t\t ctxt->warn\n-\t\t (std::make_unique<shift_count_overflow_diagnostic>\n-\t\t\t (assign,\n-\t\t\t int (TYPE_PRECISION (TREE_TYPE (rhs1))),\n-\t\t\t rhs2_cst));\n+\t\t ctxt->warn (make_shift_count_overflow_diagnostic\n+\t\t\t\t(assign,\n+\t\t\t\t int (TYPE_PRECISION (TREE_TYPE (rhs1))),\n+\t\t\t\t rhs2_cst));\n \t\t}\n \t }\n \n@@ -1602,11 +1322,10 @@ region_model::check_for_poison (const svalue *sval,\n \tcheck_expr = expr;\n else\n \tcheck_expr = nullptr;\n- if (ctxt->warn\n-\t (std::make_unique<poisoned_value_diagnostic> (diag_arg,\n-\t\t\t\t\t\t\t pkind,\n-\t\t\t\t\t\t\t src_region,\n-\t\t\t\t\t\t\t check_expr)))\n+ if (ctxt->warn (make_poisoned_value_diagnostic (diag_arg,\n+\t\t\t\t\t\t pkind,\n+\t\t\t\t\t\t src_region,\n+\t\t\t\t\t\t check_expr)))\n \t{\n \t /* We only want to report use of a poisoned value at the first\n \t place it gets used; return an unknown value to avoid generating\n@@ -3487,7 +3206,7 @@ region_model::deref_rvalue (const svalue *ptr_sval, tree ptr_tree,\n \t\tconst poisoned_svalue *poisoned_sval\n \t\t = as_a <const poisoned_svalue *> (ptr_sval);\n \t\tenum poison_kind pkind = poisoned_sval->get_poison_kind ();\n-\t\tctxt->warn (std::make_unique<poisoned_value_diagnostic>\n+\t\tctxt->warn (make_poisoned_value_diagnostic\n \t\t\t (ptr, pkind, nullptr, nullptr));\n \t }\n \t }\n@@ -3514,131 +3233,6 @@ region_model::get_rvalue_for_bits (tree type,\n return m_mgr->get_or_create_bits_within (type, bits, sval);\n }\n \n-/* A subclass of pending_diagnostic for complaining about writes to\n- constant regions of memory. */\n-\n-class write_to_const_diagnostic\n-: public pending_diagnostic_subclass<write_to_const_diagnostic>\n-{\n-public:\n- write_to_const_diagnostic (const region *reg, tree decl)\n- : m_reg (reg), m_decl (decl)\n- {}\n-\n- const char *get_kind () const final override\n- {\n- return \"write_to_const_diagnostic\";\n- }\n-\n- bool operator== (const write_to_const_diagnostic &other) const\n- {\n- return (m_reg == other.m_reg\n-\t && m_decl == other.m_decl);\n- }\n-\n- int get_controlling_option () const final override\n- {\n- return OPT_Wanalyzer_write_to_const;\n- }\n-\n- bool emit (diagnostic_emission_context &ctxt) final override\n- {\n- auto_diagnostic_group d;\n- bool warned;\n- switch (m_reg->get_kind ())\n- {\n- default:\n-\twarned = ctxt.warn (\"write to %<const%> object %qE\", m_decl);\n-\tbreak;\n- case RK_FUNCTION:\n-\twarned = ctxt.warn (\"write to function %qE\", m_decl);\n-\tbreak;\n- case RK_LABEL:\n-\twarned = ctxt.warn (\"write to label %qE\", m_decl);\n-\tbreak;\n- }\n- if (warned)\n- inform (DECL_SOURCE_LOCATION (m_decl), \"declared here\");\n- return warned;\n- }\n-\n- bool\n- describe_final_event (pretty_printer &pp,\n-\t\t\tconst evdesc::final_event &) final override\n- {\n- switch (m_reg->get_kind ())\n- {\n- default:\n-\t{\n-\t pp_printf (&pp,\n-\t\t \"write to %<const%> object %qE here\", m_decl);\n-\t return true;\n-\t}\n- case RK_FUNCTION:\n-\t{\n-\t pp_printf (&pp,\n-\t\t \"write to function %qE here\", m_decl);\n-\t return true;\n-\t}\n- case RK_LABEL:\n-\t{\n-\t pp_printf (&pp,\n-\t\t \"write to label %qE here\", m_decl);\n-\t return true;\n-\t}\n- }\n- }\n-\n-private:\n- const region *m_reg;\n- tree m_decl;\n-};\n-\n-/* A subclass of pending_diagnostic for complaining about writes to\n- string literals. */\n-\n-class write_to_string_literal_diagnostic\n-: public pending_diagnostic_subclass<write_to_string_literal_diagnostic>\n-{\n-public:\n- write_to_string_literal_diagnostic (const region *reg)\n- : m_reg (reg)\n- {}\n-\n- const char *get_kind () const final override\n- {\n- return \"write_to_string_literal_diagnostic\";\n- }\n-\n- bool operator== (const write_to_string_literal_diagnostic &other) const\n- {\n- return m_reg == other.m_reg;\n- }\n-\n- int get_controlling_option () const final override\n- {\n- return OPT_Wanalyzer_write_to_string_literal;\n- }\n-\n- bool emit (diagnostic_emission_context &ctxt) final override\n- {\n- return ctxt.warn (\"write to string literal\");\n- /* Ideally we would show the location of the STRING_CST as well,\n- but it is not available at this point. */\n- }\n-\n- bool\n- describe_final_event (pretty_printer &pp,\n-\t\t\tconst evdesc::final_event &) final override\n- {\n- pp_string (&pp, \"write to string literal here\");\n- return true;\n- }\n-\n-private:\n- const region *m_reg;\n-};\n-\n /* Use CTXT to warn If DEST_REG is a region that shouldn't be written to. */\n \n void\n@@ -3658,18 +3252,14 @@ region_model::check_for_writable_region (const region* dest_reg,\n {\n \tconst function_region *func_reg = as_a <const function_region *> (base_reg);\n \ttree fndecl = func_reg->get_fndecl ();\n-\tctxt->warn\n-\t (std::make_unique<write_to_const_diagnostic>\n-\t (func_reg, fndecl));\n+\tctxt->warn (make_write_to_const_diagnostic (func_reg, fndecl));\n }\n break;\n case RK_LABEL:\n {\n \tconst label_region *label_reg = as_a <const label_region *> (base_reg);\n \ttree label = label_reg->get_label ();\n-\tctxt->warn\n-\t (std::make_unique<write_to_const_diagnostic>\n-\t (label_reg, label));\n+\tctxt->warn (make_write_to_const_diagnostic (label_reg, label));\n }\n break;\n case RK_DECL:\n@@ -3682,13 +3272,11 @@ region_model::check_for_writable_region (const region* dest_reg,\n \t \"this\" param is \"T* const\"). */\n \tif (TREE_READONLY (decl)\n \t && is_global_var (decl))\n-\t ctxt->warn\n-\t (std::make_unique<write_to_const_diagnostic> (dest_reg, decl));\n+\t ctxt->warn (make_write_to_const_diagnostic (dest_reg, decl));\n }\n break;\n case RK_STRING:\n- ctxt->warn\n-\t(std::make_unique<write_to_string_literal_diagnostic> (dest_reg));\n+ ctxt->warn (make_write_to_string_literal_diagnostic (dest_reg));\n break;\n }\n }\ndiff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h\nindex f4cf38e3e0f..4b0160a98b0 100644\n--- a/gcc/analyzer/region-model.h\n+++ b/gcc/analyzer/region-model.h\n@@ -1329,6 +1329,28 @@ private:\n const supergraph *m_sg;\n };\n \n+/* Factory functions for various diagnostics. */\n+\n+extern std::unique_ptr<pending_diagnostic>\n+make_poisoned_value_diagnostic (tree expr, enum poison_kind pkind,\n+\t\t\t\tconst region *src_region,\n+\t\t\t\ttree check_expr);\n+\n+extern std::unique_ptr<pending_diagnostic>\n+make_shift_count_negative_diagnostic (const gassign *assign,\n+\t\t\t\t tree count_cst);\n+\n+extern std::unique_ptr<pending_diagnostic>\n+make_shift_count_overflow_diagnostic (const gassign *assign,\n+\t\t\t\t int operand_precision,\n+\t\t\t\t tree count_cst);\n+\n+extern std::unique_ptr<pending_diagnostic>\n+make_write_to_const_diagnostic (const region *dest_reg, tree decl);\n+\n+extern std::unique_ptr<pending_diagnostic>\n+make_write_to_string_literal_diagnostic (const region *reg);\n+\n } // namespace ana\n \n extern void debug (const region_model &rmodel);\ndiff --git a/gcc/analyzer/shift-diagnostics.cc b/gcc/analyzer/shift-diagnostics.cc\nnew file mode 100644\nindex 00000000000..2bc58de248d\n--- /dev/null\n+++ b/gcc/analyzer/shift-diagnostics.cc\n@@ -0,0 +1,148 @@\n+/* Diagnostics for complaining about shift operations.\n+ Copyright (C) 2020-2026 Free Software Foundation, Inc.\n+ Contributed by David Malcolm <dmalcolm@redhat.com>.\n+\n+This file is part of GCC.\n+\n+GCC is free software; you can redistribute it and/or modify it\n+under the terms of the GNU General Public License as published by\n+the Free Software Foundation; either version 3, or (at your option)\n+any later version.\n+\n+GCC is distributed in the hope that it will be useful, but\n+WITHOUT ANY WARRANTY; without even the implied warranty of\n+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+General Public License for more details.\n+\n+You should have received a copy of the GNU General Public License\n+along with GCC; see the file COPYING3. If not see\n+<http://www.gnu.org/licenses/>. */\n+\n+#include \"analyzer/common.h\"\n+\n+#include \"analyzer/region-model.h\"\n+#include \"analyzer/feasible-graph.h\"\n+#include \"diagnostics/sarif-sink.h\"\n+\n+#if ENABLE_ANALYZER\n+\n+namespace ana {\n+\n+/* A subclass of pending_diagnostic for complaining about shifts\n+ by negative counts. */\n+\n+class shift_count_negative_diagnostic\n+: public pending_diagnostic_subclass<shift_count_negative_diagnostic>\n+{\n+public:\n+ shift_count_negative_diagnostic (const gassign *assign, tree count_cst)\n+ : m_assign (assign), m_count_cst (count_cst)\n+ {}\n+\n+ const char *get_kind () const final override\n+ {\n+ return \"shift_count_negative_diagnostic\";\n+ }\n+\n+ bool operator== (const shift_count_negative_diagnostic &other) const\n+ {\n+ return (m_assign == other.m_assign\n+\t && same_tree_p (m_count_cst, other.m_count_cst));\n+ }\n+\n+ int get_controlling_option () const final override\n+ {\n+ return OPT_Wanalyzer_shift_count_negative;\n+ }\n+\n+ bool emit (diagnostic_emission_context &ctxt) final override\n+ {\n+ return ctxt.warn (\"shift by negative count (%qE)\", m_count_cst);\n+ }\n+\n+ bool\n+ describe_final_event (pretty_printer &pp,\n+\t\t\tconst evdesc::final_event &) final override\n+ {\n+ pp_printf (&pp,\n+\t \"shift by negative amount here (%qE)\",\n+\t m_count_cst);\n+ return true;\n+ }\n+\n+private:\n+ const gassign *m_assign;\n+ tree m_count_cst;\n+};\n+\n+std::unique_ptr<pending_diagnostic>\n+make_shift_count_negative_diagnostic (const gassign *assign, tree count_cst)\n+{\n+ return std::make_unique<shift_count_negative_diagnostic> (assign, count_cst);\n+}\n+\n+/* A subclass of pending_diagnostic for complaining about shifts\n+ by counts >= the width of the operand type. */\n+\n+class shift_count_overflow_diagnostic\n+: public pending_diagnostic_subclass<shift_count_overflow_diagnostic>\n+{\n+public:\n+ shift_count_overflow_diagnostic (const gassign *assign,\n+\t\t\t\t int operand_precision,\n+\t\t\t\t tree count_cst)\n+ : m_assign (assign), m_operand_precision (operand_precision),\n+ m_count_cst (count_cst)\n+ {}\n+\n+ const char *get_kind () const final override\n+ {\n+ return \"shift_count_overflow_diagnostic\";\n+ }\n+\n+ bool operator== (const shift_count_overflow_diagnostic &other) const\n+ {\n+ return (m_assign == other.m_assign\n+\t && m_operand_precision == other.m_operand_precision\n+\t && same_tree_p (m_count_cst, other.m_count_cst));\n+ }\n+\n+ int get_controlling_option () const final override\n+ {\n+ return OPT_Wanalyzer_shift_count_overflow;\n+ }\n+\n+ bool emit (diagnostic_emission_context &ctxt) final override\n+ {\n+ return ctxt.warn (\"shift by count (%qE) >= precision of type (%qi)\",\n+\t\t m_count_cst, m_operand_precision);\n+ }\n+\n+ bool\n+ describe_final_event (pretty_printer &pp,\n+\t\t\tconst evdesc::final_event &) final override\n+ {\n+ pp_printf (&pp,\n+\t \"shift by count %qE here\",\n+\t m_count_cst);\n+ return true;\n+ }\n+\n+private:\n+ const gassign *m_assign;\n+ int m_operand_precision;\n+ tree m_count_cst;\n+};\n+\n+std::unique_ptr<pending_diagnostic>\n+make_shift_count_overflow_diagnostic (const gassign *assign,\n+\t\t\t\t int operand_precision,\n+\t\t\t\t tree count_cst)\n+{\n+ return std::make_unique<shift_count_overflow_diagnostic>\n+ (assign, operand_precision, count_cst);\n+}\n+\n+} // namespace ana\n+\n+#endif /* #if ENABLE_ANALYZER */\ndiff --git a/gcc/analyzer/write-to-const-diagnostics.cc b/gcc/analyzer/write-to-const-diagnostics.cc\nnew file mode 100644\nindex 00000000000..7d71f1a32ae\n--- /dev/null\n+++ b/gcc/analyzer/write-to-const-diagnostics.cc\n@@ -0,0 +1,169 @@\n+/* Implementation of write_to_const_diagnostic and\n+ write_to_string_literal_diagnostic.\n+ Copyright (C) 2020-2026 Free Software Foundation, Inc.\n+ Contributed by David Malcolm <dmalcolm@redhat.com>.\n+\n+This file is part of GCC.\n+\n+GCC is free software; you can redistribute it and/or modify it\n+under the terms of the GNU General Public License as published by\n+the Free Software Foundation; either version 3, or (at your option)\n+any later version.\n+\n+GCC is distributed in the hope that it will be useful, but\n+WITHOUT ANY WARRANTY; without even the implied warranty of\n+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+General Public License for more details.\n+\n+You should have received a copy of the GNU General Public License\n+along with GCC; see the file COPYING3. If not see\n+<http://www.gnu.org/licenses/>. */\n+\n+#include \"analyzer/common.h\"\n+\n+#include \"analyzer/region-model.h\"\n+\n+#if ENABLE_ANALYZER\n+\n+namespace ana {\n+\n+/* A subclass of pending_diagnostic for complaining about writes to\n+ constant regions of memory. */\n+\n+class write_to_const_diagnostic\n+: public pending_diagnostic_subclass<write_to_const_diagnostic>\n+{\n+public:\n+ write_to_const_diagnostic (const region *reg, tree decl)\n+ : m_reg (reg), m_decl (decl)\n+ {}\n+\n+ const char *get_kind () const final override\n+ {\n+ return \"write_to_const_diagnostic\";\n+ }\n+\n+ bool operator== (const write_to_const_diagnostic &other) const\n+ {\n+ return (m_reg == other.m_reg\n+\t && m_decl == other.m_decl);\n+ }\n+\n+ int get_controlling_option () const final override\n+ {\n+ return OPT_Wanalyzer_write_to_const;\n+ }\n+\n+ bool emit (diagnostic_emission_context &ctxt) final override\n+ {\n+ auto_diagnostic_group d;\n+ bool warned;\n+ switch (m_reg->get_kind ())\n+ {\n+ default:\n+\twarned = ctxt.warn (\"write to %<const%> object %qE\", m_decl);\n+\tbreak;\n+ case RK_FUNCTION:\n+\twarned = ctxt.warn (\"write to function %qE\", m_decl);\n+\tbreak;\n+ case RK_LABEL:\n+\twarned = ctxt.warn (\"write to label %qE\", m_decl);\n+\tbreak;\n+ }\n+ if (warned)\n+ inform (DECL_SOURCE_LOCATION (m_decl), \"declared here\");\n+ return warned;\n+ }\n+\n+ bool\n+ describe_final_event (pretty_printer &pp,\n+\t\t\tconst evdesc::final_event &) final override\n+ {\n+ switch (m_reg->get_kind ())\n+ {\n+ default:\n+\t{\n+\t pp_printf (&pp,\n+\t\t \"write to %<const%> object %qE here\", m_decl);\n+\t return true;\n+\t}\n+ case RK_FUNCTION:\n+\t{\n+\t pp_printf (&pp,\n+\t\t \"write to function %qE here\", m_decl);\n+\t return true;\n+\t}\n+ case RK_LABEL:\n+\t{\n+\t pp_printf (&pp,\n+\t\t \"write to label %qE here\", m_decl);\n+\t return true;\n+\t}\n+ }\n+ }\n+\n+private:\n+ const region *m_reg;\n+ tree m_decl;\n+};\n+\n+std::unique_ptr<pending_diagnostic>\n+make_write_to_const_diagnostic (const region *dest_reg, tree decl)\n+{\n+ return std::make_unique<write_to_const_diagnostic> (dest_reg, decl);\n+}\n+\n+/* A subclass of pending_diagnostic for complaining about writes to\n+ string literals. */\n+\n+class write_to_string_literal_diagnostic\n+: public pending_diagnostic_subclass<write_to_string_literal_diagnostic>\n+{\n+public:\n+ write_to_string_literal_diagnostic (const region *reg)\n+ : m_reg (reg)\n+ {}\n+\n+ const char *get_kind () const final override\n+ {\n+ return \"write_to_string_literal_diagnostic\";\n+ }\n+\n+ bool operator== (const write_to_string_literal_diagnostic &other) const\n+ {\n+ return m_reg == other.m_reg;\n+ }\n+\n+ int get_controlling_option () const final override\n+ {\n+ return OPT_Wanalyzer_write_to_string_literal;\n+ }\n+\n+ bool emit (diagnostic_emission_context &ctxt) final override\n+ {\n+ return ctxt.warn (\"write to string literal\");\n+ /* Ideally we would show the location of the STRING_CST as well,\n+ but it is not available at this point. */\n+ }\n+\n+ bool\n+ describe_final_event (pretty_printer &pp,\n+\t\t\tconst evdesc::final_event &) final override\n+ {\n+ pp_string (&pp, \"write to string literal here\");\n+ return true;\n+ }\n+\n+private:\n+ const region *m_reg;\n+};\n+\n+std::unique_ptr<pending_diagnostic>\n+make_write_to_string_literal_diagnostic (const region *reg)\n+{\n+ return std::make_unique<write_to_string_literal_diagnostic> (reg);\n+}\n+\n+} // namespace ana\n+\n+#endif /* #if ENABLE_ANALYZER */\n", "prefixes": [ "pushed:", "r17-183" ] }