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" } +}
