xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/Transfer.cpp (revision 59c8e88e72633afbc47a4ace0d2170d00d51f7dc)
1 //===-- Transfer.cpp --------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  This file defines transfer functions that evaluate program statements and
10 //  update an environment accordingly.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/Analysis/FlowSensitive/Transfer.h"
15 #include "clang/AST/Decl.h"
16 #include "clang/AST/DeclBase.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/Expr.h"
19 #include "clang/AST/ExprCXX.h"
20 #include "clang/AST/OperationKinds.h"
21 #include "clang/AST/Stmt.h"
22 #include "clang/AST/StmtVisitor.h"
23 #include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
24 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
25 #include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
26 #include "clang/Analysis/FlowSensitive/RecordOps.h"
27 #include "clang/Analysis/FlowSensitive/Value.h"
28 #include "clang/Basic/Builtins.h"
29 #include "clang/Basic/OperatorKinds.h"
30 #include "llvm/ADT/STLExtras.h"
31 #include "llvm/Support/Casting.h"
32 #include "llvm/Support/ErrorHandling.h"
33 #include <cassert>
34 #include <memory>
35 #include <tuple>
36 
37 namespace clang {
38 namespace dataflow {
39 
40 const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const {
41   auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));
42   assert(BlockIt != CFCtx.getStmtToBlock().end());
43   if (!CFCtx.isBlockReachable(*BlockIt->getSecond()))
44     return nullptr;
45   const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()];
46   assert(State);
47   return &State->Env;
48 }
49 
50 static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
51                                           Environment &Env) {
52   Value *LHSValue = Env.getValueStrict(LHS);
53   Value *RHSValue = Env.getValueStrict(RHS);
54 
55   if (LHSValue == RHSValue)
56     return Env.getBoolLiteralValue(true);
57 
58   if (auto *LHSBool = dyn_cast_or_null<BoolValue>(LHSValue))
59     if (auto *RHSBool = dyn_cast_or_null<BoolValue>(RHSValue))
60       return Env.makeIff(*LHSBool, *RHSBool);
61 
62   return Env.makeAtomicBoolValue();
63 }
64 
65 static BoolValue &unpackValue(BoolValue &V, Environment &Env) {
66   if (auto *Top = llvm::dyn_cast<TopBoolValue>(&V)) {
67     auto &A = Env.getDataflowAnalysisContext().arena();
68     return A.makeBoolValue(A.makeAtomRef(Top->getAtom()));
69   }
70   return V;
71 }
72 
73 // Unpacks the value (if any) associated with `E` and updates `E` to the new
74 // value, if any unpacking occured. Also, does the lvalue-to-rvalue conversion,
75 // by skipping past the reference.
76 static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) {
77   auto *Loc = Env.getStorageLocationStrict(E);
78   if (Loc == nullptr)
79     return nullptr;
80   auto *Val = Env.getValue(*Loc);
81 
82   auto *B = dyn_cast_or_null<BoolValue>(Val);
83   if (B == nullptr)
84     return Val;
85 
86   auto &UnpackedVal = unpackValue(*B, Env);
87   if (&UnpackedVal == Val)
88     return Val;
89   Env.setValue(*Loc, UnpackedVal);
90   return &UnpackedVal;
91 }
92 
93 static void propagateValue(const Expr &From, const Expr &To, Environment &Env) {
94   if (auto *Val = Env.getValueStrict(From))
95     Env.setValueStrict(To, *Val);
96 }
97 
98 static void propagateStorageLocation(const Expr &From, const Expr &To,
99                                      Environment &Env) {
100   if (auto *Loc = Env.getStorageLocationStrict(From))
101     Env.setStorageLocationStrict(To, *Loc);
102 }
103 
104 // Propagates the value or storage location of `From` to `To` in cases where
105 // `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff
106 // `From` is a glvalue.
107 static void propagateValueOrStorageLocation(const Expr &From, const Expr &To,
108                                             Environment &Env) {
109   assert(From.isGLValue() == To.isGLValue());
110   if (From.isGLValue())
111     propagateStorageLocation(From, To, Env);
112   else
113     propagateValue(From, To, Env);
114 }
115 
116 namespace {
117 
118 class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
119 public:
120   TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
121       : StmtToEnv(StmtToEnv), Env(Env) {}
122 
123   void VisitBinaryOperator(const BinaryOperator *S) {
124     const Expr *LHS = S->getLHS();
125     assert(LHS != nullptr);
126 
127     const Expr *RHS = S->getRHS();
128     assert(RHS != nullptr);
129 
130     switch (S->getOpcode()) {
131     case BO_Assign: {
132       auto *LHSLoc = Env.getStorageLocationStrict(*LHS);
133       if (LHSLoc == nullptr)
134         break;
135 
136       auto *RHSVal = Env.getValueStrict(*RHS);
137       if (RHSVal == nullptr)
138         break;
139 
140       // Assign a value to the storage location of the left-hand side.
141       Env.setValue(*LHSLoc, *RHSVal);
142 
143       // Assign a storage location for the whole expression.
144       Env.setStorageLocation(*S, *LHSLoc);
145       break;
146     }
147     case BO_LAnd:
148     case BO_LOr: {
149       auto &Loc = Env.createStorageLocation(*S);
150       Env.setStorageLocation(*S, Loc);
151 
152       BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);
153       BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);
154 
155       if (S->getOpcode() == BO_LAnd)
156         Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal));
157       else
158         Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal));
159       break;
160     }
161     case BO_NE:
162     case BO_EQ: {
163       auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env);
164       auto &Loc = Env.createStorageLocation(*S);
165       Env.setStorageLocation(*S, Loc);
166       Env.setValue(Loc, S->getOpcode() == BO_EQ ? LHSEqRHSValue
167                                                 : Env.makeNot(LHSEqRHSValue));
168       break;
169     }
170     case BO_Comma: {
171       propagateValueOrStorageLocation(*RHS, *S, Env);
172       break;
173     }
174     default:
175       break;
176     }
177   }
178 
179   void VisitDeclRefExpr(const DeclRefExpr *S) {
180     const ValueDecl *VD = S->getDecl();
181     assert(VD != nullptr);
182 
183     // `DeclRefExpr`s to fields and non-static methods aren't glvalues, and
184     // there's also no sensible `Value` we can assign to them, so skip them.
185     if (isa<FieldDecl>(VD))
186       return;
187     if (auto *Method = dyn_cast<CXXMethodDecl>(VD);
188         Method && !Method->isStatic())
189       return;
190 
191     auto *DeclLoc = Env.getStorageLocation(*VD);
192     if (DeclLoc == nullptr)
193       return;
194 
195     Env.setStorageLocationStrict(*S, *DeclLoc);
196   }
197 
198   void VisitDeclStmt(const DeclStmt *S) {
199     // Group decls are converted into single decls in the CFG so the cast below
200     // is safe.
201     const auto &D = *cast<VarDecl>(S->getSingleDecl());
202 
203     ProcessVarDecl(D);
204   }
205 
206   void ProcessVarDecl(const VarDecl &D) {
207     // Static local vars are already initialized in `Environment`.
208     if (D.hasGlobalStorage())
209       return;
210 
211     // If this is the holding variable for a `BindingDecl`, we may already
212     // have a storage location set up -- so check. (See also explanation below
213     // where we process the `BindingDecl`.)
214     if (D.getType()->isReferenceType() && Env.getStorageLocation(D) != nullptr)
215       return;
216 
217     assert(Env.getStorageLocation(D) == nullptr);
218 
219     Env.setStorageLocation(D, Env.createObject(D));
220 
221     // `DecompositionDecl` must be handled after we've interpreted the loc
222     // itself, because the binding expression refers back to the
223     // `DecompositionDecl` (even though it has no written name).
224     if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) {
225       // If VarDecl is a DecompositionDecl, evaluate each of its bindings. This
226       // needs to be evaluated after initializing the values in the storage for
227       // VarDecl, as the bindings refer to them.
228       // FIXME: Add support for ArraySubscriptExpr.
229       // FIXME: Consider adding AST nodes used in BindingDecls to the CFG.
230       for (const auto *B : Decomp->bindings()) {
231         if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) {
232           auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase());
233           if (DE == nullptr)
234             continue;
235 
236           // ME and its base haven't been visited because they aren't included
237           // in the statements of the CFG basic block.
238           VisitDeclRefExpr(DE);
239           VisitMemberExpr(ME);
240 
241           if (auto *Loc = Env.getStorageLocation(*ME, SkipPast::Reference))
242             Env.setStorageLocation(*B, *Loc);
243         } else if (auto *VD = B->getHoldingVar()) {
244           // Holding vars are used to back the `BindingDecl`s of tuple-like
245           // types. The holding var declarations appear after the
246           // `DecompositionDecl`, so we have to explicitly process them here
247           // to know their storage location. They will be processed a second
248           // time when we visit their `VarDecl`s, so we have code that protects
249           // against this above.
250           ProcessVarDecl(*VD);
251           auto *VDLoc = Env.getStorageLocation(*VD);
252           assert(VDLoc != nullptr);
253           Env.setStorageLocation(*B, *VDLoc);
254         }
255       }
256     }
257   }
258 
259   void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
260     const Expr *SubExpr = S->getSubExpr();
261     assert(SubExpr != nullptr);
262 
263     switch (S->getCastKind()) {
264     case CK_IntegralToBoolean: {
265       // This cast creates a new, boolean value from the integral value. We
266       // model that with a fresh value in the environment, unless it's already a
267       // boolean.
268       if (auto *SubExprVal =
269               dyn_cast_or_null<BoolValue>(Env.getValueStrict(*SubExpr)))
270         Env.setValueStrict(*S, *SubExprVal);
271       else
272         // FIXME: If integer modeling is added, then update this code to create
273         // the boolean based on the integer model.
274         Env.setValueStrict(*S, Env.makeAtomicBoolValue());
275       break;
276     }
277 
278     case CK_LValueToRValue: {
279       // When an L-value is used as an R-value, it may result in sharing, so we
280       // need to unpack any nested `Top`s. We also need to strip off the
281       // `ReferenceValue` associated with the lvalue.
282       auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env);
283       if (SubExprVal == nullptr)
284         break;
285 
286       auto &ExprLoc = Env.createStorageLocation(*S);
287       Env.setStorageLocation(*S, ExprLoc);
288       Env.setValue(ExprLoc, *SubExprVal);
289       break;
290     }
291 
292     case CK_IntegralCast:
293       // FIXME: This cast creates a new integral value from the
294       // subexpression. But, because we don't model integers, we don't
295       // distinguish between this new value and the underlying one. If integer
296       // modeling is added, then update this code to create a fresh location and
297       // value.
298     case CK_UncheckedDerivedToBase:
299     case CK_ConstructorConversion:
300     case CK_UserDefinedConversion:
301       // FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
302       // CK_ConstructorConversion, and CK_UserDefinedConversion.
303     case CK_NoOp: {
304       // FIXME: Consider making `Environment::getStorageLocation` skip noop
305       // expressions (this and other similar expressions in the file) instead
306       // of assigning them storage locations.
307       propagateValueOrStorageLocation(*SubExpr, *S, Env);
308       break;
309     }
310     case CK_NullToPointer: {
311       auto &Loc = Env.createStorageLocation(S->getType());
312       Env.setStorageLocation(*S, Loc);
313 
314       auto &NullPointerVal =
315           Env.getOrCreateNullPointerValue(S->getType()->getPointeeType());
316       Env.setValue(Loc, NullPointerVal);
317       break;
318     }
319     case CK_NullToMemberPointer:
320       // FIXME: Implement pointers to members. For now, don't associate a value
321       // with this expression.
322       break;
323     case CK_FunctionToPointerDecay: {
324       StorageLocation *PointeeLoc =
325           Env.getStorageLocation(*SubExpr, SkipPast::Reference);
326       if (PointeeLoc == nullptr)
327         break;
328 
329       auto &PointerLoc = Env.createStorageLocation(*S);
330       auto &PointerVal = Env.create<PointerValue>(*PointeeLoc);
331       Env.setStorageLocation(*S, PointerLoc);
332       Env.setValue(PointerLoc, PointerVal);
333       break;
334     }
335     case CK_BuiltinFnToFnPtr:
336       // Despite its name, the result type of `BuiltinFnToFnPtr` is a function,
337       // not a function pointer. In addition, builtin functions can only be
338       // called directly; it is not legal to take their address. We therefore
339       // don't need to create a value or storage location for them.
340       break;
341     default:
342       break;
343     }
344   }
345 
346   void VisitUnaryOperator(const UnaryOperator *S) {
347     const Expr *SubExpr = S->getSubExpr();
348     assert(SubExpr != nullptr);
349 
350     switch (S->getOpcode()) {
351     case UO_Deref: {
352       const auto *SubExprVal =
353           cast_or_null<PointerValue>(Env.getValueStrict(*SubExpr));
354       if (SubExprVal == nullptr)
355         break;
356 
357       Env.setStorageLocationStrict(*S, SubExprVal->getPointeeLoc());
358       break;
359     }
360     case UO_AddrOf: {
361       // FIXME: Model pointers to members.
362       if (S->getType()->isMemberPointerType())
363         break;
364 
365       if (StorageLocation *PointeeLoc = Env.getStorageLocationStrict(*SubExpr))
366         Env.setValueStrict(*S, Env.create<PointerValue>(*PointeeLoc));
367       break;
368     }
369     case UO_LNot: {
370       auto *SubExprVal =
371           dyn_cast_or_null<BoolValue>(Env.getValueStrict(*SubExpr));
372       if (SubExprVal == nullptr)
373         break;
374 
375       auto &ExprLoc = Env.createStorageLocation(*S);
376       Env.setStorageLocation(*S, ExprLoc);
377       Env.setValue(ExprLoc, Env.makeNot(*SubExprVal));
378       break;
379     }
380     default:
381       break;
382     }
383   }
384 
385   void VisitCXXThisExpr(const CXXThisExpr *S) {
386     auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
387     if (ThisPointeeLoc == nullptr)
388       // Unions are not supported yet, and will not have a location for the
389       // `this` expression's pointee.
390       return;
391 
392     auto &Loc = Env.createStorageLocation(*S);
393     Env.setStorageLocation(*S, Loc);
394     Env.setValue(Loc, Env.create<PointerValue>(*ThisPointeeLoc));
395   }
396 
397   void VisitCXXNewExpr(const CXXNewExpr *S) {
398     auto &Loc = Env.createStorageLocation(*S);
399     Env.setStorageLocation(*S, Loc);
400     if (Value *Val = Env.createValue(S->getType()))
401       Env.setValue(Loc, *Val);
402   }
403 
404   void VisitCXXDeleteExpr(const CXXDeleteExpr *S) {
405     // Empty method.
406     // We consciously don't do anything on deletes.  Diagnosing double deletes
407     // (for example) should be done by a specific analysis, not by the
408     // framework.
409   }
410 
411   void VisitReturnStmt(const ReturnStmt *S) {
412     if (!Env.getDataflowAnalysisContext().getOptions().ContextSensitiveOpts)
413       return;
414 
415     auto *Ret = S->getRetValue();
416     if (Ret == nullptr)
417       return;
418 
419     if (Ret->isPRValue()) {
420       auto *Val = Env.getValueStrict(*Ret);
421       if (Val == nullptr)
422         return;
423 
424       // FIXME: Model NRVO.
425       Env.setReturnValue(Val);
426     } else {
427       auto *Loc = Env.getStorageLocationStrict(*Ret);
428       if (Loc == nullptr)
429         return;
430 
431       // FIXME: Model NRVO.
432       Env.setReturnStorageLocation(Loc);
433     }
434   }
435 
436   void VisitMemberExpr(const MemberExpr *S) {
437     ValueDecl *Member = S->getMemberDecl();
438     assert(Member != nullptr);
439 
440     // FIXME: Consider assigning pointer values to function member expressions.
441     if (Member->isFunctionOrFunctionTemplate())
442       return;
443 
444     // FIXME: if/when we add support for modeling enums, use that support here.
445     if (isa<EnumConstantDecl>(Member))
446       return;
447 
448     if (auto *D = dyn_cast<VarDecl>(Member)) {
449       if (D->hasGlobalStorage()) {
450         auto *VarDeclLoc = Env.getStorageLocation(*D);
451         if (VarDeclLoc == nullptr)
452           return;
453 
454         Env.setStorageLocation(*S, *VarDeclLoc);
455         return;
456       }
457     }
458 
459     AggregateStorageLocation *BaseLoc = getBaseObjectLocation(*S, Env);
460     if (BaseLoc == nullptr)
461       return;
462 
463     auto *MemberLoc = BaseLoc->getChild(*Member);
464     if (MemberLoc == nullptr)
465       return;
466     Env.setStorageLocationStrict(*S, *MemberLoc);
467   }
468 
469   void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
470     const Expr *InitExpr = S->getExpr();
471     assert(InitExpr != nullptr);
472     propagateValueOrStorageLocation(*InitExpr, *S, Env);
473   }
474 
475   void VisitCXXConstructExpr(const CXXConstructExpr *S) {
476     const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
477     assert(ConstructorDecl != nullptr);
478 
479     if (ConstructorDecl->isCopyOrMoveConstructor()) {
480       // It is permissible for a copy/move constructor to have additional
481       // parameters as long as they have default arguments defined for them.
482       assert(S->getNumArgs() != 0);
483 
484       const Expr *Arg = S->getArg(0);
485       assert(Arg != nullptr);
486 
487       auto *ArgLoc = cast_or_null<AggregateStorageLocation>(
488           Env.getStorageLocation(*Arg, SkipPast::Reference));
489       if (ArgLoc == nullptr)
490         return;
491 
492       if (S->isElidable()) {
493         Env.setStorageLocation(*S, *ArgLoc);
494       } else if (auto *ArgVal = cast_or_null<StructValue>(
495                      Env.getValue(*Arg, SkipPast::Reference))) {
496         auto &Val = *cast<StructValue>(Env.createValue(S->getType()));
497         Env.setValueStrict(*S, Val);
498         copyRecord(ArgVal->getAggregateLoc(), Val.getAggregateLoc(), Env);
499       }
500       return;
501     }
502 
503     auto &InitialVal = *cast<StructValue>(Env.createValue(S->getType()));
504     copyRecord(InitialVal.getAggregateLoc(), Env.getResultObjectLocation(*S),
505                Env);
506 
507     transferInlineCall(S, ConstructorDecl);
508   }
509 
510   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
511     if (S->getOperator() == OO_Equal) {
512       assert(S->getNumArgs() == 2);
513 
514       const Expr *Arg0 = S->getArg(0);
515       assert(Arg0 != nullptr);
516 
517       const Expr *Arg1 = S->getArg(1);
518       assert(Arg1 != nullptr);
519 
520       // Evaluate only copy and move assignment operators.
521       const auto *Method =
522           dyn_cast_or_null<CXXMethodDecl>(S->getDirectCallee());
523       if (!Method)
524         return;
525       if (!Method->isCopyAssignmentOperator() &&
526           !Method->isMoveAssignmentOperator())
527         return;
528 
529       auto *LocSrc = cast_or_null<AggregateStorageLocation>(
530           Env.getStorageLocationStrict(*Arg1));
531       auto *LocDst = cast_or_null<AggregateStorageLocation>(
532           Env.getStorageLocationStrict(*Arg0));
533 
534       if (LocSrc != nullptr && LocDst != nullptr) {
535         copyRecord(*LocSrc, *LocDst, Env);
536         Env.setStorageLocationStrict(*S, *LocDst);
537       }
538     }
539   }
540 
541   void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
542     if (S->getCastKind() == CK_ConstructorConversion) {
543       const Expr *SubExpr = S->getSubExpr();
544       assert(SubExpr != nullptr);
545 
546       propagateValue(*SubExpr, *S, Env);
547     }
548   }
549 
550   void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
551     if (Value *Val = Env.createValue(S->getType()))
552       Env.setValueStrict(*S, *Val);
553   }
554 
555   void VisitCallExpr(const CallExpr *S) {
556     // Of clang's builtins, only `__builtin_expect` is handled explicitly, since
557     // others (like trap, debugtrap, and unreachable) are handled by CFG
558     // construction.
559     if (S->isCallToStdMove()) {
560       assert(S->getNumArgs() == 1);
561 
562       const Expr *Arg = S->getArg(0);
563       assert(Arg != nullptr);
564 
565       auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None);
566       if (ArgLoc == nullptr)
567         return;
568 
569       Env.setStorageLocation(*S, *ArgLoc);
570     } else if (S->getDirectCallee() != nullptr &&
571                S->getDirectCallee()->getBuiltinID() ==
572                    Builtin::BI__builtin_expect) {
573       assert(S->getNumArgs() > 0);
574       assert(S->getArg(0) != nullptr);
575       // `__builtin_expect` returns by-value, so strip away any potential
576       // references in the argument.
577       auto *ArgLoc = Env.getStorageLocation(*S->getArg(0), SkipPast::Reference);
578       if (ArgLoc == nullptr)
579         return;
580       Env.setStorageLocation(*S, *ArgLoc);
581     } else if (const FunctionDecl *F = S->getDirectCallee()) {
582       transferInlineCall(S, F);
583     }
584   }
585 
586   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
587     const Expr *SubExpr = S->getSubExpr();
588     assert(SubExpr != nullptr);
589 
590     Value *SubExprVal = Env.getValueStrict(*SubExpr);
591     if (SubExprVal == nullptr)
592       return;
593 
594     if (StructValue *StructVal = dyn_cast<StructValue>(SubExprVal)) {
595       Env.setStorageLocation(*S, StructVal->getAggregateLoc());
596       return;
597     }
598 
599     StorageLocation &Loc = Env.createStorageLocation(*S);
600     Env.setValue(Loc, *SubExprVal);
601     Env.setStorageLocation(*S, Loc);
602   }
603 
604   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
605     const Expr *SubExpr = S->getSubExpr();
606     assert(SubExpr != nullptr);
607 
608     propagateValue(*SubExpr, *S, Env);
609   }
610 
611   void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
612     if (S->getCastKind() == CK_NoOp) {
613       const Expr *SubExpr = S->getSubExpr();
614       assert(SubExpr != nullptr);
615 
616       propagateValueOrStorageLocation(*SubExpr, *S, Env);
617     }
618   }
619 
620   void VisitConditionalOperator(const ConditionalOperator *S) {
621     // FIXME: Revisit this once flow conditions are added to the framework. For
622     // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
623     // condition.
624     if (S->isGLValue())
625       Env.setStorageLocationStrict(*S, Env.createObject(S->getType()));
626     else if (Value *Val = Env.createValue(S->getType()))
627       Env.setValueStrict(*S, *Val);
628   }
629 
630   void VisitInitListExpr(const InitListExpr *S) {
631     QualType Type = S->getType();
632 
633     if (!Type->isStructureOrClassType()) {
634       if (auto *Val = Env.createValue(Type))
635         Env.setValueStrict(*S, *Val);
636 
637       return;
638     }
639 
640     std::vector<FieldDecl *> Fields =
641         getFieldsForInitListExpr(Type->getAsRecordDecl());
642     llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
643 
644     for (auto [Field, Init] : llvm::zip(Fields, S->inits())) {
645       assert(Field != nullptr);
646       assert(Init != nullptr);
647 
648       FieldLocs.insert({Field, &Env.createObject(Field->getType(), Init)});
649     }
650 
651     auto &Loc =
652         Env.getDataflowAnalysisContext()
653             .arena()
654             .create<AggregateStorageLocation>(Type, std::move(FieldLocs));
655     StructValue &StructVal = Env.create<StructValue>(Loc);
656 
657     Env.setValue(Loc, StructVal);
658 
659     Env.setValueStrict(*S, StructVal);
660 
661     // FIXME: Implement array initialization.
662   }
663 
664   void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
665     Env.setValueStrict(*S, Env.getBoolLiteralValue(S->getValue()));
666   }
667 
668   void VisitIntegerLiteral(const IntegerLiteral *S) {
669     Env.setValueStrict(*S, Env.getIntLiteralValue(S->getValue()));
670   }
671 
672   void VisitParenExpr(const ParenExpr *S) {
673     // The CFG does not contain `ParenExpr` as top-level statements in basic
674     // blocks, however manual traversal to sub-expressions may encounter them.
675     // Redirect to the sub-expression.
676     auto *SubExpr = S->getSubExpr();
677     assert(SubExpr != nullptr);
678     Visit(SubExpr);
679   }
680 
681   void VisitExprWithCleanups(const ExprWithCleanups *S) {
682     // The CFG does not contain `ExprWithCleanups` as top-level statements in
683     // basic blocks, however manual traversal to sub-expressions may encounter
684     // them. Redirect to the sub-expression.
685     auto *SubExpr = S->getSubExpr();
686     assert(SubExpr != nullptr);
687     Visit(SubExpr);
688   }
689 
690 private:
691   /// Returns the value for the sub-expression `SubExpr` of a logic operator.
692   BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) {
693     // `SubExpr` and its parent logic operator might be part of different basic
694     // blocks. We try to access the value that is assigned to `SubExpr` in the
695     // corresponding environment.
696     if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr))
697       if (auto *Val =
698               dyn_cast_or_null<BoolValue>(SubExprEnv->getValueStrict(SubExpr)))
699         return *Val;
700 
701     // The sub-expression may lie within a basic block that isn't reachable,
702     // even if we need it to evaluate the current (reachable) expression
703     // (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr`
704     // within the current environment and then try to get the value that gets
705     // assigned to it.
706     if (Env.getValueStrict(SubExpr) == nullptr)
707       Visit(&SubExpr);
708     if (auto *Val = dyn_cast_or_null<BoolValue>(Env.getValueStrict(SubExpr)))
709       return *Val;
710 
711     // If the value of `SubExpr` is still unknown, we create a fresh symbolic
712     // boolean value for it.
713     return Env.makeAtomicBoolValue();
714   }
715 
716   // If context sensitivity is enabled, try to analyze the body of the callee
717   // `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`.
718   template <typename E>
719   void transferInlineCall(const E *S, const FunctionDecl *F) {
720     const auto &Options = Env.getDataflowAnalysisContext().getOptions();
721     if (!(Options.ContextSensitiveOpts &&
722           Env.canDescend(Options.ContextSensitiveOpts->Depth, F)))
723       return;
724 
725     const ControlFlowContext *CFCtx =
726         Env.getDataflowAnalysisContext().getControlFlowContext(F);
727     if (!CFCtx)
728       return;
729 
730     // FIXME: We don't support context-sensitive analysis of recursion, so
731     // we should return early here if `F` is the same as the `FunctionDecl`
732     // holding `S` itself.
733 
734     auto ExitBlock = CFCtx->getCFG().getExit().getBlockID();
735 
736     auto CalleeEnv = Env.pushCall(S);
737 
738     // FIXME: Use the same analysis as the caller for the callee. Note,
739     // though, that doing so would require support for changing the analysis's
740     // ASTContext.
741     assert(CFCtx->getDecl() != nullptr &&
742            "ControlFlowContexts in the environment should always carry a decl");
743     auto Analysis = NoopAnalysis(CFCtx->getDecl()->getASTContext(),
744                                  DataflowAnalysisOptions{Options});
745 
746     auto BlockToOutputState =
747         dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv);
748     assert(BlockToOutputState);
749     assert(ExitBlock < BlockToOutputState->size());
750 
751     auto &ExitState = (*BlockToOutputState)[ExitBlock];
752     assert(ExitState);
753 
754     Env.popCall(S, ExitState->Env);
755   }
756 
757   const StmtToEnvMap &StmtToEnv;
758   Environment &Env;
759 };
760 
761 } // namespace
762 
763 void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
764   TransferVisitor(StmtToEnv, Env).Visit(&S);
765 }
766 
767 } // namespace dataflow
768 } // namespace clang
769