diff --git a/clang/include/clang/AST/PreorderAST.h b/clang/include/clang/AST/PreorderAST.h index c8c90a6d4027..b5c6ed4175f8 100644 --- a/clang/include/clang/AST/PreorderAST.h +++ b/clang/include/clang/AST/PreorderAST.h @@ -88,11 +88,16 @@ namespace clang { // @param[in] Parent is the parent of the node to be added. void AddNode(Node *N, Node *Parent); - // Move the children (if any) of node N to its parent and then remove N. - // @param[in] N is the current node. - // @param[in] P is the parent of the node to be removed. P should be a - // BinaryNode. - void RemoveNode(Node *N, Node *P); + // Coalesce the BinaryNode B with its parent. This involves moving the + // children (if any) of node B to its parent and then removing B. + // @param[in] B is the current node. B should be a BinaryNode. + void CoalesceNode(BinaryNode *B); + + // Determines if a BinaryNode could be coalesced into its parent. + // @param[in] B is the current node. B should be a BinaryNode. + // @return Return true if B can be coalesced into its parent, false + // otherwise. + bool CanCoalesceNode(BinaryNode *B); // Recursively coalesce binary nodes having the same commutative and // associative operator. diff --git a/clang/lib/AST/PreorderAST.cpp b/clang/lib/AST/PreorderAST.cpp index 83c6fecbd1df..4a489d4bbcde 100644 --- a/clang/lib/AST/PreorderAST.cpp +++ b/clang/lib/AST/PreorderAST.cpp @@ -29,51 +29,57 @@ void PreorderAST::AddNode(Node *N, Node *Parent) { } } -void PreorderAST::RemoveNode(Node *N, Node *Parent) { - // The parent should be a BinaryNode. - assert(isa(Parent) && "Invalid parent"); +bool PreorderAST::CanCoalesceNode(BinaryNode *B) { + if (!B || !isa(B)) + return false; - auto *P = dyn_cast(Parent); - if (!P) { - SetError(); - return; - } + auto *P = dyn_cast_or_null(B->Parent); + if (!P) + return false; - // We will remove a BinaryNode only if its operator is equal to its - // parent's operator and the operator is commutative and associative. - if (auto *B = dyn_cast(N)) { - assert(B->Opc == P->Opc && - "BinaryNode operator must equal parent operator"); + // We can only coalesce if the operator of the current and parent node is + // commutative and associative. This is because after coalescing we later + // need to sort the nodes and if the operator is not commutative and + // associative then sorting would be incorrect. + if (!B->IsOpCommutativeAndAssociative() || + !P->IsOpCommutativeAndAssociative()) + return false; - assert(B->IsOpCommutativeAndAssociative() && - "BinaryNode operator must be commutative and associative"); + // We can coalesce in the following scenarios: + // 1. The current and parent nodes have the same operator OR + // 2. The current node is the only child of its operator node (maybe as a + // result of constant folding). + return B->Opc == P->Opc || B->Children.size() == 1; +} - if (B->Opc != P->Opc || - !B->IsOpCommutativeAndAssociative()) { - SetError(); - return; - } +void PreorderAST::CoalesceNode(BinaryNode *B) { + if (!CanCoalesceNode(B)) { + assert(0 && "Attempting to coalesce invalid node"); + SetError(); + return; } + // In the call to CanCoalesceNode above we have made sure that the parent is + // a BinaryNode. So we can safely dyn_cast here. + auto *P = dyn_cast(B->Parent); + // Remove the current node from the list of children of its parent. for (auto I = P->Children.begin(), E = P->Children.end(); I != E; ++I) { - if (*I == N) { + if (*I == B) { P->Children.erase(I); break; } } - if (auto *B = dyn_cast(N)) { - // Move all children of the current node to its parent. - for (auto *Child : B->Children) { - Child->Parent = P; - P->Children.push_back(Child); - } + // Move all children of the current node to its parent. + for (auto *Child : B->Children) { + Child->Parent = P; + P->Children.push_back(Child); } // Delete the current node. - delete N; + delete B; } void PreorderAST::Create(Expr *E, Node *Parent) { @@ -162,20 +168,8 @@ void PreorderAST::Coalesce(Node *N, bool &Changed) { if (isa(Child)) Coalesce(Child, Changed); - // We can only coalesce if the operator is commutative and associative. - if (!B->IsOpCommutativeAndAssociative()) - return; - - auto *Parent = dyn_cast_or_null(B->Parent); - if (!Parent) - return; - - // We can coalesce only if: - // 1. The parent has the same operator as the current node. - // 2. The current node is a BinaryNode with just one child (for example, as a - // result of constant folding). - if (Parent->Opc == B->Opc || B->Children.size() == 1) { - RemoveNode(B, Parent); + if (CanCoalesceNode(B)) { + CoalesceNode(B); Changed = true; } } @@ -328,6 +322,12 @@ void PreorderAST::ConstantFold(Node *N, bool &Changed) { // Add the constant folded expression to list of children of the current // BinaryNode. B->Children.push_back(new LeafExprNode(ConstFoldedExpr, B)); + + // If the constant folded expr is the only child of this BinaryNode we can + // coalesce the node. + if (B->Children.size() == 1 && CanCoalesceNode(B)) + CoalesceNode(B); + Changed = true; } diff --git a/clang/test/CheckedC/inferred-bounds/widened-bounds-semantic-compare.c b/clang/test/CheckedC/inferred-bounds/widened-bounds-semantic-compare.c index 39c4ed645326..0a6ed4468e2c 100644 --- a/clang/test/CheckedC/inferred-bounds/widened-bounds-semantic-compare.c +++ b/clang/test/CheckedC/inferred-bounds/widened-bounds-semantic-compare.c @@ -169,3 +169,15 @@ void f14(int i) { // CHECK: [B1] // CHECK-NOT: upper_bound(p) } + +void f15(_Nt_array_ptr p : count(6)) { + if (*(p + (1 * (2 * 3)))) + {} + +// CHECK: In function: f15 +// [B2] +// 1: _Nt_array_ptr p : count(6) = "a"; +// 2: *(p + (1 * (2 * 3))) +// [B1] +// upper_bound(p) = 1 +}