================
@@ -697,13 +743,203 @@ CapturedZoneInfo captureZoneInfo(const ExtractionZone 
&ExtZone) {
       if (!DeclInfo)
         DeclInfo = Info.createDeclInfo(D, ZoneRelative::OutsideFunc);
       DeclInfo->markOccurence(CurrentLocation);
-      // FIXME: check if reference mutates the Decl being referred.
+      return true;
+    }
+
+    // Conservatively marks D as possibly mutated: used both for actual
+    // direct mutations (assignment, increment/decrement, ...) and for
+    // constructs that alias D in a way we don't want to trace further (a
+    // reference bound to D, D's address taken, D captured by reference in a
+    // lambda, ...). We never try to determine whether such an alias is
+    // itself later mutated -- that would require searching beyond this one
+    // occurrence, which is exactly the cost this design avoids (and what
+    // makes ExprMutationAnalyzer prohibitively slow). The price is
+    // that we sometimes keep a parameter non-const where a full alias
+    // analysis could prove it safe to const; we never get this wrong in the
+    // other, unsafe direction.
+    void markPossiblyMutated(const Decl *D) {
+      if (!D || CurrentLocation != ZoneRelative::Inside)
+        return;
+      if (auto *DeclInfo = Info.getDeclInfoFor(D))
+        DeclInfo->IsPossiblyMutated = true;
+    }
+    void markPossiblyMutated(const Expr *E) {
+      if (!E)
+        return;
+      // A reference bound to (or a mutation reaching through) a conditional
+      // expression could end up aliasing either branch at runtime, so both
+      // have to be marked -- underlyingDecl() only follows a single lvalue
+      // path and can't express that.
+      if (const auto *CO =
+              dyn_cast<AbstractConditionalOperator>(E->IgnoreParenCasts())) {
+        markPossiblyMutated(CO->getTrueExpr());
+        markPossiblyMutated(CO->getFalseExpr());
+        return;
+      }
+      markPossiblyMutated(underlyingDecl(E));
+    }
+
+    bool VisitBinaryOperator(BinaryOperator *BO) {
+      if (BO->isAssignmentOp())
+        markPossiblyMutated(BO->getLHS());
+      return true;
+    }
+
+    bool VisitUnaryOperator(UnaryOperator *UO) {
+      if (UO->isIncrementDecrementOp() || UO->getOpcode() == UO_AddrOf)
+        markPossiblyMutated(UO->getSubExpr());
----------------
ArcsinX wrote:

Just to clarify, is it intended that we always mark `A` as mutated in case of 
`&A`? Even for code like this: `const int *P = &A;`

https://github.com/llvm/llvm-project/pull/225666
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to