diff options
author | Martin Braenne <mboehme@google.com> | 2023-05-12 11:59:21 +0000 |
---|---|---|
committer | Martin Braenne <mboehme@google.com> | 2023-05-15 04:33:29 +0000 |
commit | 48bc71505e03694caac6afb2431ff1157a2382a8 (patch) | |
tree | f5980e02f7cad79ef631df124ab81819901ee5ef /clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp | |
parent | 47f5c54f997a59bb2c65abe6b8b811f6e7553456 (diff) | |
download | llvm-48bc71505e03694caac6afb2431ff1157a2382a8.zip llvm-48bc71505e03694caac6afb2431ff1157a2382a8.tar.gz llvm-48bc71505e03694caac6afb2431ff1157a2382a8.tar.bz2 |
[clang][dataflow] Eliminate `SkipPast::ReferenceThenPointer`.
As a replacement, we provide the accessors `getImplicitObjectLocation()` and
`getBaseObjectLocation()`, which are higher-level constructs that cover the use
cases in which `SkipPast::ReferenceThenPointer` was typically used.
Unfortunately, it isn't possible to use these accessors in
UncheckedOptionalAccessModel.cpp; I've added a FIXME to the code explaining the
details. I initially attempted to resolve the issue as part of this patch, but
it turned out to be non-trivial to fix. Instead, I have therefore added a
lower-level replacement for `SkipPast::ReferenceThenPointer` that is used only
within this file.
The wider context of this change is that `SkipPast` will be going away entirely.
See also the RFC at https://discourse.llvm.org/t/70086.
Reviewed By: ymandel, gribozavr2
Differential Revision: https://reviews.llvm.org/D149838
Diffstat (limited to 'clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp')
-rw-r--r-- | clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp | 59 |
1 files changed, 44 insertions, 15 deletions
diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index e306b55..b46a57f 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -372,10 +372,26 @@ bool isNonEmptyOptional(const Value &OptionalVal, const Environment &Env) { return HasValueVal != nullptr && Env.flowConditionImplies(*HasValueVal); } +StorageLocation *maybeSkipPointer(StorageLocation *Loc, + const Environment &Env) { + if (Loc == nullptr) + return nullptr; + if (auto *Val = dyn_cast_or_null<PointerValue>(Env.getValue(*Loc))) + return &Val->getPointeeLoc(); + return Loc; +} + +Value *getValueBehindPossiblePointer(const Expr &E, const Environment &Env) { + Value *Val = Env.getValue(E, SkipPast::Reference); + if (auto *PointerVal = dyn_cast_or_null<PointerValue>(Val)) + return Env.getValue(PointerVal->getPointeeLoc()); + return Val; +} + void transferUnwrapCall(const Expr *UnwrapExpr, const Expr *ObjectExpr, LatticeTransferState &State) { if (auto *OptionalVal = - State.Env.getValue(*ObjectExpr, SkipPast::ReferenceThenPointer)) { + getValueBehindPossiblePointer(*ObjectExpr, State.Env)) { if (State.Env.getStorageLocation(*UnwrapExpr, SkipPast::None) == nullptr) if (auto *Loc = maybeInitializeOptionalValueMember( UnwrapExpr->getType(), *OptionalVal, State.Env)) @@ -396,8 +412,8 @@ void transferOptionalHasValueCall(const CXXMemberCallExpr *CallExpr, const MatchFinder::MatchResult &, LatticeTransferState &State) { if (auto *HasValueVal = getHasValue( - State.Env, State.Env.getValue(*CallExpr->getImplicitObjectArgument(), - SkipPast::ReferenceThenPointer))) { + State.Env, getValueBehindPossiblePointer( + *CallExpr->getImplicitObjectArgument(), State.Env))) { auto &CallExprLoc = State.Env.createStorageLocation(*CallExpr); State.Env.setValue(CallExprLoc, *HasValueVal); State.Env.setStorageLocation(*CallExpr, CallExprLoc); @@ -419,8 +435,7 @@ void transferValueOrImpl(const clang::Expr *ValueOrPredExpr, ->getImplicitObjectArgument(); auto *HasValueVal = getHasValue( - State.Env, - State.Env.getValue(*ObjectArgumentExpr, SkipPast::ReferenceThenPointer)); + State.Env, getValueBehindPossiblePointer(*ObjectArgumentExpr, State.Env)); if (HasValueVal == nullptr) return; @@ -472,8 +487,8 @@ void transferCallReturningOptional(const CallExpr *E, void assignOptionalValue(const Expr &E, Environment &Env, BoolValue &HasValueVal) { - if (auto *OptionalLoc = - Env.getStorageLocation(E, SkipPast::ReferenceThenPointer)) { + if (auto *OptionalLoc = maybeSkipPointer( + Env.getStorageLocation(E, SkipPast::Reference), Env)) { Env.setValue(*OptionalLoc, createOptionalValue(Env, HasValueVal)); } } @@ -550,13 +565,11 @@ void transferNulloptAssignment(const CXXOperatorCallExpr *E, transferAssignment(E, State.Env.getBoolLiteralValue(false), State); } -void transferSwap(const Expr &E1, SkipPast E1Skip, const Expr &E2, +void transferSwap(StorageLocation *Loc1, StorageLocation *Loc2, Environment &Env) { // We account for cases where one or both of the optionals are not modeled, // either lacking associated storage locations, or lacking values associated // to such storage locations. - auto *Loc1 = Env.getStorageLocation(E1, E1Skip); - auto *Loc2 = Env.getStorageLocation(E2, SkipPast::Reference); if (Loc1 == nullptr) { if (Loc2 != nullptr) @@ -590,14 +603,20 @@ void transferSwapCall(const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, LatticeTransferState &State) { assert(E->getNumArgs() == 1); - transferSwap(*E->getImplicitObjectArgument(), SkipPast::ReferenceThenPointer, - *E->getArg(0), State.Env); + transferSwap(maybeSkipPointer( + State.Env.getStorageLocation(*E->getImplicitObjectArgument(), + SkipPast::Reference), + State.Env), + State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference), + State.Env); } void transferStdSwapCall(const CallExpr *E, const MatchFinder::MatchResult &, LatticeTransferState &State) { assert(E->getNumArgs() == 2); - transferSwap(*E->getArg(0), SkipPast::Reference, *E->getArg(1), State.Env); + transferSwap(State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference), + State.Env.getStorageLocation(*E->getArg(1), SkipPast::Reference), + State.Env); } void transferStdForwardCall(const CallExpr *E, const MatchFinder::MatchResult &, @@ -756,6 +775,17 @@ auto buildTransferMatchSwitch() { }) // optional::operator*, optional::operator-> + // FIXME: This does something slightly strange for `operator->`. + // `transferUnwrapCall()` may create a new value of type `T` for the + // `optional<T>`, and it associates that value with `E`. In the case of + // `operator->`, `E` is a pointer. As a result, we associate an + // expression of pointer type with a storage location of non-pointer type + // `T`. This can confound other code that expects expressions of + // pointer type to be associated with `PointerValue`s, such as the + // centrally provided accessors `getImplicitObjectLocation()` and + // `getBaseObjectLocation()`, and this is the reason we need to use our + // own 'maybeSkipPointer()` and `getValueBehindPossiblePointer()` instead + // of these accessors. .CaseOfCFGStmt<CallExpr>(valueOperatorCall(std::nullopt), [](const CallExpr *E, const MatchFinder::MatchResult &, @@ -837,8 +867,7 @@ auto buildTransferMatchSwitch() { std::vector<SourceLocation> diagnoseUnwrapCall(const Expr *UnwrapExpr, const Expr *ObjectExpr, const Environment &Env) { - if (auto *OptionalVal = - Env.getValue(*ObjectExpr, SkipPast::ReferenceThenPointer)) { + if (auto *OptionalVal = getValueBehindPossiblePointer(*ObjectExpr, Env)) { auto *Prop = OptionalVal->getProperty("has_value"); if (auto *HasValueVal = cast_or_null<BoolValue>(Prop)) { if (Env.flowConditionImplies(*HasValueVal)) |