diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Analysis/CFG.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Analysis/CFG.cpp | 187 |
1 files changed, 127 insertions, 60 deletions
diff --git a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp index 54d15bd..ed2239f 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp @@ -39,6 +39,78 @@ static SourceLocation GetEndLoc(Decl *D) { return D->getLocation(); } +/// Helper for tryNormalizeBinaryOperator. Attempts to extract an IntegerLiteral +/// or EnumConstantDecl from the given Expr. If it fails, returns nullptr. +const Expr *tryTransformToIntOrEnumConstant(const Expr *E) { + E = E->IgnoreParens(); + if (isa<IntegerLiteral>(E)) + return E; + if (auto *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) + return isa<EnumConstantDecl>(DR->getDecl()) ? DR : nullptr; + return nullptr; +} + +/// Tries to interpret a binary operator into `Decl Op Expr` form, if Expr is +/// an integer literal or an enum constant. +/// +/// If this fails, at least one of the returned DeclRefExpr or Expr will be +/// null. +static std::tuple<const DeclRefExpr *, BinaryOperatorKind, const Expr *> +tryNormalizeBinaryOperator(const BinaryOperator *B) { + BinaryOperatorKind Op = B->getOpcode(); + + const Expr *MaybeDecl = B->getLHS(); + const Expr *Constant = tryTransformToIntOrEnumConstant(B->getRHS()); + // Expr looked like `0 == Foo` instead of `Foo == 0` + if (Constant == nullptr) { + // Flip the operator + if (Op == BO_GT) + Op = BO_LT; + else if (Op == BO_GE) + Op = BO_LE; + else if (Op == BO_LT) + Op = BO_GT; + else if (Op == BO_LE) + Op = BO_GE; + + MaybeDecl = B->getRHS(); + Constant = tryTransformToIntOrEnumConstant(B->getLHS()); + } + + auto *D = dyn_cast<DeclRefExpr>(MaybeDecl->IgnoreParenImpCasts()); + return std::make_tuple(D, Op, Constant); +} + +/// For an expression `x == Foo && x == Bar`, this determines whether the +/// `Foo` and `Bar` are either of the same enumeration type, or both integer +/// literals. +/// +/// It's an error to pass this arguments that are not either IntegerLiterals +/// or DeclRefExprs (that have decls of type EnumConstantDecl) +static bool areExprTypesCompatible(const Expr *E1, const Expr *E2) { + // User intent isn't clear if they're mixing int literals with enum + // constants. + if (isa<IntegerLiteral>(E1) != isa<IntegerLiteral>(E2)) + return false; + + // Integer literal comparisons, regardless of literal type, are acceptable. + if (isa<IntegerLiteral>(E1)) + return true; + + // IntegerLiterals are handled above and only EnumConstantDecls are expected + // beyond this point + assert(isa<DeclRefExpr>(E1) && isa<DeclRefExpr>(E2)); + auto *Decl1 = cast<DeclRefExpr>(E1)->getDecl(); + auto *Decl2 = cast<DeclRefExpr>(E2)->getDecl(); + + assert(isa<EnumConstantDecl>(Decl1) && isa<EnumConstantDecl>(Decl2)); + const DeclContext *DC1 = Decl1->getDeclContext(); + const DeclContext *DC2 = Decl2->getDeclContext(); + + assert(isa<EnumDecl>(DC1) && isa<EnumDecl>(DC2)); + return DC1 == DC2; +} + class CFGBuilder; /// The CFG builder uses a recursive algorithm to build the CFG. When @@ -176,8 +248,8 @@ private: public: /// Constructs empty scope linked to previous scope in specified place. - LocalScope(BumpVectorContext &ctx, const_iterator P) - : ctx(ctx), Vars(ctx, 4), Prev(P) {} + LocalScope(BumpVectorContext ctx, const_iterator P) + : ctx(std::move(ctx)), Vars(this->ctx, 4), Prev(P) {} /// Begin of scope in direction of CFG building (backwards). const_iterator begin() const { return const_iterator(*this, Vars.size()); } @@ -284,7 +356,7 @@ reverse_children::reverse_children(Stmt *S) { /// Example usage: /// /// CFGBuilder builder; -/// CFG* cfg = builder.BuildAST(stmt1); +/// std::unique_ptr<CFG> cfg = builder.buildCFG(decl, stmt1); /// /// CFG construction is done via a recursive walk of an AST. We actually parse /// the AST in reverse order so that the successor of a basic block is @@ -388,6 +460,7 @@ private: CFGBlock *VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc); CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I); CFGBlock *VisitLabelStmt(LabelStmt *L); + CFGBlock *VisitBlockExpr(BlockExpr *E, AddStmtChoice asc); CFGBlock *VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc); CFGBlock *VisitLogicalOperator(BinaryOperator *B); std::pair<CFGBlock *, CFGBlock *> VisitLogicalOperator(BinaryOperator *B, @@ -694,56 +767,35 @@ private: if (!LHS->isComparisonOp() || !RHS->isComparisonOp()) return TryResult(); - 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()); - } + const DeclRefExpr *Decl1; + const Expr *Expr1; + BinaryOperatorKind BO1; + std::tie(Decl1, BO1, Expr1) = tryNormalizeBinaryOperator(LHS); - if (!Decl1 || !Literal1) + if (!Decl1 || !Expr1) return TryResult(); - BinaryOperatorKind BO2 = RHS->getOpcode(); - const DeclRefExpr *Decl2 = - dyn_cast<DeclRefExpr>(RHS->getLHS()->IgnoreParenImpCasts()); - 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()->IgnoreParenImpCasts()); - Literal2 = dyn_cast<IntegerLiteral>(RHS->getLHS()->IgnoreParens()); - } + const DeclRefExpr *Decl2; + const Expr *Expr2; + BinaryOperatorKind BO2; + std::tie(Decl2, BO2, Expr2) = tryNormalizeBinaryOperator(RHS); - if (!Decl2 || !Literal2) + if (!Decl2 || !Expr2) return TryResult(); // Check that it is the same variable on both sides. if (Decl1->getDecl() != Decl2->getDecl()) return TryResult(); + // Make sure the user's intent is clear (e.g. they're comparing against two + // int literals, or two things from the same enum) + if (!areExprTypesCompatible(Expr1, Expr2)) + return TryResult(); + llvm::APSInt L1, L2; - if (!Literal1->EvaluateAsInt(L1, *Context) || - !Literal2->EvaluateAsInt(L2, *Context)) + if (!Expr1->EvaluateAsInt(L1, *Context) || + !Expr2->EvaluateAsInt(L2, *Context)) return TryResult(); // Can't compare signed with unsigned or with different bit width. @@ -773,10 +825,7 @@ private: // * Variable x is equal to the largest literal. // * Variable x is greater than largest literal. bool AlwaysTrue = true, AlwaysFalse = true; - for (unsigned int ValueIndex = 0; - ValueIndex < sizeof(Values) / sizeof(Values[0]); - ++ValueIndex) { - llvm::APSInt Value = Values[ValueIndex]; + for (llvm::APSInt Value : Values) { TryResult Res1, Res2; Res1 = analyzeLogicOperatorCondition(BO1, Value, L1); Res2 = analyzeLogicOperatorCondition(BO2, Value, L2); @@ -994,9 +1043,8 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { // For C++ constructor add initializers to CFG. if (const CXXConstructorDecl *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) { - for (CXXConstructorDecl::init_const_reverse_iterator I = CD->init_rbegin(), - E = CD->init_rend(); I != E; ++I) { - B = addInitializer(*I); + for (auto *I : llvm::reverse(CD->inits())) { + B = addInitializer(I); if (badCFG) return nullptr; } @@ -1248,13 +1296,11 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) { /// createOrReuseLocalScope - If Scope is NULL create new LocalScope. Either /// way return valid LocalScope object. LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) { - if (!Scope) { - llvm::BumpPtrAllocator &alloc = cfg->getAllocator(); - Scope = alloc.Allocate<LocalScope>(); - BumpVectorContext ctx(alloc); - new (Scope) LocalScope(ctx, ScopePos); - } - return Scope; + if (Scope) + return Scope; + llvm::BumpPtrAllocator &alloc = cfg->getAllocator(); + return new (alloc.Allocate<LocalScope>()) + LocalScope(BumpVectorContext(alloc), ScopePos); } /// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement @@ -1405,7 +1451,7 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { return VisitBinaryOperator(cast<BinaryOperator>(S), asc); case Stmt::BlockExprClass: - return VisitNoRecurse(cast<Expr>(S), asc); + return VisitBlockExpr(cast<BlockExpr>(S), asc); case Stmt::BreakStmtClass: return VisitBreakStmt(cast<BreakStmt>(S)); @@ -1894,7 +1940,15 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) { - addLocalScopeAndDtors(C); + LocalScope::const_iterator scopeBeginPos = ScopePos; + if (BuildOpts.AddImplicitDtors) { + addLocalScopeForStmt(C); + } + if (!C->body_empty() && !isa<ReturnStmt>(*C->body_rbegin())) { + // If the body ends with a ReturnStmt, the dtors will be added in VisitReturnStmt + addAutomaticObjDtors(ScopePos, scopeBeginPos, C); + } + CFGBlock *LastBlock = Block; for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend(); @@ -2277,6 +2331,18 @@ CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) { return LabelBlock; } +CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) { + CFGBlock *LastBlock = VisitNoRecurse(E, asc); + for (const BlockDecl::Capture &CI : E->getBlockDecl()->captures()) { + if (Expr *CopyExpr = CI.getCopyExpr()) { + CFGBlock *Tmp = Visit(CopyExpr); + if (Tmp) + LastBlock = Tmp; + } + } + return LastBlock; +} + CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) { CFGBlock *LastBlock = VisitNoRecurse(E, asc); for (LambdaExpr::capture_init_iterator it = E->capture_init_begin(), @@ -3104,11 +3170,11 @@ static bool shouldAddCase(bool &switchExclusivelyCovered, addCase = true; switchExclusivelyCovered = true; } - else if (condInt < lhsInt) { + else if (condInt > lhsInt) { if (const Expr *RHS = CS->getRHS()) { // Evaluate the RHS of the case value. const llvm::APSInt &V2 = RHS->EvaluateKnownConstInt(Ctx); - if (V2 <= condInt) { + if (V2 >= condInt) { addCase = true; switchExclusivelyCovered = true; } @@ -4128,7 +4194,8 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, if (const StmtExpr *SE = dyn_cast<StmtExpr>(S)) { const CompoundStmt *Sub = SE->getSubStmt(); - if (Sub->children()) { + auto Children = Sub->children(); + if (Children.begin() != Children.end()) { OS << "({ ... ; "; Helper.handledStmt(*SE->getSubStmt()->body_rbegin(),OS); OS << " })\n"; |