diff options
author | martinboehme <mboehme@google.com> | 2024-02-13 10:01:25 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-13 10:01:25 +0100 |
commit | 270f2c5575dc5dd001e91ddc2c71b0f2d23f567c (patch) | |
tree | 3e0baf228c6f443b04a6b8a1b60592fd748053b5 /clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | |
parent | 4588525d7edbc0d14c41f5fa8f3e23a3241a502e (diff) | |
download | llvm-270f2c5575dc5dd001e91ddc2c71b0f2d23f567c.zip llvm-270f2c5575dc5dd001e91ddc2c71b0f2d23f567c.tar.gz llvm-270f2c5575dc5dd001e91ddc2c71b0f2d23f567c.tar.bz2 |
[clang][dataflow] Add `Environment::initializeFieldsWithValues()`. (#81239)
This function will be useful when we change the behavior of record-type
prvalues
so that they directly initialize the associated result object. See also
the
comment here for more details:
https://github.com/llvm/llvm-project/blob/9e73656af524a2c592978aec91de67316c5ce69f/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h#L354
As part of this patch, we document and assert that synthetic fields may
not have
reference type.
There is no practical use case for this: A `StorageLocation` may not
have
reference type, and a synthetic field of the corresponding non-reference
type
can serve the same purpose.
Diffstat (limited to 'clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp')
-rw-r--r-- | clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp | 74 |
1 files changed, 47 insertions, 27 deletions
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 24811de..93a9dac 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -887,34 +887,10 @@ Value *Environment::createValueUnlessSelfReferential( if (Type->isRecordType()) { CreatedValuesCount++; - llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; - for (const FieldDecl *Field : DACtx->getModeledFields(Type)) { - assert(Field != nullptr); + auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Type)); + initializeFieldsWithValues(Loc, Visited, Depth, CreatedValuesCount); - QualType FieldType = Field->getType(); - - FieldLocs.insert( - {Field, &createLocAndMaybeValue(FieldType, Visited, Depth + 1, - CreatedValuesCount)}); - } - - RecordStorageLocation::SyntheticFieldMap SyntheticFieldLocs; - for (const auto &Entry : DACtx->getSyntheticFields(Type)) { - SyntheticFieldLocs.insert( - {Entry.getKey(), - &createLocAndMaybeValue(Entry.getValue(), Visited, Depth + 1, - CreatedValuesCount)}); - } - - RecordStorageLocation &Loc = DACtx->createRecordStorageLocation( - Type, std::move(FieldLocs), std::move(SyntheticFieldLocs)); - RecordValue &RecordVal = create<RecordValue>(Loc); - - // As we already have a storage location for the `RecordValue`, we can and - // should associate them in the environment. - setValue(Loc, RecordVal); - - return &RecordVal; + return &refreshRecordValue(Loc, *this); } return nullptr; @@ -943,6 +919,50 @@ Environment::createLocAndMaybeValue(QualType Ty, return Loc; } +void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, + llvm::DenseSet<QualType> &Visited, + int Depth, + int &CreatedValuesCount) { + auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) { + if (FieldType->isRecordType()) { + auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc); + setValue(FieldRecordLoc, create<RecordValue>(FieldRecordLoc)); + initializeFieldsWithValues(FieldRecordLoc, Visited, Depth + 1, + CreatedValuesCount); + } else { + if (!Visited.insert(FieldType.getCanonicalType()).second) + return; + if (Value *Val = createValueUnlessSelfReferential( + FieldType, Visited, Depth + 1, CreatedValuesCount)) + setValue(FieldLoc, *Val); + Visited.erase(FieldType.getCanonicalType()); + } + }; + + for (const auto [Field, FieldLoc] : Loc.children()) { + assert(Field != nullptr); + QualType FieldType = Field->getType(); + + if (FieldType->isReferenceType()) { + Loc.setChild(*Field, + &createLocAndMaybeValue(FieldType, Visited, Depth + 1, + CreatedValuesCount)); + } else { + assert(FieldLoc != nullptr); + initField(FieldType, *FieldLoc); + } + } + for (const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) { + assert(FieldLoc != nullptr); + QualType FieldType = FieldLoc->getType(); + + // Synthetic fields cannot have reference type, so we don't need to deal + // with this case. + assert(!FieldType->isReferenceType()); + initField(FieldType, Loc.getSyntheticField(FieldName)); + } +} + StorageLocation &Environment::createObjectInternal(const ValueDecl *D, QualType Ty, const Expr *InitExpr) { |