|
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