diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -429,6 +429,9 @@ } void VisitReturnStmt(const ReturnStmt *S) { + if (!Options.ContextSensitiveOpts) + return; + auto *Ret = S->getRetValue(); if (Ret == nullptr) return; @@ -443,6 +446,10 @@ auto *Loc = Env.getReturnStorageLocation(); assert(Loc != nullptr); + // FIXME: Support reference-type returns. + if (Loc->getType()->isReferenceType()) + return; + // FIXME: Model NRVO. Env.setValue(*Loc, *Val); } diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -4018,6 +4018,35 @@ {TransferOptions{/*.ContextSensitiveOpts=*/std::nullopt}}); } +// This test is a regression test, based on a real crash. +TEST(TransferTest, ContextSensitiveReturnReferenceFromNonReferenceLvalue) { + // This code exercises an unusual code path. If we return an lvalue directly, + // the code will catch that it's an l-value based on the `Value`'s kind. If we + // pass through a dummy function, the framework won't populate a value at + // all. In contrast, this code results in a (fresh) value, but it is not + // `ReferenceValue`. This test verifies that we catch this case as well. + std::string Code = R"( + class S {}; + S& target(bool b, S &s) { + return b ? s : s; + // [[p]] + } + )"; + runDataflow( + Code, + [](const llvm::StringMap> &Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results.keys(), UnorderedElementsAre("p")); + const Environment &Env = getEnvironmentAtAnnotation(Results, "p"); + + auto *Loc = Env.getReturnStorageLocation(); + ASSERT_THAT(Loc, NotNull()); + + EXPECT_THAT(Env.getValue(*Loc), IsNull()); + }, + {TransferOptions{ContextSensitiveOptions{}}}); +} + TEST(TransferTest, ContextSensitiveDepthZero) { std::string Code = R"( bool GiveBool();