diff --git a/clang/lib/Analysis/BSC/BSCBorrowChecker.cpp b/clang/lib/Analysis/BSC/BSCBorrowChecker.cpp index 6988056cee8f4063bd55d5e0a76d236eac4b58c7..95bf6993442ebd3ab3ac327252c41e7b61597c7c 100644 --- a/clang/lib/Analysis/BSC/BSCBorrowChecker.cpp +++ b/clang/lib/Analysis/BSC/BSCBorrowChecker.cpp @@ -486,8 +486,8 @@ void ActionExtract::VisitDeclStmt(DeclStmt *DS) { // the DeclStmt. for (Decl *D : DS->decls()) { if (VarDecl *VD = dyn_cast(D)) { - if (VD->getType()->isStructureType() && IsTrackedType(VD->getType()) && - isa(VD->getInit())) { + if ((VD->getType()->isStructureType() || VD->getType()->isArrayType()) && + IsTrackedType(VD->getType()) && isa(VD->getInit())) { BuildOnGet = false; Dest = std::make_unique(VD->getName().str(), VD->getType(), VD->getLocation()); @@ -514,14 +514,15 @@ void ActionExtract::VisitDeclStmt(DeclStmt *DS) { } void ActionExtract::VisitInitListExpr(InitListExpr *ILE) { - if (IsTrackedType(ILE->getType())) { + if (const RecordType *RT = + dyn_cast(ILE->getType().getCanonicalType()); + RT && IsTrackedType(ILE->getType())) { + // Handle struct/union initialization with tracked fields Kind = Action::Noop; RegionName RN = RNL; RegionName CurRN; std::unique_ptr Base = std::make_unique(*Dest); unsigned Index = 0; - const RecordType *RT = - dyn_cast(ILE->getType().getCanonicalType()); for (FieldDecl *Field : RT->getDecl()->fields()) { Kind = Action::Assign; std::unique_ptr FieldName = std::make_unique(*Base); @@ -540,6 +541,33 @@ void ActionExtract::VisitInitListExpr(InitListExpr *ILE) { BuildAction(); ++Index; } + } else if (ILE->getType()->isArrayType() && IsTrackedType(ILE->getType())) { + // Handle array initialization with borrow-qualified elements + Kind = Action::Noop; + RegionName RN = RNL; + RegionName CurRN; + std::unique_ptr Base = std::make_unique(*Dest); + const ArrayType *AT = ILE->getType()->getAsArrayTypeUnsafe(); + QualType ElementType = AT->getElementType(); + unsigned Index = 0; + for (Expr *Init : ILE->inits()) { + Kind = Action::Assign; + std::unique_ptr ArrayElem = std::make_unique(*Base); + ArrayElem = std::make_unique( + std::move(ArrayElem), "[" + std::to_string(Index) + "]", + ElementType, ILE->getBeginLoc()); + Dest = std::move(ArrayElem); + if (IsTrackedType(ElementType)) + CurRN = RN; + RNL = CurRN; + op = RHS; + Visit(Init); + if (RNL.isInvalid() || RNR.isInvalid() || Sources.empty()) + Kind = Action::Init; + if (Dest) + BuildAction(); + ++Index; + } } else { for (Expr *Init : ILE->inits()) { Visit(Init); diff --git a/clang/lib/Sema/BSC/SemaDeclBSC.cpp b/clang/lib/Sema/BSC/SemaDeclBSC.cpp index c9991e6011754a4a20e424f0fed2a523803ad173..304d02b91e4ed1cf4795432c08e3f6b1c712c684 100644 --- a/clang/lib/Sema/BSC/SemaDeclBSC.cpp +++ b/clang/lib/Sema/BSC/SemaDeclBSC.cpp @@ -291,6 +291,16 @@ class BorrowCheckerPrologue : public TreeTransform { E->getType(), VK_LValue); } + // Replace with temporary variable and wrap in ImplicitCastExpr. + Expr *ReplaceWithTemporaryVariableAndWrap(Expr *E) { + DeclRefExpr *DRE = ReplaceWithTemporaryVariable(E); + CastKind Kind = + DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; + return ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, + DRE, nullptr, VK_PRValue, + FPOptionsOverride()); + } + CompoundStmt *GetOrWrapWithCompoundStmt(Stmt *S) { if (isa(S)) return dyn_cast(S); @@ -428,23 +438,13 @@ public: ExprResult Res = getDerived().TransformExpr(RS->getRetValue()); Expr *E = Res.get(); if (CallExpr *CE = dyn_cast_or_null(E)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(CE); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - ImplicitCastExpr *ICE = - ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, DRE, - nullptr, VK_PRValue, FPOptionsOverride()); + Expr *ICE = ReplaceWithTemporaryVariableAndWrap(CE); replacedNodesMap.Insert(ICE, CE); RS->setRetValue(ICE); return RS; } if (UnaryOperator *UO = dyn_cast(E)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(UO); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - ImplicitCastExpr *ICE = - ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, DRE, - nullptr, VK_PRValue, FPOptionsOverride()); + Expr *ICE = ReplaceWithTemporaryVariableAndWrap(UO); replacedNodesMap.Insert(ICE, UO); RS->setRetValue(ICE); return RS; @@ -477,12 +477,7 @@ public: ExprResult ResLHS = getDerived().TransformExpr(BO->getLHS()); Expr *ELHS = ResLHS.get(); if (CallExpr *CE = dyn_cast(ELHS)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(CE); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - ELHS = - ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, DRE, - nullptr, VK_PRValue, FPOptionsOverride()); + ELHS = ReplaceWithTemporaryVariableAndWrap(CE); replacedNodesMap.Insert(ELHS, CE); } BO->setLHS(ELHS); @@ -491,12 +486,7 @@ public: Expr *ERHS = ResRHS.get(); if (BO->getOpcode() < BO_Assign) { if (CallExpr *CE = dyn_cast(ERHS)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(CE); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - ERHS = ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, - DRE, nullptr, VK_PRValue, - FPOptionsOverride()); + ERHS = ReplaceWithTemporaryVariableAndWrap(CE); replacedNodesMap.Insert(ERHS, CE); } } @@ -513,23 +503,25 @@ public: Expr *E = Res.get(); if (CallExpr *NestedCall = dyn_cast(E)) { - E = ReplaceWithTemporaryVariable(NestedCall); - CastKind Kind = - E->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, E->getType(), Kind, E, - nullptr, VK_PRValue, FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(NestedCall); replacedNodesMap.Insert(E, NestedCall); } else if (UnaryOperator *UO = dyn_cast(E)) { if (UO->getOpcode() >= UO_AddrMut && UO->getOpcode() <= UO_AddrConstDeref) { - E = ReplaceWithTemporaryVariable(UO); - CastKind Kind = - E->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, E->getType(), Kind, E, - nullptr, VK_PRValue, - FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(UO); replacedNodesMap.Insert(E, UO); } + } else if (CStyleCastExpr *CSCE = dyn_cast(E)) { + // Handle cast from non-borrow to borrow qualified type. + if (CSCE->getType().isBorrowQualified()) { + Expr *SubExpr = CSCE->getSubExpr()->IgnoreParenImpCasts(); + if (DeclRefExpr *DRE = dyn_cast(SubExpr)) { + if (!DRE->getType().isBorrowQualified()) { + E = ReplaceWithTemporaryVariableAndWrap(CSCE); + replacedNodesMap.Insert(E, CSCE); + } + } + } } CE->setArg(i, E); } @@ -587,13 +579,7 @@ public: } else if (UnaryOperator *UO = dyn_cast(E)) { if (UO->getOpcode() >= UO_AddrMut && UO->getOpcode() <= UO_AddrConstDeref) { - E = ReplaceWithTemporaryVariable(UO); - CastKind Kind = - E->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - ImplicitCastExpr *ICE = ImplicitCastExpr::Create( - getSema().Context, E->getType(), Kind, E, nullptr, VK_PRValue, - FPOptionsOverride()); - E = ICE; + E = ReplaceWithTemporaryVariableAndWrap(UO); replacedNodesMap.Insert(E, UO); } } @@ -606,11 +592,7 @@ public: ExprResult Res = getDerived().TransformExpr(ME->getBase()); Expr *E = Res.get(); if (CallExpr *CE = dyn_cast(E)) { - E = ReplaceWithTemporaryVariable(CE); - CastKind Kind = - E->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, E->getType(), Kind, E, - nullptr, VK_PRValue, FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(CE); replacedNodesMap.Insert(E, CE); } ME->setBase(E); @@ -621,20 +603,10 @@ public: ExprResult Res = getDerived().TransformExpr(PE->getSubExpr()); Expr *E = Res.get(); if (CallExpr *CE = dyn_cast(E)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(E); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, - DRE, nullptr, VK_PRValue, - FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(E); replacedNodesMap.Insert(E, CE); } else if (BinaryOperator *BO = dyn_cast(E)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(E); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, - DRE, nullptr, VK_PRValue, - FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(E); replacedNodesMap.Insert(E, BO); } PE->setSubExpr(E); @@ -653,20 +625,10 @@ public: Expr *E = Res.get(); if (UO->getOpcode() == UO_Deref) { if (CallExpr *CE = dyn_cast(E)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(E); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, - DRE, nullptr, VK_PRValue, - FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(E); replacedNodesMap.Insert(E, CE); } else if (BinaryOperator *BO = dyn_cast(E)) { - DeclRefExpr *DRE = ReplaceWithTemporaryVariable(E); - CastKind Kind = - DRE->getType()->getAsCXXRecordDecl() ? CK_NoOp : CK_LValueToRValue; - E = ImplicitCastExpr::Create(getSema().Context, DRE->getType(), Kind, - DRE, nullptr, VK_PRValue, - FPOptionsOverride()); + E = ReplaceWithTemporaryVariableAndWrap(E); replacedNodesMap.Insert(E, BO); } } diff --git a/clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_array_int/borrow_array_int.cbs b/clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_array_int/borrow_array_int.cbs new file mode 100644 index 0000000000000000000000000000000000000000..fef908dfeba74b9c0eac452f381d72f6494d3d98 --- /dev/null +++ b/clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_array_int/borrow_array_int.cbs @@ -0,0 +1,16 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +void test(int *borrow p) { + int *borrow arr[2] = {p}; +} + +int main(){ + int * borrow a = (int* borrow)malloc(sizeof(int)); + test(a); + return 0; +} diff --git a/clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_qual_Cstyle_Cast_in_call_expr/borrow_qual_Cstyle_Cast_in_call_expr.cbs b/clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_qual_Cstyle_Cast_in_call_expr/borrow_qual_Cstyle_Cast_in_call_expr.cbs new file mode 100644 index 0000000000000000000000000000000000000000..11d9904a33efb0a22e4159c434e3c80ee45b9050 --- /dev/null +++ b/clang/test/BSC/Positive/Ownership/borrow_check_rules/borrow_qual_Cstyle_Cast_in_call_expr/borrow_qual_Cstyle_Cast_in_call_expr.cbs @@ -0,0 +1,21 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +int *borrow foo(int *borrow a, int *borrow b){ + return a; +} + +void test(int *p, int *q) { + int *borrow m = foo((int *borrow)p, (int *borrow)q); +} + +int main(){ + int * a = malloc(sizeof(int)); + int * b = malloc(sizeof(int)); + test(a,b); + return 0; +} \ No newline at end of file