Skip to content

Commit f5df084

Browse files
committed
[clang][nullability] Remove RecordValue.
This class no longer serves any purpose; see also the discussion here: https://reviews.llvm.org/D155204#inline-1503204 A lot of existing tests in TransferTest.cpp check for the existence of `RecordValue`s. Some of these checks are now simply redundant and have been removed. In other cases, tests were checking for the existence of a `RecordValue` as a way of testing whether a record has been initialized. I have typically changed these test to instead check whether a field of the record has a value.
1 parent 694c444 commit f5df084

File tree

13 files changed

+130
-396
lines changed

13 files changed

+130
-396
lines changed

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

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class Environment {
8484
virtual ComparisonResult compare(QualType Type, const Value &Val1,
8585
const Environment &Env1, const Value &Val2,
8686
const Environment &Env2) {
87-
// FIXME: Consider adding QualType to RecordValue and removing the Type
87+
// FIXME: Consider adding `QualType` to `Value` and removing the `Type`
8888
// argument here.
8989
return ComparisonResult::Unknown;
9090
}
@@ -407,20 +407,15 @@ class Environment {
407407
/// storage locations and values for indirections until it finds a
408408
/// non-pointer/non-reference type.
409409
///
410-
/// If `Type` is a class, struct, or union type, creates values for all
411-
/// modeled fields (including synthetic fields) and calls `setValue()` to
412-
/// associate the `RecordValue` with its storage location
413-
/// (`RecordValue::getLoc()`).
414-
///
415410
/// If `Type` is one of the following types, this function will always return
416411
/// a non-null pointer:
417412
/// - `bool`
418413
/// - Any integer type
419-
/// - Any class, struct, or union type
420414
///
421415
/// Requirements:
422416
///
423-
/// `Type` must not be null.
417+
/// - `Type` must not be null.
418+
/// - `Type` must not be a reference type or record type.
424419
Value *createValue(QualType Type);
425420

426421
/// Creates an object (i.e. a storage location with an associated value) of
@@ -452,6 +447,7 @@ class Environment {
452447
/// Initializes the fields (including synthetic fields) of `Loc` with values,
453448
/// unless values of the field type are not supported or we hit one of the
454449
/// limits at which we stop producing values.
450+
/// If a field already has a value, that value is preserved.
455451
/// If `Type` is provided, initializes only those fields that are modeled for
456452
/// `Type`; this is intended for use in cases where `Loc` is a derived type
457453
/// and we only want to initialize the fields of a base type.
@@ -461,6 +457,10 @@ class Environment {
461457
}
462458

463459
/// Assigns `Val` as the value of `Loc` in the environment.
460+
///
461+
/// Requirements:
462+
///
463+
/// `Loc` must not be a `RecordStorageLocation`.
464464
void setValue(const StorageLocation &Loc, Value &Val);
465465

466466
/// Clears any association between `Loc` and a value in the environment.
@@ -470,20 +470,24 @@ class Environment {
470470
///
471471
/// Requirements:
472472
///
473-
/// - `E` must be a prvalue
474-
/// - If `Val` is a `RecordValue`, its `RecordStorageLocation` must be
475-
/// `getResultObjectLocation(E)`. An exception to this is if `E` is an
476-
/// expression that originally creates a `RecordValue` (such as a
477-
/// `CXXConstructExpr` or `CallExpr`), as these establish the location of
478-
/// the result object in the first place.
473+
/// - `E` must be a prvalue.
474+
/// - `E` must not have record type.
479475
void setValue(const Expr &E, Value &Val);
480476

481477
/// Returns the value assigned to `Loc` in the environment or null if `Loc`
482478
/// isn't assigned a value in the environment.
479+
///
480+
/// Requirements:
481+
///
482+
/// `Loc` must not be a `RecordStorageLocation`.
483483
Value *getValue(const StorageLocation &Loc) const;
484484

485485
/// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a
486486
/// storage location in the environment, otherwise returns null.
487+
///
488+
/// Requirements:
489+
///
490+
/// `D` must not have record type.
487491
Value *getValue(const ValueDecl &D) const;
488492

489493
/// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a
@@ -811,12 +815,6 @@ class RecordInitListHelper {
811815
std::optional<ImplicitValueInitExpr> ImplicitValueInitForUnion;
812816
};
813817

814-
/// Associates a new `RecordValue` with `Loc` and returns the new value.
815-
RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env);
816-
817-
/// Associates a new `RecordValue` with `Expr` and returns the new value.
818-
RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env);
819-
820818
} // namespace dataflow
821819
} // namespace clang
822820

clang/include/clang/Analysis/FlowSensitive/Value.h

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ class Value {
3535
enum class Kind {
3636
Integer,
3737
Pointer,
38-
Record,
3938

4039
// TODO: Top values should not be need to be type-specific.
4140
TopBool,
@@ -67,7 +66,6 @@ class Value {
6766
/// Properties may not be set on `RecordValue`s; use synthetic fields instead
6867
/// (for details, see documentation for `RecordStorageLocation`).
6968
void setProperty(llvm::StringRef Name, Value &Val) {
70-
assert(getKind() != Kind::Record);
7169
Properties.insert_or_assign(Name, &Val);
7270
}
7371

@@ -184,45 +182,6 @@ class PointerValue final : public Value {
184182
StorageLocation &PointeeLoc;
185183
};
186184

187-
/// Models a value of `struct` or `class` type.
188-
/// In C++, prvalues of class type serve only a limited purpose: They can only
189-
/// be used to initialize a result object. It is not possible to access member
190-
/// variables or call member functions on a prvalue of class type.
191-
/// Correspondingly, `RecordValue` also serves only a limited purpose: It
192-
/// conveys a prvalue of class type from the place where the object is
193-
/// constructed to the result object that it initializes.
194-
///
195-
/// When creating a prvalue of class type, we already need a storage location
196-
/// for `this`, even though prvalues are otherwise not associated with storage
197-
/// locations. `RecordValue` is therefore essentially a wrapper for a storage
198-
/// location, which is then used to set the storage location for the result
199-
/// object when we process the AST node for that result object.
200-
///
201-
/// For example:
202-
/// MyStruct S = MyStruct(3);
203-
///
204-
/// In this example, `MyStruct(3) is a prvalue, which is modeled as a
205-
/// `RecordValue` that wraps a `RecordStorageLocation`. This
206-
/// `RecordStorageLocation` is then used as the storage location for `S`.
207-
///
208-
/// Over time, we may eliminate `RecordValue` entirely. See also the discussion
209-
/// here: https://reviews.llvm.org/D155204#inline-1503204
210-
class RecordValue final : public Value {
211-
public:
212-
explicit RecordValue(RecordStorageLocation &Loc)
213-
: Value(Kind::Record), Loc(Loc) {}
214-
215-
static bool classof(const Value *Val) {
216-
return Val->getKind() == Kind::Record;
217-
}
218-
219-
/// Returns the storage location that this `RecordValue` is associated with.
220-
RecordStorageLocation &getLoc() const { return Loc; }
221-
222-
private:
223-
RecordStorageLocation &Loc;
224-
};
225-
226185
raw_ostream &operator<<(raw_ostream &OS, const Value &Val);
227186

228187
} // namespace dataflow

clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Lines changed: 26 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/ADT/DenseSet.h"
2424
#include "llvm/ADT/MapVector.h"
2525
#include "llvm/ADT/STLExtras.h"
26+
#include "llvm/ADT/ScopeExit.h"
2627
#include "llvm/Support/ErrorHandling.h"
2728
#include <cassert>
2829
#include <utility>
@@ -79,7 +80,6 @@ static bool equateUnknownValues(Value::Kind K) {
7980
switch (K) {
8081
case Value::Kind::Integer:
8182
case Value::Kind::Pointer:
82-
case Value::Kind::Record:
8383
return true;
8484
default:
8585
return false;
@@ -144,25 +144,7 @@ static Value *joinDistinctValues(QualType Type, Value &Val1,
144144
return &A.makeBoolValue(JoinedVal);
145145
}
146146

147-
Value *JoinedVal = nullptr;
148-
if (auto *RecordVal1 = dyn_cast<RecordValue>(&Val1)) {
149-
auto *RecordVal2 = cast<RecordValue>(&Val2);
150-
151-
if (&RecordVal1->getLoc() == &RecordVal2->getLoc())
152-
// `RecordVal1` and `RecordVal2` may have different properties associated
153-
// with them. Create a new `RecordValue` with the same location but
154-
// without any properties so that we soundly approximate both values. If a
155-
// particular analysis needs to join properties, it should do so in
156-
// `DataflowAnalysis::join()`.
157-
JoinedVal = &JoinedEnv.create<RecordValue>(RecordVal1->getLoc());
158-
else
159-
// If the locations for the two records are different, need to create a
160-
// completely new value.
161-
JoinedVal = JoinedEnv.createValue(Type);
162-
} else {
163-
JoinedVal = JoinedEnv.createValue(Type);
164-
}
165-
147+
Value *JoinedVal = JoinedEnv.createValue(Type);
166148
if (JoinedVal)
167149
Model.join(Type, Val1, Env1, Val2, Env2, *JoinedVal, JoinedEnv);
168150

@@ -627,7 +609,6 @@ void Environment::initialize() {
627609
auto &ThisLoc =
628610
cast<RecordStorageLocation>(createStorageLocation(ThisPointeeType));
629611
setThisPointeeStorageLocation(ThisLoc);
630-
refreshRecordValue(ThisLoc, *this);
631612
// Initialize fields of `*this` with values, but only if we're not
632613
// analyzing a constructor; after all, it's the constructor's job to do
633614
// this (and we want to be able to test that).
@@ -794,10 +775,6 @@ void Environment::popCall(const CXXConstructExpr *Call,
794775
// See also comment in `popCall(const CallExpr *, const Environment &)` above.
795776
this->LocToVal = std::move(CalleeEnv.LocToVal);
796777
this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
797-
798-
if (Value *Val = CalleeEnv.getValue(*CalleeEnv.ThisPointeeLoc)) {
799-
setValue(*Call, *Val);
800-
}
801778
}
802779

803780
bool Environment::equivalentTo(const Environment &Other,
@@ -1021,24 +998,23 @@ void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,
1021998
}
1022999

10231000
void Environment::setValue(const StorageLocation &Loc, Value &Val) {
1024-
assert(!isa<RecordValue>(&Val) || &cast<RecordValue>(&Val)->getLoc() == &Loc);
1025-
1001+
// Records should not be associated with values.
1002+
assert(!isa<RecordStorageLocation>(Loc));
10261003
LocToVal[&Loc] = &Val;
10271004
}
10281005

10291006
void Environment::setValue(const Expr &E, Value &Val) {
10301007
const Expr &CanonE = ignoreCFGOmittedNodes(E);
10311008

1032-
if (auto *RecordVal = dyn_cast<RecordValue>(&Val)) {
1033-
assert(&RecordVal->getLoc() == &getResultObjectLocation(CanonE));
1034-
(void)RecordVal;
1035-
}
1036-
10371009
assert(CanonE.isPRValue());
1010+
// Records should not be associated with values.
1011+
assert(!CanonE.getType()->isRecordType());
10381012
ExprToVal[&CanonE] = &Val;
10391013
}
10401014

10411015
Value *Environment::getValue(const StorageLocation &Loc) const {
1016+
// Records should not be associated with values.
1017+
assert(!isa<RecordStorageLocation>(Loc));
10421018
return LocToVal.lookup(&Loc);
10431019
}
10441020

@@ -1050,6 +1026,9 @@ Value *Environment::getValue(const ValueDecl &D) const {
10501026
}
10511027

10521028
Value *Environment::getValue(const Expr &E) const {
1029+
// Records should not be associated with values.
1030+
assert(!E.getType()->isRecordType());
1031+
10531032
if (E.isPRValue()) {
10541033
auto It = ExprToVal.find(&ignoreCFGOmittedNodes(E));
10551034
return It == ExprToVal.end() ? nullptr : It->second;
@@ -1078,6 +1057,7 @@ Value *Environment::createValueUnlessSelfReferential(
10781057
int &CreatedValuesCount) {
10791058
assert(!Type.isNull());
10801059
assert(!Type->isReferenceType());
1060+
assert(!Type->isRecordType());
10811061

10821062
// Allow unlimited fields at depth 1; only cap at deeper nesting levels.
10831063
if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
@@ -1106,15 +1086,6 @@ Value *Environment::createValueUnlessSelfReferential(
11061086
return &arena().create<PointerValue>(PointeeLoc);
11071087
}
11081088

1109-
if (Type->isRecordType()) {
1110-
CreatedValuesCount++;
1111-
auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Type));
1112-
initializeFieldsWithValues(Loc, Loc.getType(), Visited, Depth,
1113-
CreatedValuesCount);
1114-
1115-
return &refreshRecordValue(Loc, *this);
1116-
}
1117-
11181089
return nullptr;
11191090
}
11201091

@@ -1124,20 +1095,23 @@ Environment::createLocAndMaybeValue(QualType Ty,
11241095
int Depth, int &CreatedValuesCount) {
11251096
if (!Visited.insert(Ty.getCanonicalType()).second)
11261097
return createStorageLocation(Ty.getNonReferenceType());
1127-
Value *Val = createValueUnlessSelfReferential(
1128-
Ty.getNonReferenceType(), Visited, Depth, CreatedValuesCount);
1129-
Visited.erase(Ty.getCanonicalType());
1098+
auto EraseVisited = llvm::make_scope_exit(
1099+
[&Visited, Ty] { Visited.erase(Ty.getCanonicalType()); });
11301100

11311101
Ty = Ty.getNonReferenceType();
11321102

1133-
if (Val == nullptr)
1134-
return createStorageLocation(Ty);
1135-
1136-
if (Ty->isRecordType())
1137-
return cast<RecordValue>(Val)->getLoc();
1103+
if (Ty->isRecordType()) {
1104+
auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Ty));
1105+
initializeFieldsWithValues(Loc, Ty, Visited, Depth, CreatedValuesCount);
1106+
return Loc;
1107+
}
11381108

11391109
StorageLocation &Loc = createStorageLocation(Ty);
1140-
setValue(Loc, *Val);
1110+
1111+
if (Value *Val = createValueUnlessSelfReferential(Ty, Visited, Depth,
1112+
CreatedValuesCount))
1113+
setValue(Loc, *Val);
1114+
11411115
return Loc;
11421116
}
11431117

@@ -1149,10 +1123,11 @@ void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,
11491123
auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
11501124
if (FieldType->isRecordType()) {
11511125
auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc);
1152-
setValue(FieldRecordLoc, create<RecordValue>(FieldRecordLoc));
11531126
initializeFieldsWithValues(FieldRecordLoc, FieldRecordLoc.getType(),
11541127
Visited, Depth + 1, CreatedValuesCount);
11551128
} else {
1129+
if (getValue(FieldLoc) != nullptr)
1130+
return;
11561131
if (!Visited.insert(FieldType.getCanonicalType()).second)
11571132
return;
11581133
if (Value *Val = createValueUnlessSelfReferential(
@@ -1210,7 +1185,6 @@ StorageLocation &Environment::createObjectInternal(const ValueDecl *D,
12101185
auto &RecordLoc = cast<RecordStorageLocation>(Loc);
12111186
if (!InitExpr)
12121187
initializeFieldsWithValues(RecordLoc);
1213-
refreshRecordValue(RecordLoc, *this);
12141188
} else {
12151189
Value *Val = nullptr;
12161190
if (InitExpr)
@@ -1407,25 +1381,5 @@ RecordInitListHelper::RecordInitListHelper(const InitListExpr *InitList) {
14071381
}
14081382
}
14091383

1410-
RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env) {
1411-
auto &NewVal = Env.create<RecordValue>(Loc);
1412-
Env.setValue(Loc, NewVal);
1413-
return NewVal;
1414-
}
1415-
1416-
RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env) {
1417-
assert(Expr.getType()->isRecordType());
1418-
1419-
if (Expr.isPRValue())
1420-
refreshRecordValue(Env.getResultObjectLocation(Expr), Env);
1421-
1422-
if (auto *Loc = Env.get<RecordStorageLocation>(Expr))
1423-
refreshRecordValue(*Loc, Env);
1424-
1425-
auto &NewVal = *cast<RecordValue>(Env.createValue(Expr.getType()));
1426-
Env.setStorageLocation(Expr, NewVal.getLoc());
1427-
return NewVal;
1428-
}
1429-
14301384
} // namespace dataflow
14311385
} // namespace clang

clang/lib/Analysis/FlowSensitive/DebugSupport.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ llvm::StringRef debugString(Value::Kind Kind) {
2828
return "Integer";
2929
case Value::Kind::Pointer:
3030
return "Pointer";
31-
case Value::Kind::Record:
32-
return "Record";
3331
case Value::Kind::AtomicBool:
3432
return "AtomicBool";
3533
case Value::Kind::TopBool:

0 commit comments

Comments
 (0)