// Visitors to walk an AST and construct the CFG.
CFGBlock *VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc);
CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc);
+ CFGBlock *VisitAttributedStmt(AttributedStmt *A, AddStmtChoice asc);
CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc);
CFGBlock *VisitBreakStmt(BreakStmt *B);
CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc);
case Stmt::InitListExprClass:
return VisitInitListExpr(cast<InitListExpr>(S), asc);
+ case Stmt::AttributedStmtClass:
+ return VisitAttributedStmt(cast<AttributedStmt>(S), asc);
+
case Stmt::AddrLabelExprClass:
return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc);
return Block;
}
-CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U,
- AddStmtChoice asc) {
+static bool isFallthroughStatement(const AttributedStmt *A) {
+ bool isFallthrough = hasSpecificAttr<FallThroughAttr>(A->getAttrs());
+ assert((!isFallthrough || isa<NullStmt>(A->getSubStmt())) &&
+ "expected fallthrough not to have children");
+ return isFallthrough;
+}
+
+CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A,
+ AddStmtChoice asc) {
+ // AttributedStmts for [[likely]] can have arbitrary statements as children,
+ // and the current visitation order here would add the AttributedStmts
+ // for [[likely]] after the child nodes, which is undesirable: For example,
+ // if the child contains an unconditional return, the [[likely]] would be
+ // considered unreachable.
+ // So only add the AttributedStmt for FallThrough, which has CFG effects and
+ // also no children, and omit the others. None of the other current StmtAttrs
+ // have semantic meaning for the CFG.
+ if (isFallthroughStatement(A) && asc.alwaysAdd(*this, A)) {
+ autoCreateBlock();
+ appendStmt(Block, A);
+ }
+
+ return VisitChildren(A);
+}
+
+CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc) {
if (asc.alwaysAdd(*this, U)) {
autoCreateBlock();
appendStmt(Block, U);