]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
analyzer: add pointer diff folding
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 20 May 2026 12:52:48 +0000 (08:52 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Wed, 20 May 2026 12:52:48 +0000 (08:52 -0400)
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 <dmalcolm@redhat.com>
gcc/analyzer/region-model-manager.cc
gcc/testsuite/c-c++-common/analyzer/ptr-subtraction-2.c [new file with mode: 0644]

index ba7f9db507b6c5c76755ba16a3c607fb9a326bfd..4b1aacccb63202450ed3223602ff73132ca7aa3d 100644 (file)
@@ -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 (file)
index 0000000..a3c21ac
--- /dev/null
@@ -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" }
+}