Index: clang/include/clang/Analysis/Analyses/Dominators.h =================================================================== --- clang/include/clang/Analysis/Analyses/Dominators.h +++ clang/include/clang/Analysis/Analyses/Dominators.h @@ -155,13 +155,51 @@ } // namespace clang +namespace llvm { + +/// Clang's CFG contains nullpointers for unreachable succesors, e.g. when an +/// if statement's condition is always false, it's 'then' branch is represented +/// with a nullptr. This however will result in a nullpointer derefernece for +/// dominator tree calculation. +/// +/// To circumvent this, let's just crudely specialize the children getters +/// used in LLVM's dominator tree builder. +namespace DomTreeBuilder { + +using ClangCFGDomChildrenGetter = +SemiNCAInfo>::ChildrenGetter; + +using ClangCFGDomReverseChildrenGetter = +SemiNCAInfo>::ChildrenGetter; + +template <> +template <> +ClangCFGDomChildrenGetter::ResultTy ClangCFGDomChildrenGetter::Get( + clang::CFGBlock *N, std::integral_constant) { + auto RChildren = reverse(children(N)); + ResultTy Ret(RChildren.begin(), RChildren.end()); + Ret.erase(std::remove(Ret.begin(), Ret.end(), nullptr), Ret.end()); + return Ret; +} + +template <> +template <> +ClangCFGDomReverseChildrenGetter::ResultTy +ClangCFGDomReverseChildrenGetter::Get( + clang::CFGBlock *N, std::integral_constant) { + auto RChildren = reverse(children(N)); + ResultTy Ret(RChildren.begin(), RChildren.end()); + Ret.erase(std::remove(Ret.begin(), Ret.end(), nullptr), Ret.end()); + return Ret; +} + +} // end of namespace DomTreeBuilder + //===------------------------------------- /// DominatorTree GraphTraits specialization so the DominatorTree can be /// iterable by generic graph iterators. /// -namespace llvm { - -template <> struct GraphTraits< ::clang::DomTreeNode* > { +template <> struct GraphTraits { using NodeRef = ::clang::DomTreeNode *; using ChildIteratorType = ::clang::DomTreeNode::iterator; Index: clang/test/Analysis/domtest.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/domtest.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_analyze_cc1 %s \ +// RUN: -analyzer-checker=debug.DumpCFG \ +// RUN: -analyzer-checker=debug.DumpDominators \ +// RUN: 2>&1 | FileCheck %s + +namespace pr42041_unreachable_cfg_successor { +enum Kind { + A +}; + +void f() { + switch(Kind{}) { + case A: + break; + } +} +} // end of namespace pr42041_unreachable_cfg_successor + +// CHECK: void f() +// CHECK-NEXT: [B3 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// +// CHECK: [B1] +// CHECK-NEXT: 1: {} +// CHECK-NEXT: 2: pr42041_unreachable_cfg_successor::Kind[B1.1] +// CHECK-SAME: (CXXFunctionalCastExpr, NoOp, +// CHECK-SAME: enum pr42041_unreachable_cfg_successor::Kind) +// CHECK-NEXT: 3: [B1.2] (ImplicitCastExpr, IntegralCast, int) +// CHECK-NEXT: T: switch [B1.3] +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (2): B2 B0(Unreachable) +// +// CHECK: [B2] +// CHECK-NEXT: case A: +// CHECK-NEXT: T: break; +// CHECK-NEXT: Preds (1): B1 +// CHECK-NEXT: Succs (1): B0 +// +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (2): B2 B1(Unreachable) +// +// CHECK: Immediate dominance tree (Node#,IDom#): +// CHECK-NEXT: (0,2) +// CHECK-NEXT: (1,3) +// CHECK-NEXT: (2,1) +// CHECK-NEXT: (3,3)