forked from OSchip/llvm-project
[clang][dataflow] Do not crash on missing `Value` for struct-typed variable init.
Remove constraint that an initializing expression of struct type must have an associated `Value`. This invariant is not and will not be guaranteed by the framework, because of potentially uninitialized fields. Differential Revision: https://reviews.llvm.org/D123961
This commit is contained in:
parent
489894f363
commit
eb2131bdba
|
@ -168,27 +168,25 @@ public:
|
|||
auto &Val =
|
||||
Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc));
|
||||
Env.setValue(Loc, Val);
|
||||
} else {
|
||||
// FIXME: The initializer expression must always be assigned a value.
|
||||
// Replace this with an assert when we have sufficient coverage of
|
||||
// language features.
|
||||
if (Value *Val = Env.createValue(D.getType()))
|
||||
Env.setValue(Loc, *Val);
|
||||
return;
|
||||
}
|
||||
} else if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) {
|
||||
Env.setValue(Loc, *InitExprVal);
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) {
|
||||
Env.setValue(Loc, *InitExprVal);
|
||||
} else if (!D.getType()->isStructureOrClassType()) {
|
||||
// FIXME: The initializer expression must always be assigned a value.
|
||||
// Replace this with an assert when we have sufficient coverage of
|
||||
// language features.
|
||||
if (Value *Val = Env.createValue(D.getType()))
|
||||
Env.setValue(Loc, *Val);
|
||||
} else {
|
||||
llvm_unreachable("structs and classes must always be assigned values");
|
||||
}
|
||||
// We arrive here in (the few) cases where an expression is intentionally
|
||||
// "uninterpreted". There are two ways to handle this situation: propagate
|
||||
// the status, so that uninterpreted initializers result in uninterpreted
|
||||
// variables, or provide a default value. We choose the latter so that later
|
||||
// refinements of the variable can be used for reasoning about the
|
||||
// surrounding code.
|
||||
//
|
||||
// FIXME. If and when we interpret all language cases, change this to assert
|
||||
// that `InitExpr` is interpreted, rather than supplying a default value
|
||||
// (assuming we don't update the environment API to return references).
|
||||
if (Value *Val = Env.createValue(D.getType()))
|
||||
Env.setValue(Loc, *Val);
|
||||
}
|
||||
|
||||
void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
|
||||
|
|
|
@ -187,6 +187,54 @@ TEST_F(TransferTest, StructVarDecl) {
|
|||
});
|
||||
}
|
||||
|
||||
TEST_F(TransferTest, StructVarDeclWithInit) {
|
||||
std::string Code = R"(
|
||||
struct A {
|
||||
int Bar;
|
||||
};
|
||||
|
||||
A Gen();
|
||||
|
||||
void target() {
|
||||
A Foo = Gen();
|
||||
// [[p]]
|
||||
}
|
||||
)";
|
||||
runDataflow(
|
||||
Code, [](llvm::ArrayRef<
|
||||
std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
|
||||
Results,
|
||||
ASTContext &ASTCtx) {
|
||||
ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
|
||||
const Environment &Env = Results[0].second.Env;
|
||||
|
||||
const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
|
||||
ASSERT_THAT(FooDecl, NotNull());
|
||||
|
||||
ASSERT_TRUE(FooDecl->getType()->isStructureType());
|
||||
auto FooFields = FooDecl->getType()->getAsRecordDecl()->fields();
|
||||
|
||||
FieldDecl *BarDecl = nullptr;
|
||||
for (FieldDecl *Field : FooFields) {
|
||||
if (Field->getNameAsString() == "Bar") {
|
||||
BarDecl = Field;
|
||||
} else {
|
||||
FAIL() << "Unexpected field: " << Field->getNameAsString();
|
||||
}
|
||||
}
|
||||
ASSERT_THAT(BarDecl, NotNull());
|
||||
|
||||
const auto *FooLoc = cast<AggregateStorageLocation>(
|
||||
Env.getStorageLocation(*FooDecl, SkipPast::None));
|
||||
const auto *BarLoc =
|
||||
cast<ScalarStorageLocation>(&FooLoc->getChild(*BarDecl));
|
||||
|
||||
const auto *FooVal = cast<StructValue>(Env.getValue(*FooLoc));
|
||||
const auto *BarVal = cast<IntegerValue>(FooVal->getChild(*BarDecl));
|
||||
EXPECT_EQ(Env.getValue(*BarLoc), BarVal);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_F(TransferTest, ClassVarDecl) {
|
||||
std::string Code = R"(
|
||||
class A {
|
||||
|
|
Loading…
Reference in New Issue