Skip to content

Commit 1f6741c

Browse files
authored
[clang][dataflow] Don't clear cached field state if field is const (#113698)
... in the unchecked optional access model.
1 parent bd6ab32 commit 1f6741c

File tree

2 files changed

+28
-3
lines changed

2 files changed

+28
-3
lines changed

clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -601,10 +601,14 @@ void handleNonConstMemberCall(const CallExpr *CE,
601601
dataflow::RecordStorageLocation *RecordLoc,
602602
const MatchFinder::MatchResult &Result,
603603
LatticeTransferState &State) {
604-
// When a non-const member function is called, reset some state.
605604
if (RecordLoc != nullptr) {
605+
// When a non-const member function is called, clear all (non-const)
606+
// optional fields of the receiver. Const-qualified fields can't be
607+
// changed (at least, not without UB).
606608
for (const auto &[Field, FieldLoc] : RecordLoc->children()) {
607-
if (isSupportedOptionalType(Field->getType())) {
609+
QualType FieldType = Field->getType();
610+
if (!FieldType.isConstQualified() &&
611+
isSupportedOptionalType(Field->getType())) {
608612
auto *FieldRecordLoc = cast_or_null<RecordStorageLocation>(FieldLoc);
609613
if (FieldRecordLoc) {
610614
setHasValue(*FieldRecordLoc, State.Env.makeAtomicBoolValue(),

clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2167,7 +2167,7 @@ TEST_P(UncheckedOptionalAccessTest, OptionalReturnedFromFuntionCall) {
21672167
)");
21682168
}
21692169

2170-
TEST_P(UncheckedOptionalAccessTest, OptionalFieldModified) {
2170+
TEST_P(UncheckedOptionalAccessTest, NonConstMethodMayClearOptionalField) {
21712171
ExpectDiagnosticsFor(
21722172
R"(
21732173
#include "unchecked_optional_access_test.h"
@@ -2187,6 +2187,27 @@ TEST_P(UncheckedOptionalAccessTest, OptionalFieldModified) {
21872187
)");
21882188
}
21892189

2190+
TEST_P(UncheckedOptionalAccessTest,
2191+
NonConstMethodMayNotClearConstOptionalField) {
2192+
ExpectDiagnosticsFor(
2193+
R"(
2194+
#include "unchecked_optional_access_test.h"
2195+
2196+
struct Foo {
2197+
const $ns::$optional<std::string> opt;
2198+
void clear();
2199+
};
2200+
2201+
void target(Foo& foo) {
2202+
if (foo.opt) {
2203+
foo.opt.value();
2204+
foo.clear();
2205+
foo.opt.value();
2206+
}
2207+
}
2208+
)");
2209+
}
2210+
21902211
TEST_P(UncheckedOptionalAccessTest, StdSwap) {
21912212
ExpectDiagnosticsFor(
21922213
R"(

0 commit comments

Comments
 (0)