[PATCH] check for Incorrect logic in operator

Richard Smith richard at metafoo.co.uk
Fri Dec 13 10:18:43 PST 2013


On Thu, Dec 12, 2013 at 7:02 PM, Richard Trieu <rtrieu at google.com> wrote:

>
>
>
> On Wed, Dec 11, 2013 at 3:59 AM, Anders Rönnholm <
> Anders.Ronnholm at evidente.se> wrote:
>
>>  Hi,
>>
>>
>>
>> I haven’t received any comments on this patch. Is anyone reviewing it?
>>
>>
>>
>> //Anders
>>
>>
>>
>> *From:* Anders Rönnholm
>> *Sent:* den 21 november 2013 08:52
>> *To:* 'Anna Zaks'; Richard Trieu
>> *Cc:* Jordan Rose; Ted Kremenek; cfe-commits at cs.uiuc.edu
>> *Subject:* RE: [PATCH] check for Incorrect logic in operator
>>
>>
>>
>> Hi,
>>
>>
>>
>> Here is an updated patch I’d like to get reviewed. The warnings have been
>> moved to the unreachable-code  group, I hope that’s fine.
>>
>>
>>
>> Thanks,
>>
>> Anders
>>
>>
>>
>
> I don't like the warnings in the unreachable-code group, since in the
> always true case, it is the opposite of unreachable code.
>

The tautological comparison group makes more sense for this warning.


>  However, existing the existing warning groups that this would belong to
> are on by default, which typically exclude CFG warnings.
>

We can have some warnings in a group on by default and some off by default,
but this does suggest that we'd want a new warning subgroup for this
warning.


>  We may need a temporary solution until we merge the old and new warnings.
>
> Also, does your patch cause the unreachable-code warning to trigger in
> more cases now?
>
> More comments inline.
>
>  Index: lib/Analysis/CFG.cpp
> ===================================================================
> --- lib/Analysis/CFG.cpp (revision 194562)
> +++ lib/Analysis/CFG.cpp (working copy)
> @@ -483,6 +483,192 @@
>      B->addSuccessor(S, cfg->getBumpVectorContext());
>    }
>
> +  /// \brief Find a relational comparison with an expression evaluating
> to a
> +  /// boolean and a constant other than 0 and 1.
> +  /// e.g. if ((x < y) == 10)
> +  TryResult checkIncorrectRelationalOperator(const BinaryOperator *B) {
> +    const IntegerLiteral *IntLiteral =
> +        dyn_cast<IntegerLiteral>(B->getLHS()->IgnoreParens());
> +    const Expr *BoolExpr = B->getRHS()->IgnoreParens();
> +    bool IntFirst = true;
> +    if (!IntLiteral) {
> +      IntLiteral = dyn_cast<IntegerLiteral>(B->getRHS()->IgnoreParens());
> +      BoolExpr = B->getLHS()->IgnoreParens();
> +      IntFirst = false;
> +    }
> +
> +    if (!IntLiteral || !BoolExpr->isKnownToHaveBooleanValue())
> +      return TryResult();
> +
> +    llvm::APInt IntValue = IntLiteral->getValue();
> +    if ((IntValue != 1) && (IntValue != 0)) {
> +      BuildOpts.Observer->compareBoolWithInt(B);
>
>  Check that BuildOpts.Observer is not null before dereferencing.
>
> +      bool IntLarger = !IntValue.isNegative();
> +      BinaryOperatorKind Bok = B->getOpcode();
> +      if (Bok == BO_GT || Bok == BO_GE) {
> +        return TryResult(IntFirst != IntLarger);
> +      } else {
> +        return TryResult(IntFirst == IntLarger);
> +      }
> +    }
> +    return TryResult();
> +  }
> +
> +  /// Find a equality comparison with an expression evaluating to a
> boolean and
> +  /// a constant other than 0 and 1.
> +  /// e.g. if (!x == 10)
> +  TryResult checkIncorrectEqualityOperator(const BinaryOperator *B) {
> +    const IntegerLiteral *IntLiteral =
> +        dyn_cast<IntegerLiteral>(B->getLHS()->IgnoreParens());
> +    const Expr *BoolExpr = B->getRHS()->IgnoreParens();
> +
> +    if (!IntLiteral) {
> +      IntLiteral = dyn_cast<IntegerLiteral>(B->getRHS()->IgnoreParens());
> +      BoolExpr = B->getLHS()->IgnoreParens();
> +    }
> +
> +    if (!IntLiteral || !BoolExpr->isKnownToHaveBooleanValue())
> +      return TryResult();
> +
> +    llvm::APInt IntValue = IntLiteral->getValue();
> +    if ((IntValue != 1) && (IntValue != 0)) {
> +      BuildOpts.Observer->compareBoolWithInt(B);
> +      return TryResult(B->getOpcode() != BO_EQ);
> +    }
> +    return TryResult();
> +  }
> +
> +  bool analyzeLogicOperatorCondition(BinaryOperatorKind Relation,
> +                                     const llvm::APSInt Value1,
> +                                     const llvm::APSInt Value2) {
>
> A switch statement would be nicer here.  Also, add an assert that the two
> values have the same signedness and bit width.
>
> +    return (Relation == BO_EQ && (Value1 == Value2)) ||
> +           (Relation == BO_NE && (Value1 != Value2)) ||
> +           (Relation == BO_LT && (Value1 <  Value2)) ||
> +           (Relation == BO_LE && (Value1 <= Value2)) ||
> +           (Relation == BO_GT && (Value1 >  Value2)) ||
> +           (Relation == BO_GE && (Value1 >= Value2));
> +  }
> +
> +  /// \brief Find a pair of comparison expressions with or without
> parentheses
> +  /// with a shared variable and constants and a logical operator between
> them
> +  /// that always evaluates to either true or false.
> +  /// e.g. if (x != 3 || x != 4)
> +  TryResult checkIncorrectLogicOperator(const BinaryOperator *B) {
> +    const BinaryOperator *LHS =
> +        dyn_cast<BinaryOperator>(B->getLHS()->IgnoreParens());
> +    const BinaryOperator *RHS =
> +        dyn_cast<BinaryOperator>(B->getRHS()->IgnoreParens());
> +    if (!LHS || !RHS)
> +      return TryResult();
> +
> +    if (!LHS->isComparisonOp() || !RHS->isComparisonOp())
> +      return TryResult();
> +
>
> Instead of looking for an integer literal, see if the expression can be
> evaluated, and use that as the constant value.  This will allow things like
> 1+2 and -1.
>
> +    BinaryOperatorKind BO1 = LHS->getOpcode();
> +    const DeclRefExpr *Decl1 =
> +        dyn_cast<DeclRefExpr>(LHS->getLHS()->IgnoreParenImpCasts());
> +    const IntegerLiteral *Literal1 =
> +        dyn_cast<IntegerLiteral>(LHS->getRHS()->IgnoreParens());
> +
> +    if (!Decl1 && !Literal1) {
> +      if (BO1 == BO_GT)
> +        BO1 = BO_LT;
> +      else if (BO1 == BO_GE)
> +        BO1 = BO_LE;
> +      else if (BO1 == BO_LT)
> +        BO1 = BO_GT;
> +      else if (BO1 == BO_LE)
> +        BO1 = BO_GE;
> +      Decl1 =
> +          dyn_cast<DeclRefExpr>(LHS->getRHS()->IgnoreParenImpCasts());
> +      Literal1 = dyn_cast<IntegerLiteral>(LHS->getLHS()->IgnoreParens());
> +    }
> +
>  +    if (!Decl1 || !Literal1)
> +      return TryResult();
> +
> +    BinaryOperatorKind BO2 = RHS->getOpcode();
> +    const DeclRefExpr *Decl2 =
> +
>  dyn_cast<DeclRefExpr>(RHS->getLHS()->IgnoreImpCasts()->IgnoreParens());
>
> ->IgnoreParenImpCasts() instead of ->IgnoreImpCasts()->IgnoreParens()
>
> +    const IntegerLiteral *Literal2 =
> +        dyn_cast<IntegerLiteral>(RHS->getRHS()->IgnoreParens());
> +
> +    if (!Decl2 && !Literal2) {
> +      if (BO2 == BO_GT)
> +        BO2 = BO_LT;
> +      else if (BO2 == BO_GE)
> +        BO2 = BO_LE;
> +      else if (BO2 == BO_LT)
> +        BO2 = BO_GT;
> +      else if (BO2 == BO_LE)
> +        BO2 = BO_GE;
> +      Decl2 =
> +
>  dyn_cast<DeclRefExpr>(RHS->getRHS()->IgnoreImpCasts()->IgnoreParens());
> +      Literal2 = dyn_cast<IntegerLiteral>(RHS->getLHS()->IgnoreParens());
> +    }
> +
> +    if (!Decl2 || !Literal2)
> +      return TryResult();
> +
> +    // Check that it is the same variable on both sides.
> +    if (Decl1->getNameInfo().getAsString() !=
> Decl2->getNameInfo().getAsString())
>
> Decl1->getDecl() != Decl2->getDecl()
>
> +      return TryResult();
> +
> +    // evaluate if expression is always true/false
> +    llvm::APSInt L1,L2;
> +    if (!Literal1->EvaluateAsInt(L1,*Context) ||
> +        !Literal2->EvaluateAsInt(L2,*Context))
> +      return TryResult();
> +
> +    const llvm::APSInt MinValueL1 =
> +        llvm::APSInt::getMinValue(L1.getBitWidth(),L1.isUnsigned());
> +    const llvm::APSInt MaxValueL1 =
> +        llvm::APSInt::getMaxValue(L1.getBitWidth(),L1.isUnsigned());
> +
> +    const llvm::APSInt MinValueL2 =
> +        llvm::APSInt::getMinValue(L2.getBitWidth(),L2.isUnsigned());
> +    const llvm::APSInt MaxValueL2 =
> +        llvm::APSInt::getMaxValue(L2.getBitWidth(),L2.isUnsigned());
> +    bool AlwaysTrue = true, AlwaysFalse = true;
>
> What is going on here?
> +    for (int Offset = -3; Offset <=3; ++Offset) {
> +      for (int Selvalue = 1; Selvalue <= 2; Selvalue++) {
> +
> +        llvm::APSInt SelInt = (Selvalue==1 ? L1 : L2);
> +        llvm::APSInt SelMin = (Selvalue==1 ? MinValueL1 : MinValueL2);
> +        llvm::APSInt SelMax = (Selvalue==1 ? MaxValueL1 : MaxValueL2);
> +
> +        llvm::APSInt OffsetAPS =
> +            llvm::APSInt(llvm::APInt(SelInt.getBitWidth(), Offset),
> +                         SelInt.isUnsigned());
> +
> +        if ((SelInt + OffsetAPS) > SelMax)
> +          continue;
> +        else if ((SelInt + OffsetAPS) < SelMin)
> +          continue;
> +        else
> +          SelInt += OffsetAPS;
> +
> +        bool Res1,Res2;
> +        Res1 = analyzeLogicOperatorCondition(BO1,SelInt, L1);
> +        Res2 = analyzeLogicOperatorCondition(BO2,SelInt, L2);
> +        if (B->getOpcode() == BO_LAnd) {
> +            AlwaysTrue  &= (Res1 && Res2);
> +            AlwaysFalse &= !(Res1 && Res2);
> +        } else {
> +            AlwaysTrue  &= (Res1 || Res2);
> +            AlwaysFalse &= !(Res1 || Res2);
> +        }
> +      }
> +    }
> +
> +    if(AlwaysTrue || AlwaysFalse) {
> +      BuildOpts.Observer->compareAlwaysTrue(B,AlwaysTrue);
> +      return TryResult(AlwaysTrue);
> +    }
> +
> +    return TryResult();
> +  }
> +
>    /// Try and evaluate an expression to an integer constant.
>    bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) {
>      if (!BuildOpts.PruneTriviallyFalseEdges)
> @@ -565,13 +751,24 @@
>              // is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
>              if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
>                return RHS.isTrue();
> +          } else {
> +            TryResult BopRes = checkIncorrectLogicOperator(Bop);
> +            if (BopRes.isKnown())
> +              return BopRes.isTrue();
>            }
>          }
>
>          return TryResult();
> +      } else if (Bop->isEqualityOp()) {
> +          TryResult BopRes = checkIncorrectEqualityOperator(Bop);
> +          if (BopRes.isKnown())
> +            return BopRes.isTrue();
> +      } else if (Bop->isRelationalOp()) {
> +        TryResult BopRes = checkIncorrectRelationalOperator(Bop);
> +        if (BopRes.isKnown())
> +          return BopRes.isTrue();
>        }
>      }
> -
>      bool Result;
>      if (E->EvaluateAsBooleanCondition(Result, *Context))
>        return Result;
> @@ -1311,6 +1508,8 @@
>      else {
>        RHSBlock->setTerminator(Term);
>        TryResult KnownVal = tryEvaluateBool(RHS);
> +      if (!KnownVal.isKnown())
> +        KnownVal = tryEvaluateBool(B);
>        addSuccessor(RHSBlock, KnownVal.isFalse() ? NULL : TrueBlock);
>        addSuccessor(RHSBlock, KnownVal.isTrue() ? NULL : FalseBlock);
>      }
> Index: lib/Sema/AnalysisBasedWarnings.cpp
> ===================================================================
> --- lib/Sema/AnalysisBasedWarnings.cpp (revision 194562)
> +++ lib/Sema/AnalysisBasedWarnings.cpp (working copy)
> @@ -77,6 +77,60 @@
>    reachable_code::FindUnreachableCode(AC, UC);
> }
>
> +/// \brief Warn on logical operator errors in CFGBuilder
> +class LogicalErrorsHandler : public CFGCallback {
> +  Sema &S;
> +public:
> +  LogicalErrorsHandler(Sema &S) : CFGCallback(),S(S) {}
> +  void compareAlwaysTrue(const BinaryOperator* B, bool isAlwaysTrue) {
> +    if (B->getLHS()->getExprLoc().isMacroID() ||
> +        B->getRHS()->getExprLoc().isMacroID())
> +      return;
> +
> +    const BinaryOperator *LHS =
> +        dyn_cast<BinaryOperator>(B->getLHS()->IgnoreParens());
> +    const BinaryOperator *RHS =
> +        dyn_cast<BinaryOperator>(B->getRHS()->IgnoreParens());
> +
> +    if (LHS)
> +      if (LHS->getLHS()->getExprLoc().isMacroID() ||
> +          LHS->getRHS()->getExprLoc().isMacroID())
> +            return;
> +    if (RHS)
> +      if (RHS->getLHS()->getExprLoc().isMacroID() ||
> +          RHS->getRHS()->getExprLoc().isMacroID())
> +            return;
> +
> +    SourceRange DiagRange(B->getLHS()->getLocStart(),
> B->getRHS()->getLocEnd());
> +    S.Diag(B->getExprLoc(), diag::warn_operator_always_true_comparison)
> +        << DiagRange << isAlwaysTrue;
> +  }
> +
> +  void compareBoolWithInt(const BinaryOperator* B) {
> +    if (B->getLHS()->getExprLoc().isMacroID() ||
> +        B->getRHS()->getExprLoc().isMacroID())
> +      return;
> +
> +    const BinaryOperator *LHS =
> +        dyn_cast<BinaryOperator>(B->getLHS()->IgnoreParens());
> +    const BinaryOperator *RHS =
> +        dyn_cast<BinaryOperator>(B->getRHS()->IgnoreParens());
> +
> +    if (LHS)
> +      if (LHS->getLHS()->getExprLoc().isMacroID() ||
> +          LHS->getRHS()->getExprLoc().isMacroID())
> +            return;
> +    if (RHS)
> +      if (RHS->getLHS()->getExprLoc().isMacroID() ||
> +          RHS->getRHS()->getExprLoc().isMacroID())
> +            return;
> +
> +    SourceRange DiagRange(B->getLHS()->getLocStart(),
> B->getRHS()->getLocEnd());
> +    S.Diag(B->getExprLoc(), diag::warn_bool_and_int_comparison) <<
> DiagRange;
> +  }
> +};
> +
> +
>
> //===----------------------------------------------------------------------===//
> // Check for missing return value.
>
> //===----------------------------------------------------------------------===//
> @@ -1723,8 +1777,11 @@
>      bool isTemplateInstantiation = false;
>      if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
>        isTemplateInstantiation = Function->isTemplateInstantiation();
> -    if (!isTemplateInstantiation)
> +    if (!isTemplateInstantiation) {
> +      LogicalErrorsHandler Leh(S);
> +      AC.getCFGBuildOptions().Observer = &Leh;
>        CheckUnreachable(S, AC);
> +    }
>    }
>
>    // Check for thread safety violations
> Index: lib/AST/Expr.cpp
> ===================================================================
> --- lib/AST/Expr.cpp (revision 194562)
> +++ lib/AST/Expr.cpp (working copy)
> @@ -152,6 +152,8 @@
>      switch (UO->getOpcode()) {
>      case UO_Plus:
>        return UO->getSubExpr()->isKnownToHaveBooleanValue();
> +    case UO_LNot:
> +      return true;
>      default:
>        return false;
>      }
> Index: test/Sema/warn-overlap.c
> ===================================================================
> --- test/Sema/warn-overlap.c (revision 0)
> +++ test/Sema/warn-overlap.c (working copy)
>
> Add some tests with different variable types and different constant types.
>
> @@ -0,0 +1,51 @@
> +// RUN: %clang_cc1 -fsyntax-only -verify -Wunreachable-code %s
> +
> +#define mydefine 2
> +
> +void f(int x) {
> +  int y = 0;
> +  // > || <
> +  if (x > 2 || x < 1) { }
> +  if (x > 2 || x < 2) { }
> +  if (x != 2 || x != 3) { } // expected-warning {{logical disjunction
> always evaluates to true}}
> +  if (x > 2 || x < 3) { } // expected-warning {{logical disjunction
> always evaluates to true}}
> +
> +  if (x > 2 || x <= 1) { }
> +  if (x > 2 || x <= 2) { } // expected-warning {{logical disjunction
> always evaluates to true}}
> +  if (x > 2 || x <= 3) { } // expected-warning {{logical disjunction
> always evaluates to true}}
> +
> +  if (x >= 2 || x < 1) { }
> +  if (x >= 2 || x < 2) { } // expected-warning {{logical disjunction
> always evaluates to true}}
> +  if (x >= 2 || x < 3) { } // expected-warning {{logical disjunction
> always evaluates to true}}
> +
> +  if (x >= 2 || x <= 1) { } // expected-warning {{logical disjunction
> always evaluates to true}}
> +  if (x >= 2 || x <= 2) { } // expected-warning {{logical disjunction
> always evaluates to true}}
> +  if (x >= 2 || x <= 3) { } // expected-warning {{logical disjunction
> always evaluates to true}}
> +
> +  // > && <
> +  if (x > 2 && x < 1) { }  // expected-warning {{logical disjunction
> always evaluates to false}}
> +  if (x > 2 && x < 2) { }  // expected-warning {{logical disjunction
> always evaluates to false}}
> +  if (x > 2 && x < 3) { }  // expected-warning {{logical disjunction
> always evaluates to false}}
> +
> +  if (x > 2 && x <= 1) { }  // expected-warning {{logical disjunction
> always evaluates to false}}
> +  if (x > 2 && x <= 2) { }  // expected-warning {{logical disjunction
> always evaluates to false}}
> +  if (x > 2 && x <= 3) { }
> +
> +  if (x >= 2 && x < 1) { }  // expected-warning {{logical disjunction
> always evaluates to false}}
> +  if (x >= 2 && x < 2) { }  // expected-warning {{logical disjunction
> always evaluates to false}}
> +  if (x >= 2 && x < 3) { }
> +
> +  if (x >= 2 && x <= 1) { }  // expected-warning {{logical disjunction
> always evaluates to false}}
> +  if (x >= 2 && x <= 2) { }
> +  if (x >= 2 && x <= 3) { }
> +
> +  // !=, ==, ..
> +  if (x != 2 || x != 3) { }  // expected-warning {{logical disjunction
> always evaluates to true}}
> +  if (x != 2 || x < 3) { }   // expected-warning {{logical disjunction
> always evaluates to true}}
> +  if (x == 2 && x == 3) { }  // expected-warning {{logical disjunction
> always evaluates to false}}
> +  if (x == 2 && x > 3) { }   // expected-warning {{logical disjunction
> always evaluates to false}}
> +
> +  if (x == mydefine && x > 3) { }  // no-warning
> +  if (x == 2 && y > 3) { }  // no-warning
> +}
> +
> Index: test/Sema/warn-compint.c
> ===================================================================
> --- test/Sema/warn-compint.c (revision 0)
> +++ test/Sema/warn-compint.c (working copy)
> @@ -0,0 +1,39 @@
> +// RUN: %clang_cc1 -fsyntax-only -verify -Wunreachable-code %s
> +
> +#define mydefine 2
> +
> +void err(int x, int y) {
> +
> +    if (!x == 10) {}  // expected-warning {{comparison of a boolean
> expression with an integer other than 0 or 1}}
> +    if (!x != 10) {}  // expected-warning {{comparison of a boolean
> expression with an integer other than 0 or 1}}
> +    if (!x <  10) {}  // expected-warning {{comparison of a boolean
> expression with an integer other than 0 or 1}}
> +    if (!x >  10) {}  // expected-warning {{comparison of a boolean
> expression with an integer other than 0 or 1}}
> +    if (!x >= 10) {}  // expected-warning {{comparison of a boolean
> expression with an integer other than 0 or 1}}
> +    if (!x <= 10) {}  // expected-warning {{comparison of a boolean
> expression with an integer other than 0 or 1}}
> +
> +    if ((x < y) == 10) {}  // expected-warning {{comparison of a boolean
> expression with an integer other than 0 or 1}}
> +    if ((x < y) != 10) {}  // expected-warning {{comparison of a boolean
> expression with an integer other than 0 or 1}}
> +    if ((x < y) <  10) {}  // expected-warning {{comparison of a boolean
> expression with an integer other than 0 or 1}}
> +    if ((x < y) >  10) {}  // expected-warning {{comparison of a boolean
> expression with an integer other than 0 or 1}}
> +    if ((x < y) >= 10) {}  // expected-warning {{comparison of a boolean
> expression with an integer other than 0 or 1}}
> +    if ((x < y) <= 10) {}  // expected-warning {{comparison of a boolean
> expression with an integer other than 0 or 1}}
> +}
> +
> +void noerr(int x, int y) {
> +
> +    if (!x == 1) {}
> +    if (!x != 0) {}
> +    if (!x <  1) {}
> +    if (!x >  0) {}
> +    if (!x >= 1) {}
> +    if (!x <= 0) {}
> +
> +    if ((x < y) == 1) {}
> +    if ((x < y) != 0) {}
> +    if ((x < y) <  1) {}
> +    if ((x < y) >  0) {}
> +    if ((x < y) >= 1) {}
> +    if ((x < y) <= 0) {}
> +
> +    if ((x < mydefine) <= 10) {}
> +} // no-warning
> Index: include/clang/Basic/DiagnosticSemaKinds.td
> ===================================================================
> --- include/clang/Basic/DiagnosticSemaKinds.td (revision 194562)
> +++ include/clang/Basic/DiagnosticSemaKinds.td (working copy)
> @@ -339,6 +339,12 @@
>    InGroup<MissingNoreturn>, DefaultIgnore;
> def warn_unreachable : Warning<"will never be executed">,
>    InGroup<DiagGroup<"unreachable-code">>, DefaultIgnore;
>
> Still don't like the logical disjunction text.  I think it would be
> confusing for users.
>
> +def warn_operator_always_true_comparison : Warning<
> +  "logical disjunction always evaluates to %select{false|true}0">,
> +  InGroup<DiagGroup<"unreachable-code">>, DefaultIgnore;
> +def warn_bool_and_int_comparison : Warning<
> +  "comparison of a boolean expression with an integer other than 0 or 1">,
> +  InGroup<DiagGroup<"unreachable-code">>, DefaultIgnore;
>
> /// Built-in functions.
> def ext_implicit_lib_function_decl : ExtWarn<
> Index: include/clang/Analysis/CFG.h
> ===================================================================
> --- include/clang/Analysis/CFG.h (revision 194562)
> +++ include/clang/Analysis/CFG.h (working copy)
> @@ -45,6 +45,7 @@
>    class ASTContext;
>    class CXXRecordDecl;
>    class CXXDeleteExpr;
> +  class BinaryOperator;
>
> /// CFGElement - Represents a top-level expression in a basic block.
> class CFGElement {
> @@ -609,6 +610,16 @@
>    }
> };
>
> What's the plan with CFGCallBack?  New methods added as needed for each
> new warning?  Does the CFGBuilder need to support multiple CFGCallBack's at
> once?
>
> +/// \brief CFGCallback defines methods that should be called when a
> logical
> +/// operator error is found when building the CFG.
> +class CFGCallback {
> +public:
> +  CFGCallback(){}
> +  virtual void compareAlwaysTrue(const BinaryOperator *B, bool
> isAlwaysTrue) {};
> +  virtual void compareBoolWithInt(const BinaryOperator *B) {};
> +  virtual ~CFGCallback(){}
> +};
> +
> /// CFG - Represents a source-level, intra-procedural CFG that represents
> the
> ///  control-flow of a Stmt.  The Stmt can represent an entire function
> body,
> ///  or a single expression.  A CFG will always contain one empty block
> that
> @@ -627,7 +638,7 @@
>    public:
>      typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs;
>      ForcedBlkExprs **forcedBlkExprs;
> -
> +    CFGCallback* Observer;
>      bool PruneTriviallyFalseEdges;
>      bool AddEHEdges;
>      bool AddInitializers;
> @@ -650,7 +661,7 @@
>      }
>
>      BuildOptions()
> -    : forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
> +    : forcedBlkExprs(0), Observer(0), PruneTriviallyFalseEdges(true)
>        ,AddEHEdges(false)
>        ,AddInitializers(false)
>        ,AddImplicitDtors(false)
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131213/9456d01e/attachment.html>


More information about the cfe-commits mailing list