[clang] [analyzer] Avoid out-of-order node traversal on void return (PR #117863)

Arseniy Zaostrovnykh via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 27 04:17:33 PST 2024


================
@@ -278,7 +278,9 @@ class ExplodedNode : public llvm::FoldingSetNode {
   /// Useful for explaining control flow that follows the current node.
   /// If the statement belongs to a body-farmed definition, retrieve the
   /// call site for that definition.
-  const Stmt *getNextStmtForDiagnostics() const;
+  /// If skipPurge is true, skip the purge-dead-symbols nodes (that are often
+  /// inserted out-of-order by the endinge).
+  const Stmt *getNextStmtForDiagnostics(bool skipPurge) const;
----------------
necto wrote:

I cannot speak generally, but it breaks on more test case: clang/test/Analysis/copy-elision.cpp.
In short for the following code, it moves the report further down the execution:
```C++
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -std=c++11 \
// RUN:    -analyzer-config elide-constructors=false -DNO_ELIDE_FLAG              \
// RUN:    -analyzer-config eagerly-assume=false -verify=expected,no-elide %s

void clang_analyzer_eval(bool);
void clang_analyzer_dump(int);

template <typename T> struct AddressVector {
  T *buf[20];
  int len;

  AddressVector() : len(0) {}

  void push(T *t) {
    buf[len] = t;
    ++len;
  }
};

class ClassWithDestructor {
  AddressVector<ClassWithDestructor> &v;

public:
  ClassWithDestructor(AddressVector<ClassWithDestructor> &v) : v(v) {
    push();
  }

  ClassWithDestructor(ClassWithDestructor &&c) : v(c.v) { push(); }
  ClassWithDestructor(const ClassWithDestructor &c) : v(c.v) { push(); }

  ~ClassWithDestructor() { push(); }

  void push() { v.push(this); }
};

struct TestCtorInitializer {
  ClassWithDestructor c;
  TestCtorInitializer(AddressVector<ClassWithDestructor> &v)
    : c(ClassWithDestructor(v)) {} // currently: <- address of stack var leaks via 'v'
};

void testCtorInitializer() {
  AddressVector<ClassWithDestructor> v;
  {
    TestCtorInitializer t(v); // skipping-purge: <- address of stack var leaks via 'v'
  }
}
```
I.e., it ends up skipping one more stack frame.
I don't think it is a large difference, although I slightly prefer the current report to the one resulting if we skip purge always. Moreover, I wanted to reduce the test footprint, so I minimized the behavior change.
Do you think it is better simplify the logic and skip purge always?

https://github.com/llvm/llvm-project/pull/117863


More information about the cfe-commits mailing list