|
27 | 27 | #include "clang/Analysis/FlowSensitive/Value.h"
|
28 | 28 | #include "clang/Basic/Builtins.h"
|
29 | 29 | #include "clang/Basic/OperatorKinds.h"
|
30 |
| -#include "llvm/ADT/STLExtras.h" |
31 | 30 | #include "llvm/Support/Casting.h"
|
32 |
| -#include "llvm/Support/ErrorHandling.h" |
| 31 | +#include "llvm/Support/Debug.h" |
| 32 | +#include <assert.h> |
33 | 33 | #include <cassert>
|
34 |
| -#include <memory> |
35 |
| -#include <tuple> |
| 34 | + |
| 35 | +#define DEBUG_TYPE "dataflow" |
36 | 36 |
|
37 | 37 | namespace clang {
|
38 | 38 | namespace dataflow {
|
@@ -629,17 +629,66 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
|
629 | 629 | return;
|
630 | 630 | }
|
631 | 631 |
|
632 |
| - std::vector<FieldDecl *> Fields = |
633 |
| - getFieldsForInitListExpr(Type->getAsRecordDecl()); |
634 | 632 | llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
|
635 | 633 |
|
636 |
| - for (auto [Field, Init] : llvm::zip(Fields, S->inits())) { |
637 |
| - assert(Field != nullptr); |
638 |
| - assert(Init != nullptr); |
| 634 | + // This only contains the direct fields for the given type. |
| 635 | + std::vector<FieldDecl *> FieldsForInit = |
| 636 | + getFieldsForInitListExpr(Type->getAsRecordDecl()); |
639 | 637 |
|
640 |
| - FieldLocs.insert({Field, &Env.createObject(Field->getType(), Init)}); |
| 638 | + // `S->inits()` contains all the initializer epressions, including the |
| 639 | + // ones for direct base classes. |
| 640 | + auto Inits = S->inits(); |
| 641 | + size_t InitIdx = 0; |
| 642 | + |
| 643 | + // Initialize base classes. |
| 644 | + if (auto* R = S->getType()->getAsCXXRecordDecl()) { |
| 645 | + assert(FieldsForInit.size() + R->getNumBases() == Inits.size()); |
| 646 | + for ([[maybe_unused]] const CXXBaseSpecifier &Base : R->bases()) { |
| 647 | + assert(InitIdx < Inits.size()); |
| 648 | + auto Init = Inits[InitIdx++]; |
| 649 | + assert(Base.getType().getCanonicalType() == |
| 650 | + Init->getType().getCanonicalType()); |
| 651 | + auto* BaseVal = cast_or_null<RecordValue>(Env.getValue(*Init)); |
| 652 | + if (!BaseVal) |
| 653 | + BaseVal = cast<RecordValue>(Env.createValue(Init->getType())); |
| 654 | + // Take ownership of the fields of the `RecordValue` for the base class |
| 655 | + // and incorporate them into the "flattened" set of fields for the |
| 656 | + // derived class. |
| 657 | + auto Children = BaseVal->getLoc().children(); |
| 658 | + FieldLocs.insert(Children.begin(), Children.end()); |
| 659 | + } |
641 | 660 | }
|
642 | 661 |
|
| 662 | + assert(FieldsForInit.size() == Inits.size() - InitIdx); |
| 663 | + for (auto Field : FieldsForInit) { |
| 664 | + assert(InitIdx < Inits.size()); |
| 665 | + auto Init = Inits[InitIdx++]; |
| 666 | + assert( |
| 667 | + // The types are same, or |
| 668 | + Field->getType().getCanonicalType().getUnqualifiedType() == |
| 669 | + Init->getType().getCanonicalType() || |
| 670 | + // The field's type is T&, and initializer is T |
| 671 | + (Field->getType()->isReferenceType() && |
| 672 | + Field->getType().getCanonicalType()->getPointeeType() == |
| 673 | + Init->getType().getCanonicalType())); |
| 674 | + auto& Loc = Env.createObject(Field->getType(), Init); |
| 675 | + FieldLocs.insert({Field, &Loc}); |
| 676 | + } |
| 677 | + |
| 678 | + LLVM_DEBUG({ |
| 679 | + // Check that we satisfy the invariant that a `RecordStorageLoation` |
| 680 | + // contains exactly the set of modeled fields for that type. |
| 681 | + // `ModeledFields` includes fields from all the bases, but only the |
| 682 | + // modeled ones. However, if a class type is initialized with an |
| 683 | + // `InitListExpr`, all fields in the class, including those from base |
| 684 | + // classes, are included in the set of modeled fields. The code above |
| 685 | + // should therefore populate exactly the modeled fields. |
| 686 | + auto ModeledFields = Env.getDataflowAnalysisContext().getModeledFields(Type); |
| 687 | + assert(ModeledFields.size() == FieldLocs.size()); |
| 688 | + for ([[maybe_unused]] auto [Field, Loc] : FieldLocs) |
| 689 | + assert(ModeledFields.contains(cast_or_null<FieldDecl>(Field))); |
| 690 | + }); |
| 691 | + |
643 | 692 | auto &Loc =
|
644 | 693 | Env.getDataflowAnalysisContext().arena().create<RecordStorageLocation>(
|
645 | 694 | Type, std::move(FieldLocs));
|
|
0 commit comments