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/DataflowEnvironment.h" 24 #include "clang/Analysis/FlowSensitive/Value.h" 25 #include "clang/Basic/Builtins.h" 26 #include "clang/Basic/OperatorKinds.h" 27 #include "llvm/ADT/STLExtras.h" 28 #include "llvm/Support/Casting.h" 29 #include <cassert> 30 #include <memory> 31 #include <tuple> 32 33 namespace clang { 34 namespace dataflow { 35 36 static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, 37 Environment &Env) { 38 if (auto *LHSValue = 39 dyn_cast_or_null<BoolValue>(Env.getValue(LHS, SkipPast::Reference))) 40 if (auto *RHSValue = 41 dyn_cast_or_null<BoolValue>(Env.getValue(RHS, SkipPast::Reference))) 42 return Env.makeIff(*LHSValue, *RHSValue); 43 44 return Env.makeAtomicBoolValue(); 45 } 46 47 class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { 48 public: 49 TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env) 50 : StmtToEnv(StmtToEnv), Env(Env) {} 51 52 void VisitBinaryOperator(const BinaryOperator *S) { 53 const Expr *LHS = S->getLHS(); 54 assert(LHS != nullptr); 55 56 const Expr *RHS = S->getRHS(); 57 assert(RHS != nullptr); 58 59 switch (S->getOpcode()) { 60 case BO_Assign: { 61 auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference); 62 if (LHSLoc == nullptr) 63 break; 64 65 auto *RHSVal = Env.getValue(*RHS, SkipPast::Reference); 66 if (RHSVal == nullptr) 67 break; 68 69 // Assign a value to the storage location of the left-hand side. 70 Env.setValue(*LHSLoc, *RHSVal); 71 72 // Assign a storage location for the whole expression. 73 Env.setStorageLocation(*S, *LHSLoc); 74 break; 75 } 76 case BO_LAnd: 77 case BO_LOr: { 78 BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS); 79 BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS); 80 81 auto &Loc = Env.createStorageLocation(*S); 82 Env.setStorageLocation(*S, Loc); 83 if (S->getOpcode() == BO_LAnd) 84 Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal)); 85 else 86 Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal)); 87 break; 88 } 89 case BO_NE: 90 case BO_EQ: { 91 auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env); 92 auto &Loc = Env.createStorageLocation(*S); 93 Env.setStorageLocation(*S, Loc); 94 Env.setValue(Loc, S->getOpcode() == BO_EQ ? LHSEqRHSValue 95 : Env.makeNot(LHSEqRHSValue)); 96 break; 97 } 98 case BO_Comma: { 99 if (auto *Loc = Env.getStorageLocation(*RHS, SkipPast::None)) 100 Env.setStorageLocation(*S, *Loc); 101 break; 102 } 103 default: 104 break; 105 } 106 } 107 108 void VisitDeclRefExpr(const DeclRefExpr *S) { 109 assert(S->getDecl() != nullptr); 110 auto *DeclLoc = Env.getStorageLocation(*S->getDecl(), SkipPast::None); 111 if (DeclLoc == nullptr) 112 return; 113 114 if (S->getDecl()->getType()->isReferenceType()) { 115 Env.setStorageLocation(*S, *DeclLoc); 116 } else { 117 auto &Loc = Env.createStorageLocation(*S); 118 auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc)); 119 Env.setStorageLocation(*S, Loc); 120 Env.setValue(Loc, Val); 121 } 122 } 123 124 void VisitDeclStmt(const DeclStmt *S) { 125 // Group decls are converted into single decls in the CFG so the cast below 126 // is safe. 127 const auto &D = *cast<VarDecl>(S->getSingleDecl()); 128 129 // Static local vars are already initialized in `Environment`. 130 if (D.hasGlobalStorage()) 131 return; 132 133 auto &Loc = Env.createStorageLocation(D); 134 Env.setStorageLocation(D, Loc); 135 136 const Expr *InitExpr = D.getInit(); 137 if (InitExpr == nullptr) { 138 // No initializer expression - associate `Loc` with a new value. 139 if (Value *Val = Env.createValue(D.getType())) 140 Env.setValue(Loc, *Val); 141 return; 142 } 143 144 if (D.getType()->isReferenceType()) { 145 // Initializing a reference variable - do not create a reference to 146 // reference. 147 if (auto *InitExprLoc = 148 Env.getStorageLocation(*InitExpr, SkipPast::Reference)) { 149 auto &Val = 150 Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc)); 151 Env.setValue(Loc, Val); 152 } 153 } else if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) { 154 Env.setValue(Loc, *InitExprVal); 155 } 156 157 if (Env.getValue(Loc) == nullptr) { 158 // We arrive here in (the few) cases where an expression is intentionally 159 // "uninterpreted". There are two ways to handle this situation: propagate 160 // the status, so that uninterpreted initializers result in uninterpreted 161 // variables, or provide a default value. We choose the latter so that 162 // later refinements of the variable can be used for reasoning about the 163 // surrounding code. 164 // 165 // FIXME. If and when we interpret all language cases, change this to 166 // assert that `InitExpr` is interpreted, rather than supplying a default 167 // value (assuming we don't update the environment API to return 168 // references). 169 if (Value *Val = Env.createValue(D.getType())) 170 Env.setValue(Loc, *Val); 171 } 172 173 if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) { 174 // If VarDecl is a DecompositionDecl, evaluate each of its bindings. This 175 // needs to be evaluated after initializing the values in the storage for 176 // VarDecl, as the bindings refer to them. 177 // FIXME: Add support for ArraySubscriptExpr. 178 // FIXME: Consider adding AST nodes that are used for structured bindings 179 // to the CFG. 180 for (const auto *B : Decomp->bindings()) { 181 auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding()); 182 if (ME == nullptr) 183 continue; 184 185 auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase()); 186 if (DE == nullptr) 187 continue; 188 189 // ME and its base haven't been visited because they aren't included in 190 // the statements of the CFG basic block. 191 VisitDeclRefExpr(DE); 192 VisitMemberExpr(ME); 193 194 if (auto *Loc = Env.getStorageLocation(*ME, SkipPast::Reference)) 195 Env.setStorageLocation(*B, *Loc); 196 } 197 } 198 } 199 200 void VisitImplicitCastExpr(const ImplicitCastExpr *S) { 201 const Expr *SubExpr = S->getSubExpr(); 202 assert(SubExpr != nullptr); 203 204 switch (S->getCastKind()) { 205 case CK_IntegralToBoolean: { 206 // This cast creates a new, boolean value from the integral value. We 207 // model that with a fresh value in the environment, unless it's already a 208 // boolean. 209 auto &Loc = Env.createStorageLocation(*S); 210 Env.setStorageLocation(*S, Loc); 211 if (auto *SubExprVal = dyn_cast_or_null<BoolValue>( 212 Env.getValue(*SubExpr, SkipPast::Reference))) 213 Env.setValue(Loc, *SubExprVal); 214 else 215 // FIXME: If integer modeling is added, then update this code to create 216 // the boolean based on the integer model. 217 Env.setValue(Loc, Env.makeAtomicBoolValue()); 218 break; 219 } 220 221 case CK_LValueToRValue: { 222 auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference); 223 if (SubExprVal == nullptr) 224 break; 225 226 auto &ExprLoc = Env.createStorageLocation(*S); 227 Env.setStorageLocation(*S, ExprLoc); 228 Env.setValue(ExprLoc, *SubExprVal); 229 break; 230 } 231 232 case CK_IntegralCast: 233 // FIXME: This cast creates a new integral value from the 234 // subexpression. But, because we don't model integers, we don't 235 // distinguish between this new value and the underlying one. If integer 236 // modeling is added, then update this code to create a fresh location and 237 // value. 238 case CK_UncheckedDerivedToBase: 239 case CK_ConstructorConversion: 240 case CK_UserDefinedConversion: 241 // FIXME: Add tests that excercise CK_UncheckedDerivedToBase, 242 // CK_ConstructorConversion, and CK_UserDefinedConversion. 243 case CK_NoOp: { 244 // FIXME: Consider making `Environment::getStorageLocation` skip noop 245 // expressions (this and other similar expressions in the file) instead of 246 // assigning them storage locations. 247 auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 248 if (SubExprLoc == nullptr) 249 break; 250 251 Env.setStorageLocation(*S, *SubExprLoc); 252 break; 253 } 254 case CK_NullToPointer: 255 case CK_NullToMemberPointer: { 256 auto &Loc = Env.createStorageLocation(S->getType()); 257 Env.setStorageLocation(*S, Loc); 258 259 auto &NullPointerVal = 260 Env.getOrCreateNullPointerValue(S->getType()->getPointeeType()); 261 Env.setValue(Loc, NullPointerVal); 262 break; 263 } 264 default: 265 break; 266 } 267 } 268 269 void VisitUnaryOperator(const UnaryOperator *S) { 270 const Expr *SubExpr = S->getSubExpr(); 271 assert(SubExpr != nullptr); 272 273 switch (S->getOpcode()) { 274 case UO_Deref: { 275 // Skip past a reference to handle dereference of a dependent pointer. 276 const auto *SubExprVal = cast_or_null<PointerValue>( 277 Env.getValue(*SubExpr, SkipPast::Reference)); 278 if (SubExprVal == nullptr) 279 break; 280 281 auto &Loc = Env.createStorageLocation(*S); 282 Env.setStorageLocation(*S, Loc); 283 Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>( 284 SubExprVal->getPointeeLoc()))); 285 break; 286 } 287 case UO_AddrOf: { 288 // Do not form a pointer to a reference. If `SubExpr` is assigned a 289 // `ReferenceValue` then form a value that points to the location of its 290 // pointee. 291 StorageLocation *PointeeLoc = 292 Env.getStorageLocation(*SubExpr, SkipPast::Reference); 293 if (PointeeLoc == nullptr) 294 break; 295 296 auto &PointerLoc = Env.createStorageLocation(*S); 297 auto &PointerVal = 298 Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc)); 299 Env.setStorageLocation(*S, PointerLoc); 300 Env.setValue(PointerLoc, PointerVal); 301 break; 302 } 303 case UO_LNot: { 304 auto *SubExprVal = 305 dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr, SkipPast::None)); 306 if (SubExprVal == nullptr) 307 break; 308 309 auto &ExprLoc = Env.createStorageLocation(*S); 310 Env.setStorageLocation(*S, ExprLoc); 311 Env.setValue(ExprLoc, Env.makeNot(*SubExprVal)); 312 break; 313 } 314 default: 315 break; 316 } 317 } 318 319 void VisitCXXThisExpr(const CXXThisExpr *S) { 320 auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation(); 321 if (ThisPointeeLoc == nullptr) 322 // Unions are not supported yet, and will not have a location for the 323 // `this` expression's pointee. 324 return; 325 326 auto &Loc = Env.createStorageLocation(*S); 327 Env.setStorageLocation(*S, Loc); 328 Env.setValue(Loc, Env.takeOwnership( 329 std::make_unique<PointerValue>(*ThisPointeeLoc))); 330 } 331 332 void VisitMemberExpr(const MemberExpr *S) { 333 ValueDecl *Member = S->getMemberDecl(); 334 assert(Member != nullptr); 335 336 // FIXME: Consider assigning pointer values to function member expressions. 337 if (Member->isFunctionOrFunctionTemplate()) 338 return; 339 340 if (auto *D = dyn_cast<VarDecl>(Member)) { 341 if (D->hasGlobalStorage()) { 342 auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None); 343 if (VarDeclLoc == nullptr) 344 return; 345 346 if (VarDeclLoc->getType()->isReferenceType()) { 347 Env.setStorageLocation(*S, *VarDeclLoc); 348 } else { 349 auto &Loc = Env.createStorageLocation(*S); 350 Env.setStorageLocation(*S, Loc); 351 Env.setValue(Loc, Env.takeOwnership( 352 std::make_unique<ReferenceValue>(*VarDeclLoc))); 353 } 354 return; 355 } 356 } 357 358 // The receiver can be either a value or a pointer to a value. Skip past the 359 // indirection to handle both cases. 360 auto *BaseLoc = cast_or_null<AggregateStorageLocation>( 361 Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer)); 362 if (BaseLoc == nullptr) 363 return; 364 365 // FIXME: Add support for union types. 366 if (BaseLoc->getType()->isUnionType()) 367 return; 368 369 auto &MemberLoc = BaseLoc->getChild(*Member); 370 if (MemberLoc.getType()->isReferenceType()) { 371 Env.setStorageLocation(*S, MemberLoc); 372 } else { 373 auto &Loc = Env.createStorageLocation(*S); 374 Env.setStorageLocation(*S, Loc); 375 Env.setValue( 376 Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc))); 377 } 378 } 379 380 void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { 381 const Expr *InitExpr = S->getExpr(); 382 assert(InitExpr != nullptr); 383 384 Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None); 385 if (InitExprVal == nullptr) 386 return; 387 388 const FieldDecl *Field = S->getField(); 389 assert(Field != nullptr); 390 391 auto &ThisLoc = 392 *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation()); 393 auto &FieldLoc = ThisLoc.getChild(*Field); 394 Env.setValue(FieldLoc, *InitExprVal); 395 } 396 397 void VisitCXXConstructExpr(const CXXConstructExpr *S) { 398 const CXXConstructorDecl *ConstructorDecl = S->getConstructor(); 399 assert(ConstructorDecl != nullptr); 400 401 if (ConstructorDecl->isCopyOrMoveConstructor()) { 402 assert(S->getNumArgs() == 1); 403 404 const Expr *Arg = S->getArg(0); 405 assert(Arg != nullptr); 406 407 if (S->isElidable()) { 408 auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference); 409 if (ArgLoc == nullptr) 410 return; 411 412 Env.setStorageLocation(*S, *ArgLoc); 413 } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) { 414 auto &Loc = Env.createStorageLocation(*S); 415 Env.setStorageLocation(*S, Loc); 416 Env.setValue(Loc, *ArgVal); 417 } 418 return; 419 } 420 421 auto &Loc = Env.createStorageLocation(*S); 422 Env.setStorageLocation(*S, Loc); 423 if (Value *Val = Env.createValue(S->getType())) 424 Env.setValue(Loc, *Val); 425 } 426 427 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { 428 if (S->getOperator() == OO_Equal) { 429 assert(S->getNumArgs() == 2); 430 431 const Expr *Arg0 = S->getArg(0); 432 assert(Arg0 != nullptr); 433 434 const Expr *Arg1 = S->getArg(1); 435 assert(Arg1 != nullptr); 436 437 // Evaluate only copy and move assignment operators. 438 auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType(); 439 auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType(); 440 if (Arg0Type != Arg1Type) 441 return; 442 443 auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference); 444 if (ObjectLoc == nullptr) 445 return; 446 447 auto *Val = Env.getValue(*Arg1, SkipPast::Reference); 448 if (Val == nullptr) 449 return; 450 451 // Assign a value to the storage location of the object. 452 Env.setValue(*ObjectLoc, *Val); 453 454 // FIXME: Add a test for the value of the whole expression. 455 // Assign a storage location for the whole expression. 456 Env.setStorageLocation(*S, *ObjectLoc); 457 } 458 } 459 460 void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) { 461 if (S->getCastKind() == CK_ConstructorConversion) { 462 const Expr *SubExpr = S->getSubExpr(); 463 assert(SubExpr != nullptr); 464 465 auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 466 if (SubExprLoc == nullptr) 467 return; 468 469 Env.setStorageLocation(*S, *SubExprLoc); 470 } 471 } 472 473 void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) { 474 auto &Loc = Env.createStorageLocation(*S); 475 Env.setStorageLocation(*S, Loc); 476 if (Value *Val = Env.createValue(S->getType())) 477 Env.setValue(Loc, *Val); 478 } 479 480 void VisitCallExpr(const CallExpr *S) { 481 // Of clang's builtins, only `__builtin_expect` is handled explicitly, since 482 // others (like trap, debugtrap, and unreachable) are handled by CFG 483 // construction. 484 if (S->isCallToStdMove()) { 485 assert(S->getNumArgs() == 1); 486 487 const Expr *Arg = S->getArg(0); 488 assert(Arg != nullptr); 489 490 auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None); 491 if (ArgLoc == nullptr) 492 return; 493 494 Env.setStorageLocation(*S, *ArgLoc); 495 } else if (S->getDirectCallee() != nullptr && 496 S->getDirectCallee()->getBuiltinID() == 497 Builtin::BI__builtin_expect) { 498 assert(S->getNumArgs() > 0); 499 assert(S->getArg(0) != nullptr); 500 // `__builtin_expect` returns by-value, so strip away any potential 501 // references in the argument. 502 auto *ArgLoc = Env.getStorageLocation(*S->getArg(0), SkipPast::Reference); 503 if (ArgLoc == nullptr) 504 return; 505 Env.setStorageLocation(*S, *ArgLoc); 506 } 507 } 508 509 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) { 510 const Expr *SubExpr = S->getSubExpr(); 511 assert(SubExpr != nullptr); 512 513 auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 514 if (SubExprLoc == nullptr) 515 return; 516 517 Env.setStorageLocation(*S, *SubExprLoc); 518 } 519 520 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { 521 const Expr *SubExpr = S->getSubExpr(); 522 assert(SubExpr != nullptr); 523 524 auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 525 if (SubExprLoc == nullptr) 526 return; 527 528 Env.setStorageLocation(*S, *SubExprLoc); 529 } 530 531 void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) { 532 if (S->getCastKind() == CK_NoOp) { 533 const Expr *SubExpr = S->getSubExpr(); 534 assert(SubExpr != nullptr); 535 536 auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); 537 if (SubExprLoc == nullptr) 538 return; 539 540 Env.setStorageLocation(*S, *SubExprLoc); 541 } 542 } 543 544 void VisitConditionalOperator(const ConditionalOperator *S) { 545 // FIXME: Revisit this once flow conditions are added to the framework. For 546 // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow 547 // condition. 548 auto &Loc = Env.createStorageLocation(*S); 549 Env.setStorageLocation(*S, Loc); 550 if (Value *Val = Env.createValue(S->getType())) 551 Env.setValue(Loc, *Val); 552 } 553 554 void VisitInitListExpr(const InitListExpr *S) { 555 QualType Type = S->getType(); 556 557 auto &Loc = Env.createStorageLocation(*S); 558 Env.setStorageLocation(*S, Loc); 559 560 auto *Val = Env.createValue(Type); 561 if (Val == nullptr) 562 return; 563 564 Env.setValue(Loc, *Val); 565 566 if (Type->isStructureOrClassType()) { 567 for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) { 568 const FieldDecl *Field = std::get<0>(IT); 569 assert(Field != nullptr); 570 571 const Expr *Init = std::get<1>(IT); 572 assert(Init != nullptr); 573 574 if (Value *InitVal = Env.getValue(*Init, SkipPast::None)) 575 cast<StructValue>(Val)->setChild(*Field, *InitVal); 576 } 577 } 578 // FIXME: Implement array initialization. 579 } 580 581 void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) { 582 auto &Loc = Env.createStorageLocation(*S); 583 Env.setStorageLocation(*S, Loc); 584 Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue())); 585 } 586 587 void VisitParenExpr(const ParenExpr *S) { 588 // The CFG does not contain `ParenExpr` as top-level statements in basic 589 // blocks, however manual traversal to sub-expressions may encounter them. 590 // Redirect to the sub-expression. 591 auto *SubExpr = S->getSubExpr(); 592 assert(SubExpr != nullptr); 593 Visit(SubExpr); 594 } 595 596 void VisitExprWithCleanups(const ExprWithCleanups *S) { 597 // The CFG does not contain `ExprWithCleanups` as top-level statements in 598 // basic blocks, however manual traversal to sub-expressions may encounter 599 // them. Redirect to the sub-expression. 600 auto *SubExpr = S->getSubExpr(); 601 assert(SubExpr != nullptr); 602 Visit(SubExpr); 603 } 604 605 private: 606 BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) { 607 // `SubExpr` and its parent logic operator might be part of different basic 608 // blocks. We try to access the value that is assigned to `SubExpr` in the 609 // corresponding environment. 610 if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) { 611 if (auto *Val = dyn_cast_or_null<BoolValue>( 612 SubExprEnv->getValue(SubExpr, SkipPast::Reference))) 613 return *Val; 614 } 615 616 if (Env.getStorageLocation(SubExpr, SkipPast::None) == nullptr) { 617 // Sub-expressions that are logic operators are not added in basic blocks 618 // (e.g. see CFG for `bool d = a && (b || c);`). If `SubExpr` is a logic 619 // operator, it may not have been evaluated and assigned a value yet. In 620 // that case, we need to first visit `SubExpr` and then try to get the 621 // value that gets assigned to it. 622 Visit(&SubExpr); 623 } 624 625 if (auto *Val = dyn_cast_or_null<BoolValue>( 626 Env.getValue(SubExpr, SkipPast::Reference))) 627 return *Val; 628 629 // If the value of `SubExpr` is still unknown, we create a fresh symbolic 630 // boolean value for it. 631 return Env.makeAtomicBoolValue(); 632 } 633 634 const StmtToEnvMap &StmtToEnv; 635 Environment &Env; 636 }; 637 638 void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) { 639 TransferVisitor(StmtToEnv, Env).Visit(&S); 640 } 641 642 } // namespace dataflow 643 } // namespace clang 644