diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index fcadb2cf9791..000000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text eol=lf diff --git a/clang/docs/checkedc/3C/CONTRIBUTING.md b/clang/docs/checkedc/3C/CONTRIBUTING.md index 8ae8a321f026..b93f1440ca35 100644 --- a/clang/docs/checkedc/3C/CONTRIBUTING.md +++ b/clang/docs/checkedc/3C/CONTRIBUTING.md @@ -42,10 +42,11 @@ here. You must grant the same license on your contribution as the existing codebase. We do not have a formal contributor license agreement (CLA) process at this time, but we may set one up and require you to complete it before we accept your contribution. Also be -aware that we need to keep 5C working, so you may have to wait for us -to address 5C-specific problems arising from your 3C pull request -and/or we may ask you to make specific changes to your pull request to -accommodate 5C's code. +aware that we need to keep 5C ([our proprietary extension of +3C](README.md#what-3c-users-should-know-about-the-development-process)) +working, so you may have to wait for us to address 5C-specific +problems arising from your 3C pull request and/or we may ask you to +make specific changes to your pull request to accommodate 5C's code. ## Testing diff --git a/clang/include/clang/3C/AVarBoundsInfo.h b/clang/include/clang/3C/AVarBoundsInfo.h index 597d32f59cab..420319b052ce 100644 --- a/clang/include/clang/3C/AVarBoundsInfo.h +++ b/clang/include/clang/3C/AVarBoundsInfo.h @@ -362,8 +362,7 @@ class AVarBoundsInfo { class ContextSensitiveBoundsKeyVisitor : public RecursiveASTVisitor { public: - explicit ContextSensitiveBoundsKeyVisitor(ASTContext *C, ProgramInfo &I, - ConstraintResolver *CResolver); + explicit ContextSensitiveBoundsKeyVisitor(ASTContext *C, ProgramInfo &I); virtual ~ContextSensitiveBoundsKeyVisitor(); @@ -372,7 +371,6 @@ class ContextSensitiveBoundsKeyVisitor private: ASTContext *Context; ProgramInfo &Info; - ConstraintResolver *CR; }; #endif // LLVM_CLANG_3C_AVARBOUNDSINFO_H diff --git a/clang/include/clang/3C/RewriteUtils.h b/clang/include/clang/3C/RewriteUtils.h index 2fdd43ca1c08..29338cc8e846 100644 --- a/clang/include/clang/3C/RewriteUtils.h +++ b/clang/include/clang/3C/RewriteUtils.h @@ -193,14 +193,13 @@ class GlobalVariableGroups { // detected array variables. class ArrayBoundsRewriter { public: - ArrayBoundsRewriter(ASTContext *C, ProgramInfo &I) : Context(C), Info(I) {} + ArrayBoundsRewriter(ProgramInfo &I) : Info(I) {} // Get the string representation of the bounds for the given variable. std::string getBoundsString(PVConstraint *PV, Decl *D, bool Isitype = false); // Check if the constraint variable has newly created bounds string. bool hasNewBoundsString(PVConstraint *PV, Decl *D, bool Isitype = false); private: - ASTContext *Context; ProgramInfo &Info; }; diff --git a/clang/include/clang/AST/PreorderAST.h b/clang/include/clang/AST/PreorderAST.h index 364251fb3335..bf578f7608ae 100644 --- a/clang/include/clang/AST/PreorderAST.h +++ b/clang/include/clang/AST/PreorderAST.h @@ -23,29 +23,32 @@ namespace clang { using Result = Lexicographic::Result; + class OperatorNode; class Node { public: - enum class NodeKind { BinaryNode, LeafExprNode }; + enum class NodeKind { OperatorNode, LeafExprNode }; NodeKind Kind; - Node *Parent; + OperatorNode *Parent; - Node(NodeKind Kind, Node *Parent) : + Node(NodeKind Kind, OperatorNode *Parent) : Kind(Kind), Parent(Parent) {} }; - class BinaryNode : public Node { + class OperatorNode : public Node { public: BinaryOperator::Opcode Opc; + // Note: An OperatorNode has a list of children because the preorder AST is + // an n-ary tree. llvm::SmallVector Children; - BinaryNode(BinaryOperator::Opcode Opc, Node *Parent) : - Node(NodeKind::BinaryNode, Parent), + OperatorNode(BinaryOperator::Opcode Opc, OperatorNode *Parent) : + Node(NodeKind::OperatorNode, Parent), Opc(Opc) {} static bool classof(const Node *N) { - return N->Kind == NodeKind::BinaryNode; + return N->Kind == NodeKind::OperatorNode; } // Is the operator commutative and associative? @@ -58,7 +61,7 @@ namespace clang { public: Expr *E; - LeafExprNode(Expr *E, Node *Parent) : + LeafExprNode(Expr *E, OperatorNode *Parent) : Node(NodeKind::LeafExprNode, Parent), E(E) {} @@ -81,27 +84,32 @@ namespace clang { // Create a PreorderAST for the expression E. // @param[in] E is the sub expression to be added to a new node. // @param[in] Parent is the parent of the new node. - void Create(Expr *E, Node *Parent = nullptr); + void Create(Expr *E, OperatorNode *Parent = nullptr); // Add a new node to the AST. // @param[in] Node is the current node to be added. // @param[in] Parent is the parent of the node to be added. - void AddNode(Node *N, Node *Parent); + void AddNode(Node *N, OperatorNode *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 OperatorNode O with its parent. This involves moving the + // children (if any) of node O to its parent and then removing O. + // @param[in] O is the current node. O should be a OperatorNode. + void CoalesceNode(OperatorNode *O); - // Recursively coalesce binary nodes having the same commutative and + // Determines if a OperatorNode could be coalesced into its parent. + // @param[in] O is the current node. O should be a OperatorNode. + // @return Return true if O can be coalesced into its parent, false + // otherwise. + bool CanCoalesceNode(OperatorNode *O); + + // Recursively coalesce OperatoreNodes having the same commutative and // associative operator. // @param[in] N is current node of the AST. Initial value is Root. // @param[in] Changed indicates whether a node was coalesced. We need this // to control when to stop recursive coalescing. void Coalesce(Node *N, bool &Changed); - // Sort the children expressions in a binary node of the AST. + // Sort the children expressions in a OperatorNode of the AST. // @param[in] N is current node of the AST. Initial value is Root. void Sort(Node *N); diff --git a/clang/lib/3C/AVarBoundsInfo.cpp b/clang/lib/3C/AVarBoundsInfo.cpp index afaf09e1b1e8..eaf0cd94f2b0 100644 --- a/clang/lib/3C/AVarBoundsInfo.cpp +++ b/clang/lib/3C/AVarBoundsInfo.cpp @@ -898,7 +898,6 @@ bool AvarBoundsInference::inferBounds(BoundsKey K, AVarGraph &BKGraph, std::set PotentialB; PotentialB.clear(); for (auto TK : PotBDs[K]) { - ProgramVar *TKVar = BI->getProgramVar(TK); getReachableBoundKeys(Kvar->getScope(), TK, PotentialB, BKGraph, true); } @@ -1333,8 +1332,8 @@ bool AVarBoundsInfo::areSameProgramVar(BoundsKey B1, BoundsKey B2) { } ContextSensitiveBoundsKeyVisitor::ContextSensitiveBoundsKeyVisitor( - ASTContext *C, ProgramInfo &I, ConstraintResolver *CResolver) - : Context(C), Info(I), CR(CResolver) { + ASTContext *C, ProgramInfo &I) + : Context(C), Info(I) { Info.getABoundsInfo().resetContextSensitiveBoundsKey(); } diff --git a/clang/lib/3C/ArrayBoundsInferenceConsumer.cpp b/clang/lib/3C/ArrayBoundsInferenceConsumer.cpp index aae1ef786228..787afd50b9d7 100644 --- a/clang/lib/3C/ArrayBoundsInferenceConsumer.cpp +++ b/clang/lib/3C/ArrayBoundsInferenceConsumer.cpp @@ -613,7 +613,6 @@ bool LocalVarABVisitor::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { bool LocalVarABVisitor::VisitDeclStmt(DeclStmt *S) { // Build rules based on initializers. - auto &ABoundsInfo = Info.getABoundsInfo(); for (const auto &D : S->decls()) if (VarDecl *VD = dyn_cast(D)) { Expr *InitE = VD->getInit(); diff --git a/clang/lib/3C/ConstraintBuilder.cpp b/clang/lib/3C/ConstraintBuilder.cpp index d9a79370022f..5f4f8b380ff4 100644 --- a/clang/lib/3C/ConstraintBuilder.cpp +++ b/clang/lib/3C/ConstraintBuilder.cpp @@ -546,7 +546,7 @@ void ConstraintBuilderConsumer::HandleTranslationUnit(ASTContext &C) { TypeVarVisitor TV = TypeVarVisitor(&C, Info); ConstraintResolver CSResolver(Info, &C); ContextSensitiveBoundsKeyVisitor CSBV = - ContextSensitiveBoundsKeyVisitor(&C, Info, &CSResolver); + ContextSensitiveBoundsKeyVisitor(&C, Info); ConstraintGenVisitor GV = ConstraintGenVisitor(&C, Info, TV); TranslationUnitDecl *TUD = C.getTranslationUnitDecl(); // Generate constraints. diff --git a/clang/lib/3C/DeclRewriter.cpp b/clang/lib/3C/DeclRewriter.cpp index 7559c7ba0efb..3a584d0b5ae0 100644 --- a/clang/lib/3C/DeclRewriter.cpp +++ b/clang/lib/3C/DeclRewriter.cpp @@ -30,7 +30,7 @@ using namespace clang; void DeclRewriter::rewriteDecls(ASTContext &Context, ProgramInfo &Info, Rewriter &R) { // Compute the bounds information for all the array variables. - ArrayBoundsRewriter ABRewriter(&Context, Info); + ArrayBoundsRewriter ABRewriter(Info); // Collect function and record declarations that need to be rewritten in a set // as well as their rewriten types in a map. diff --git a/clang/lib/AST/PreorderAST.cpp b/clang/lib/AST/PreorderAST.cpp index 4703e1e6444e..54b621940c84 100644 --- a/clang/lib/AST/PreorderAST.cpp +++ b/clang/lib/AST/PreorderAST.cpp @@ -17,80 +17,76 @@ using namespace clang; -void PreorderAST::AddNode(Node *N, Node *Parent) { +void PreorderAST::AddNode(Node *N, OperatorNode *Parent) { // If the root is null, make the current node the root. if (!Root) Root = N; // Add the current node to the list of children of its parent. - if (Parent) { - assert(isa(Parent) && "Invalid parent"); - dyn_cast(Parent)->Children.push_back(N); - } + if (Parent) + Parent->Children.push_back(N); } -void PreorderAST::RemoveNode(Node *N, Node *Parent) { - // The parent should be a BinaryNode. - assert(isa(Parent) && "Invalid parent"); - - auto *P = dyn_cast(Parent); - if (!P) { - SetError(); - return; - } +bool PreorderAST::CanCoalesceNode(OperatorNode *O) { + if (!O || !isa(O) || !O->Parent) + 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 (!O->IsOpCommutativeAndAssociative() || + !O->Parent->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 O->Opc == O->Parent->Opc || O->Children.size() == 1; +} - if (B->Opc != P->Opc || - !B->IsOpCommutativeAndAssociative()) { - SetError(); - return; - } +void PreorderAST::CoalesceNode(OperatorNode *O) { + if (!CanCoalesceNode(O)) { + assert(0 && "Attempting to coalesce invalid node"); + SetError(); + return; } // 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) { - P->Children.erase(I); + for (auto I = O->Parent->Children.begin(), + E = O->Parent->Children.end(); I != E; ++I) { + if (*I == O) { + O->Parent->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 : O->Children) { + Child->Parent = O->Parent; + O->Parent->Children.push_back(Child); } // Delete the current node. - delete N; + delete O; } -void PreorderAST::Create(Expr *E, Node *Parent) { +void PreorderAST::Create(Expr *E, OperatorNode *Parent) { if (!E) return; E = Lex.IgnoreValuePreservingOperations(Ctx, E->IgnoreParens()); if (!Parent) { - // The invariant is that the root node must be a BinaryNode with an + // The invariant is that the root node must be a OperatorNode with an // addition operator. So for expressions like "if (*p)", we don't have a // BinaryOperator. So when we enter this function there is no root and the - // parent is null. So we create a new BinaryNode with + as the operator and - // add 0 as a LeafNodeExpr child of this BinaryNode. This helps us compare - // expressions like "p" and "p + 1" by normalizing "p" to "p + 0". + // parent is null. So we create a new OperatorNode with + as the operator + // and add 0 as a LeafExprNode child of this OperatorNode. This helps us + // compare expressions like "p" and "p + 1" by normalizing "p" to "p + 0". - auto *N = new BinaryNode(BO_Add, Parent); + auto *N = new OperatorNode(BO_Add, Parent); AddNode(N, Parent); llvm::APInt Zero(Ctx.getTargetInfo().getIntWidth(), 0); @@ -142,7 +138,7 @@ void PreorderAST::Create(Expr *E, Node *Parent) { // to RHS. } - auto *N = new BinaryNode(BinOp, Parent); + auto *N = new OperatorNode(BinOp, Parent); AddNode(N, Parent); Create(LHS, /*Parent*/ N); @@ -158,29 +154,17 @@ void PreorderAST::Coalesce(Node *N, bool &Changed) { if (Error) return; - auto *B = dyn_cast_or_null(N); - if (!B) + auto *O = dyn_cast_or_null(N); + if (!O) return; // Coalesce the children first. - for (auto *Child : B->Children) - if (isa(Child)) + for (auto *Child : O->Children) + 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(O)) { + CoalesceNode(O); Changed = true; } } @@ -204,71 +188,71 @@ bool PreorderAST::CompareNodes(const Node *N1, const Node *N2) { return Lex.CompareExpr(L1->E, L2->E) == Result::LessThan; } - // N2:BinaryNodeExpr < N1:LeafExprNode. + // N2:OperatorNodeExpr < N1:LeafExprNode. return false; } - // N1:BinaryNodeExpr < N2:LeafExprNode. + // N1:OperatorNodeExpr < N2:LeafExprNode. if (isa(N2)) return true; - // Compare N1:BinaryNode and N2:BinaryNode. - const auto *B1 = dyn_cast(N1); - const auto *B2 = dyn_cast(N2); + // Compare N1:OperatorNode and N2:OperatorNode. + const auto *O1 = dyn_cast(N1); + const auto *O2 = dyn_cast(N2); - if (B1->Opc != B2->Opc) - return B1->Opc < B2->Opc; - return B1->Children.size() < B2->Children.size(); + if (O1->Opc != O2->Opc) + return O1->Opc < O2->Opc; + return O1->Children.size() < O2->Children.size(); } void PreorderAST::Sort(Node *N) { - auto *B = dyn_cast_or_null(N); - if (!B) + auto *O = dyn_cast_or_null(N); + if (!O) return; // Sort the children first. - for (auto *Child : B->Children) - if (isa(Child)) + for (auto *Child : O->Children) + if (isa(Child)) Sort(Child); // We can only sort if the operator is commutative and associative. - if (!B->IsOpCommutativeAndAssociative()) + if (!O->IsOpCommutativeAndAssociative()) return; // Sort the children. - llvm::sort(B->Children.begin(), B->Children.end(), + llvm::sort(O->Children.begin(), O->Children.end(), [&](const Node *N1, const Node *N2) { return CompareNodes(N1, N2); }); } void PreorderAST::ConstantFold(Node *N, bool &Changed) { - // Note: This function assumes that the children of each BinaryNode of the + // Note: This function assumes that the children of each OperatorNode of the // preorder AST have already been sorted. if (Error) return; - auto *B = dyn_cast_or_null(N); - if (!B) + auto *O = dyn_cast_or_null(N); + if (!O) return; size_t ConstStartIdx = 0; unsigned NumConsts = 0; llvm::APSInt ConstFoldedVal; - for (size_t I = 0; I != B->Children.size(); ++I) { - auto *Child = B->Children[I]; + for (size_t I = 0; I != O->Children.size(); ++I) { + auto *Child = O->Children[I]; - // Recursively constant fold the children of a BinaryNode. - if (isa(Child)) { + // Recursively constant fold the children of a OperatorNode. + if (isa(Child)) { ConstantFold(Child, Changed); continue; } // We can only constant fold if the operator is commutative and // associative. - if (!B->IsOpCommutativeAndAssociative()) + if (!O->IsOpCommutativeAndAssociative()) continue; auto *ChildLeafNode = dyn_cast_or_null(Child); @@ -291,7 +275,7 @@ void PreorderAST::ConstantFold(Node *N, bool &Changed) { } else { // Constant fold based on the operator. bool Overflow; - switch(B->Opc) { + switch(O->Opc) { default: continue; case BO_Add: ConstFoldedVal = ConstFoldedVal.sadd_ov(CurrConstVal, Overflow); @@ -318,10 +302,10 @@ void PreorderAST::ConstantFold(Node *N, bool &Changed) { // erase the iterator automatically points to the new location of the element // following the one we just erased. llvm::SmallVector::iterator I = - B->Children.begin() + ConstStartIdx; + O->Children.begin() + ConstStartIdx; while (NumConsts--) { delete(*I); - B->Children.erase(I); + O->Children.erase(I); } llvm::APInt IntVal(Ctx.getTargetInfo().getIntWidth(), @@ -331,8 +315,14 @@ void PreorderAST::ConstantFold(Node *N, bool &Changed) { SourceLocation()); // Add the constant folded expression to list of children of the current - // BinaryNode. - B->Children.push_back(new LeafExprNode(ConstFoldedExpr, B)); + // OperatorNode. + O->Children.push_back(new LeafExprNode(ConstFoldedExpr, O)); + + // If the constant folded expr is the only child of this OperatorNode we can + // coalesce the node. + if (O->Children.size() == 1 && CanCoalesceNode(O)) + CoalesceNode(O); + Changed = true; } @@ -346,26 +336,26 @@ bool PreorderAST::GetDerefOffset(Node *UpperNode, Node *DerefNode, // (integer part of deref expr - integer part of upper bound expr). // Since we have already normalized exprs like "*p" to "*(p + 0)" we require - // that the root of the preorder AST is a BinaryNode. - auto *B1 = dyn_cast_or_null(UpperNode); - auto *B2 = dyn_cast_or_null(DerefNode); + // that the root of the preorder AST is a OperatorNode. + auto *O1 = dyn_cast_or_null(UpperNode); + auto *O2 = dyn_cast_or_null(DerefNode); - if (!B1 || !B2) + if (!O1 || !O2) return false; // If the opcodes mismatch we cannot have a valid offset. - if (B1->Opc != B2->Opc) + if (O1->Opc != O2->Opc) return false; // We have already constant folded the constants. So return false if the // number of children mismatch. - if (B1->Children.size() != B2->Children.size()) + if (O1->Children.size() != O2->Children.size()) return false; // Check if the children are equivalent. - for (size_t I = 0; I != B1->Children.size(); ++I) { - auto *Child1 = B1->Children[I]; - auto *Child2 = B2->Children[I]; + for (size_t I = 0; I != O1->Children.size(); ++I) { + auto *Child1 = O1->Children[I]; + auto *Child2 = O2->Children[I]; if (IsEqual(Child1, Child2)) continue; @@ -391,7 +381,7 @@ bool PreorderAST::GetDerefOffset(Node *UpperNode, Node *DerefNode, // addition. // Note: We have already converted (ptr - offset) to (ptr + -offset). So // its okay to only check for addition. - if (B1->Opc != BO_Add) + if (O1->Opc != BO_Add) return false; // This guards us from a case where the constants were not folded for @@ -421,25 +411,25 @@ bool PreorderAST::IsEqual(Node *N1, Node *N2) { if ((N1 && !N2) || (!N1 && N2)) return false; - if (const auto *B1 = dyn_cast(N1)) { + if (const auto *O1 = dyn_cast(N1)) { // If the types of the nodes mismatch. - if (!isa(N2)) + if (!isa(N2)) return false; - const auto *B2 = dyn_cast(N2); + const auto *O2 = dyn_cast(N2); // If the Opcodes mismatch. - if (B1->Opc != B2->Opc) + if (O1->Opc != O2->Opc) return false; // If the number of children of the two nodes mismatch. - if (B1->Children.size() != B2->Children.size()) + if (O1->Children.size() != O2->Children.size()) return false; // Match each child of the two nodes. - for (size_t I = 0; I != B1->Children.size(); ++I) { - auto *Child1 = B1->Children[I]; - auto *Child2 = B2->Children[I]; + for (size_t I = 0; I != O1->Children.size(); ++I) { + auto *Child1 = O1->Children[I]; + auto *Child2 = O2->Children[I]; // If any child differs between the two nodes. if (!IsEqual(Child1, Child2)) @@ -482,10 +472,10 @@ void PreorderAST::Normalize() { } void PreorderAST::PrettyPrint(Node *N) { - if (const auto *B = dyn_cast_or_null(N)) { - OS << BinaryOperator::getOpcodeStr(B->Opc) << "\n"; + if (const auto *O = dyn_cast_or_null(N)) { + OS << BinaryOperator::getOpcodeStr(O->Opc) << "\n"; - for (auto *Child : B->Children) + for (auto *Child : O->Children) PrettyPrint(Child); } else if (const auto *L = dyn_cast_or_null(N)) @@ -493,8 +483,8 @@ void PreorderAST::PrettyPrint(Node *N) { } void PreorderAST::Cleanup(Node *N) { - if (auto *B = dyn_cast_or_null(N)) - for (auto *Child : B->Children) + if (auto *O = dyn_cast_or_null(N)) + for (auto *Child : O->Children) Cleanup(Child); if (N) 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 +}