From 2be2534715626924066a4eac6078e77815ae3c1b Mon Sep 17 00:00:00 2001 From: wuhuiquan Date: Wed, 21 May 2025 09:20:48 +0800 Subject: [PATCH] [safezone] add safe statement features --- clang/docs/BSC/BiShengCLanguageUserManual.md | 52 ++++------ clang/include/clang/AST/ASTDumper.h | 2 +- clang/include/clang/AST/BSC/ExprBSC.h | 40 ++++++++ clang/include/clang/AST/BSC/StmtBSC.h | 52 ++++++++++ clang/include/clang/AST/BSC/WalkerBSC.h | 4 + clang/include/clang/AST/RecursiveASTVisitor.h | 3 + clang/include/clang/AST/Stmt.h | 2 + clang/include/clang/AST/StmtVisitor.h | 1 + clang/include/clang/AST/TextNodeDumper.h | 4 +- clang/include/clang/Basic/BSC/BSCStmtNodes.td | 4 +- .../Basic/BSC/DiagnosticBSCCommonKinds.td | 3 +- .../clang/Basic/BSC/DiagnosticBSCSemaKinds.td | 1 - clang/include/clang/Basic/Specifiers.h | 1 + clang/include/clang/Parse/Parser.h | 6 ++ clang/include/clang/Sema/DeclSpec.h | 4 + clang/include/clang/Sema/Scope.h | 10 +- clang/include/clang/Sema/Sema.h | 10 +- clang/include/clang/Sema/Template.h | 1 + .../include/clang/Serialization/ASTBitCodes.h | 12 ++- clang/lib/AST/ASTDumper.cpp | 3 + clang/lib/AST/ASTStructuralEquivalence.cpp | 1 + clang/lib/AST/Expr.cpp | 4 + clang/lib/AST/ExprClassification.cpp | 10 +- clang/lib/AST/ExprConstant.cpp | 4 + clang/lib/AST/ItaniumMangle.cpp | 7 ++ clang/lib/AST/Stmt.cpp | 5 + clang/lib/AST/StmtPrinter.cpp | 9 ++ clang/lib/AST/StmtProfile.cpp | 5 + clang/lib/AST/TextNodeDumper.cpp | 20 ++++ .../lib/Analysis/BSC/BSCNullabilityCheck.cpp | 17 ++++ clang/lib/CodeGen/CGExpr.cpp | 7 ++ clang/lib/CodeGen/CGExprScalar.cpp | 3 +- clang/lib/CodeGen/CGStmt.cpp | 13 +++ clang/lib/CodeGen/CodeGenFunction.h | 3 + clang/lib/Parse/BSC/ParseExprBSC.cpp | 41 ++++++++ clang/lib/Parse/BSC/ParseStmtBSC.cpp | 45 +++++++++ clang/lib/Parse/ParseDecl.cpp | 8 ++ clang/lib/Parse/ParseExpr.cpp | 3 + clang/lib/Parse/ParseStmt.cpp | 11 ++- clang/lib/Parse/Parser.cpp | 2 + clang/lib/Sema/BSC/SemaBSCSafeZone.cpp | 12 +++ clang/lib/Sema/BSC/SemaDeclBSC.cpp | 19 +++- clang/lib/Sema/BSC/SemaStmtBSC.cpp | 12 +++ clang/lib/Sema/Scope.cpp | 2 + clang/lib/Sema/SemaDecl.cpp | 15 ++- clang/lib/Sema/SemaExceptionSpec.cpp | 6 ++ clang/lib/Sema/SemaExpr.cpp | 19 ++-- clang/lib/Sema/TreeTransform.h | 56 +++++++++++ clang/lib/Serialization/ASTReaderStmt.cpp | 23 +++++ clang/lib/Serialization/ASTWriterStmt.cpp | 19 ++++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 8 +- ...owned_struct_member_function_call_safe.cbs | 4 +- .../struct_member_function_call_safe.cbs | 4 +- .../check_zone/safe_zone_check.cbs | 13 ++- .../duplicate_declspec/duplicate_declspec.cbs | 2 + .../identical_declspec/identical_declspec.cbs | 7 +- .../Negative/SafeZone/safe_expr/safe_expr.cbs | 55 +++++++++++ .../safe_function_point.cbs | 10 +- .../Negative/SafeZone/safe_stmt/safe_stmt.cbs | 61 ++++++++++++ .../member_function_pointer_reborrow_ast.cbs | 4 +- ...truct_member_function_pointer_reborrow.cbs | 8 +- ...truct_member_function_pointer_reborrow.cbs | 6 +- .../Positive/SafeZone/safe_expr/safe_expr.cbs | 94 +++++++++++++++++++ .../safe_serialization.cbs | 64 +++++++++++++ .../Positive/SafeZone/safe_stmt/safe_stmt.cbs | 93 ++++++++++++++++++ libcbs/src/cell/cell.hbs | 6 +- libcbs/src/list/list.hbs | 2 +- libcbs/src/map/hash_map.hbs | 8 +- libcbs/src/option/option.hbs | 4 +- libcbs/src/rc/rc.hbs | 2 +- libcbs/src/result/result.hbs | 8 +- libcbs/src/vec/vec.hbs | 4 +- 72 files changed, 980 insertions(+), 103 deletions(-) create mode 100644 clang/test/BSC/Negative/SafeZone/safe_expr/safe_expr.cbs create mode 100644 clang/test/BSC/Negative/SafeZone/safe_stmt/safe_stmt.cbs create mode 100644 clang/test/BSC/Positive/SafeZone/safe_expr/safe_expr.cbs create mode 100644 clang/test/BSC/Positive/SafeZone/safe_serialization.cbs/safe_serialization.cbs create mode 100644 clang/test/BSC/Positive/SafeZone/safe_stmt/safe_stmt.cbs diff --git a/clang/docs/BSC/BiShengCLanguageUserManual.md b/clang/docs/BSC/BiShengCLanguageUserManual.md index a80a3bf1be83..9269057c95ba 100644 --- a/clang/docs/BSC/BiShengCLanguageUserManual.md +++ b/clang/docs/BSC/BiShengCLanguageUserManual.md @@ -3418,7 +3418,7 @@ void test() { c 语言有很多规则过于灵活,不方便编译器做静态检查。因此我们引入一个新语法,使得在一定范围内的毕昇 c 代码必须遵循更严格的约束,保证在这个范围内的代码肯定不会出现“内存安全”问题。 -允许用 safe/unsafe 关键字修饰一个代码块或者一个函数。 +允许用 safe/unsafe 关键字修饰函数、语句、括号表达式。 - ​ unsafe 表示这段代码在非安全区,这部分代码遵循标准 c 的规定,同时这部分代码的安全性由用户保证。 @@ -3454,17 +3454,15 @@ safe void safe_free(FileID* owned p) { int main(void) { FileID* owned p1 = create(); FileID* owned p2 = consume_and_return(p1); - // 使用 safe 修饰代码块,表示这段代码在安全区 - safe { - safe_free(p2); - } + // 使用 safe 修饰语句,表示这段代码在安全区 + safe safe_free(p2); return 0; } ``` #### 语法规则: -1. 允许使用 safe/unsafe 修饰代码块、函数声明、函数签名、函数定义。 +1. 允许使用 safe/unsafe 修饰函数声明、函数签名、函数定义、函数指针、语句、括号表达式。 ```c // 修饰函数签名 @@ -3477,36 +3475,39 @@ int main(void) { } // 修饰函数指针 safe int (*p)(int, int); - - int main() { + + safe int main(void) { safe { // 修饰代码块 int a = 1; } unsafe { int b = 1; } + // 修饰语句 + safe int c = 1; + unsafe c++; + // 修饰括号表达式 + char d = unsafe((char)c); return 0; } ``` -2. 不允许使用 safe/unsafe 修饰全局变量、类型声明、typedef 声明(允许修饰函数指针)、static_assert。 +2. 不允许使用 safe/unsafe 修饰全局变量、函数外类型声明、typedef 声明(允许修饰函数指针)。 ```c #include - + safe int g_a; // error: 不允许修饰全局变量 - safe struct b { // error: 不允许修饰类型声明 + safe struct b { // error: 不允许修饰函数外类型声明 int a; }; safe typedef int mm; // error: 不允许修饰 typedef safe typedef int (*p)(int a); // ok: 允许修饰函数指针 int main() { - safe int a; // error: 不允许修饰类型声明 - safe static_assert(1, "error"); // error: 不允许修饰 static_assert return 0; } ``` - + 3. safe 修饰的函数,参数类型和返回类型必须是 safe 类型。 非 safe 类型包括:裸指针类型、union 类型、成员中包含不安全类型的 struct 类型、成员中包含不安全类型的数组类型。 @@ -3588,8 +3589,8 @@ int main(void) { ```c safe void test1(int a) {} safe void test2(void) {} + safe void (*p)(int a); int main() { - safe void (*p)(int a); p = test1; // ok p = test2; // error: 参数类型不一致,不允许赋值 } @@ -3618,7 +3619,7 @@ int main(void) { } ``` -13. 安全区内允许再包含 unsafe 修饰的代码块、非安全区内也允许再包含 safe 修饰的代码块。 +13. 安全区内允许再包含 unsafe 修饰的语句、函数指针、括号表达式,非安全区内也允许再包含 safe 修饰的语句、函数指针、括号表达式。 ```c int test1(int a, int b) { @@ -3630,26 +3631,11 @@ int main(void) { int main() { safe { int a = 0; + unsafe a++; unsafe { a = test1(1, 3); - safe { - a = test2(3, 5); - } - } - } - } - ``` - -14. 安全区内不允许使用标签和 goto 语句。 - - ```c - void test(int a) { - safe { - if (a < 10) { - goto error; // error: 安全区不允许使用 goto 语句 + safe a = test2(3, 5); } - error: // error: 安全区内不允许使用标签 - return; } } ``` diff --git a/clang/include/clang/AST/ASTDumper.h b/clang/include/clang/AST/ASTDumper.h index 18994b8dd00a..c650dd52d474 100644 --- a/clang/include/clang/AST/ASTDumper.h +++ b/clang/include/clang/AST/ASTDumper.h @@ -46,7 +46,7 @@ public: #if ENABLE_BSC void VisitTraitTemplateDecl(const TraitTemplateDecl *D); void VisitCompoundStmt(const CompoundStmt *Node); - #endif +#endif }; } // namespace clang diff --git a/clang/include/clang/AST/BSC/ExprBSC.h b/clang/include/clang/AST/BSC/ExprBSC.h index 7a45a20c6aca..e2354f79361c 100644 --- a/clang/include/clang/AST/BSC/ExprBSC.h +++ b/clang/include/clang/AST/BSC/ExprBSC.h @@ -56,6 +56,46 @@ private: friend class ASTStmtWriter; }; +class SafeExpr : public Expr { + SafeZoneSpecifier SafeZoneSpec; + SourceLocation Loc; + Stmt *SubExpr; + +public: + SafeExpr(SourceLocation loc, SafeZoneSpecifier safeZoneSpec, Expr *val) + : Expr(SafeExprClass, val->getType(), val->getValueKind(), + val->getObjectKind()), + SafeZoneSpec(safeZoneSpec), Loc(loc), SubExpr(val) {} + + /// Construct an empty safe expression. + explicit SafeExpr(EmptyShell Empty) : Expr(SafeExprClass, Empty) {} + + const Expr *getSubExpr() const { return cast(SubExpr); } + Expr *getSubExpr() { return cast(SubExpr); } + void setSubExpr(Expr *E) { SubExpr = E; } + + SafeZoneSpecifier getSafeZoneSpecifier() const { return SafeZoneSpec; } + void setSafeZoneSpecifier(SafeZoneSpecifier sz) { SafeZoneSpec = sz; } + + SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return SubExpr->getEndLoc(); + } + + SourceLocation getSafeLoc() const { return Loc; } + void setSafeLoc(SourceLocation loc) { Loc = loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SafeExprClass; + } + + // Iterators + child_range children() { return child_range(&SubExpr, &SubExpr + 1); } + const_child_range children() const { + return const_child_range(&SubExpr, &SubExpr + 1); + } +}; + } // namespace clang #endif // ENABLE_BSC diff --git a/clang/include/clang/AST/BSC/StmtBSC.h b/clang/include/clang/AST/BSC/StmtBSC.h index 484cf97c69d5..04f7e6defe95 100644 --- a/clang/include/clang/AST/BSC/StmtBSC.h +++ b/clang/include/clang/AST/BSC/StmtBSC.h @@ -16,6 +16,58 @@ #if ENABLE_BSC +#include "clang/AST/Stmt.h" +#include "clang/Sema/Scope.h" +namespace clang { +class ASTContext; + +struct ScopeSafeZoneInfo { + SafeZoneSpecifier SafeZoneSpec; + SafeZoneSource SafeZoneSrc; + SourceLocation SafeZoneLoc; +}; + +class SafeStmt : public Stmt { + SafeZoneSpecifier SafeZoneSpec; + Stmt *SubStmt; + SourceLocation Loc; + +public: + // build safe or unsafe statement + SafeStmt(SourceLocation loc, SafeZoneSpecifier safeZoneSpec, Stmt *substmt) + : Stmt(SafeStmtClass), SafeZoneSpec(safeZoneSpec), SubStmt(substmt) { + setSafeLoc(loc); + }; + + explicit SafeStmt(EmptyShell Empty) : Stmt(SafeStmtClass, Empty) {} + + Stmt *getSubStmt() { return SubStmt; } + const Stmt *getSubStmt() const { return SubStmt; } + void setSubStmt(Stmt *SS) { SubStmt = SS; } + + SafeZoneSpecifier getSafeZoneSpecifier() const { return SafeZoneSpec; } + void setSafeZoneSpecifier(SafeZoneSpecifier sz) { SafeZoneSpec = sz; } + + SourceLocation getSafeLoc() const { return Loc; } + void setSafeLoc(SourceLocation L) { Loc = L; } + + SourceLocation getBeginLoc() const { return getSafeLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { + return SubStmt->getEndLoc(); + } + + child_range children() { return child_range(&SubStmt, &SubStmt + 1); } + const_child_range children() const { + return const_child_range(&SubStmt, &SubStmt + 1); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SafeStmtClass; + } +}; + +} // namespace clang + #endif // ENABLE_BSC #endif \ No newline at end of file diff --git a/clang/include/clang/AST/BSC/WalkerBSC.h b/clang/include/clang/AST/BSC/WalkerBSC.h index 9def7ca98e82..f8a11c8f0d3a 100644 --- a/clang/include/clang/AST/BSC/WalkerBSC.h +++ b/clang/include/clang/AST/BSC/WalkerBSC.h @@ -265,6 +265,10 @@ public: return false; } + bool VisitSafeStmt(SafeStmt *SS) { return true; } + + bool VisitSafeExpr(SafeExpr *SE) { return true; } + bool VisitInitListExpr(InitListExpr *ILE) { if (VisitQualType(ILE->getType())) { return true; diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 407aa23d1a56..bc3497687391 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -19,6 +19,7 @@ #if ENABLE_BSC #include "clang/AST/BSC/DeclBSC.h" #include "clang/AST/BSC/ExprBSC.h" +#include "clang/AST/BSC/StmtBSC.h" #endif #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -2500,6 +2501,8 @@ DEF_TRAVERSE_STMT(ObjCForCollectionStmt, {}) DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, {}) #if ENABLE_BSC DEF_TRAVERSE_STMT(AwaitExpr, {}) +DEF_TRAVERSE_STMT(SafeExpr, {}) +DEF_TRAVERSE_STMT(SafeStmt, {}) #endif DEF_TRAVERSE_STMT(CXXForRangeStmt, { diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 0b4abd1a7fba..de06deb35f65 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -1581,6 +1581,8 @@ public: } SafeZoneSpecifier getCompSafeZoneSpecifier() const { return SafeZoneSpec; } + + void setCompSafeZoneSpecifier(SafeZoneSpecifier sz) { SafeZoneSpec = sz; } #endif SourceLocation getBeginLoc() const { return LBraceLoc; } diff --git a/clang/include/clang/AST/StmtVisitor.h b/clang/include/clang/AST/StmtVisitor.h index da654e5a616b..a52645f1f2ed 100644 --- a/clang/include/clang/AST/StmtVisitor.h +++ b/clang/include/clang/AST/StmtVisitor.h @@ -15,6 +15,7 @@ #if ENABLE_BSC #include "clang/AST/BSC/ExprBSC.h" +#include "clang/AST/BSC/StmtBSC.h" #endif #include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index c7ecc0d7bae1..b7e0887d3389 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -339,7 +339,9 @@ public: void VisitVarDecl(const VarDecl *D); #if ENABLE_BSC void VisitImplTraitDecl(const ImplTraitDecl *D); - #endif + void VisitSafeStmt(const SafeStmt *SS); + void VisitSafeExpr(const SafeExpr *SE); +#endif void VisitBindingDecl(const BindingDecl *D); void VisitCapturedDecl(const CapturedDecl *D); void VisitImportDecl(const ImportDecl *D); diff --git a/clang/include/clang/Basic/BSC/BSCStmtNodes.td b/clang/include/clang/Basic/BSC/BSCStmtNodes.td index bab4fc2038c1..6dda7420b53b 100644 --- a/clang/include/clang/Basic/BSC/BSCStmtNodes.td +++ b/clang/include/clang/Basic/BSC/BSCStmtNodes.td @@ -1 +1,3 @@ -def AwaitExpr : StmtNode; \ No newline at end of file +def AwaitExpr : StmtNode; +def SafeExpr : StmtNode; +def SafeStmt : StmtNode; \ No newline at end of file diff --git a/clang/include/clang/Basic/BSC/DiagnosticBSCCommonKinds.td b/clang/include/clang/Basic/BSC/DiagnosticBSCCommonKinds.td index db5cebb8bf79..422b5a780ec7 100644 --- a/clang/include/clang/Basic/BSC/DiagnosticBSCCommonKinds.td +++ b/clang/include/clang/Basic/BSC/DiagnosticBSCCommonKinds.td @@ -1 +1,2 @@ -def err_unsafe_action : Error<"%0 is forbidden in the safe zone">; \ No newline at end of file +def err_unsafe_action : Error<"%0 is forbidden in the safe zone">; +def err_safe_zone_decl : Error<"%select{|'safe'|'unsafe'}0 can only appear before on function or statement or parenthesized expression"> ; \ No newline at end of file diff --git a/clang/include/clang/Basic/BSC/DiagnosticBSCSemaKinds.td b/clang/include/clang/Basic/BSC/DiagnosticBSCSemaKinds.td index a32f34e84627..835962d4cbd6 100644 --- a/clang/include/clang/Basic/BSC/DiagnosticBSCSemaKinds.td +++ b/clang/include/clang/Basic/BSC/DiagnosticBSCSemaKinds.td @@ -116,7 +116,6 @@ def err_constexpr_if_cond_expr_unsupported_type : Error< def err_unsafe_cast : Error<"conversion from type %0 to %1 is forbidden in the safe zone">; def err_unsafe_fun_cast : Error<"conversion from type %0 to %1 is forbidden">; def err_safe_function : Error<"%0 is forbidden in the safe function">; -def err_safe_zone_decl : Error<"%select{|'safe'|'unsafe'}0 can only appear before on function or compound statement"> ; def err_safe_global_var : Error<"defining mutable global variables is not allowed within the safe zone"> ; // BSC owned struct diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index 72154a835a48..c2b2ec398340 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -415,6 +415,7 @@ namespace clang { SZS_Inherit = 0, SZS_Function = 1, SZS_Compound = 2, + SZS_SafeStmt = 3, }; enum PreferInlineScopeSpecifier { diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index a8ec7ce8df21..d361c380830d 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2169,6 +2169,12 @@ private: StmtResult ParseExprStatement(ParsedStmtContext StmtCtx); StmtResult ParseLabeledStatement(ParsedAttributes &Attrs, ParsedStmtContext StmtCtx); +#if ENABLE_BSC + StmtResult ParseSafeStatement(ParsedStmtContext StmtCtx); + ExprResult ParseSafeExpression(); + struct ScopeSafeZoneInfo getCurScopeSafeZoneInfo(); + void setCurScopeSafeZoneInfo(struct ScopeSafeZoneInfo SZ); +#endif StmtResult ParseCaseStatement(ParsedStmtContext StmtCtx, bool MissingCase = false, ExprResult Expr = ExprResult()); diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 2f84558ae9fd..4f576b9b2dd8 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -670,6 +670,10 @@ public: return (SafeZoneSpecifier)FS_safe_zone_specified; } SourceLocation getSafeZoneSpecifierLoc() const { return FS_safe_zone_loc; } + void SetSafeZoneSpecifier(SafeZoneSpecifier SZS) { + FS_safe_zone_specified = SZS; + } + void SetSafeZoneSpecifierLoc(SourceLocation SL) { FS_safe_zone_loc = SL; } #endif ExplicitSpecifier getExplicitSpecifier() const { diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h index d0a425ec2237..1852ac8212de 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -16,14 +16,17 @@ #include "clang/AST/Decl.h" #include "clang/Basic/Diagnostic.h" #if ENABLE_BSC +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" -#include #endif #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/iterator_range.h" #include +#if ENABLE_BSC +#include +#endif namespace llvm { @@ -233,6 +236,7 @@ private: #if ENABLE_BSC SafeZoneSpecifier SafeZoneSpec; SafeZoneSource SafeZoneSrc; + SourceLocation SafeZoneLoc; #endif public: @@ -281,9 +285,13 @@ public: void setScopeSafeZoneSource(SafeZoneSource SafeZoneSrc) { const_cast(this)->SafeZoneSrc = SafeZoneSrc; } + void setScopeSafeZoneLoc(SourceLocation SafeZoneLoc) { + const_cast(this)->SafeZoneLoc = SafeZoneLoc; + } SafeZoneSpecifier getScopeSafeZoneSpecifier() const { return SafeZoneSpec; } SafeZoneSource getScopeSafeZoneSource() const { return SafeZoneSrc; } + SourceLocation getScopeSafeZoneLoc() const { return SafeZoneLoc; } #endif // Set whether we're in the scope of a condition variable, where 'continue' // is disallowed despite being a continue scope. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9b81a134c800..4f06eec6d8a0 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -22,6 +22,7 @@ #if ENABLE_BSC #include "clang/AST/BSC/DeclBSC.h" #include "clang/AST/BSC/ExprBSC.h" +#include "clang/AST/BSC/StmtBSC.h" #endif #include "clang/AST/ComparisonCategories.h" #include "clang/AST/DeclTemplate.h" @@ -5125,6 +5126,12 @@ public: Stmt *SubStmt, Scope *CurScope); StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, SourceLocation ColonLoc, Stmt *SubStmt); +#if ENABLE_BSC + StmtResult ActOnSafeStmt(SourceLocation SafeZoneLoc, + SafeZoneSpecifier safeZoneSpec, Stmt *SubStmt); + ExprResult ActOnSafeExpr(SourceLocation SafeZoneLoc, + SafeZoneSpecifier safeZoneSpec, Expr *SubExpr); +#endif StmtResult BuildAttributedStmt(SourceLocation AttrsLoc, ArrayRef Attrs, Stmt *SubStmt); @@ -12428,6 +12435,7 @@ public: void PopInsSafeZone(); sema::InsCompoundSafeZoneInfo &getCurInsCompoundSafeZone() const; SafeZoneSpecifier getInstantiationSafeZoneSpecifier(); + void setInstantiationSafeZoneSpecifier(SafeZoneSpecifier SZ); bool HasDiffBorrowOrOwnedParamsTypeAtBothFunction(QualType LHS, QualType RHS); ExprResult CheckBSCConstexprCondition(SourceLocation Loc, Expr *CondExpr, bool IsConstexpr); @@ -12453,7 +12461,7 @@ public: bool CheckBSCOverloadedOperatorDeclaration(FunctionDecl *FnDecl); bool CheckIsUnsafeOverloadCall(Expr *Fn); bool FindSafeFeatures(const FunctionDecl* FnDecl); - bool HasSafeZoneInCompoundStmt(const CompoundStmt* CompStmt); + bool HasSafeZoneInStmt(const Stmt *CompStmt); bool HasSafeZoneInFunction(const FunctionDecl* FnDecl); void CheckMemberThisCallAccess(Expr *ActualArgExpr, QualType formalType); bool CheckNeedCastQualifiedType(QualType actualType, QualType formalType); diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 56bd73685974..a98db2c0a75c 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -462,6 +462,7 @@ enum class TemplateSubstitutionKind : char { } #if ENABLE_BSC SafeZoneSpecifier getScopeSafeZoneSpecifier() const { return SafeZoneSpec; } + void setScopeSafeZoneSpecifier(SafeZoneSpecifier SZ) { SafeZoneSpec = SZ; } #endif /// Find the instantiation of the declaration D within the current /// instantiation scope. diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 6e3fa5e2e3c1..a0391e4a83aa 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1580,6 +1580,10 @@ enum StmtCode { /// A LabelStmt record. STMT_LABEL, +#if ENABLE_BSC + /// A SafeStmt record. + STMT_SAFE, +#endif /// An AttributedStmt record. STMT_ATTRIBUTED, @@ -1655,6 +1659,10 @@ enum StmtCode { /// A ParenListExpr record. EXPR_PAREN_LIST, +#if ENABLE_BSC + /// A SafeExpr record. + EXPR_SAFE, +#endif /// A UnaryOperator record. EXPR_UNARY_OPERATOR, @@ -2024,9 +2032,9 @@ enum StmtCode { EXPR_COAWAIT, EXPR_COYIELD, EXPR_DEPENDENT_COAWAIT, - #if ENABLE_BSC +#if ENABLE_BSC EXPR_BSC_AWAIT, - #endif +#endif // FixedPointLiteral EXPR_FIXEDPOINT_LITERAL, diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index 23eafbda5684..3d0c8e4f9a18 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -13,6 +13,9 @@ #include "clang/AST/ASTDumper.h" #include "clang/AST/ASTContext.h" +#if ENABLE_BSC +#include "clang/AST/BSC/StmtBSC.h" +#endif #include "clang/AST/DeclLookups.h" #include "clang/AST/JSONNodeDumper.h" #include "clang/Basic/Builtins.h" diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 8dead93769d4..028da580e183 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -65,6 +65,7 @@ #if ENABLE_BSC #include "clang/AST/BSC/DeclBSC.h" #include "clang/AST/BSC/ExprBSC.h" +#include "clang/AST/BSC/StmtBSC.h" #endif #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index c55477431d52..48d6c2e56484 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Attr.h" #if ENABLE_BSC #include "clang/AST/BSC/ExprBSC.h" +#include "clang/AST/BSC/StmtBSC.h" #endif #include "clang/AST/ComputeDependence.h" #include "clang/AST/DeclCXX.h" @@ -3592,6 +3593,9 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case ShuffleVectorExprClass: case ConvertVectorExprClass: case AsTypeExprClass: +#if ENABLE_BSC + case SafeExprClass: +#endif // These have a side-effect if any subexpression does. break; diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 289362792dae..4046685e06a0 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -10,11 +10,14 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/Expr.h" #include "clang/AST/ASTContext.h" +#if ENABLE_BSC +#include "clang/AST/BSC/ExprBSC.h" +#endif #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "llvm/Support/ErrorHandling.h" @@ -303,6 +306,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::ParenExprClass: return ClassifyInternal(Ctx, cast(E)->getSubExpr()); +#if ENABLE_BSC + case Expr::SafeExprClass: + return ClassifyInternal(Ctx, cast(E)->getSubExpr()); +#endif + // C11 6.5.1.1p4: [A generic selection] is an lvalue, a function designator, // or a void expression if its result expression is, respectively, an // lvalue, a function designator, or a void expression. diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 0d7aa2caeab1..1036fad80de1 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -15471,6 +15471,10 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::ParenExprClass: return CheckICE(cast(E)->getSubExpr(), Ctx); +#if ENABLE_BSC + case Expr::SafeExprClass: + return CheckICE(cast(E)->getSubExpr(), Ctx); +#endif case Expr::GenericSelectionExprClass: return CheckICE(cast(E)->getResultExpr(), Ctx); case Expr::IntegerLiteralClass: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 9d67b30faebc..326d35ee0daf 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Attr.h" #if ENABLE_BSC #include "clang/AST/BSC/DeclBSC.h" +#include "clang/AST/BSC/ExprBSC.h" #endif #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" @@ -4924,6 +4925,12 @@ recurse: E = cast(E)->getSubExpr(); goto recurse; +#if ENABLE_BSC + case Expr::SafeExprClass: + E = cast(E)->getSubExpr(); + goto recurse; +#endif + case Expr::ConceptSpecializationExprClass: { // ::= L E # external name Out << "L_Z"; diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 9d849acf2049..dddc3abc0c9e 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Attr.h" #if ENABLE_BSC #include "clang/AST/BSC/ExprBSC.h" +#include "clang/AST/BSC/StmtBSC.h" #endif #include "clang/AST/Decl.h" #include "clang/AST/DeclGroup.h" @@ -226,6 +227,10 @@ const Stmt *Stmt::stripLabelLikeStatements() const { S = SC->getSubStmt(); else if (const auto *AS = dyn_cast(S)) S = AS->getSubStmt(); +#if ENABLE_BSC + else if (const auto *SS = dyn_cast(S)) + S = SS->getSubStmt(); +#endif else return S; } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 8b829627c235..39abed1a1358 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -310,6 +310,15 @@ void StmtPrinter::VisitLabelStmt(LabelStmt *Node) { PrintStmt(Node->getSubStmt(), 0); } +#if ENABLE_BSC +void StmtPrinter::VisitSafeStmt(SafeStmt *Node) { + PrintStmt(Node->getSubStmt(), 0); +} +void StmtPrinter::VisitSafeExpr(SafeExpr *Node) { + PrintExpr(Node->getSubExpr()); +} +#endif + void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) { for (const auto *Attr : Node->getAttrs()) { Attr->printPretty(OS, Policy); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 6421ee9aba71..40498c81efb2 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -259,6 +259,11 @@ void StmtProfiler::VisitLabelStmt(const LabelStmt *S) { VisitDecl(S->getDecl()); } +#if ENABLE_BSC +void StmtProfiler::VisitSafeStmt(const SafeStmt *S) { VisitStmt(S); } +void StmtProfiler::VisitSafeExpr(const SafeExpr *S) { VisitExpr(S); } +#endif + void StmtProfiler::VisitAttributedStmt(const AttributedStmt *S) { VisitStmt(S); // TODO: maybe visit attributes? diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index ac36729795bd..f8e33b298c12 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -2437,3 +2437,23 @@ void TextNodeDumper::VisitCompoundStmt(const CompoundStmt *S) { if (S->hasStoredFPFeatures()) printFPOptions(S->getStoredFPFeatures()); } + +#if ENABLE_BSC +void TextNodeDumper::VisitSafeStmt(const SafeStmt *SS) { + SafeZoneSpecifier SafeZoneSpec = SS->getSafeZoneSpecifier(); + if (SafeZoneSpec == SZ_Safe) { + OS << " safe"; + } else if (SafeZoneSpec == SZ_Unsafe) { + OS << " unsafe"; + } +} + +void TextNodeDumper::VisitSafeExpr(const SafeExpr *SE) { + SafeZoneSpecifier SafeZoneSpec = SE->getSafeZoneSpecifier(); + if (SafeZoneSpec == SZ_Safe) { + OS << " safe"; + } else if (SafeZoneSpec == SZ_Unsafe) { + OS << " unsafe"; + } +} +#endif diff --git a/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp b/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp index cd70652457ea..111d821cafb2 100644 --- a/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp +++ b/clang/lib/Analysis/BSC/BSCNullabilityCheck.cpp @@ -16,6 +16,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" +#include "clang/AST/BSC/ExprBSC.h" #include "clang/Analysis/FlowSensitive/DataflowWorklist.h" #include "llvm/ADT/DenseMap.h" #include "clang/AST/ParentMap.h" @@ -264,6 +265,22 @@ bool TransferFunctions::IsStmtInSafeZone(Stmt *S) { return false; } } + if (auto *SS = dyn_cast(ParentStmt)) { + SafeZoneSpecifier SafeZoneSpec = SS->getSafeZoneSpecifier(); + if (SafeZoneSpec == SZ_Safe) { + return true; + } else if (SafeZoneSpec == SZ_Unsafe) { + return false; + } + } + if (auto *SE = dyn_cast(ParentStmt)) { + SafeZoneSpecifier SafeZoneSpec = SE->getSafeZoneSpecifier(); + if (SafeZoneSpec == SZ_Safe) { + return true; + } else if (SafeZoneSpec == SZ_Unsafe) { + return false; + } + } ParentStmt = PM.getParent(ParentStmt); } return Fd.getSafeZoneSpecifier() == SZ_Safe; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index f78b66c13ed5..142b88d803e5 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -24,6 +24,9 @@ #include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#if ENABLE_BSC +#include "clang/AST/BSC/ExprBSC.h" +#endif #include "clang/AST/DeclObjC.h" #include "clang/AST/NSAPI.h" #include "clang/Basic/Builtins.h" @@ -1361,6 +1364,10 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { } case Expr::ParenExprClass: return EmitLValue(cast(E)->getSubExpr()); +#if ENABLE_BSC + case Expr::SafeExprClass: + return EmitLValue(cast(E)->getSubExpr()); +#endif case Expr::GenericSelectionExprClass: return EmitLValue(cast(E)->getResultExpr()); case Expr::PredefinedExprClass: diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index c689fa310858..ed03aa8efe9f 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -449,7 +449,8 @@ public: } #if ENABLE_BSC Value *VisitAwaitExpr(AwaitExpr *E) { return Visit(E->getSubExpr()); } - #endif + Value *VisitSafeExpr(SafeExpr *E) { return Visit(E->getSubExpr()); } +#endif // Leaves. Value *VisitIntegerLiteral(const IntegerLiteral *E) { diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 9935fcc0d3ea..396a9167045e 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -99,6 +99,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef Attrs) { case Stmt::CompoundStmtClass: case Stmt::DeclStmtClass: case Stmt::LabelStmtClass: +#if ENABLE_BSC + case Stmt::SafeStmtClass: +#endif case Stmt::AttributedStmtClass: case Stmt::GotoStmtClass: case Stmt::BreakStmtClass: @@ -443,6 +446,11 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S, case Stmt::LabelStmtClass: EmitLabelStmt(cast(*S)); break; +#if ENABLE_BSC + case Stmt::SafeStmtClass: + EmitSafeStmt(cast(*S)); + break; +#endif case Stmt::AttributedStmtClass: EmitAttributedStmt(cast(*S)); break; @@ -681,6 +689,11 @@ void CodeGenFunction::LexicalScope::rescopeLabels() { } } +#if ENABLE_BSC +void CodeGenFunction::EmitSafeStmt(const SafeStmt &S) { + EmitStmt(S.getSubStmt()); +} +#endif void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) { EmitLabel(S.getDecl()); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 672acd844525..fd37ee40e49a 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3234,6 +3234,9 @@ public: void EmitLabel(const LabelDecl *D); // helper for EmitLabelStmt. void EmitLabelStmt(const LabelStmt &S); +#if ENABLE_BSC + void EmitSafeStmt(const SafeStmt &S); +#endif void EmitAttributedStmt(const AttributedStmt &S); void EmitGotoStmt(const GotoStmt &S); void EmitIndirectGotoStmt(const IndirectGotoStmt &S); diff --git a/clang/lib/Parse/BSC/ParseExprBSC.cpp b/clang/lib/Parse/BSC/ParseExprBSC.cpp index 3c2ea08d30e9..4db1891d36fe 100644 --- a/clang/lib/Parse/BSC/ParseExprBSC.cpp +++ b/clang/lib/Parse/BSC/ParseExprBSC.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/Parser.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" #include "clang/Parse/RAIIObjectsForParser.h" using namespace clang; @@ -157,4 +158,44 @@ bool Parser::IsSupportedOverloadType(OverloadedOperatorKind Op) { } } +/// ParseSafeExpression:In BSC grammar, use of the 'safe' or 'unsafe' keyword to +/// modify parenthetical expressions is permitted, such as `int a = safe +/// (funcall())`. +/// +/// safe-expression +/// 'safe' ParenExpression +/// 'unsafe' ParenExpression +ExprResult Parser::ParseSafeExpression() { + SafeZoneSpecifier SafeZoneSpec = SZ_None; + SourceLocation SafeLoc; + if (Tok.is(tok::kw_safe)) { + SafeZoneSpec = SZ_Safe; + SafeLoc = ConsumeToken(); + } else if (Tok.is(tok::kw_unsafe)) { + SafeZoneSpec = SZ_Unsafe; + SafeLoc = ConsumeToken(); + } + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << "safe"; + return ExprError(); + } + struct ScopeSafeZoneInfo newInfo = {SafeZoneSpec, SZS_SafeStmt, SafeLoc}; + struct ScopeSafeZoneInfo oldInfo = getCurScopeSafeZoneInfo(); + setCurScopeSafeZoneInfo(newInfo); + + ParenParseOption ParenExprType = SimpleExpr; + ParsedType CastTy; + SourceLocation RParenLoc; + ExprResult SubExpr = + ParseParenExpression(ParenExprType, false, false, CastTy, RParenLoc); + if (SubExpr.isInvalid()) { + setCurScopeSafeZoneInfo(oldInfo); + return ExprError(); + } + + ExprResult Expr = Actions.ActOnSafeExpr(SafeLoc, SafeZoneSpec, SubExpr.get()); + setCurScopeSafeZoneInfo(oldInfo); + return Expr; +} + #endif // ENABLE_BSC \ No newline at end of file diff --git a/clang/lib/Parse/BSC/ParseStmtBSC.cpp b/clang/lib/Parse/BSC/ParseStmtBSC.cpp index 7e729c8cd160..ccf1dcfcd59e 100644 --- a/clang/lib/Parse/BSC/ParseStmtBSC.cpp +++ b/clang/lib/Parse/BSC/ParseStmtBSC.cpp @@ -13,6 +13,7 @@ #if ENABLE_BSC +#include "clang/Basic/SourceLocation.h" #include "clang/Parse/Parser.h" using namespace clang; @@ -29,5 +30,49 @@ void Parser::CheckStmtTokInSafeZone(tok::TokenKind Kind) { break; } } +struct ScopeSafeZoneInfo Parser::getCurScopeSafeZoneInfo() { + if (getCurScope()) { + return {getCurScope()->getScopeSafeZoneSpecifier(), + getCurScope()->getScopeSafeZoneSource(), + getCurScope()->getScopeSafeZoneLoc()}; + } + return {SZ_None, SZS_Inherit, SourceLocation()}; +} + +void Parser::setCurScopeSafeZoneInfo(struct ScopeSafeZoneInfo SZ) { + if (getCurScope()) { + getCurScope()->setScopeSafeZoneSpecifier(SZ.SafeZoneSpec); + getCurScope()->setScopeSafeZoneSource(SZ.SafeZoneSrc); + getCurScope()->setScopeSafeZoneLoc(SZ.SafeZoneLoc); + } +} + +/// ParseSafeExpression:In BSC grammar, use of the 'safe' or 'unsafe' keyword to +/// modify statement is permitted, such as `safe int a = funcall()`. +/// +/// safe-statement +/// 'safe' statement +/// 'unsafe' statement +StmtResult Parser::ParseSafeStatement(ParsedStmtContext StmtCtx) { + SafeZoneSpecifier SafeZoneSpec = SZ_None; + SourceLocation SafeLoc; + if (Tok.is(tok::kw_safe)) { + SafeZoneSpec = SZ_Safe; + SafeLoc = ConsumeToken(); + } else if (Tok.is(tok::kw_unsafe)) { + SafeZoneSpec = SZ_Unsafe; + SafeLoc = ConsumeToken(); + } + struct ScopeSafeZoneInfo newInfo = {SafeZoneSpec, SZS_SafeStmt, SafeLoc}; + struct ScopeSafeZoneInfo oldInfo = getCurScopeSafeZoneInfo(); + setCurScopeSafeZoneInfo(newInfo); + StmtResult SubStmt = ParseStatement(nullptr, StmtCtx); + if (SubStmt.isInvalid()) + SubStmt = Actions.ActOnNullStmt(SafeLoc); + + StmtResult Stmt = Actions.ActOnSafeStmt(SafeLoc, SafeZoneSpec, SubStmt.get()); + setCurScopeSafeZoneInfo(oldInfo); + return Stmt; +} #endif \ No newline at end of file diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 3faa4ceba9ca..69a96dca84b7 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -4641,6 +4641,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, #if ENABLE_BSC DS.SetRangeEnd(ConsumedEnd.isValid() ? ConsumedEnd : SwitchTok.getLocation()); + // Handle the case where the "safe" keyword modifies the function pointer + if (getCurScope() && + getCurScope()->getScopeSafeZoneSource() == SZS_SafeStmt) { + DS.SetSafeZoneSpecifier(getCurScope()->getScopeSafeZoneSpecifier()); + DS.SetSafeZoneSpecifierLoc(getCurScope()->getScopeSafeZoneLoc()); + } #else DS.SetRangeEnd(ConsumedEnd.isValid() ? ConsumedEnd : Tok.getLocation()); #endif @@ -7224,6 +7230,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, if (SafeZoneSpec != SZ_None) { getCurScope()->setScopeSafeZoneSpecifier(SafeZoneSpec); getCurScope()->setScopeSafeZoneSource(SZS_Function); + getCurScope()->setScopeSafeZoneLoc( + D.getDeclSpec().getSafeZoneSpecifierLoc()); } #endif diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 4feb552a2fd1..d65a3ec279de 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1060,6 +1060,9 @@ ExprResult Parser::ParseCastExpression( isVectorLiteral, NotPrimaryExpression); #if ENABLE_BSC + case tok::kw_safe: + case tok::kw_unsafe: + return ParseSafeExpression(); case tok::kw_union: case tok::kw_enum: case tok::kw_struct: diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index caa799abb883..63aa081f1555 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -325,12 +325,14 @@ Default: Token Next = NextToken(); if (Next.is(tok::l_brace)) return ParseCompoundStatement(); + if (Next.is(tok::l_paren)) + return ParseExprStatement(StmtCtx); if (Next.is(tok::kw_safe) || Next.is(tok::kw_unsafe)) { Diag(Next.getLocation(), diag::err_duplicate_declspec) << Tok.getKind(); ConsumeToken(); return StmtError(); } - goto Default; + return ParseSafeStatement(StmtCtx); } #endif @@ -1083,13 +1085,13 @@ StmtResult Parser::ParseCompoundStatement(bool isStmtExpr, ResetPreferInlineScopeToNone(); SafeZoneSpecifier SafeZoneSpec = SZ_None; - + SourceLocation SafeZoneLoc; if (Tok.is(tok::kw_safe)) { SafeZoneSpec = SZ_Safe; - ConsumeToken(); + SafeZoneLoc = ConsumeToken(); } else if (Tok.is(tok::kw_unsafe)) { SafeZoneSpec = SZ_Unsafe; - ConsumeToken(); + SafeZoneLoc = ConsumeToken(); } #endif @@ -1102,6 +1104,7 @@ StmtResult Parser::ParseCompoundStatement(bool isStmtExpr, if (getCurScope() && SafeZoneSpec != SZ_None) { getCurScope()->setScopeSafeZoneSpecifier(SafeZoneSpec); getCurScope()->setScopeSafeZoneSource(SZS_Compound); + getCurScope()->setScopeSafeZoneLoc(SafeZoneLoc); } #endif // Parse the statements in the body. diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index d4268f68d979..178d939e3056 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1405,6 +1405,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, if (SafeZoneSpec != SZ_None) { getCurScope()->setScopeSafeZoneSpecifier(SafeZoneSpec); getCurScope()->setScopeSafeZoneSource(SZS_Function); + getCurScope()->setScopeSafeZoneLoc( + D.getDeclSpec().getSafeZoneSpecifierLoc()); } #endif diff --git a/clang/lib/Sema/BSC/SemaBSCSafeZone.cpp b/clang/lib/Sema/BSC/SemaBSCSafeZone.cpp index cad99765f657..83e6c5dd069e 100644 --- a/clang/lib/Sema/BSC/SemaBSCSafeZone.cpp +++ b/clang/lib/Sema/BSC/SemaBSCSafeZone.cpp @@ -438,6 +438,18 @@ sema::InsCompoundSafeZoneInfo &Sema::getCurInsCompoundSafeZone() const { return getCurFunction()->InsCompoundSafeZone.back(); } +void Sema::setInstantiationSafeZoneSpecifier(SafeZoneSpecifier SZ) { + if (getCurFunction()) { + if (getCurFunction()->InsCompoundSafeZone.size() == 0) { + if (CurrentInstantiationScope) + CurrentInstantiationScope->setScopeSafeZoneSpecifier(SZ); + } else { + PopInsSafeZone(); + PushInsSafeZone(SZ); + } + } +} + SafeZoneSpecifier Sema::getInstantiationSafeZoneSpecifier() { SafeZoneSpecifier SafeZoneSpec = SZ_None; if (getCurFunction()) { diff --git a/clang/lib/Sema/BSC/SemaDeclBSC.cpp b/clang/lib/Sema/BSC/SemaDeclBSC.cpp index 4e77f12f9ec3..c9991e601175 100644 --- a/clang/lib/Sema/BSC/SemaDeclBSC.cpp +++ b/clang/lib/Sema/BSC/SemaDeclBSC.cpp @@ -122,19 +122,32 @@ bool Sema::FindSafeFeatures(const FunctionDecl* FnDecl) { return false; } -bool Sema::HasSafeZoneInCompoundStmt(const CompoundStmt* CompStmt) { +bool Sema::HasSafeZoneInStmt(const Stmt *CompStmt) { if (!CompStmt) { return false; } for (const Stmt *child: CompStmt->children()) { + if (!child) { + continue; + } if (auto *CompChild = dyn_cast(child)) { if (CompChild->getCompSafeZoneSpecifier() == SZ_Safe) { return true; } - if (HasSafeZoneInCompoundStmt(CompChild)) { + } + if (auto *CompChild = dyn_cast(child)) { + if (CompChild->getSafeZoneSpecifier() == SZ_Safe) { return true; } } + if (auto *CompChild = dyn_cast(child)) { + if (CompChild->getSafeZoneSpecifier() == SZ_Safe) { + return true; + } + } + if (HasSafeZoneInStmt(child)) { + return true; + } } return false; } @@ -150,7 +163,7 @@ bool Sema::HasSafeZoneInFunction(const FunctionDecl* FnDecl) { if (!FuncBody) { return false; } - return HasSafeZoneInCompoundStmt(FuncBody); + return HasSafeZoneInStmt(FuncBody); } /// BSC's dataflow analysis process is as follows: diff --git a/clang/lib/Sema/BSC/SemaStmtBSC.cpp b/clang/lib/Sema/BSC/SemaStmtBSC.cpp index fd6376ab73e4..84f50142c19b 100644 --- a/clang/lib/Sema/BSC/SemaStmtBSC.cpp +++ b/clang/lib/Sema/BSC/SemaStmtBSC.cpp @@ -50,4 +50,16 @@ ExprResult Sema::CheckBSCConstexprCondition(SourceLocation Loc, Expr *CondExpr, } return CheckCXXBooleanCondition(CondExpr, IsConstexpr); } + +StmtResult Sema::ActOnSafeStmt(SourceLocation SafeZoneLoc, + SafeZoneSpecifier safeZoneSpec, Stmt *SubStmt) { + SafeStmt *LS = new (Context) SafeStmt(SafeZoneLoc, safeZoneSpec, SubStmt); + return LS; +} + +ExprResult Sema::ActOnSafeExpr(SourceLocation SafeZoneLoc, + SafeZoneSpecifier safeZoneSpec, Expr *SubExpr) { + SafeExpr *LS = new (Context) SafeExpr(SafeZoneLoc, safeZoneSpec, SubExpr); + return LS; +} #endif \ No newline at end of file diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp index 56189b086554..21037d0df6a0 100644 --- a/clang/lib/Sema/Scope.cpp +++ b/clang/lib/Sema/Scope.cpp @@ -42,6 +42,7 @@ void Scope::setFlags(Scope *parent, unsigned flags) { #if ENABLE_BSC SafeZoneSpec = parent->SafeZoneSpec; SafeZoneSrc = SZS_Inherit; + SafeZoneLoc = parent->SafeZoneLoc; #endif if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope | FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) == @@ -58,6 +59,7 @@ void Scope::setFlags(Scope *parent, unsigned flags) { #if ENABLE_BSC SafeZoneSpec = SZ_Unsafe; SafeZoneSrc = SZS_Inherit; + SafeZoneLoc = SourceLocation(); #endif } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 53e980a3d396..89f05e90ced2 100755 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6526,12 +6526,17 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, QualType T = TInfo->getType(); if (TryDesugarTrait(T)) AddToScope = false; - // 'safe' or 'unsafe' can only appear before on function or compound - // statement + // 'safe' or 'unsafe' can only appear before on function or statement or + // parenthesized expression. if (D.getDeclSpec().getSafeZoneSpecifier() != SZ_None && - !R->isFunctionPointerType() && !R->isFunctionType()) - Diag(D.getDeclSpec().getSafeZoneSpecifierLoc(), diag::err_safe_zone_decl) - << D.getDeclSpec().getSafeZoneSpecifier(); + !R->isFunctionPointerType() && !R->isFunctionType()) { + if (!getCurScope() || + (getCurScope() && + getCurScope()->getScopeSafeZoneSource() != SZS_SafeStmt)) + Diag(D.getDeclSpec().getSafeZoneSpecifierLoc(), + diag::err_safe_zone_decl) + << D.getDeclSpec().getSafeZoneSpecifier(); + } } #endif // If this has an identifier and is not a function template specialization, diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 439346acbc7a..288c0eb6ccf8 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1285,6 +1285,9 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::ObjCIvarRefExprClass: case Expr::ParenExprClass: case Expr::ParenListExprClass: +#if ENABLE_BSC + case Expr::SafeExprClass: +#endif case Expr::ShuffleVectorExprClass: case Expr::StmtExprClass: case Expr::ConvertVectorExprClass: @@ -1512,6 +1515,9 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Stmt::OMPParallelGenericLoopDirectiveClass: case Stmt::OMPTargetParallelGenericLoopDirectiveClass: case Stmt::ReturnStmtClass: +#if ENABLE_BSC + case Stmt::SafeStmtClass: +#endif case Stmt::SEHExceptStmtClass: case Stmt::SEHFinallyStmtClass: case Stmt::SEHLeaveStmtClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 17c2a48c89f5..10c488b24d5b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -7105,14 +7105,6 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, #if ENABLE_BSC if (getLangOpts().BSC) { - // unsafe function call is forbidden in the safe zone - if ((IsInSafeZone()) && - (Fn->getType()->checkFunctionProtoType(SZ_None) || - Fn->getType()->checkFunctionProtoType(SZ_Unsafe))) { - Diag(Fn->getBeginLoc(), diag::err_unsafe_action) - << "unsafe function call"; - } - // // This branch is for attempting to parse a function-call // in the body of template function. Such as: // @Code: @@ -7498,7 +7490,16 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // Keep flag unchanged in transformation. TheCall->getCallee()->IsDesugaredBSCMethodCall = Fn->IsDesugaredBSCMethodCall; TheCall->getCallee()->HasBSCScopeSpec = Fn->HasBSCScopeSpec; - #endif + if (getLangOpts().BSC) { + // unsafe function call is forbidden in the safe zone + if ((IsInSafeZone()) && + (Fn->getType()->checkFunctionProtoType(SZ_None) || + Fn->getType()->checkFunctionProtoType(SZ_Unsafe))) { + Diag(Fn->getBeginLoc(), diag::err_unsafe_action) + << "unsafe function call"; + } + } +#endif } if (!Context.isDependenceAllowed()) { diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index b21dca918839..00c79b543822 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -17,6 +17,7 @@ #include "TypeLocBuilder.h" #if ENABLE_BSC #include "clang/AST/BSC/ExprBSC.h" +#include "clang/AST/BSC/StmtBSC.h" #endif #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -1322,6 +1323,26 @@ public: return SemaRef.ActOnLabelStmt(IdentLoc, L, ColonLoc, SubStmt); } +#if ENABLE_BSC + /// Build a new safe statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + StmtResult RebuildSafeStmt(SourceLocation SafeZoneLoc, + SafeZoneSpecifier safeZoneSpec, Stmt *SubStmt) { + return SemaRef.ActOnSafeStmt(SafeZoneLoc, safeZoneSpec, SubStmt); + } + + /// Build a new safe expression. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildSafeExpr(SourceLocation SafeZoneLoc, + SafeZoneSpecifier safeZoneSpec, Expr *SubExpr) { + return SemaRef.ActOnSafeExpr(SafeZoneLoc, safeZoneSpec, SubExpr); + } +#endif + /// Build a new attributed statement. /// /// By default, performs semantic analysis to build the new statement. @@ -7557,6 +7578,41 @@ TreeTransform::TransformLabelStmt(LabelStmt *S, StmtDiscardKind SDK) { SubStmt.get()); } +#if ENABLE_BSC +template +StmtResult TreeTransform::TransformSafeStmt(SafeStmt *S) { + SafeZoneSpecifier OldSafeZoneSpec = + getSema().getInstantiationSafeZoneSpecifier(); + getSema().setInstantiationSafeZoneSpecifier(S->getSafeZoneSpecifier()); + StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); + if (SubStmt.isInvalid()) { + getSema().setInstantiationSafeZoneSpecifier(OldSafeZoneSpec); + return StmtError(); + } + StmtResult Stmt = getDerived().RebuildSafeStmt( + S->getSafeLoc(), S->getSafeZoneSpecifier(), SubStmt.get()); + getSema().setInstantiationSafeZoneSpecifier(OldSafeZoneSpec); + return Stmt; +} + +template +ExprResult TreeTransform::TransformSafeExpr(SafeExpr *E) { + SafeZoneSpecifier OldSafeZoneSpec = + getSema().getInstantiationSafeZoneSpecifier(); + getSema().setInstantiationSafeZoneSpecifier(E->getSafeZoneSpecifier()); + ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + if (SubExpr.isInvalid()) { + getSema().setInstantiationSafeZoneSpecifier(OldSafeZoneSpec); + return ExprError(); + } + + ExprResult Stmt = getDerived().RebuildSafeExpr( + E->getSafeLoc(), E->getSafeZoneSpecifier(), SubExpr.get()); + getSema().setInstantiationSafeZoneSpecifier(OldSafeZoneSpec); + return Stmt; +} +#endif + template const Attr *TreeTransform::TransformAttr(const Attr *R) { if (!R) diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 8842ad291d47..27d5cd32d6b3 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -156,6 +156,7 @@ void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) { assert(S->hasStoredFPFeatures() == HasFPFeatures); #if ENABLE_BSC S->setSafeSpecifier(static_cast(Record.readInt())); + S->setCompSafeZoneSpecifier(static_cast(Record.readInt())); #endif while (NumStmts--) Stmts.push_back(Record.readSubStmt()); @@ -201,6 +202,22 @@ void ASTStmtReader::VisitLabelStmt(LabelStmt *S) { S->setSideEntry(IsSideEntry); } +#if ENABLE_BSC +void ASTStmtReader::VisitSafeStmt(SafeStmt *S) { + VisitStmt(S); + S->setSafeZoneSpecifier(static_cast(Record.readInt())); + S->setSubStmt(Record.readSubStmt()); + S->setSafeLoc(readSourceLocation()); +} + +void ASTStmtReader::VisitSafeExpr(SafeExpr *E) { + VisitExpr(E); + E->setSafeZoneSpecifier(static_cast(Record.readInt())); + E->setSubExpr(Record.readSubExpr()); + E->setSafeLoc(readSourceLocation()); +} +#endif + void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) { VisitStmt(S); // NumAttrs in AttributedStmt is set when creating an empty @@ -4026,6 +4043,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { case EXPR_BSC_AWAIT: S = new (Context) AwaitExpr(Empty); break; + case STMT_SAFE: + S = new (Context) SafeStmt(Empty); + break; + case EXPR_SAFE: + S = new (Context) SafeExpr(Empty); + break; #endif case EXPR_CONCEPT_SPECIALIZATION: { diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index cb19ab6202fa..c450058f51a5 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -94,6 +94,7 @@ void ASTStmtWriter::VisitCompoundStmt(CompoundStmt *S) { Record.push_back(S->hasStoredFPFeatures()); #if ENABLE_BSC Record.push_back(S->getSafeSpecifier()); + Record.push_back(S->getCompSafeZoneSpecifier()); #endif for (auto *CS : S->body()) #if ENABLE_BSC @@ -148,6 +149,24 @@ void ASTStmtWriter::VisitLabelStmt(LabelStmt *S) { Code = serialization::STMT_LABEL; } +#if ENABLE_BSC +void ASTStmtWriter::VisitSafeStmt(SafeStmt *S) { + VisitStmt(S); + Record.push_back(S->getSafeZoneSpecifier()); + Record.AddStmt(S->getSubStmt()); + Record.AddSourceLocation(S->getSafeLoc()); + Code = serialization::STMT_SAFE; +} + +void ASTStmtWriter::VisitSafeExpr(SafeExpr *E) { + VisitExpr(E); + Record.push_back(E->getSafeZoneSpecifier()); + Record.AddStmt(E->getSubExpr()); + Record.AddSourceLocation(E->getSafeLoc()); + Code = serialization::EXPR_SAFE; +} +#endif + void ASTStmtWriter::VisitAttributedStmt(AttributedStmt *S) { VisitStmt(S); Record.push_back(S->getAttrs().size()); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index ed21da387547..ab31adbd0821 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1486,7 +1486,10 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, Engine.addAbortedBlock(node, currBldrCtx->getBlock()); break; } - +#if ENABLE_BSC + case Stmt::SafeExprClass: + llvm_unreachable("SafeExprs already handled."); +#endif case Stmt::ParenExprClass: llvm_unreachable("ParenExprs already handled."); case Stmt::GenericSelectionExprClass: @@ -1509,6 +1512,9 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::NullStmtClass: case Stmt::SwitchStmtClass: case Stmt::WhileStmtClass: +#if ENABLE_BSC + case Stmt::SafeStmtClass: +#endif case Expr::MSDependentExistsStmtClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ImplicitValueInitExprClass: diff --git a/clang/test/BSC/Negative/Method/This/this_as_first_parameter/member_function_call/owned_struct_member_function_call_safe/owned_struct_member_function_call_safe.cbs b/clang/test/BSC/Negative/Method/This/this_as_first_parameter/member_function_call/owned_struct_member_function_call_safe/owned_struct_member_function_call_safe.cbs index 2c2b506cc0e1..f0cadaf33af3 100644 --- a/clang/test/BSC/Negative/Method/This/this_as_first_parameter/member_function_call/owned_struct_member_function_call_safe/owned_struct_member_function_call_safe.cbs +++ b/clang/test/BSC/Negative/Method/This/this_as_first_parameter/member_function_call/owned_struct_member_function_call_safe/owned_struct_member_function_call_safe.cbs @@ -5,8 +5,8 @@ owned struct Bar { public: int a; }; -T* owned safe_malloc(T value); -void free_owned(T* owned p); +safe T* owned safe_malloc(T value); +safe void free_owned(T* owned p); // T* owned safe_malloc(T value) { // T * p = (T *) malloc( sizeof(T) ); diff --git a/clang/test/BSC/Negative/Method/This/this_as_first_parameter/member_function_call/struct_member_function_call_safe/struct_member_function_call_safe.cbs b/clang/test/BSC/Negative/Method/This/this_as_first_parameter/member_function_call/struct_member_function_call_safe/struct_member_function_call_safe.cbs index 35e004ae2bbf..6f8f96d0478f 100644 --- a/clang/test/BSC/Negative/Method/This/this_as_first_parameter/member_function_call/struct_member_function_call_safe/struct_member_function_call_safe.cbs +++ b/clang/test/BSC/Negative/Method/This/this_as_first_parameter/member_function_call/struct_member_function_call_safe/struct_member_function_call_safe.cbs @@ -4,8 +4,8 @@ struct Foo { int a; }; -T* owned safe_malloc(T value); -void free_owned(T* owned p); +safe T* owned safe_malloc(T value); +safe void free_owned(T* owned p); safe int struct Foo::getA(This this) { return this.a; diff --git a/clang/test/BSC/Negative/NullabilityCheck/check_zone/safe_zone_check.cbs b/clang/test/BSC/Negative/NullabilityCheck/check_zone/safe_zone_check.cbs index 70c8370c750d..a49163c72207 100644 --- a/clang/test/BSC/Negative/NullabilityCheck/check_zone/safe_zone_check.cbs +++ b/clang/test/BSC/Negative/NullabilityCheck/check_zone/safe_zone_check.cbs @@ -7,9 +7,11 @@ safe void check_dereferenced_test1(void) { unsafe { int a = 2; *p = a; + safe *p = a; // expected-error {{nullable pointer cannot be dereferenced}} } } - *p = 5; // expected-error {{nullable pointer cannot be dereferenced}} + *p = 5; // expected-error {{nullable pointer cannot be dereferenced}} + unsafe *p = 5; // ok } void check_dereferenced_test2() { int *borrow _Nullable p = nullptr; @@ -35,6 +37,15 @@ void check_dereferenced_test3() { } } + +void check_dereferenced_test4() { + int *borrow _Nullable p = nullptr; + if (p != nullptr) { + safe *p = 5; + } + safe *p = 10; // expected-error {{nullable pointer cannot be dereferenced}} +} + safe void check_assigned_test(void) { int *borrow p = nullptr; // expected-error {{nonnull pointer cannot be assigned by nullable pointer}} unsafe { diff --git a/clang/test/BSC/Negative/SafeZone/duplicate_declspec/duplicate_declspec.cbs b/clang/test/BSC/Negative/SafeZone/duplicate_declspec/duplicate_declspec.cbs index 834c857988cb..4abf03a78c95 100644 --- a/clang/test/BSC/Negative/SafeZone/duplicate_declspec/duplicate_declspec.cbs +++ b/clang/test/BSC/Negative/SafeZone/duplicate_declspec/duplicate_declspec.cbs @@ -23,7 +23,9 @@ int main() int b = 1; } safe safe int (*r)(int a); // expected-error {{duplicate 'safe' declaration specifier}} + // expected-error@-1 {{uninitialized declarator is forbidden in the safe zone}} unsafe safe int (*s)(int a); // expected-error {{duplicate 'unsafe' declaration specifier}} + // expected-error@-1 {{uninitialized declarator is forbidden in the safe zone}} return 0; } \ No newline at end of file diff --git a/clang/test/BSC/Negative/SafeZone/identical_declspec/identical_declspec.cbs b/clang/test/BSC/Negative/SafeZone/identical_declspec/identical_declspec.cbs index 36710ee205f4..40e05081dfb7 100644 --- a/clang/test/BSC/Negative/SafeZone/identical_declspec/identical_declspec.cbs +++ b/clang/test/BSC/Negative/SafeZone/identical_declspec/identical_declspec.cbs @@ -5,11 +5,11 @@ safe int add(int x, int y) { // expected-error {{conflicting types for 'add'}} return x + y; } -safe int g_a; // expected-error {{'safe' can only appear before on function or compound statement}} -safe struct b { // expected-error {{'safe' can only appear before on function or compound statement}} +safe int g_a; // expected-error {{'safe' can only appear before on function or statement or parenthesized expression}} +safe struct b { // expected-error {{'safe' can only appear before on function or statement or parenthesized expression}} int a; }; -safe enum c { // expected-error {{'safe' can only appear before on function or compound statement}} +safe enum c { // expected-error {{'safe' can only appear before on function or statement or parenthesized expression}} TA, TB, TC @@ -35,6 +35,7 @@ int (*pfun)(int x, int y); int main() { unsafe int (*qq)(int x, int y); // expected-note {{previous definition is here}} safe int (*qq)(int x, int y); // expected-error {{redefinition of 'qq' with a different type: 'safe int (*)(int, int)' vs 'int (*)(int, int)'}} + // expected-error@-1 {{uninitialized declarator is forbidden in the safe zone}} sapfun = safun; sapfun = unfun; // expected-error {{incompatible function pointer types assigning to 'safe int (*)(int, int)' from 'int (int, int)'}} diff --git a/clang/test/BSC/Negative/SafeZone/safe_expr/safe_expr.cbs b/clang/test/BSC/Negative/SafeZone/safe_expr/safe_expr.cbs new file mode 100644 index 000000000000..44d1b66f6391 --- /dev/null +++ b/clang/test/BSC/Negative/SafeZone/safe_expr/safe_expr.cbs @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +safe void test_safe_expr1(void){ + int a = 0; + a++; // expected-error {{'++' operator is forbidden in the safe zone}} + int a1 = unsafe(a++); // ok + int *b = &a; // expected-error {{'&' operator is forbidden in the safe zone}} + int *c = unsafe(&a); // ok + unsafe { + int *d = &a; // ok + int *e = safe(&a); // expected-error {{'&' operator is forbidden in the safe zone}} + } +} + +void test_safe_expr2() { + int a = 0; + a++; // ok + int a1 = safe(a++); // expected-error {{'++' operator is forbidden in the safe zone}} + int *b = &a; // ok + int *c = safe(&a); // expected-error {{'&' operator is forbidden in the safe zone}} + safe { + int *d = &a; // expected-error {{'&' operator is forbidden in the safe zone}} + int *e = unsafe(&a); // ok + } +} + +safe void foo(T* owned p) { + T * a = (T*)p // expected-error {{conversion from type 'T *owned' to 'T *' is forbidden in the safe zone}} + T * b = unsafe((T*)p); // ok + T * c = (T*)p; // expected-error {{conversion from type 'T *owned' to 'T *' is forbidden in the safe zone}} +} + +safe void test_safe_expr3(void) { + int a = 0; + int *owned p = unsafe((int *owned)&a); + foo(p); +} + +int getNum() { + return 1; +} + +safe void setNum(int b) { + int a = b; + return; +} + +safe void test_safe_expr4(void) { + setNum(getNum()); // expected-error {{unsafe function call is forbidden in the safe zone}} + setNum(unsafe(getNum())); // ok + unsafe { + setNum(getNum()); // ok + setNum(safe(getNum())); // expected-error {{unsafe function call is forbidden in the safe zone}} + } +} \ No newline at end of file diff --git a/clang/test/BSC/Negative/SafeZone/safe_function_point/safe_function_point.cbs b/clang/test/BSC/Negative/SafeZone/safe_function_point/safe_function_point.cbs index 71334939e789..7a42a402b74e 100644 --- a/clang/test/BSC/Negative/SafeZone/safe_function_point/safe_function_point.cbs +++ b/clang/test/BSC/Negative/SafeZone/safe_function_point/safe_function_point.cbs @@ -8,17 +8,21 @@ safe double dadd(double a, double b) { return a + b; } +safe int dadd2(double a, double b) { + return 1; +} + typedef safe int (*TP)(int a, int b); int main() { - safe int (*p)(int a, int b); + safe int (*p)(int a, int b) = add; p = add; //ok TP tp = add; // ok - safe int (*pa)(int a); + safe int (*pa)(int a); // expected-error {{uninitialized declarator is forbidden in the safe zone}} pa = add; // expected-error {{incompatible function pointer types assigning to 'safe int (*)(int)' from 'safe int (int, int)'}} - safe int (*pp)(double a, double b); + safe int (*pp)(double a, double b) = dadd2; pp = add; // expected-error {{incompatible function pointer types assigning to 'safe int (*)(double, double)' from 'safe int (int, int)'}} pp = dadd; // expected-error {{incompatible function pointer types assigning to 'safe int (*)(double, double)' from 'safe double (double, double)'}} diff --git a/clang/test/BSC/Negative/SafeZone/safe_stmt/safe_stmt.cbs b/clang/test/BSC/Negative/SafeZone/safe_stmt/safe_stmt.cbs new file mode 100644 index 000000000000..2552cc07b7ac --- /dev/null +++ b/clang/test/BSC/Negative/SafeZone/safe_stmt/safe_stmt.cbs @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +safe void test_safe_stmt1(void){ + int a = 0; + a++; // expected-error {{'++' operator is forbidden in the safe zone}} + unsafe a++; // ok + int *b = &a; // expected-error {{'&' operator is forbidden in the safe zone}} + unsafe int *c = &a; // ok + unsafe { + int *d = &a; // ok + safe int *e = &a; // expected-error {{'&' operator is forbidden in the safe zone}} + } +} + +void test_safe_stmt2() { + int a = 0; + a++; // ok + safe a++; // expected-error {{'++' operator is forbidden in the safe zone}} + int *b = &a; // ok + safe int *c = &a; // expected-error {{'&' operator is forbidden in the safe zone}} + safe { + int *d = &a; // expected-error {{'&' operator is forbidden in the safe zone}} + unsafe int *e = &a; // ok + } +} + +T add(T a, T b) { + return a + b; +} + +safe void foo(T* owned p) { + T * a = (T*)p // expected-error {{conversion from type 'T *owned' to 'T *' is forbidden in the safe zone}} + unsafe T * b = (T*)p; // ok + T * c = (T*)p; // expected-error {{conversion from type 'T *owned' to 'T *' is forbidden in the safe zone}} +} + +safe void test_safe_stmt3(void) { + int a = 0; + for (int i = 0; i < 10; i++) { // expected-error {{'++' operator is forbidden in the safe zone}} + a++; // expected-error {{'++' operator is forbidden in the safe zone}} + } + unsafe for (int i = 0; i < 10; i++) { // ok + a++; // ok + } + while(a > 0) { + a--; // expected-error {{'--' operator is forbidden in the safe zone}} + } + unsafe while(a < 10) { + a++; // ok + } + test_safe_stmt2(); // expected-error {{unsafe function call is forbidden in the safe zone}} + unsafe test_safe_stmt2(); // ok + unsafe switch(a) { + case 1: a++; // ok + case 2: a = a +5; + safe default: a--; // expected-error {{'--' operator is forbidden in the safe zone}} + } + add(1, 2); // expected-error {{unsafe function call is forbidden in the safe zone}} + unsafe int *owned p = (int *owned)&a; + foo(p); +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Method/This/this_as_first_parameter/member_function_pointer_reborrow/member_function_pointer_reborrow_ast/member_function_pointer_reborrow_ast.cbs b/clang/test/BSC/Positive/Method/This/this_as_first_parameter/member_function_pointer_reborrow/member_function_pointer_reborrow_ast/member_function_pointer_reborrow_ast.cbs index 56c709110448..03af527fd4a0 100644 --- a/clang/test/BSC/Positive/Method/This/this_as_first_parameter/member_function_pointer_reborrow/member_function_pointer_reborrow_ast/member_function_pointer_reborrow_ast.cbs +++ b/clang/test/BSC/Positive/Method/This/this_as_first_parameter/member_function_pointer_reborrow/member_function_pointer_reborrow_ast/member_function_pointer_reborrow_ast.cbs @@ -6,8 +6,8 @@ struct Foo { int a; }; -T* owned safe_malloc(T value); -void free_owned(T* owned p); +safe T* owned safe_malloc(T value); +safe void free_owned(T* owned p); int struct Foo::getB(This* this) { diff --git a/clang/test/BSC/Positive/Method/This/this_as_first_parameter/member_function_pointer_reborrow/owned_struct_member_function_pointer_reborrow/owned_struct_member_function_pointer_reborrow.cbs b/clang/test/BSC/Positive/Method/This/this_as_first_parameter/member_function_pointer_reborrow/owned_struct_member_function_pointer_reborrow/owned_struct_member_function_pointer_reborrow.cbs index 74e71d7e76f7..de3d0b238946 100644 --- a/clang/test/BSC/Positive/Method/This/this_as_first_parameter/member_function_pointer_reborrow/owned_struct_member_function_pointer_reborrow/owned_struct_member_function_pointer_reborrow.cbs +++ b/clang/test/BSC/Positive/Method/This/this_as_first_parameter/member_function_pointer_reborrow/owned_struct_member_function_pointer_reborrow/owned_struct_member_function_pointer_reborrow.cbs @@ -18,9 +18,9 @@ T* owned safe_malloc(T value); void free_owned(T* owned p); T* owned safe_malloc(T value) { - T * p = (T *) malloc( sizeof(T) ); - *p = value; - return (T* owned)p; + T * p = (T *) malloc( sizeof(T) ); + *p = value; + return (T* owned)p; } void free_owned(T* owned p) { @@ -54,7 +54,7 @@ safe int Bar::getC_2(const This* borrow this) { } safe void Bar::getD(This* owned this) { - free_owned(this); + unsafe free_owned(this); } void test_non_pointer_This_call_reborrow() { diff --git a/clang/test/BSC/Positive/Method/This/this_as_first_parameter/member_function_pointer_reborrow/struct_member_function_pointer_reborrow/struct_member_function_pointer_reborrow.cbs b/clang/test/BSC/Positive/Method/This/this_as_first_parameter/member_function_pointer_reborrow/struct_member_function_pointer_reborrow/struct_member_function_pointer_reborrow.cbs index dc07fd416eaf..b65020f5003f 100644 --- a/clang/test/BSC/Positive/Method/This/this_as_first_parameter/member_function_pointer_reborrow/struct_member_function_pointer_reborrow/struct_member_function_pointer_reborrow.cbs +++ b/clang/test/BSC/Positive/Method/This/this_as_first_parameter/member_function_pointer_reborrow/struct_member_function_pointer_reborrow/struct_member_function_pointer_reborrow.cbs @@ -14,7 +14,7 @@ struct Foo { }; T* owned safe_malloc(T value); -void free_owned(T* owned p); +safe void free_owned(T* owned p); T* owned safe_malloc(T value) { T * p = (T *) malloc( sizeof(T) ); @@ -22,8 +22,8 @@ T* owned safe_malloc(T value) { return (T* owned)p; } -void free_owned(T* owned p) { - free( (void *)p ); +safe void free_owned(T* owned p) { + unsafe free( (void *)p ); } int struct Foo::getB(This* this) { diff --git a/clang/test/BSC/Positive/SafeZone/safe_expr/safe_expr.cbs b/clang/test/BSC/Positive/SafeZone/safe_expr/safe_expr.cbs new file mode 100644 index 000000000000..a2f18db5c492 --- /dev/null +++ b/clang/test/BSC/Positive/SafeZone/safe_expr/safe_expr.cbs @@ -0,0 +1,94 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// RUN: %clang -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +int *g_a; +safe void test_safe_stmt1(void) { + int v = 1; + g_a = unsafe(&v); + int *borrow a = unsafe(&mut *g_a); + int b = *a; +} + +safe void test_safe_stmt2(void) { + int v = 1; + g_a = unsafe(&v); + int b = 0; + b = unsafe(*g_a); +} + +safe void test_safe_stmt3(void){ + int v = 1; + g_a = unsafe(&v); + for(int i = 0; i < 10; i = i + 1) { + int b = unsafe(*g_a); + } +} + +int test_safe_stmt4() { + return 1; +} + +safe void test_safe_stmt5(int a) { + int b = a; + return; +} + +safe void test_safe_stmt6(void) { + test_safe_stmt5(unsafe(test_safe_stmt4())); +} + +int main() { + test_safe_stmt1(); + test_safe_stmt2(); + test_safe_stmt3(); + test_safe_stmt6(); +} + +// CHECK: int *g_a; +// CHECK-EMPTY: +// CHECK: void test_safe_stmt1(void) { +// CHECK-NEXT: int v = 1; +// CHECK-NEXT: g_a = (&v); +// CHECK-NEXT: int * a = (&*g_a); +// CHECK-NEXT: int b = *a; +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK: void test_safe_stmt2(void) { +// CHECK-NEXT: int v = 1; +// CHECK-NEXT: g_a = (&v); +// CHECK-NEXT: int b = 0; +// CHECK-NEXT: b = (*g_a); +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK: void test_safe_stmt3(void) { +// CHECK-NEXT: int v = 1; +// CHECK-NEXT: g_a = (&v); +// CHECK-NEXT: for (int i = 0; i < 10; i = i + 1) { +// CHECK-NEXT: int b = (*g_a); +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK: int test_safe_stmt4() { +// CHECK-NEXT: return 1; +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK: void test_safe_stmt5(int a) { +// CHECK-NEXT: int b = a; +// CHECK-NEXT: return; +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK: void test_safe_stmt6(void) { +// CHECK-NEXT: test_safe_stmt5((test_safe_stmt4())); +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK: int main() { +// CHECK-NEXT: test_safe_stmt1(); +// CHECK-NEXT: test_safe_stmt2(); +// CHECK-NEXT: test_safe_stmt3(); +// CHECK-NEXT: test_safe_stmt6(); +// CHECK-NEXT: } \ No newline at end of file diff --git a/clang/test/BSC/Positive/SafeZone/safe_serialization.cbs/safe_serialization.cbs b/clang/test/BSC/Positive/SafeZone/safe_serialization.cbs/safe_serialization.cbs new file mode 100644 index 000000000000..7eaf84cea4dc --- /dev/null +++ b/clang/test/BSC/Positive/SafeZone/safe_serialization.cbs/safe_serialization.cbs @@ -0,0 +1,64 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +// RUN: %clang -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output + +// Test with serialization: +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-pch -o %t %s +// RUN: %clang_cc1 -x bsc -triple x86_64-unknown-unknown -include-pch %t -ast-dump-all /dev/null \ +// RUN: | sed -e "s/ //" -e "s/ imported//" \ +// RUN: | FileCheck --strict-whitespace %s + +int *g_a; + +safe void test_safe_stmt1(void) { + int v = 1; + unsafe g_a = &v; + unsafe int *borrow a = &mut *g_a; + safe int b = *a; + safe { + int c = *a; + } +} + +int main() { + test_safe_stmt1(); +} + +// CHECK: FunctionDecl 0x{{[^ ]*}} line:[[@LINE-14]]:11 used test_safe_stmt1 'void (void)' +// CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} +// CHECK-NEXT: DeclStmt 0x{{[^ ]*}} +// CHECK-NEXT: VarDecl 0x{{[^ ]*}} col:9 used v 'int' cinit +// CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} 'int' 1 +// CHECK-NEXT: SafeStmt 0x{{[^ ]*}} unsafe +// CHECK-NEXT: BinaryOperator 0x{{[^ ]*}} 'int *' '=' +// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'int *' lvalue Var 0x{{[^ ]*}} 'g_a' 'int *' +// CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} 'int *' prefix '&' cannot overflow +// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'int' lvalue Var 0x{{[^ ]*}} 'v' 'int' +// CHECK-NEXT: SafeStmt 0x{{[^ ]*}} unsafe +// CHECK-NEXT: DeclStmt 0x{{[^ ]*}} +// CHECK-NEXT: VarDecl 0x{{[^ ]*}} col:24 used a 'int *borrow' cinit +// CHECK-NEXT: ImplicitCastExpr 0x{{[^ ]*}} 'int *' +// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'int *' lvalue Var 0x{{[^ ]*}} 'g_a' 'int *' +// CHECK-NEXT: SafeStmt 0x{{[^ ]*}} safe +// CHECK-NEXT: DeclStmt 0x{{[^ ]*}} +// CHECK-NEXT: VarDecl 0x{{[^ ]*}} col:14 b 'int' cinit +// CHECK-NEXT: ImplicitCastExpr 0x{{[^ ]*}} 'int' +// CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} 'int' lvalue prefix '*' cannot overflow +// CHECK-NEXT: ImplicitCastExpr 0x{{[^ ]*}} 'int *borrow' +// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'int *borrow' lvalue Var 0x{{[^ ]*}} 'a' 'int *borrow' +// CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} safe +// CHECK-NEXT: DeclStmt 0x{{[^ ]*}} +// CHECK-NEXT: VarDecl 0x{{[^ ]*}} col:13 c 'int' cinit +// CHECK-NEXT: ImplicitCastExpr 0x{{[^ ]*}} 'int' +// CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} 'int' lvalue prefix '*' cannot overflow +// CHECK-NEXT: ImplicitCastExpr 0x{{[^ ]*}} 'int *borrow' +// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'int *borrow' lvalue Var 0x{{[^ ]*}} 'a' 'int *borrow' +// CHECK: FunctionDecl 0x{{[^ ]*}} line:[[@LINE-33]]:5 main 'int (void)' +// CHECK-NEXT: CompoundStmt 0x{{[^ ]*}} +// CHECK-NEXT: CallExpr 0x{{[^ ]*}} 'void' +// CHECK-NEXT: ImplicitCastExpr 0x{{[^ ]*}} 'void (*)(void)' +// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'void (void)' Function 0x{{[^ ]*}} 'test_safe_stmt1' 'void (void)' diff --git a/clang/test/BSC/Positive/SafeZone/safe_stmt/safe_stmt.cbs b/clang/test/BSC/Positive/SafeZone/safe_stmt/safe_stmt.cbs new file mode 100644 index 000000000000..9fb1ebcd94aa --- /dev/null +++ b/clang/test/BSC/Positive/SafeZone/safe_stmt/safe_stmt.cbs @@ -0,0 +1,93 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// RUN: %clang -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +int *g_a; +safe void test_safe_stmt1(void) { + int v = 1; + unsafe g_a = &v; + unsafe int *borrow a = &mut *g_a; + int b = *a; +} + +safe void test_safe_stmt2(void) { + int v = 1; + unsafe g_a = &v; + int b = 0; + unsafe b = *g_a; +} + +safe void test_safe_stmt3(void){ + int v = 1; + unsafe g_a = &v; + unsafe for(int i = 0; i < 10; i++) { + int b = *g_a; + } +} + +safe void test_safe_stmt4(void){ + int v = 1; + unsafe g_a = &v; + unsafe for(int i = 0; i < 10; i++) { + int b = *g_a; + safe { + b = b + 1; + unsafe b++; + } + } +} + +int main() { + test_safe_stmt1(); + test_safe_stmt2(); + test_safe_stmt3(); + test_safe_stmt4(); +} + +// CHECK: int *g_a; +// CHECK-EMPTY: +// CHECK: void test_safe_stmt1(void) { +// CHECK-NEXT: int v = 1; +// CHECK-NEXT: g_a = &v; +// CHECK-NEXT: int * a = &*g_a; +// CHECK-NEXT: int b = *a; +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK: void test_safe_stmt2(void) { +// CHECK-NEXT: int v = 1; +// CHECK-NEXT: g_a = &v; +// CHECK-NEXT: int b = 0; +// CHECK-NEXT: b = *g_a; +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK: void test_safe_stmt3(void) { +// CHECK-NEXT: int v = 1; +// CHECK-NEXT: g_a = &v; +// CHECK-NEXT: for (int i = 0; i < 10; i++) { +// CHECK-NEXT: int b = *g_a; +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK: void test_safe_stmt4(void) { +// CHECK-NEXT: int v = 1; +// CHECK-NEXT: g_a = &v; +// CHECK-NEXT: for (int i = 0; i < 10; i++) { +// CHECK-NEXT: int b = *g_a; +// CHECK-NEXT: { +// CHECK-NEXT: b = b + 1; +// CHECK-NEXT: b++; +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK: int main() { +// CHECK-NEXT: test_safe_stmt1(); +// CHECK-NEXT: test_safe_stmt2(); +// CHECK-NEXT: test_safe_stmt3(); +// CHECK-NEXT: test_safe_stmt4(); +// CHECK-NEXT: } +// CHECK-EMPTY: diff --git a/libcbs/src/cell/cell.hbs b/libcbs/src/cell/cell.hbs index 16c09cb7e321..cb237b941442 100644 --- a/libcbs/src/cell/cell.hbs +++ b/libcbs/src/cell/cell.hbs @@ -10,7 +10,7 @@ struct Cell { }; safe Cell Cell::new(T value) { - _Static_assert(is_move_semantic() == false, "Cell can only be used for copyable type."); + unsafe _Static_assert(is_move_semantic() == false, "Cell can only be used for copyable type."); Cell cell = { .value = value }; return cell; } @@ -18,13 +18,13 @@ safe Cell Cell::new(T value) { // Return a copy of the contained value, // Here T should not be owned type, because borrow type cannot move ownership. safe T Cell::get(const This * borrow this) { - _Static_assert(is_move_semantic() == false, "Cell can only be used for copyable type."); + unsafe _Static_assert(is_move_semantic() == false, "Cell can only be used for copyable type."); return this->value; } // Replace the contained value by val. safe void Cell::set(const This * borrow this, T val) { - _Static_assert(is_move_semantic() == false, "Cell can only be used for copyable type."); + unsafe _Static_assert(is_move_semantic() == false, "Cell can only be used for copyable type."); unsafe { Cell * borrow p = (Cell * borrow)this; p->value = val; diff --git a/libcbs/src/list/list.hbs b/libcbs/src/list/list.hbs index 035e36a2479c..8328b4ba1191 100644 --- a/libcbs/src/list/list.hbs +++ b/libcbs/src/list/list.hbs @@ -66,7 +66,7 @@ static void LinkedList::unlink_node(LinkedList * borrow this, _BSC_ListNod safe LinkedList LinkedList::new(void){ - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate LinkedList with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap T with an owned struct."); diff --git a/libcbs/src/map/hash_map.hbs b/libcbs/src/map/hash_map.hbs index ca96bb32caec..e12c04ca5e00 100644 --- a/libcbs/src/map/hash_map.hbs +++ b/libcbs/src/map/hash_map.hbs @@ -224,11 +224,11 @@ safe Option HashMap::remove(HashMap* borrow this, const K* // The hash map will be able to hold at least `cap` elements without // reallocating. If `cap` is 0, the hash map will not allocate. safe HashMap HashMap::with_capacity_and_hasher(size_t cap, S hash_builder) { - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate HashMap with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap K with an owned struct."); - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate HashMap with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap V with an owned struct."); @@ -245,11 +245,11 @@ safe HashMap HashMap::with_capacity_and_hasher(size_t cap, S h // The hash map is initially created with a capacity of 0, // so it will not allocate until it is first inserted into. safe HashMap HashMap::with_hasher(S hash_builder) { - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate HashMap with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap K with an owned struct."); - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate HashMap with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap V with an owned struct."); diff --git a/libcbs/src/option/option.hbs b/libcbs/src/option/option.hbs index 28d3b0add1c5..352e87990944 100644 --- a/libcbs/src/option/option.hbs +++ b/libcbs/src/option/option.hbs @@ -45,7 +45,7 @@ safe _Bool Option::is_some(const Option* borrow this) { // Creates a `Some` value. safe Option Option::Some(T t) { - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate Option with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap T with an owned struct."); @@ -62,7 +62,7 @@ safe Option Option::Some(T t) { // Creates a `None` value. safe Option Option::None(void) { - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate Option with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap T with an owned struct."); diff --git a/libcbs/src/rc/rc.hbs b/libcbs/src/rc/rc.hbs index 4237279e16c9..17bd0d4741ff 100644 --- a/libcbs/src/rc/rc.hbs +++ b/libcbs/src/rc/rc.hbs @@ -26,7 +26,7 @@ public: }; safe Rc Rc::new(T data) { - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate Rc with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap T with an owned struct."); diff --git a/libcbs/src/result/result.hbs b/libcbs/src/result/result.hbs index 91ef47be6853..de66ba061f51 100644 --- a/libcbs/src/result/result.hbs +++ b/libcbs/src/result/result.hbs @@ -51,11 +51,11 @@ safe _Bool Result::is_ok(const Result* borrow this) { // Creates an `Ok` value. safe Result Result::Ok(T t) { - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate Result with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap T with an owned struct."); - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate Result with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap E with an owned struct."); @@ -73,11 +73,11 @@ safe Result Result::Ok(T t) { // Creates an `Err` value. safe Result Result::Err(E e) { - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate Result with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap T with an owned struct."); - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate Result with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap E with an owned struct."); diff --git a/libcbs/src/vec/vec.hbs b/libcbs/src/vec/vec.hbs index e2f493d97f05..4dad010aafde 100644 --- a/libcbs/src/vec/vec.hbs +++ b/libcbs/src/vec/vec.hbs @@ -64,7 +64,7 @@ safe size_t Vec::length(const Vec* borrow this) { } safe Vec Vec::new(void) { - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate Vec with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap T with an owned struct."); @@ -136,7 +136,7 @@ safe void Vec::shrink_to_fit(Vec* borrow this) { } safe Vec Vec::with_capacity(size_t cap) { - _Static_assert(is_move_semantic() == false || is_owned_struct() == true, + unsafe _Static_assert(is_move_semantic() == false || is_owned_struct() == true, "Can only instantiate Vec with owned struct or copyable type, " "because BSC doesn't know how to free memory for other types. " "Fix: You can wrap T with an owned struct."); -- Gitee