Skip to content

Commit 270f2c5

Browse files
authored
[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.
1 parent 4588525 commit 270f2c5

File tree

3 files changed

+68
-29
lines changed

3 files changed

+68
-29
lines changed

clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ class DataflowAnalysisContext {
100100
/// to add to a `RecordStorageLocation` of a given type.
101101
/// Typically, this is called from the constructor of a `DataflowAnalysis`
102102
///
103+
/// The field types returned by the callback may not have reference type.
104+
///
103105
/// To maintain the invariant that all `RecordStorageLocation`s of a given
104106
/// type have the same fields:
105107
/// * The callback must always return the same result for a given type
@@ -205,8 +207,17 @@ class DataflowAnalysisContext {
205207
/// type.
206208
llvm::StringMap<QualType> getSyntheticFields(QualType Type) {
207209
assert(Type->isRecordType());
208-
if (SyntheticFieldCallback)
209-
return SyntheticFieldCallback(Type);
210+
if (SyntheticFieldCallback) {
211+
llvm::StringMap<QualType> Result = SyntheticFieldCallback(Type);
212+
// Synthetic fields are not allowed to have reference type.
213+
assert([&Result] {
214+
for (const auto &Entry : Result)
215+
if (Entry.getValue()->isReferenceType())
216+
return false;
217+
return true;
218+
}());
219+
return Result;
220+
}
210221
return {};
211222
}
212223

clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,14 @@ class Environment {
681681
llvm::DenseSet<QualType> &Visited,
682682
int Depth, int &CreatedValuesCount);
683683

684+
/// Initializes the fields (including synthetic fields) of `Loc` with values,
685+
/// unless values of the field type are not supported or we hit one of the
686+
/// limits at which we stop producing values (controlled by `Visited`,
687+
/// `Depth`, and `CreatedValuesCount`).
688+
void initializeFieldsWithValues(RecordStorageLocation &Loc,
689+
llvm::DenseSet<QualType> &Visited, int Depth,
690+
int &CreatedValuesCount);
691+
684692
/// Shared implementation of `createObject()` overloads.
685693
/// `D` and `InitExpr` may be null.
686694
StorageLocation &createObjectInternal(const ValueDecl *D, QualType Ty,

clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -887,34 +887,10 @@ Value *Environment::createValueUnlessSelfReferential(
887887

888888
if (Type->isRecordType()) {
889889
CreatedValuesCount++;
890-
llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
891-
for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
892-
assert(Field != nullptr);
890+
auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Type));
891+
initializeFieldsWithValues(Loc, Visited, Depth, CreatedValuesCount);
893892

894-
QualType FieldType = Field->getType();
895-
896-
FieldLocs.insert(
897-
{Field, &createLocAndMaybeValue(FieldType, Visited, Depth + 1,
898-
CreatedValuesCount)});
899-
}
900-
901-
RecordStorageLocation::SyntheticFieldMap SyntheticFieldLocs;
902-
for (const auto &Entry : DACtx->getSyntheticFields(Type)) {
903-
SyntheticFieldLocs.insert(
904-
{Entry.getKey(),
905-
&createLocAndMaybeValue(Entry.getValue(), Visited, Depth + 1,
906-
CreatedValuesCount)});
907-
}
908-
909-
RecordStorageLocation &Loc = DACtx->createRecordStorageLocation(
910-
Type, std::move(FieldLocs), std::move(SyntheticFieldLocs));
911-
RecordValue &RecordVal = create<RecordValue>(Loc);
912-
913-
// As we already have a storage location for the `RecordValue`, we can and
914-
// should associate them in the environment.
915-
setValue(Loc, RecordVal);
916-
917-
return &RecordVal;
893+
return &refreshRecordValue(Loc, *this);
918894
}
919895

920896
return nullptr;
@@ -943,6 +919,50 @@ Environment::createLocAndMaybeValue(QualType Ty,
943919
return Loc;
944920
}
945921

922+
void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,
923+
llvm::DenseSet<QualType> &Visited,
924+
int Depth,
925+
int &CreatedValuesCount) {
926+
auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
927+
if (FieldType->isRecordType()) {
928+
auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc);
929+
setValue(FieldRecordLoc, create<RecordValue>(FieldRecordLoc));
930+
initializeFieldsWithValues(FieldRecordLoc, Visited, Depth + 1,
931+
CreatedValuesCount);
932+
} else {
933+
if (!Visited.insert(FieldType.getCanonicalType()).second)
934+
return;
935+
if (Value *Val = createValueUnlessSelfReferential(
936+
FieldType, Visited, Depth + 1, CreatedValuesCount))
937+
setValue(FieldLoc, *Val);
938+
Visited.erase(FieldType.getCanonicalType());
939+
}
940+
};
941+
942+
for (const auto [Field, FieldLoc] : Loc.children()) {
943+
assert(Field != nullptr);
944+
QualType FieldType = Field->getType();
945+
946+
if (FieldType->isReferenceType()) {
947+
Loc.setChild(*Field,
948+
&createLocAndMaybeValue(FieldType, Visited, Depth + 1,
949+
CreatedValuesCount));
950+
} else {
951+
assert(FieldLoc != nullptr);
952+
initField(FieldType, *FieldLoc);
953+
}
954+
}
955+
for (const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) {
956+
assert(FieldLoc != nullptr);
957+
QualType FieldType = FieldLoc->getType();
958+
959+
// Synthetic fields cannot have reference type, so we don't need to deal
960+
// with this case.
961+
assert(!FieldType->isReferenceType());
962+
initField(FieldType, Loc.getSyntheticField(FieldName));
963+
}
964+
}
965+
946966
StorageLocation &Environment::createObjectInternal(const ValueDecl *D,
947967
QualType Ty,
948968
const Expr *InitExpr) {

0 commit comments

Comments
 (0)