[clang] [Clang][Sema] Diagnose invalid 'pure'/'const' attributes on writes (PR #217817)

via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 21 06:38:51 PDT 2026


================
@@ -284,6 +284,76 @@ static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg) {
   return foundRecursion;
 }
 
+namespace {
+/// Walks a 'pure'/'const' function body looking for stores through pointer
+/// or reference parameters, and stores to global or static-local variables.
+/// This is a syntactic heuristic, not a proof: it only catches direct writes
+/// reachable via straightforward lvalue expressions in the function's own
+/// body. It intentionally does not attempt interprocedural analysis (that's
+/// undecidable in general), locally-allocated memory escaping, or writes
+/// mediated through a level of indirection the visitor doesn't unwrap.
+class PureConstWriteChecker : public DynamicRecursiveASTVisitor {
+public:
+  PureConstWriteChecker(Sema &sema, const FunctionDecl *functionDecl,
+                        bool isConstAttr)
+      : S(sema), FD(functionDecl), IsConstAttr(isConstAttr) {}
+
+  bool VisitBinaryOperator(BinaryOperator *BO) override {
+    if (BO->isAssignmentOp() || BO->isCompoundAssignmentOp())
+      checkLvalue(BO->getLHS());
+
+    return true;
+  }
+
+private:
+  Sema &S;
+  const FunctionDecl *FD;
+  bool IsConstAttr;
+
+  void checkLvalue(const Expr *E) {
+    E = E->IgnoreParenImpCasts();
+    if (const auto *UO = dyn_cast<UnaryOperator>(E)) {
+      if (UO->getOpcode() == UO_Deref) {
+        checkPointerBase(UO->getSubExpr());
+        return;
+      }
+    }
+    if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
----------------
AhmedKamel10 wrote:

I've refactored both DRE and VD checks to use early returns.

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


More information about the cfe-commits mailing list