https://gcc.gnu.org/g:5caef7c4a904a065706ad375691f3b9d9bf525cb

commit r17-626-g5caef7c4a904a065706ad375691f3b9d9bf525cb
Author: David Malcolm <[email protected]>
Date:   Wed May 20 08:52:48 2026 -0400

    analyzer: add pointer diff folding
    
    Doing so allows -fanalyzer to handle std::string size() on non-empty
    strings.
    
    gcc/analyzer/ChangeLog:
            * region-model-manager.cc
            (region_model_manager::maybe_fold_binop): Fold
            "(X POINTER_PLUS Y) POINTER_DIFF_EXPR X" to Y.
    
    gcc/testsuite/ChangeLog:
            * c-c++-common/analyzer/ptr-subtraction-2.c: New test.
    
    Signed-off-by: David Malcolm <[email protected]>

Diff:
---
 gcc/analyzer/region-model-manager.cc               |  7 ++++++
 .../c-c++-common/analyzer/ptr-subtraction-2.c      | 28 ++++++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/gcc/analyzer/region-model-manager.cc 
b/gcc/analyzer/region-model-manager.cc
index ba7f9db507b6..4b1aacccb632 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -738,6 +738,13 @@ region_model_manager::maybe_fold_binop (tree type, enum 
tree_code op,
          if (binop->get_arg0 () == arg1)
            return get_or_create_cast (type, binop->get_arg1 ());
       break;
+    case POINTER_DIFF_EXPR:
+      /* (X POINTER_PLUS Y) POINTER_DIFF_EXPR X -> Y.  */
+      if (const binop_svalue *binop = arg0->dyn_cast_binop_svalue ())
+       if (binop->get_op () == POINTER_PLUS_EXPR)
+         if (binop->get_arg0 () == arg1)
+           return get_or_create_cast (type, binop->get_arg1 ());
+      break;
     case MULT_EXPR:
       /* (VAL * 0).  */
       if (cst1
diff --git a/gcc/testsuite/c-c++-common/analyzer/ptr-subtraction-2.c 
b/gcc/testsuite/c-c++-common/analyzer/ptr-subtraction-2.c
new file mode 100644
index 000000000000..a3c21ac54da1
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/analyzer/ptr-subtraction-2.c
@@ -0,0 +1,28 @@
+#include "analyzer-decls.h"
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __SIZE_TYPE__ size_t;
+
+ptrdiff_t
+ptrdiff_hidden_from_optimizer (const char *, const char *)
+  __attribute__((noinline));
+
+ptrdiff_t
+ptrdiff_hidden_from_optimizer (const char *p, const char *q)
+{
+  return p - q;
+}
+
+void
+test_concrete (void)
+{
+  const char *abc = "abc";
+  __analyzer_eval (ptrdiff_hidden_from_optimizer (abc + 3, abc) == 3); // { 
dg-warning "TRUE" }
+}
+
+void
+test_symbolic (size_t sz)
+{
+  const char *abc = "abc";
+  __analyzer_eval (ptrdiff_hidden_from_optimizer (abc + sz, abc) == sz); // { 
dg-warning "TRUE" }
+}

Reply via email to