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