clang 20.0.0git
Transfer.cpp
Go to the documentation of this file.
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
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"
21#include "clang/AST/Stmt.h"
32#include "llvm/Support/Casting.h"
33#include "llvm/Support/Debug.h"
34#include <assert.h>
35#include <cassert>
36
37#define DEBUG_TYPE "dataflow"
38
39namespace clang {
40namespace dataflow {
41
43 const CFGBlock *Block = ACFG.blockForStmt(S);
44 if (Block == nullptr) {
45 assert(false);
46 return nullptr;
47 }
48 if (!ACFG.isBlockReachable(*Block))
49 return nullptr;
50 if (Block->getBlockID() == CurBlockID)
51 return &CurState.Env;
52 const auto &State = BlockToState[Block->getBlockID()];
53 if (!(State))
54 return nullptr;
55 return &State->Env;
56}
57
58static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
60 Value *LHSValue = Env.getValue(LHS);
61 Value *RHSValue = Env.getValue(RHS);
62
63 if (LHSValue == RHSValue)
64 return Env.getBoolLiteralValue(true);
65
66 if (auto *LHSBool = dyn_cast_or_null<BoolValue>(LHSValue))
67 if (auto *RHSBool = dyn_cast_or_null<BoolValue>(RHSValue))
68 return Env.makeIff(*LHSBool, *RHSBool);
69
70 if (auto *LHSPtr = dyn_cast_or_null<PointerValue>(LHSValue))
71 if (auto *RHSPtr = dyn_cast_or_null<PointerValue>(RHSValue))
72 // If the storage locations are the same, the pointers definitely compare
73 // the same. If the storage locations are different, they may still alias,
74 // so we fall through to the case below that returns an atom.
75 if (&LHSPtr->getPointeeLoc() == &RHSPtr->getPointeeLoc())
76 return Env.getBoolLiteralValue(true);
77
78 return Env.makeAtomicBoolValue();
79}
80
82 if (auto *Top = llvm::dyn_cast<TopBoolValue>(&V)) {
84 return A.makeBoolValue(A.makeAtomRef(Top->getAtom()));
85 }
86 return V;
87}
88
89// Unpacks the value (if any) associated with `E` and updates `E` to the new
90// value, if any unpacking occured. Also, does the lvalue-to-rvalue conversion,
91// by skipping past the reference.
93 auto *Loc = Env.getStorageLocation(E);
94 if (Loc == nullptr)
95 return nullptr;
96 auto *Val = Env.getValue(*Loc);
97
98 auto *B = dyn_cast_or_null<BoolValue>(Val);
99 if (B == nullptr)
100 return Val;
101
102 auto &UnpackedVal = unpackValue(*B, Env);
103 if (&UnpackedVal == Val)
104 return Val;
105 Env.setValue(*Loc, UnpackedVal);
106 return &UnpackedVal;
107}
108
109static void propagateValue(const Expr &From, const Expr &To, Environment &Env) {
110 if (From.getType()->isRecordType())
111 return;
112 if (auto *Val = Env.getValue(From))
113 Env.setValue(To, *Val);
114}
115
116static void propagateStorageLocation(const Expr &From, const Expr &To,
117 Environment &Env) {
118 if (auto *Loc = Env.getStorageLocation(From))
120}
121
122// Propagates the value or storage location of `From` to `To` in cases where
123// `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff
124// `From` is a glvalue.
125static void propagateValueOrStorageLocation(const Expr &From, const Expr &To,
126 Environment &Env) {
127 assert(From.isGLValue() == To.isGLValue());
128 if (From.isGLValue())
129 propagateStorageLocation(From, To, Env);
130 else
131 propagateValue(From, To, Env);
132}
133
134namespace {
135
136class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
137public:
138 TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
139 Environment::ValueModel &Model)
140 : StmtToEnv(StmtToEnv), Env(Env), Model(Model) {}
141
142 void VisitBinaryOperator(const BinaryOperator *S) {
143 const Expr *LHS = S->getLHS();
144 assert(LHS != nullptr);
145
146 const Expr *RHS = S->getRHS();
147 assert(RHS != nullptr);
148
149 // Do compound assignments up-front, as there are so many of them and we
150 // don't want to list all of them in the switch statement below.
151 // To avoid generating unnecessary values, we don't create a new value but
152 // instead leave it to the specific analysis to do this if desired.
153 if (S->isCompoundAssignmentOp())
154 propagateStorageLocation(*S->getLHS(), *S, Env);
155
156 switch (S->getOpcode()) {
157 case BO_Assign: {
158 auto *LHSLoc = Env.getStorageLocation(*LHS);
159 if (LHSLoc == nullptr)
160 break;
161
162 auto *RHSVal = Env.getValue(*RHS);
163 if (RHSVal == nullptr)
164 break;
165
166 // Assign a value to the storage location of the left-hand side.
167 Env.setValue(*LHSLoc, *RHSVal);
168
169 // Assign a storage location for the whole expression.
170 Env.setStorageLocation(*S, *LHSLoc);
171 break;
172 }
173 case BO_LAnd:
174 case BO_LOr: {
175 BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);
176 BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);
177
178 if (S->getOpcode() == BO_LAnd)
179 Env.setValue(*S, Env.makeAnd(LHSVal, RHSVal));
180 else
181 Env.setValue(*S, Env.makeOr(LHSVal, RHSVal));
182 break;
183 }
184 case BO_NE:
185 case BO_EQ: {
186 auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env);
187 Env.setValue(*S, S->getOpcode() == BO_EQ ? LHSEqRHSValue
188 : Env.makeNot(LHSEqRHSValue));
189 break;
190 }
191 case BO_Comma: {
192 propagateValueOrStorageLocation(*RHS, *S, Env);
193 break;
194 }
195 default:
196 break;
197 }
198 }
199
200 void VisitDeclRefExpr(const DeclRefExpr *S) {
201 const ValueDecl *VD = S->getDecl();
202 assert(VD != nullptr);
203
204 // Some `DeclRefExpr`s aren't glvalues, so we can't associate them with a
205 // `StorageLocation`, and there's also no sensible `Value` that we can
206 // assign to them. Examples:
207 // - Non-static member variables
208 // - Non static member functions
209 // Note: Member operators are an exception to this, but apparently only
210 // if the `DeclRefExpr` is used within the callee of a
211 // `CXXOperatorCallExpr`. In other cases, for example when applying the
212 // address-of operator, the `DeclRefExpr` is a prvalue.
213 if (!S->isGLValue())
214 return;
215
216 auto *DeclLoc = Env.getStorageLocation(*VD);
217 if (DeclLoc == nullptr)
218 return;
219
220 Env.setStorageLocation(*S, *DeclLoc);
221 }
222
223 void VisitDeclStmt(const DeclStmt *S) {
224 // Group decls are converted into single decls in the CFG so the cast below
225 // is safe.
226 const auto &D = *cast<VarDecl>(S->getSingleDecl());
227
228 ProcessVarDecl(D);
229 }
230
231 void ProcessVarDecl(const VarDecl &D) {
232 // Static local vars are already initialized in `Environment`.
233 if (D.hasGlobalStorage())
234 return;
235
236 // If this is the holding variable for a `BindingDecl`, we may already
237 // have a storage location set up -- so check. (See also explanation below
238 // where we process the `BindingDecl`.)
239 if (D.getType()->isReferenceType() && Env.getStorageLocation(D) != nullptr)
240 return;
241
242 assert(Env.getStorageLocation(D) == nullptr);
243
244 Env.setStorageLocation(D, Env.createObject(D));
245
246 // `DecompositionDecl` must be handled after we've interpreted the loc
247 // itself, because the binding expression refers back to the
248 // `DecompositionDecl` (even though it has no written name).
249 if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) {
250 // If VarDecl is a DecompositionDecl, evaluate each of its bindings. This
251 // needs to be evaluated after initializing the values in the storage for
252 // VarDecl, as the bindings refer to them.
253 // FIXME: Add support for ArraySubscriptExpr.
254 // FIXME: Consider adding AST nodes used in BindingDecls to the CFG.
255 for (const auto *B : Decomp->bindings()) {
256 if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) {
257 auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase());
258 if (DE == nullptr)
259 continue;
260
261 // ME and its base haven't been visited because they aren't included
262 // in the statements of the CFG basic block.
263 VisitDeclRefExpr(DE);
264 VisitMemberExpr(ME);
265
266 if (auto *Loc = Env.getStorageLocation(*ME))
267 Env.setStorageLocation(*B, *Loc);
268 } else if (auto *VD = B->getHoldingVar()) {
269 // Holding vars are used to back the `BindingDecl`s of tuple-like
270 // types. The holding var declarations appear after the
271 // `DecompositionDecl`, so we have to explicitly process them here
272 // to know their storage location. They will be processed a second
273 // time when we visit their `VarDecl`s, so we have code that protects
274 // against this above.
275 ProcessVarDecl(*VD);
276 auto *VDLoc = Env.getStorageLocation(*VD);
277 assert(VDLoc != nullptr);
278 Env.setStorageLocation(*B, *VDLoc);
279 }
280 }
281 }
282 }
283
284 void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
285 const Expr *SubExpr = S->getSubExpr();
286 assert(SubExpr != nullptr);
287
288 switch (S->getCastKind()) {
289 case CK_IntegralToBoolean: {
290 // This cast creates a new, boolean value from the integral value. We
291 // model that with a fresh value in the environment, unless it's already a
292 // boolean.
293 if (auto *SubExprVal =
294 dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr)))
295 Env.setValue(*S, *SubExprVal);
296 else
297 // FIXME: If integer modeling is added, then update this code to create
298 // the boolean based on the integer model.
299 Env.setValue(*S, Env.makeAtomicBoolValue());
300 break;
301 }
302
303 case CK_LValueToRValue: {
304 // When an L-value is used as an R-value, it may result in sharing, so we
305 // need to unpack any nested `Top`s.
306 auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env);
307 if (SubExprVal == nullptr)
308 break;
309
310 Env.setValue(*S, *SubExprVal);
311 break;
312 }
313
314 case CK_IntegralCast:
315 // FIXME: This cast creates a new integral value from the
316 // subexpression. But, because we don't model integers, we don't
317 // distinguish between this new value and the underlying one. If integer
318 // modeling is added, then update this code to create a fresh location and
319 // value.
320 case CK_UncheckedDerivedToBase:
321 case CK_ConstructorConversion:
322 case CK_UserDefinedConversion:
323 // FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
324 // CK_ConstructorConversion, and CK_UserDefinedConversion.
325 case CK_NoOp: {
326 // FIXME: Consider making `Environment::getStorageLocation` skip noop
327 // expressions (this and other similar expressions in the file) instead
328 // of assigning them storage locations.
329 propagateValueOrStorageLocation(*SubExpr, *S, Env);
330 break;
331 }
332 case CK_NullToPointer: {
333 auto &NullPointerVal =
334 Env.getOrCreateNullPointerValue(S->getType()->getPointeeType());
335 Env.setValue(*S, NullPointerVal);
336 break;
337 }
338 case CK_NullToMemberPointer:
339 // FIXME: Implement pointers to members. For now, don't associate a value
340 // with this expression.
341 break;
342 case CK_FunctionToPointerDecay: {
343 StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr);
344 if (PointeeLoc == nullptr)
345 break;
346
347 Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc));
348 break;
349 }
350 case CK_BuiltinFnToFnPtr:
351 // Despite its name, the result type of `BuiltinFnToFnPtr` is a function,
352 // not a function pointer. In addition, builtin functions can only be
353 // called directly; it is not legal to take their address. We therefore
354 // don't need to create a value or storage location for them.
355 break;
356 default:
357 break;
358 }
359 }
360
361 void VisitUnaryOperator(const UnaryOperator *S) {
362 const Expr *SubExpr = S->getSubExpr();
363 assert(SubExpr != nullptr);
364
365 switch (S->getOpcode()) {
366 case UO_Deref: {
367 const auto *SubExprVal = Env.get<PointerValue>(*SubExpr);
368 if (SubExprVal == nullptr)
369 break;
370
371 Env.setStorageLocation(*S, SubExprVal->getPointeeLoc());
372 break;
373 }
374 case UO_AddrOf: {
375 // FIXME: Model pointers to members.
376 if (S->getType()->isMemberPointerType())
377 break;
378
379 if (StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr))
380 Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc));
381 break;
382 }
383 case UO_LNot: {
384 auto *SubExprVal = dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr));
385 if (SubExprVal == nullptr)
386 break;
387
388 Env.setValue(*S, Env.makeNot(*SubExprVal));
389 break;
390 }
391 case UO_PreInc:
392 case UO_PreDec:
393 // Propagate the storage location and clear out any value associated with
394 // it (to represent the fact that the value has definitely changed).
395 // To avoid generating unnecessary values, we leave it to the specific
396 // analysis to create a new value if desired.
397 propagateStorageLocation(*S->getSubExpr(), *S, Env);
398 if (StorageLocation *Loc = Env.getStorageLocation(*S->getSubExpr()))
399 Env.clearValue(*Loc);
400 break;
401 case UO_PostInc:
402 case UO_PostDec:
403 // Propagate the old value, then clear out any value associated with the
404 // storage location (to represent the fact that the value has definitely
405 // changed). See above for rationale.
406 propagateValue(*S->getSubExpr(), *S, Env);
407 if (StorageLocation *Loc = Env.getStorageLocation(*S->getSubExpr()))
408 Env.clearValue(*Loc);
409 break;
410 default:
411 break;
412 }
413 }
414
415 void VisitCXXThisExpr(const CXXThisExpr *S) {
416 auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
417 if (ThisPointeeLoc == nullptr)
418 // Unions are not supported yet, and will not have a location for the
419 // `this` expression's pointee.
420 return;
421
422 Env.setValue(*S, Env.create<PointerValue>(*ThisPointeeLoc));
423 }
424
425 void VisitCXXNewExpr(const CXXNewExpr *S) {
426 if (Value *Val = Env.createValue(S->getType()))
427 Env.setValue(*S, *Val);
428 }
429
430 void VisitCXXDeleteExpr(const CXXDeleteExpr *S) {
431 // Empty method.
432 // We consciously don't do anything on deletes. Diagnosing double deletes
433 // (for example) should be done by a specific analysis, not by the
434 // framework.
435 }
436
437 void VisitReturnStmt(const ReturnStmt *S) {
438 if (!Env.getDataflowAnalysisContext().getOptions().ContextSensitiveOpts)
439 return;
440
441 auto *Ret = S->getRetValue();
442 if (Ret == nullptr)
443 return;
444
445 if (Ret->isPRValue()) {
446 if (Ret->getType()->isRecordType())
447 return;
448
449 auto *Val = Env.getValue(*Ret);
450 if (Val == nullptr)
451 return;
452
453 // FIXME: Model NRVO.
454 Env.setReturnValue(Val);
455 } else {
456 auto *Loc = Env.getStorageLocation(*Ret);
457 if (Loc == nullptr)
458 return;
459
460 // FIXME: Model NRVO.
461 Env.setReturnStorageLocation(Loc);
462 }
463 }
464
465 void VisitMemberExpr(const MemberExpr *S) {
466 ValueDecl *Member = S->getMemberDecl();
467 assert(Member != nullptr);
468
469 // FIXME: Consider assigning pointer values to function member expressions.
470 if (Member->isFunctionOrFunctionTemplate())
471 return;
472
473 // FIXME: if/when we add support for modeling enums, use that support here.
474 if (isa<EnumConstantDecl>(Member))
475 return;
476
477 if (auto *D = dyn_cast<VarDecl>(Member)) {
478 if (D->hasGlobalStorage()) {
479 auto *VarDeclLoc = Env.getStorageLocation(*D);
480 if (VarDeclLoc == nullptr)
481 return;
482
483 Env.setStorageLocation(*S, *VarDeclLoc);
484 return;
485 }
486 }
487
488 RecordStorageLocation *BaseLoc = getBaseObjectLocation(*S, Env);
489 if (BaseLoc == nullptr)
490 return;
491
492 auto *MemberLoc = BaseLoc->getChild(*Member);
493 if (MemberLoc == nullptr)
494 return;
495 Env.setStorageLocation(*S, *MemberLoc);
496 }
497
498 void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *S) {
499 const Expr *ArgExpr = S->getExpr();
500 assert(ArgExpr != nullptr);
501 propagateValueOrStorageLocation(*ArgExpr, *S, Env);
502
503 if (S->isPRValue() && S->getType()->isRecordType()) {
504 auto &Loc = Env.getResultObjectLocation(*S);
505 Env.initializeFieldsWithValues(Loc);
506 }
507 }
508
509 void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
510 const Expr *InitExpr = S->getExpr();
511 assert(InitExpr != nullptr);
512
513 // If this is a prvalue of record type, the handler for `*InitExpr` (if one
514 // exists) will initialize the result object; there is no value to propgate
515 // here.
516 if (S->getType()->isRecordType() && S->isPRValue())
517 return;
518
519 propagateValueOrStorageLocation(*InitExpr, *S, Env);
520 }
521
522 void VisitCXXConstructExpr(const CXXConstructExpr *S) {
523 const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
524 assert(ConstructorDecl != nullptr);
525
526 // `CXXConstructExpr` can have array type if default-initializing an array
527 // of records. We don't handle this specifically beyond potentially inlining
528 // the call.
529 if (!S->getType()->isRecordType()) {
530 transferInlineCall(S, ConstructorDecl);
531 return;
532 }
533
534 RecordStorageLocation &Loc = Env.getResultObjectLocation(*S);
535
536 if (ConstructorDecl->isCopyOrMoveConstructor()) {
537 // It is permissible for a copy/move constructor to have additional
538 // parameters as long as they have default arguments defined for them.
539 assert(S->getNumArgs() != 0);
540
541 const Expr *Arg = S->getArg(0);
542 assert(Arg != nullptr);
543
544 auto *ArgLoc = Env.get<RecordStorageLocation>(*Arg);
545 if (ArgLoc == nullptr)
546 return;
547
548 // Even if the copy/move constructor call is elidable, we choose to copy
549 // the record in all cases (which isn't wrong, just potentially not
550 // optimal).
551 copyRecord(*ArgLoc, Loc, Env);
552 return;
553 }
554
555 Env.initializeFieldsWithValues(Loc, S->getType());
556
557 transferInlineCall(S, ConstructorDecl);
558 }
559
560 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
561 if (S->getOperator() == OO_Equal) {
562 assert(S->getNumArgs() == 2);
563
564 const Expr *Arg0 = S->getArg(0);
565 assert(Arg0 != nullptr);
566
567 const Expr *Arg1 = S->getArg(1);
568 assert(Arg1 != nullptr);
569
570 // Evaluate only copy and move assignment operators.
571 const auto *Method =
572 dyn_cast_or_null<CXXMethodDecl>(S->getDirectCallee());
573 if (!Method)
574 return;
575 if (!Method->isCopyAssignmentOperator() &&
576 !Method->isMoveAssignmentOperator())
577 return;
578
579 RecordStorageLocation *LocSrc = nullptr;
580 if (Arg1->isPRValue()) {
581 LocSrc = &Env.getResultObjectLocation(*Arg1);
582 } else {
583 LocSrc = Env.get<RecordStorageLocation>(*Arg1);
584 }
585 auto *LocDst = Env.get<RecordStorageLocation>(*Arg0);
586
587 if (LocSrc == nullptr || LocDst == nullptr)
588 return;
589
590 copyRecord(*LocSrc, *LocDst, Env);
591
592 // The assignment operator can have an arbitrary return type. We model the
593 // return value only if the return type is the same as or a base class of
594 // the destination type.
595 if (S->getType().getCanonicalType().getUnqualifiedType() !=
596 LocDst->getType().getCanonicalType().getUnqualifiedType()) {
597 auto ReturnDecl = S->getType()->getAsCXXRecordDecl();
598 auto DstDecl = LocDst->getType()->getAsCXXRecordDecl();
599 if (ReturnDecl == nullptr || DstDecl == nullptr)
600 return;
601 if (!DstDecl->isDerivedFrom(ReturnDecl))
602 return;
603 }
604
605 if (S->isGLValue())
606 Env.setStorageLocation(*S, *LocDst);
607 else
608 copyRecord(*LocDst, Env.getResultObjectLocation(*S), Env);
609
610 return;
611 }
612
613 // `CXXOperatorCallExpr` can be a prvalue. Call `VisitCallExpr`() to
614 // initialize the prvalue's fields with values.
615 VisitCallExpr(S);
616 }
617
618 void VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *RBO) {
619 propagateValue(*RBO->getSemanticForm(), *RBO, Env);
620 }
621
622 void VisitCallExpr(const CallExpr *S) {
623 // Of clang's builtins, only `__builtin_expect` is handled explicitly, since
624 // others (like trap, debugtrap, and unreachable) are handled by CFG
625 // construction.
626 if (S->isCallToStdMove()) {
627 assert(S->getNumArgs() == 1);
628
629 const Expr *Arg = S->getArg(0);
630 assert(Arg != nullptr);
631
632 auto *ArgLoc = Env.getStorageLocation(*Arg);
633 if (ArgLoc == nullptr)
634 return;
635
636 Env.setStorageLocation(*S, *ArgLoc);
637 } else if (S->getDirectCallee() != nullptr &&
638 S->getDirectCallee()->getBuiltinID() ==
639 Builtin::BI__builtin_expect) {
640 assert(S->getNumArgs() > 0);
641 assert(S->getArg(0) != nullptr);
642 auto *ArgVal = Env.getValue(*S->getArg(0));
643 if (ArgVal == nullptr)
644 return;
645 Env.setValue(*S, *ArgVal);
646 } else if (const FunctionDecl *F = S->getDirectCallee()) {
647 transferInlineCall(S, F);
648
649 // If this call produces a prvalue of record type, initialize its fields
650 // with values.
651 if (S->getType()->isRecordType() && S->isPRValue()) {
652 RecordStorageLocation &Loc = Env.getResultObjectLocation(*S);
653 Env.initializeFieldsWithValues(Loc);
654 }
655 }
656 }
657
658 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
659 const Expr *SubExpr = S->getSubExpr();
660 assert(SubExpr != nullptr);
661
662 StorageLocation &Loc = Env.createStorageLocation(*S);
663 Env.setStorageLocation(*S, Loc);
664
665 if (SubExpr->getType()->isRecordType())
666 // Nothing else left to do -- we initialized the record when transferring
667 // `SubExpr`.
668 return;
669
670 if (Value *SubExprVal = Env.getValue(*SubExpr))
671 Env.setValue(Loc, *SubExprVal);
672 }
673
674 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
675 const Expr *SubExpr = S->getSubExpr();
676 assert(SubExpr != nullptr);
677
678 propagateValue(*SubExpr, *S, Env);
679 }
680
681 void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
682 if (S->getCastKind() == CK_NoOp) {
683 const Expr *SubExpr = S->getSubExpr();
684 assert(SubExpr != nullptr);
685
686 propagateValueOrStorageLocation(*SubExpr, *S, Env);
687 }
688 }
689
690 void VisitConditionalOperator(const ConditionalOperator *S) {
691 const Environment *TrueEnv = StmtToEnv.getEnvironment(*S->getTrueExpr());
692 const Environment *FalseEnv = StmtToEnv.getEnvironment(*S->getFalseExpr());
693
694 if (TrueEnv == nullptr || FalseEnv == nullptr) {
695 // If the true or false branch is dead, we may not have an environment for
696 // it. We could handle this specifically by forwarding the value or
697 // location of the live branch, but this case is rare enough that this
698 // probably isn't worth the additional complexity.
699 return;
700 }
701
702 if (S->isGLValue()) {
703 StorageLocation *TrueLoc = TrueEnv->getStorageLocation(*S->getTrueExpr());
704 StorageLocation *FalseLoc =
705 FalseEnv->getStorageLocation(*S->getFalseExpr());
706 if (TrueLoc == FalseLoc && TrueLoc != nullptr)
707 Env.setStorageLocation(*S, *TrueLoc);
708 } else if (!S->getType()->isRecordType()) {
709 // The conditional operator can evaluate to either of the values of the
710 // two branches. To model this, join these two values together to yield
711 // the result of the conditional operator.
712 // Note: Most joins happen in `computeBlockInputState()`, but this case is
713 // different:
714 // - `computeBlockInputState()` (which in turn calls `Environment::join()`
715 // joins values associated with the _same_ expression or storage
716 // location, then associates the joined value with that expression or
717 // storage location. This join has nothing to do with transfer --
718 // instead, it joins together the results of performing transfer on two
719 // different blocks.
720 // - Here, we join values associated with _different_ expressions (the
721 // true and false branch), then associate the joined value with a third
722 // expression (the conditional operator itself). This join is what it
723 // means to perform transfer on the conditional operator.
725 S->getType(), TrueEnv->getValue(*S->getTrueExpr()), *TrueEnv,
726 FalseEnv->getValue(*S->getFalseExpr()), *FalseEnv, Env, Model))
727 Env.setValue(*S, *Val);
728 }
729 }
730
731 void VisitInitListExpr(const InitListExpr *S) {
732 QualType Type = S->getType();
733
734 if (!Type->isRecordType()) {
735 // Until array initialization is implemented, we skip arrays and don't
736 // need to care about cases where `getNumInits() > 1`.
737 if (!Type->isArrayType() && S->getNumInits() == 1)
738 propagateValueOrStorageLocation(*S->getInit(0), *S, Env);
739 return;
740 }
741
742 // If the initializer list is transparent, there's nothing to do.
743 if (S->isSemanticForm() && S->isTransparent())
744 return;
745
746 RecordStorageLocation &Loc = Env.getResultObjectLocation(*S);
747
748 // Initialization of base classes and fields of record type happens when we
749 // visit the nested `CXXConstructExpr` or `InitListExpr` for that base class
750 // or field. We therefore only need to deal with fields of non-record type
751 // here.
752
753 RecordInitListHelper InitListHelper(S);
754
755 for (auto [Field, Init] : InitListHelper.field_inits()) {
756 if (Field->getType()->isRecordType())
757 continue;
758 if (Field->getType()->isReferenceType()) {
759 assert(Field->getType().getCanonicalType()->getPointeeType() ==
760 Init->getType().getCanonicalType());
761 Loc.setChild(*Field, &Env.createObject(Field->getType(), Init));
762 continue;
763 }
764 assert(Field->getType().getCanonicalType().getUnqualifiedType() ==
765 Init->getType().getCanonicalType().getUnqualifiedType());
766 StorageLocation *FieldLoc = Loc.getChild(*Field);
767 // Locations for non-reference fields must always be non-null.
768 assert(FieldLoc != nullptr);
769 Value *Val = Env.getValue(*Init);
770 if (Val == nullptr && isa<ImplicitValueInitExpr>(Init) &&
771 Init->getType()->isPointerType())
772 Val =
773 &Env.getOrCreateNullPointerValue(Init->getType()->getPointeeType());
774 if (Val == nullptr)
775 Val = Env.createValue(Field->getType());
776 if (Val != nullptr)
777 Env.setValue(*FieldLoc, *Val);
778 }
779
780 for (const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) {
781 QualType FieldType = FieldLoc->getType();
782 if (FieldType->isRecordType()) {
783 Env.initializeFieldsWithValues(*cast<RecordStorageLocation>(FieldLoc));
784 } else {
785 if (Value *Val = Env.createValue(FieldType))
786 Env.setValue(*FieldLoc, *Val);
787 }
788 }
789
790 // FIXME: Implement array initialization.
791 }
792
793 void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
794 Env.setValue(*S, Env.getBoolLiteralValue(S->getValue()));
795 }
796
797 void VisitIntegerLiteral(const IntegerLiteral *S) {
798 Env.setValue(*S, Env.getIntLiteralValue(S->getValue()));
799 }
800
801 void VisitParenExpr(const ParenExpr *S) {
802 // The CFG does not contain `ParenExpr` as top-level statements in basic
803 // blocks, however manual traversal to sub-expressions may encounter them.
804 // Redirect to the sub-expression.
805 auto *SubExpr = S->getSubExpr();
806 assert(SubExpr != nullptr);
807 Visit(SubExpr);
808 }
809
810 void VisitExprWithCleanups(const ExprWithCleanups *S) {
811 // The CFG does not contain `ExprWithCleanups` as top-level statements in
812 // basic blocks, however manual traversal to sub-expressions may encounter
813 // them. Redirect to the sub-expression.
814 auto *SubExpr = S->getSubExpr();
815 assert(SubExpr != nullptr);
816 Visit(SubExpr);
817 }
818
819private:
820 /// Returns the value for the sub-expression `SubExpr` of a logic operator.
821 BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) {
822 // `SubExpr` and its parent logic operator might be part of different basic
823 // blocks. We try to access the value that is assigned to `SubExpr` in the
824 // corresponding environment.
825 if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr))
826 if (auto *Val =
827 dyn_cast_or_null<BoolValue>(SubExprEnv->getValue(SubExpr)))
828 return *Val;
829
830 // The sub-expression may lie within a basic block that isn't reachable,
831 // even if we need it to evaluate the current (reachable) expression
832 // (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr`
833 // within the current environment and then try to get the value that gets
834 // assigned to it.
835 if (Env.getValue(SubExpr) == nullptr)
836 Visit(&SubExpr);
837 if (auto *Val = dyn_cast_or_null<BoolValue>(Env.getValue(SubExpr)))
838 return *Val;
839
840 // If the value of `SubExpr` is still unknown, we create a fresh symbolic
841 // boolean value for it.
842 return Env.makeAtomicBoolValue();
843 }
844
845 // If context sensitivity is enabled, try to analyze the body of the callee
846 // `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`.
847 template <typename E>
848 void transferInlineCall(const E *S, const FunctionDecl *F) {
849 const auto &Options = Env.getDataflowAnalysisContext().getOptions();
850 if (!(Options.ContextSensitiveOpts &&
851 Env.canDescend(Options.ContextSensitiveOpts->Depth, F)))
852 return;
853
854 const AdornedCFG *ACFG = Env.getDataflowAnalysisContext().getAdornedCFG(F);
855 if (!ACFG)
856 return;
857
858 // FIXME: We don't support context-sensitive analysis of recursion, so
859 // we should return early here if `F` is the same as the `FunctionDecl`
860 // holding `S` itself.
861
862 auto ExitBlock = ACFG->getCFG().getExit().getBlockID();
863
864 auto CalleeEnv = Env.pushCall(S);
865
866 // FIXME: Use the same analysis as the caller for the callee. Note,
867 // though, that doing so would require support for changing the analysis's
868 // ASTContext.
869 auto Analysis = NoopAnalysis(ACFG->getDecl().getASTContext(),
870 DataflowAnalysisOptions{Options});
871
872 auto BlockToOutputState =
873 dataflow::runDataflowAnalysis(*ACFG, Analysis, CalleeEnv);
874 assert(BlockToOutputState);
875 assert(ExitBlock < BlockToOutputState->size());
876
877 auto &ExitState = (*BlockToOutputState)[ExitBlock];
878 assert(ExitState);
879
880 Env.popCall(S, ExitState->Env);
881 }
882
883 const StmtToEnvMap &StmtToEnv;
884 Environment &Env;
885 Environment::ValueModel &Model;
886};
887
888} // namespace
889
890void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
892 TransferVisitor(StmtToEnv, Env, Model).Visit(&S);
893}
894
895} // namespace dataflow
896} // namespace clang
#define V(N, I)
Definition: ASTContext.h:3341
MatchType Type
Defines enum values for all the target-independent builtin functions.
const Decl * D
Expr * E
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
const Environment & Env
Definition: HTMLLogger.cpp:148
Defines an enumeration for C++ overloaded operators.
SourceLocation Loc
Definition: SemaObjC.cpp:759
TypeErasedDataflowAnalysis & Analysis
The analysis to be run.
Represents a single basic block in a source-level CFG.
Definition: CFG.h:604
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:195
This represents one expression.
Definition: Expr.h:110
bool isGLValue() const
Definition: Expr.h:280
QualType getType() const
Definition: Expr.h:142
Stmt - This represents one statement.
Definition: Stmt.h:84
bool isRecordType() const
Definition: Type.h:8103
const CFGBlock * blockForStmt(const Stmt &S) const
Returns the basic block that contains S, or null if no basic block containing S is found.
Definition: AdornedCFG.h:68
bool isBlockReachable(const CFGBlock &B) const
Returns whether B is reachable from the entry block.
Definition: AdornedCFG.h:73
BoolValue & makeBoolValue(const Formula &)
Creates a BoolValue wrapping a particular formula.
Definition: Arena.cpp:112
Models a boolean.
Definition: Value.h:94
Supplements Environment with non-standard comparison and join operations.
Holds the state of the program (store and heap) at a given program point.
BoolValue & makeIff(BoolValue &LHS, BoolValue &RHS) const
Returns a boolean value represents LHS <=> RHS.
StorageLocation * getStorageLocation(const ValueDecl &D) const
Returns the storage location assigned to D in the environment, or null if D isn't assigned a storage ...
BoolValue & makeAtomicBoolValue() const
Returns an atomic boolean value.
Value * getValue(const StorageLocation &Loc) const
Returns the value assigned to Loc in the environment or null if Loc isn't assigned a value in the env...
BoolValue & getBoolLiteralValue(bool Value) const
Returns a symbolic boolean value that models a boolean literal equal to Value
DataflowAnalysisContext & getDataflowAnalysisContext() const
Returns the DataflowAnalysisContext used by the environment.
static Value * joinValues(QualType Ty, Value *Val1, const Environment &Env1, Value *Val2, const Environment &Env2, Environment &JoinedEnv, Environment::ValueModel &Model)
Returns a value that approximates both Val1 and Val2, or null if no such value can be produced.
void setStorageLocation(const ValueDecl &D, StorageLocation &Loc)
Assigns Loc as the storage location of D in the environment.
void setValue(const StorageLocation &Loc, Value &Val)
Assigns Val as the value of Loc in the environment.
Maps statements to the environments of basic blocks that contain them.
Definition: Transfer.h:26
const Environment * getEnvironment(const Stmt &S) const
Returns the environment of the basic block that contains S.
Definition: Transfer.cpp:42
Base class for all values computed by abstract interpretation.
Definition: Value.h:33
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env, Environment::ValueModel &Model)
Evaluates S and updates Env accordingly.
Definition: Transfer.cpp:890
static void propagateValueOrStorageLocation(const Expr &From, const Expr &To, Environment &Env)
Definition: Transfer.cpp:125
static void propagateStorageLocation(const Expr &From, const Expr &To, Environment &Env)
Definition: Transfer.cpp:116
static void propagateValue(const Expr &From, const Expr &To, Environment &Env)
Definition: Transfer.cpp:109
static Value * maybeUnpackLValueExpr(const Expr &E, Environment &Env)
Definition: Transfer.cpp:92
void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst, Environment &Env)
Copies a record (struct, class, or union) from Src to Dst.
Definition: RecordOps.cpp:51
static BoolValue & unpackValue(BoolValue &V, Environment &Env)
Definition: Transfer.cpp:81
static BoolValue & evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, Environment &Env)
Definition: Transfer.cpp:58
RecordStorageLocation * getBaseObjectLocation(const MemberExpr &ME, const Environment &Env)
Returns the storage location for the base object of a MemberExpr, or null if none is defined in the e...
llvm::Expected< std::vector< std::optional< DataflowAnalysisState< typename AnalysisT::Lattice > > > > runDataflowAnalysis(const AdornedCFG &ACFG, AnalysisT &Analysis, const Environment &InitEnv, CFGEltCallbacks< AnalysisT > PostAnalysisCallbacks={}, std::int32_t MaxBlockVisits=kDefaultMaxBlockVisits)
Performs dataflow analysis and returns a mapping from basic block IDs to dataflow analysis states tha...
bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:275
The JSON file list parser is used to communicate input to InstallAPI.
Environment Env
Model of the state of the program (store and heap).