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 @@ -251,6 +251,18 @@ } } + void VisitFullExpr(const FullExpr *S) { + assert(S->getSubExpr() != nullptr); + const Expr *SubExpr = S->getSubExpr()->IgnoreParens(); + assert(SubExpr != nullptr); + + auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); + if (SubExprLoc == nullptr) + return; + + Env.setStorageLocation(*S, *SubExprLoc); + } + void VisitUnaryOperator(const UnaryOperator *S) { // The CFG does not contain `ParenExpr` as top-level statements in basic // blocks, however sub-expressions can still be of that type. diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -77,26 +77,26 @@ : StmtToEnv(StmtToEnv), Env(Env), BlockSuccIdx(BlockSuccIdx) {} void VisitIfStmt(const IfStmt *S) { - auto *Cond = S->getCond()->IgnoreParenImpCasts(); + auto *Cond = S->getCond()->IgnoreParens(); assert(Cond != nullptr); extendFlowCondition(*Cond); } void VisitWhileStmt(const WhileStmt *S) { - auto *Cond = S->getCond()->IgnoreParenImpCasts(); + auto *Cond = S->getCond()->IgnoreParens(); assert(Cond != nullptr); extendFlowCondition(*Cond); } void VisitBinaryOperator(const BinaryOperator *S) { assert(S->getOpcode() == BO_LAnd || S->getOpcode() == BO_LOr); - auto *LHS = S->getLHS()->IgnoreParenImpCasts(); + auto *LHS = S->getLHS()->IgnoreParens(); assert(LHS != nullptr); extendFlowCondition(*LHS); } void VisitConditionalOperator(const ConditionalOperator *S) { - auto *Cond = S->getCond()->IgnoreParenImpCasts(); + auto *Cond = S->getCond()->IgnoreParens(); assert(Cond != nullptr); extendFlowCondition(*Cond); } diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -1152,4 +1152,39 @@ }); } +// FIXME: Remove this test once it provides no additional test coverage. +TEST_F(FlowConditionTest, DoesNotAssertForImplicitCastToBool) { + std::string Code = R"( + void target(int *Ptr) { + bool Foo = false; + if (Ptr) { + Foo = true; + /*[[p1]]*/ + } + + (void)0; + /*[[p2]]*/ + } + )"; + runDataflow( + Code, [](llvm::ArrayRef< + std::pair>> + Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results, ElementsAre(Pair("p2", _), Pair("p1", _))); + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + const Environment &Env1 = Results[1].second.Env; + auto &FooVal1 = + *cast(Env1.getValue(*FooDecl, SkipPast::Reference)); + EXPECT_TRUE(Env1.flowConditionImplies(FooVal1)); + + const Environment &Env2 = Results[0].second.Env; + auto &FooVal2 = + *cast(Env2.getValue(*FooDecl, SkipPast::Reference)); + EXPECT_FALSE(Env2.flowConditionImplies(FooVal2)); + }); +} + } // namespace