@@ -267,9 +267,10 @@ Environment::Environment(DataflowAnalysisContext &DACtx)
267
267
268
268
Environment::Environment (const Environment &Other)
269
269
: DACtx(Other.DACtx), CallStack(Other.CallStack),
270
- ReturnLoc(Other.ReturnLoc), ThisPointeeLoc(Other.ThisPointeeLoc),
271
- DeclToLoc(Other.DeclToLoc), ExprToLoc(Other.ExprToLoc),
272
- LocToVal(Other.LocToVal), MemberLocToStruct(Other.MemberLocToStruct),
270
+ ReturnVal(Other.ReturnVal), ReturnLoc(Other.ReturnLoc),
271
+ ThisPointeeLoc(Other.ThisPointeeLoc), DeclToLoc(Other.DeclToLoc),
272
+ ExprToLoc(Other.ExprToLoc), LocToVal(Other.LocToVal),
273
+ MemberLocToStruct(Other.MemberLocToStruct),
273
274
FlowConditionToken(&DACtx->forkFlowCondition (*Other.FlowConditionToken)) {
274
275
}
275
276
@@ -302,9 +303,6 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
302
303
createValue (ParamDecl->getType ().getNonReferenceType ()))
303
304
setValue (ParamLoc, *ParamVal);
304
305
}
305
-
306
- QualType ReturnType = FuncDecl->getReturnType ();
307
- ReturnLoc = &createStorageLocation (ReturnType);
308
306
}
309
307
310
308
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
@@ -331,9 +329,6 @@ bool Environment::canDescend(unsigned MaxDepth,
331
329
Environment Environment::pushCall (const CallExpr *Call) const {
332
330
Environment Env (*this );
333
331
334
- // FIXME: Support references here.
335
- Env.ReturnLoc = getStorageLocation (*Call, SkipPast::Reference);
336
-
337
332
if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {
338
333
if (const Expr *Arg = MethodCall->getImplicitObjectArgument ()) {
339
334
if (!isa<CXXThisExpr>(Arg))
@@ -352,10 +347,9 @@ Environment Environment::pushCall(const CallExpr *Call) const {
352
347
Environment Environment::pushCall (const CXXConstructExpr *Call) const {
353
348
Environment Env (*this );
354
349
355
- // FIXME: Support references here.
356
- Env.ReturnLoc = getStorageLocation (*Call, SkipPast::Reference);
357
-
358
- Env.ThisPointeeLoc = Env.ReturnLoc ;
350
+ Env.ThisPointeeLoc = &Env.createStorageLocation (Call->getType ());
351
+ if (Value *Val = Env.createValue (Call->getType ()))
352
+ Env.setValue (*Env.ThisPointeeLoc , *Val);
359
353
360
354
Env.pushCallInternal (Call->getConstructor (),
361
355
llvm::ArrayRef (Call->getArgs (), Call->getNumArgs ()));
@@ -365,6 +359,12 @@ Environment Environment::pushCall(const CXXConstructExpr *Call) const {
365
359
366
360
void Environment::pushCallInternal (const FunctionDecl *FuncDecl,
367
361
ArrayRef<const Expr *> Args) {
362
+ // Canonicalize to the definition of the function. This ensures that we're
363
+ // putting arguments into the same `ParamVarDecl`s` that the callee will later
364
+ // be retrieving them from.
365
+ assert (FuncDecl->getDefinition () != nullptr );
366
+ FuncDecl = FuncDecl->getDefinition ();
367
+
368
368
CallStack.push_back (FuncDecl);
369
369
370
370
initFieldsGlobalsAndFuncs (FuncDecl);
@@ -399,23 +399,46 @@ void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
399
399
}
400
400
}
401
401
402
- void Environment::popCall (const Environment &CalleeEnv) {
402
+ void Environment::popCall (const CallExpr *Call, const Environment &CalleeEnv) {
403
403
// We ignore `DACtx` because it's already the same in both. We don't want the
404
- // callee's `DeclCtx`, `ReturnLoc` or `ThisPointeeLoc`. We don't bring back
405
- // `DeclToLoc` and `ExprToLoc` because we want to be able to later analyze the
406
- // same callee in a different context, and `setStorageLocation` requires there
407
- // to not already be a storage location assigned. Conceptually, these maps
408
- // capture information from the local scope, so when popping that scope, we do
409
- // not propagate the maps.
404
+ // callee's `DeclCtx`, `ReturnVal`, ` ReturnLoc` or `ThisPointeeLoc`. We don't
405
+ // bring back `DeclToLoc` and `ExprToLoc` because we want to be able to later
406
+ // analyze the same callee in a different context, and `setStorageLocation`
407
+ // requires there to not already be a storage location assigned. Conceptually,
408
+ // these maps capture information from the local scope, so when popping that
409
+ // scope, we do not propagate the maps.
410
410
this ->LocToVal = std::move (CalleeEnv.LocToVal );
411
411
this ->MemberLocToStruct = std::move (CalleeEnv.MemberLocToStruct );
412
412
this ->FlowConditionToken = std::move (CalleeEnv.FlowConditionToken );
413
+
414
+ if (Call->isGLValue ()) {
415
+ if (CalleeEnv.ReturnLoc != nullptr )
416
+ setStorageLocationStrict (*Call, *CalleeEnv.ReturnLoc );
417
+ } else if (!Call->getType ()->isVoidType ()) {
418
+ if (CalleeEnv.ReturnVal != nullptr )
419
+ setValueStrict (*Call, *CalleeEnv.ReturnVal );
420
+ }
421
+ }
422
+
423
+ void Environment::popCall (const CXXConstructExpr *Call,
424
+ const Environment &CalleeEnv) {
425
+ // See also comment in `popCall(const CallExpr *, const Environment &)` above.
426
+ this ->LocToVal = std::move (CalleeEnv.LocToVal );
427
+ this ->MemberLocToStruct = std::move (CalleeEnv.MemberLocToStruct );
428
+ this ->FlowConditionToken = std::move (CalleeEnv.FlowConditionToken );
429
+
430
+ if (Value *Val = CalleeEnv.getValue (*CalleeEnv.ThisPointeeLoc )) {
431
+ setValueStrict (*Call, *Val);
432
+ }
413
433
}
414
434
415
435
bool Environment::equivalentTo (const Environment &Other,
416
436
Environment::ValueModel &Model) const {
417
437
assert (DACtx == Other.DACtx );
418
438
439
+ if (ReturnVal != Other.ReturnVal )
440
+ return false ;
441
+
419
442
if (ReturnLoc != Other.ReturnLoc )
420
443
return false ;
421
444
@@ -453,6 +476,7 @@ bool Environment::equivalentTo(const Environment &Other,
453
476
LatticeJoinEffect Environment::widen (const Environment &PrevEnv,
454
477
Environment::ValueModel &Model) {
455
478
assert (DACtx == PrevEnv.DACtx );
479
+ assert (ReturnVal == PrevEnv.ReturnVal );
456
480
assert (ReturnLoc == PrevEnv.ReturnLoc );
457
481
assert (ThisPointeeLoc == PrevEnv.ThisPointeeLoc );
458
482
assert (CallStack == PrevEnv.CallStack );
@@ -514,7 +538,6 @@ LatticeJoinEffect Environment::widen(const Environment &PrevEnv,
514
538
LatticeJoinEffect Environment::join (const Environment &Other,
515
539
Environment::ValueModel &Model) {
516
540
assert (DACtx == Other.DACtx );
517
- assert (ReturnLoc == Other.ReturnLoc );
518
541
assert (ThisPointeeLoc == Other.ThisPointeeLoc );
519
542
assert (CallStack == Other.CallStack );
520
543
@@ -523,9 +546,38 @@ LatticeJoinEffect Environment::join(const Environment &Other,
523
546
Environment JoinedEnv (*DACtx);
524
547
525
548
JoinedEnv.CallStack = CallStack;
526
- JoinedEnv.ReturnLoc = ReturnLoc;
527
549
JoinedEnv.ThisPointeeLoc = ThisPointeeLoc;
528
550
551
+ if (ReturnVal == nullptr || Other.ReturnVal == nullptr ) {
552
+ // `ReturnVal` might not always get set -- for example if we have a return
553
+ // statement of the form `return some_other_func()` and we decide not to
554
+ // analyze `some_other_func()`.
555
+ // In this case, we can't say anything about the joined return value -- we
556
+ // don't simply want to propagate the return value that we do have, because
557
+ // it might not be the correct one.
558
+ // This occurs for example in the test `ContextSensitiveMutualRecursion`.
559
+ JoinedEnv.ReturnVal = nullptr ;
560
+ } else if (areEquivalentValues (*ReturnVal, *Other.ReturnVal )) {
561
+ JoinedEnv.ReturnVal = ReturnVal;
562
+ } else {
563
+ assert (!CallStack.empty ());
564
+ // FIXME: Make `CallStack` a vector of `FunctionDecl` so we don't need this
565
+ // cast.
566
+ auto *Func = dyn_cast<FunctionDecl>(CallStack.back ());
567
+ assert (Func != nullptr );
568
+ if (Value *MergedVal =
569
+ mergeDistinctValues (Func->getReturnType (), *ReturnVal, *this ,
570
+ *Other.ReturnVal , Other, JoinedEnv, Model)) {
571
+ JoinedEnv.ReturnVal = MergedVal;
572
+ Effect = LatticeJoinEffect::Changed;
573
+ }
574
+ }
575
+
576
+ if (ReturnLoc == Other.ReturnLoc )
577
+ JoinedEnv.ReturnLoc = ReturnLoc;
578
+ else
579
+ JoinedEnv.ReturnLoc = nullptr ;
580
+
529
581
// FIXME: Once we're able to remove declarations from `DeclToLoc` when their
530
582
// lifetime ends, add an assertion that there aren't any entries in
531
583
// `DeclToLoc` and `Other.DeclToLoc` that map the same declaration to
@@ -659,10 +711,6 @@ StorageLocation *Environment::getThisPointeeStorageLocation() const {
659
711
return ThisPointeeLoc;
660
712
}
661
713
662
- StorageLocation *Environment::getReturnStorageLocation () const {
663
- return ReturnLoc;
664
- }
665
-
666
714
PointerValue &Environment::getOrCreateNullPointerValue (QualType PointeeType) {
667
715
return DACtx->getOrCreateNullPointerValue (PointeeType);
668
716
}
0 commit comments