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