================
@@ -3016,43 +3018,62 @@ void ExprEngine::processSwitch(const SwitchStmt 
*Switch, ExplodedNode *Pred,
 // Transfer functions: Loads and stores.
 
//===----------------------------------------------------------------------===//
 
-void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
-                                        ExplodedNode *Pred,
-                                        ExplodedNodeSet &Dst) {
+std::optional<std::pair<SVal, QualType>>
+ExprEngine::resolveAsLambdaCapturedVar(const Expr *Ex, const ValueDecl *VD,
+                                       ExplodedNode *Pred) {
   ProgramStateRef state = Pred->getState();
   const StackFrame *SF = Pred->getStackFrame();
 
-  auto resolveAsLambdaCapturedVar =
-      [&](const ValueDecl *VD) -> std::optional<std::pair<SVal, QualType>> {
-    const auto *MD = dyn_cast<CXXMethodDecl>(SF->getDecl());
-    const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Ex);
-    if (AMgr.options.ShouldInlineLambdas && DeclRefEx &&
-        DeclRefEx->refersToEnclosingVariableOrCapture() && MD &&
-        MD->getParent()->isLambda()) {
-      // Lookup the field of the lambda.
-      const CXXRecordDecl *CXXRec = MD->getParent();
-      llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
-      FieldDecl *LambdaThisCaptureField;
-      CXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField);
-
-      // Sema follows a sequence of complex rules to determine whether the
-      // variable should be captured.
-      if (const FieldDecl *FD = LambdaCaptureFields[VD]) {
+  const auto *MD = dyn_cast<CXXMethodDecl>(SF->getDecl());
+  const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Ex);
+  if (AMgr.options.ShouldInlineLambdas && DeclRefEx &&
+      DeclRefEx->refersToEnclosingVariableOrCapture() && MD &&
+      MD->getParent()->isLambda()) {
+    // Lookup the field of the lambda.
+    const CXXRecordDecl *CXXRec = MD->getParent();
+    llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
+    FieldDecl *LambdaThisCaptureField;
+    CXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField);
+
+    // Sema follows a sequence of complex rules to determine whether the
+    // variable should be captured.
+    if (const FieldDecl *FD = LambdaCaptureFields[VD]) {
+      if (MD->isImplicitObjectMemberFunction()) {
         Loc CXXThis = svalBuilder.getCXXThis(MD, SF);
         SVal CXXThisVal = state->getSVal(CXXThis);
-        return std::make_pair(state->getLValue(FD, CXXThisVal), FD->getType());
+        return {{state->getLValue(FD, CXXThisVal), FD->getType()}};
+      }
+      const ParmVarDecl *PVD = MD->getParamDecl(0);
+      if (const Expr *CallSite = SF->getCallSite()) {
+        const ParamVarRegion *PVR =
+            MRMgr.getParamVarRegion(CallSite, /*Index=*/0, SF);
+        const Expr *SelfArgExpr = cast<CallExpr>(CallSite)->getArg(0);
+        if (PVD->getType()->isReferenceType()) {
+          state =
+              state->bindLoc(loc::MemRegionVal(PVR),
+                             state->getSVal(SelfArgExpr, SF->getParent()), SF);
+          SVal ParamSVal = state->getSVal(loc::MemRegionVal(PVR));
----------------
NagyDonat wrote:

This code seems to be incorrect, because you compute a new, updated `state`, 
which is then discarded after one `getSVal` and one `getLValue` call.

This naturally raises the question that which `ProgramState` is the accurate 
representation of the state (in particular memory contents) that could be 
observed if the analyzed code was executed?
- If the accurate representation is the new, updated state (where the value 
`state->getSVal(SelfArgExpr, SF->getParent())` is stored at the location 
`loc::MemRegionVal(PVR)`), then why are you discarding it? Wouldn't it be more 
accurate to use a state that contains this binding during the rest of the 
analysis as well?
  - Also, in this case, is this the most natural place to add this binding to 
the state? Was this value written to that memory location just now? Or was it 
already written there by some earlier step (which is then not modeled properly)?
- If the accurate representation is the original `state`, then why do you 
define `ParamSVal` in this roundabout way instead of writing `SVal ParamSVal = 
state->getSVal(SelfArgExpr, SF->getParent());`?
  - Is it significant that the new, updated state participates in the 
`getLValue()` call? (I'd guess yes, but I'm not sure.)
  - Could you avoid creating the updated state (which – in this case – does not 
represent real behavior of the program) by calling `desugarReferece` etc. 
directly?



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

Reply via email to