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