Skip to content

Commit e8fce95

Browse files
authored
[clang][nullability] Remove RecordValue. (#89052)
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 b2323f4 commit e8fce95

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
@@ -775,12 +779,6 @@ RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
775779
RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
776780
const Environment &Env);
777781

778-
/// Associates a new `RecordValue` with `Loc` and returns the new value.
779-
RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env);
780-
781-
/// Associates a new `RecordValue` with `Expr` and returns the new value.
782-
RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env);
783-
784782
} // namespace dataflow
785783
} // namespace clang
786784

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
@@ -24,6 +24,7 @@
2424
#include "llvm/ADT/DenseSet.h"
2525
#include "llvm/ADT/MapVector.h"
2626
#include "llvm/ADT/STLExtras.h"
27+
#include "llvm/ADT/ScopeExit.h"
2728
#include "llvm/Support/ErrorHandling.h"
2829
#include <cassert>
2930
#include <utility>
@@ -80,7 +81,6 @@ static bool equateUnknownValues(Value::Kind K) {
8081
switch (K) {
8182
case Value::Kind::Integer:
8283
case Value::Kind::Pointer:
83-
case Value::Kind::Record:
8484
return true;
8585
default:
8686
return false;
@@ -145,25 +145,7 @@ static Value *joinDistinctValues(QualType Type, Value &Val1,
145145
return &A.makeBoolValue(JoinedVal);
146146
}
147147

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

@@ -565,7 +547,6 @@ void Environment::initialize() {
565547
auto &ThisLoc =
566548
cast<RecordStorageLocation>(createStorageLocation(ThisPointeeType));
567549
setThisPointeeStorageLocation(ThisLoc);
568-
refreshRecordValue(ThisLoc, *this);
569550
// Initialize fields of `*this` with values, but only if we're not
570551
// analyzing a constructor; after all, it's the constructor's job to do
571552
// this (and we want to be able to test that).
@@ -709,10 +690,6 @@ void Environment::popCall(const CXXConstructExpr *Call,
709690
// See also comment in `popCall(const CallExpr *, const Environment &)` above.
710691
this->LocToVal = std::move(CalleeEnv.LocToVal);
711692
this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
712-
713-
if (Value *Val = CalleeEnv.getValue(*CalleeEnv.ThisPointeeLoc)) {
714-
setValue(*Call, *Val);
715-
}
716693
}
717694

718695
bool Environment::equivalentTo(const Environment &Other,
@@ -936,24 +913,23 @@ void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,
936913
}
937914

938915
void Environment::setValue(const StorageLocation &Loc, Value &Val) {
939-
assert(!isa<RecordValue>(&Val) || &cast<RecordValue>(&Val)->getLoc() == &Loc);
940-
916+
// Records should not be associated with values.
917+
assert(!isa<RecordStorageLocation>(Loc));
941918
LocToVal[&Loc] = &Val;
942919
}
943920

944921
void Environment::setValue(const Expr &E, Value &Val) {
945922
const Expr &CanonE = ignoreCFGOmittedNodes(E);
946923

947-
if (auto *RecordVal = dyn_cast<RecordValue>(&Val)) {
948-
assert(&RecordVal->getLoc() == &getResultObjectLocation(CanonE));
949-
(void)RecordVal;
950-
}
951-
952924
assert(CanonE.isPRValue());
925+
// Records should not be associated with values.
926+
assert(!CanonE.getType()->isRecordType());
953927
ExprToVal[&CanonE] = &Val;
954928
}
955929

956930
Value *Environment::getValue(const StorageLocation &Loc) const {
931+
// Records should not be associated with values.
932+
assert(!isa<RecordStorageLocation>(Loc));
957933
return LocToVal.lookup(&Loc);
958934
}
959935

@@ -965,6 +941,9 @@ Value *Environment::getValue(const ValueDecl &D) const {
965941
}
966942

967943
Value *Environment::getValue(const Expr &E) const {
944+
// Records should not be associated with values.
945+
assert(!E.getType()->isRecordType());
946+
968947
if (E.isPRValue()) {
969948
auto It = ExprToVal.find(&ignoreCFGOmittedNodes(E));
970949
return It == ExprToVal.end() ? nullptr : It->second;
@@ -993,6 +972,7 @@ Value *Environment::createValueUnlessSelfReferential(
993972
int &CreatedValuesCount) {
994973
assert(!Type.isNull());
995974
assert(!Type->isReferenceType());
975+
assert(!Type->isRecordType());
996976

997977
// Allow unlimited fields at depth 1; only cap at deeper nesting levels.
998978
if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
@@ -1021,15 +1001,6 @@ Value *Environment::createValueUnlessSelfReferential(
10211001
return &arena().create<PointerValue>(PointeeLoc);
10221002
}
10231003

1024-
if (Type->isRecordType()) {
1025-
CreatedValuesCount++;
1026-
auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Type));
1027-
initializeFieldsWithValues(Loc, Loc.getType(), Visited, Depth,
1028-
CreatedValuesCount);
1029-
1030-
return &refreshRecordValue(Loc, *this);
1031-
}
1032-
10331004
return nullptr;
10341005
}
10351006

@@ -1039,20 +1010,23 @@ Environment::createLocAndMaybeValue(QualType Ty,
10391010
int Depth, int &CreatedValuesCount) {
10401011
if (!Visited.insert(Ty.getCanonicalType()).second)
10411012
return createStorageLocation(Ty.getNonReferenceType());
1042-
Value *Val = createValueUnlessSelfReferential(
1043-
Ty.getNonReferenceType(), Visited, Depth, CreatedValuesCount);
1044-
Visited.erase(Ty.getCanonicalType());
1013+
auto EraseVisited = llvm::make_scope_exit(
1014+
[&Visited, Ty] { Visited.erase(Ty.getCanonicalType()); });
10451015

10461016
Ty = Ty.getNonReferenceType();
10471017

1048-
if (Val == nullptr)
1049-
return createStorageLocation(Ty);
1050-
1051-
if (Ty->isRecordType())
1052-
return cast<RecordValue>(Val)->getLoc();
1018+
if (Ty->isRecordType()) {
1019+
auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Ty));
1020+
initializeFieldsWithValues(Loc, Ty, Visited, Depth, CreatedValuesCount);
1021+
return Loc;
1022+
}
10531023

10541024
StorageLocation &Loc = createStorageLocation(Ty);
1055-
setValue(Loc, *Val);
1025+
1026+
if (Value *Val = createValueUnlessSelfReferential(Ty, Visited, Depth,
1027+
CreatedValuesCount))
1028+
setValue(Loc, *Val);
1029+
10561030
return Loc;
10571031
}
10581032

@@ -1064,10 +1038,11 @@ void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,
10641038
auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
10651039
if (FieldType->isRecordType()) {
10661040
auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc);
1067-
setValue(FieldRecordLoc, create<RecordValue>(FieldRecordLoc));
10681041
initializeFieldsWithValues(FieldRecordLoc, FieldRecordLoc.getType(),
10691042
Visited, Depth + 1, CreatedValuesCount);
10701043
} else {
1044+
if (getValue(FieldLoc) != nullptr)
1045+
return;
10711046
if (!Visited.insert(FieldType.getCanonicalType()).second)
10721047
return;
10731048
if (Value *Val = createValueUnlessSelfReferential(
@@ -1125,7 +1100,6 @@ StorageLocation &Environment::createObjectInternal(const ValueDecl *D,
11251100
auto &RecordLoc = cast<RecordStorageLocation>(Loc);
11261101
if (!InitExpr)
11271102
initializeFieldsWithValues(RecordLoc);
1128-
refreshRecordValue(RecordLoc, *this);
11291103
} else {
11301104
Value *Val = nullptr;
11311105
if (InitExpr)
@@ -1264,25 +1238,5 @@ RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
12641238
return Env.get<RecordStorageLocation>(*Base);
12651239
}
12661240

1267-
RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env) {
1268-
auto &NewVal = Env.create<RecordValue>(Loc);
1269-
Env.setValue(Loc, NewVal);
1270-
return NewVal;
1271-
}
1272-
1273-
RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env) {
1274-
assert(Expr.getType()->isRecordType());
1275-
1276-
if (Expr.isPRValue())
1277-
refreshRecordValue(Env.getResultObjectLocation(Expr), Env);
1278-
1279-
if (auto *Loc = Env.get<RecordStorageLocation>(Expr))
1280-
refreshRecordValue(*Loc, Env);
1281-
1282-
auto &NewVal = *cast<RecordValue>(Env.createValue(Expr.getType()));
1283-
Env.setStorageLocation(Expr, NewVal.getLoc());
1284-
return NewVal;
1285-
}
1286-
12871241
} // namespace dataflow
12881242
} // 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)