[clang] [clang][dataflow] Add `Environment::initializeFieldsWithValues()`. (PR #81239)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 9 02:06:22 PST 2024
https://github.com/martinboehme updated https://github.com/llvm/llvm-project/pull/81239
>From bdd8b6c864c46c79f28182cd855690c42a46ad8b Mon Sep 17 00:00:00 2001
From: Martin Braenne <mboehme at google.com>
Date: Fri, 9 Feb 2024 10:05:18 +0000
Subject: [PATCH] [clang][dataflow] Add
`Environment::initializeFieldsWithValues()`.
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.
---
.../FlowSensitive/DataflowAnalysisContext.h | 15 +++-
.../FlowSensitive/DataflowEnvironment.h | 8 ++
.../FlowSensitive/DataflowEnvironment.cpp | 74 ++++++++++++-------
3 files changed, 68 insertions(+), 29 deletions(-)
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
index 20e45cc27b01fa..98bdf037880ab0 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
@@ -100,6 +100,8 @@ class DataflowAnalysisContext {
/// to add to a `RecordStorageLocation` of a given type.
/// Typically, this is called from the constructor of a `DataflowAnalysis`
///
+ /// The field types returned by the callback may not have reference type.
+ ///
/// To maintain the invariant that all `RecordStorageLocation`s of a given
/// type have the same fields:
/// * The callback must always return the same result for a given type
@@ -205,8 +207,17 @@ class DataflowAnalysisContext {
/// type.
llvm::StringMap<QualType> getSyntheticFields(QualType Type) {
assert(Type->isRecordType());
- if (SyntheticFieldCallback)
- return SyntheticFieldCallback(Type);
+ if (SyntheticFieldCallback) {
+ llvm::StringMap<QualType> Result = SyntheticFieldCallback(Type);
+ // Synthetic fields are not allowed to have reference type.
+ assert([&Result] {
+ for (const auto &Entry : Result)
+ if (Entry.getValue()->isReferenceType())
+ return false;
+ return true;
+ }());
+ return Result;
+ }
return {};
}
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 5c737a561a7c13..0aecc749bf415c 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -681,6 +681,14 @@ class Environment {
llvm::DenseSet<QualType> &Visited,
int Depth, int &CreatedValuesCount);
+ /// Initializes the fields (including synthetic fields) of `Loc` with values,
+ /// unless values of the field type are not supported or we hit one of the
+ /// limits at which we stop producing values (controlled by `Visited`,
+ /// `Depth`, and `CreatedValuesCount`).
+ void initializeFieldsWithValues(RecordStorageLocation &Loc,
+ llvm::DenseSet<QualType> &Visited, int Depth,
+ int &CreatedValuesCount);
+
/// Shared implementation of `createObject()` overloads.
/// `D` and `InitExpr` may be null.
StorageLocation &createObjectInternal(const ValueDecl *D, QualType Ty,
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index 24811ded970e81..93a9dac3bc905f 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) {
More information about the cfe-commits
mailing list