|
20 | 20 | #include "clang/AST/OperationKinds.h" |
21 | 21 | #include "clang/AST/Stmt.h" |
22 | 22 | #include "clang/AST/StmtVisitor.h" |
| 23 | +#include "clang/AST/Type.h" |
23 | 24 | #include "clang/Analysis/FlowSensitive/ASTOps.h" |
24 | 25 | #include "clang/Analysis/FlowSensitive/AdornedCFG.h" |
25 | 26 | #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" |
26 | 27 | #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" |
27 | 28 | #include "clang/Analysis/FlowSensitive/NoopAnalysis.h" |
28 | 29 | #include "clang/Analysis/FlowSensitive/RecordOps.h" |
| 30 | +#include "clang/Analysis/FlowSensitive/StorageLocation.h" |
29 | 31 | #include "clang/Analysis/FlowSensitive/Value.h" |
30 | 32 | #include "clang/Basic/Builtins.h" |
| 33 | +#include "clang/Basic/LLVM.h" |
31 | 34 | #include "clang/Basic/OperatorKinds.h" |
32 | 35 | #include "llvm/Support/Casting.h" |
33 | 36 | #include <assert.h> |
@@ -287,7 +290,7 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { |
287 | 290 | } |
288 | 291 | } |
289 | 292 |
|
290 | | - void VisitImplicitCastExpr(const ImplicitCastExpr *S) { |
| 293 | + void VisitCastExpr(const CastExpr *S) { |
291 | 294 | const Expr *SubExpr = S->getSubExpr(); |
292 | 295 | assert(SubExpr != nullptr); |
293 | 296 |
|
@@ -317,17 +320,70 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { |
317 | 320 | break; |
318 | 321 | } |
319 | 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 | + } |
320 | 377 | case CK_IntegralCast: |
321 | 378 | // FIXME: This cast creates a new integral value from the |
322 | 379 | // subexpression. But, because we don't model integers, we don't |
323 | 380 | // distinguish between this new value and the underlying one. If integer |
324 | 381 | // modeling is added, then update this code to create a fresh location and |
325 | 382 | // value. |
326 | 383 | case CK_UncheckedDerivedToBase: |
| 384 | + case CK_DerivedToBase: |
327 | 385 | case CK_ConstructorConversion: |
328 | 386 | case CK_UserDefinedConversion: |
329 | | - // FIXME: Add tests that excercise CK_UncheckedDerivedToBase, |
330 | | - // CK_ConstructorConversion, and CK_UserDefinedConversion. |
331 | 387 | case CK_NoOp: { |
332 | 388 | // FIXME: Consider making `Environment::getStorageLocation` skip noop |
333 | 389 | // expressions (this and other similar expressions in the file) instead |
@@ -554,7 +610,15 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { |
554 | 610 | // Even if the copy/move constructor call is elidable, we choose to copy |
555 | 611 | // the record in all cases (which isn't wrong, just potentially not |
556 | 612 | // optimal). |
557 | | - copyRecord(*ArgLoc, Loc, Env); |
| 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()); |
558 | 622 | return; |
559 | 623 | } |
560 | 624 |
|
@@ -684,15 +748,6 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { |
684 | 748 | propagateValue(*SubExpr, *S, Env); |
685 | 749 | } |
686 | 750 |
|
687 | | - void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) { |
688 | | - if (S->getCastKind() == CK_NoOp) { |
689 | | - const Expr *SubExpr = S->getSubExpr(); |
690 | | - assert(SubExpr != nullptr); |
691 | | - |
692 | | - propagateValueOrStorageLocation(*SubExpr, *S, Env); |
693 | | - } |
694 | | - } |
695 | | - |
696 | 751 | void VisitConditionalOperator(const ConditionalOperator *S) { |
697 | 752 | const Environment *TrueEnv = StmtToEnv.getEnvironment(*S->getTrueExpr()); |
698 | 753 | const Environment *FalseEnv = StmtToEnv.getEnvironment(*S->getFalseExpr()); |
|
0 commit comments