Skip to content

Commit c4e9463

Browse files
authored
Revert "[clang][dataflow] Correctly handle InitListExpr of union type." (#82856)
Reverts #82348, which caused crashes when analyzing empty InitListExprs for unions, e.g. ```cc union U { double double_value; int int_value; }; void target() { U value; value = {}; } ``` Co-authored-by: Samira Bazuzi <[email protected]>
1 parent 96e536e commit c4e9463

File tree

5 files changed

+20
-65
lines changed

5 files changed

+20
-65
lines changed

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -753,12 +753,9 @@ RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
753753
RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
754754
const Environment &Env);
755755

756-
/// Returns the fields of a `RecordDecl` that are initialized by an
757-
/// `InitListExpr`, in the order in which they appear in
758-
/// `InitListExpr::inits()`.
759-
/// `Init->getType()` must be a record type.
760-
std::vector<const FieldDecl *>
761-
getFieldsForInitListExpr(const InitListExpr *InitList);
756+
/// Returns the fields of `RD` that are initialized by an `InitListExpr`, in the
757+
/// order in which they appear in `InitListExpr::inits()`.
758+
std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD);
762759

763760
/// Associates a new `RecordValue` with `Loc` and returns the new value.
764761
RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env);

clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,8 @@ getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields,
361361
if (const auto *FD = dyn_cast<FieldDecl>(VD))
362362
Fields.insert(FD);
363363
} else if (auto *InitList = dyn_cast<InitListExpr>(&S)) {
364-
if (InitList->getType()->isRecordType())
365-
for (const auto *FD : getFieldsForInitListExpr(InitList))
364+
if (RecordDecl *RD = InitList->getType()->getAsRecordDecl())
365+
for (const auto *FD : getFieldsForInitListExpr(RD))
366366
Fields.insert(FD);
367367
}
368368
}
@@ -1104,22 +1104,12 @@ RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
11041104
return Env.get<RecordStorageLocation>(*Base);
11051105
}
11061106

1107-
std::vector<const FieldDecl *>
1108-
getFieldsForInitListExpr(const InitListExpr *InitList) {
1109-
const RecordDecl *RD = InitList->getType()->getAsRecordDecl();
1110-
assert(RD != nullptr);
1111-
1112-
std::vector<const FieldDecl *> Fields;
1113-
1114-
if (InitList->getType()->isUnionType()) {
1115-
Fields.push_back(InitList->getInitializedFieldInUnion());
1116-
return Fields;
1117-
}
1118-
1107+
std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD) {
11191108
// Unnamed bitfields are only used for padding and do not appear in
11201109
// `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s
11211110
// field list, and we thus need to remove them before mapping inits to
11221111
// fields to avoid mapping inits to the wrongs fields.
1112+
std::vector<FieldDecl *> Fields;
11231113
llvm::copy_if(
11241114
RD->fields(), std::back_inserter(Fields),
11251115
[](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); });

clang/lib/Analysis/FlowSensitive/Transfer.cpp

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,14 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
663663
void VisitInitListExpr(const InitListExpr *S) {
664664
QualType Type = S->getType();
665665

666-
if (!Type->isRecordType()) {
666+
if (Type->isUnionType()) {
667+
// FIXME: Initialize unions properly.
668+
if (auto *Val = Env.createValue(Type))
669+
Env.setValue(*S, *Val);
670+
return;
671+
}
672+
673+
if (!Type->isStructureOrClassType()) {
667674
// Until array initialization is implemented, we don't need to care about
668675
// cases where `getNumInits() > 1`.
669676
if (S->getNumInits() == 1)
@@ -681,9 +688,10 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
681688
llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
682689

683690
// This only contains the direct fields for the given type.
684-
std::vector<const FieldDecl *> FieldsForInit = getFieldsForInitListExpr(S);
691+
std::vector<FieldDecl *> FieldsForInit =
692+
getFieldsForInitListExpr(Type->getAsRecordDecl());
685693

686-
// `S->inits()` contains all the initializer expressions, including the
694+
// `S->inits()` contains all the initializer epressions, including the
687695
// ones for direct base classes.
688696
auto Inits = S->inits();
689697
size_t InitIdx = 0;
@@ -723,17 +731,6 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
723731
FieldLocs.insert({Field, &Loc});
724732
}
725733

726-
// In the case of a union, we don't in general have initializers for all
727-
// of the fields. Create storage locations for the remaining fields (but
728-
// don't associate them with values).
729-
if (Type->isUnionType()) {
730-
for (const FieldDecl *Field :
731-
Env.getDataflowAnalysisContext().getModeledFields(Type)) {
732-
if (auto [it, inserted] = FieldLocs.insert({Field, nullptr}); inserted)
733-
it->second = &Env.createStorageLocation(Field->getType());
734-
}
735-
}
736-
737734
// Check that we satisfy the invariant that a `RecordStorageLoation`
738735
// contains exactly the set of modeled fields for that type.
739736
// `ModeledFields` includes fields from all the bases, but only the

clang/unittests/Analysis/FlowSensitive/TestingSupport.h

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -432,8 +432,6 @@ llvm::Error checkDataflowWithNoopAnalysis(
432432
{});
433433

434434
/// Returns the `ValueDecl` for the given identifier.
435-
/// The returned pointer is guaranteed to be non-null; the function asserts if
436-
/// no `ValueDecl` with the given name is found.
437435
///
438436
/// Requirements:
439437
///
@@ -477,15 +475,6 @@ ValueT &getValueForDecl(ASTContext &ASTCtx, const Environment &Env,
477475
return *cast<ValueT>(Env.getValue(*VD));
478476
}
479477

480-
/// Returns the storage location for the field called `Name` of `Loc`.
481-
/// Optionally casts the field storage location to `T`.
482-
template <typename T = StorageLocation>
483-
std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T &>
484-
getFieldLoc(const RecordStorageLocation &Loc, llvm::StringRef Name,
485-
ASTContext &ASTCtx) {
486-
return *cast<T>(Loc.getChild(*findValueDecl(ASTCtx, Name)));
487-
}
488-
489478
/// Returns the value of a `Field` on the record referenced by `Loc.`
490479
/// Returns null if `Loc` is null.
491480
inline Value *getFieldValue(const RecordStorageLocation *Loc,
@@ -498,14 +487,6 @@ inline Value *getFieldValue(const RecordStorageLocation *Loc,
498487
return Env.getValue(*FieldLoc);
499488
}
500489

501-
/// Returns the value of a `Field` on the record referenced by `Loc.`
502-
/// Returns null if `Loc` is null.
503-
inline Value *getFieldValue(const RecordStorageLocation *Loc,
504-
llvm::StringRef Name, ASTContext &ASTCtx,
505-
const Environment &Env) {
506-
return getFieldValue(Loc, *findValueDecl(ASTCtx, Name), Env);
507-
}
508-
509490
/// Creates and owns constraints which are boolean values.
510491
class ConstraintContext {
511492
unsigned NextAtom = 0;

clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2377,24 +2377,14 @@ TEST(TransferTest, InitListExprAsUnion) {
23772377
} F;
23782378
23792379
public:
2380-
constexpr target() : F{nullptr} {
2381-
int *null = nullptr;
2382-
F.b; // Make sure we reference 'b' so it is modeled.
2383-
// [[p]]
2384-
}
2380+
constexpr target() : F{nullptr} {}
23852381
};
23862382
)cc";
23872383
runDataflow(
23882384
Code,
23892385
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
23902386
ASTContext &ASTCtx) {
2391-
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
2392-
2393-
auto &FLoc = getFieldLoc<RecordStorageLocation>(
2394-
*Env.getThisPointeeStorageLocation(), "F", ASTCtx);
2395-
auto *AVal = cast<PointerValue>(getFieldValue(&FLoc, "a", ASTCtx, Env));
2396-
ASSERT_EQ(AVal, &getValueForDecl<PointerValue>(ASTCtx, Env, "null"));
2397-
ASSERT_EQ(getFieldValue(&FLoc, "b", ASTCtx, Env), nullptr);
2387+
// Just verify that it doesn't crash.
23982388
});
23992389
}
24002390

0 commit comments

Comments
 (0)