diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -205,13 +205,14 @@ // /// Builds and returns the logical formula defining the flow condition /// identified by `Token`. If a value in the formula is present as a key in - /// `Substitutions`, it will be substituted with the value it maps to. + /// `Substitutions`, and it is not a True/False boolean literal, it will be + /// substituted with the value it maps to. /// As an example, say we have flow condition tokens FC1, FC2, FC3 and /// FlowConditionConstraints: { FC1: C1, - /// FC2: C2, + /// FC2: C2 ^ True, /// FC3: (FC1 v FC2) ^ C3 } - /// buildAndSubstituteFlowCondition(FC3, {{C1 -> C1'}}) will return a value - /// corresponding to (C1' v C2) ^ C3. + /// buildAndSubstituteFlowCondition(FC3, {{C1 -> C1', True -> _ }}) will + /// return a value corresponding to (C1' v (C2 ^ True)) ^ C3. BoolValue &buildAndSubstituteFlowCondition( AtomicBoolValue &Token, llvm::DenseMap Substitutions); diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -172,10 +172,20 @@ BoolValue &DataflowAnalysisContext::substituteBoolValue( BoolValue &Val, llvm::DenseMap &SubstitutionsCache) { + if (&Val == &getBoolLiteralValue(true) || + &Val == &getBoolLiteralValue(false)) { + // Don't substitute boolean values representing true / false. + return Val; + } + auto IT = SubstitutionsCache.find(&Val); if (IT != SubstitutionsCache.end()) { + // Return memoized result of substituting this boolean value. return *IT->second; } + + // Handle substitution on the boolean value (and its subvalues), saving the + // result into `SubstitutionsCache`. BoolValue *Result; switch (Val.getKind()) { case Value::Kind::AtomicBool: { diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowAnalysisContextTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowAnalysisContextTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/DataflowAnalysisContextTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DataflowAnalysisContextTest.cpp @@ -276,6 +276,38 @@ Context.getOrCreateConjunction(X, Context.getOrCreateConjunction(Y, Z)))); } +TEST_F(DataflowAnalysisContextTest, SubstituteFlowConditionsTrueUnchanged) { + auto &True = Context.getBoolLiteralValue(true); + auto &Other = Context.createAtomicBoolValue(); + + // FC = True + auto &FC = Context.makeFlowConditionToken(); + Context.addFlowConditionConstraint(FC, True); + + // `True` should never be substituted + auto &FCNoSubstitution = Context.buildAndSubstituteFlowCondition(FC, {{}}); + auto &FCTrySubstituteTrue = + Context.buildAndSubstituteFlowCondition(FC, {{&True, &Other}}); + EXPECT_TRUE( + Context.equivalentBoolValues(FCNoSubstitution, FCTrySubstituteTrue)); +} + +TEST_F(DataflowAnalysisContextTest, SubstituteFlowConditionsFalseUnchanged) { + auto &False = Context.getBoolLiteralValue(false); + auto &Other = Context.createAtomicBoolValue(); + + // FC = False + auto &FC = Context.makeFlowConditionToken(); + Context.addFlowConditionConstraint(FC, False); + + // `False` should never be substituted + auto &FCNoSubstitution = Context.buildAndSubstituteFlowCondition(FC, {{}}); + auto &FCTrySubstituteFalse = + Context.buildAndSubstituteFlowCondition(FC, {{&False, &Other}}); + EXPECT_TRUE( + Context.equivalentBoolValues(FCNoSubstitution, FCTrySubstituteFalse)); +} + TEST_F(DataflowAnalysisContextTest, SubstituteFlowConditionsAtomicFC) { auto &X = Context.createAtomicBoolValue(); auto &True = Context.getBoolLiteralValue(true);