diff --git a/clang/include/clang/AST/BSC/WalkerBSC.h b/clang/include/clang/AST/BSC/WalkerBSC.h new file mode 100644 index 0000000000000000000000000000000000000000..5f8435f9c8d0a18fc15e4153a6382287fa106451 --- /dev/null +++ b/clang/include/clang/AST/BSC/WalkerBSC.h @@ -0,0 +1,355 @@ +//===- WalkerBSC.h - Classes for traversing BSC ASTs --*- BSC -*-=====// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the BSC Walker utilities. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_WALKERBSC_H +#define LLVM_CLANG_AST_WALKERBSC_H + +#if ENABLE_BSC + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeOrdering.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeVisitor.h" + +namespace clang { +class ASTContext; + +static bool IsBSCDesugared(Decl *D, ASTContext *Context) { + for (auto DD : Context->BSCDesugaredMap) { + for (auto &DesugaredDecl : DD.second) { + if (isa(D)) { + NamedDecl *ND = cast(D); + if (ND == DesugaredDecl) { + return true; + } + } + } + } + return false; +} + +class BSCFeatureFinder : public StmtVisitor, + public DeclVisitor, + public TypeVisitor { +public: + using TypeVisitor::Visit; + using DeclVisitor::Visit; + using StmtVisitor::Visit; + + BSCFeatureFinder(ASTContext &Context) : Context(Context) {} + + /*--------------Types--------------*/ + + bool VisitType(const Type *T) { + if (isa(T)) { + if (VisitQualType(cast(T)->getPointeeType())) { + return true; + } + } + + if (isa(T)) { + if (VisitQualType(cast(T)->getInnerType())) { + return true; + } + } + + if (const FunctionProtoType *FPT = dyn_cast(T)) { + if (VisitQualType(FPT->getReturnType())) { + return true; + } + for (auto &P : FPT->getParamTypes()) { + if (VisitQualType(P)) { + return true; + } + } + } + + if (T->isTraitType() || T->isTraitPointerType() || T->hasTraitType()) { + return true; + } + return false; + } + + bool VisitQualType(QualType QT) { + if (QT.isOwnedQualified() || QT.isBorrowQualified() || + QT->hasBorrowFields() || QT->hasOwnedFields()) { + return true; + } + if (IsDesugaredFromTraitType(QT)) { + return true; + } + if (QT->getAs()) { + return true; + } + if (auto *TT = QT->getAs()) { + if (auto *TD = TT->getDecl()) + if (isa(TD) || isa(TD)) + return true; + } + if (VisitType(QT.getTypePtr())) { + return true; + } + return false; + } + + /*--------------Decls--------------*/ + bool VisitBSCMethodDecl(BSCMethodDecl *MD) { return true; } + + bool VisitFunctionDecl(FunctionDecl *FD) { + if (VisitQualType(FD->getType())) { + return true; + } + + // async related funcs + if (IsBSCDesugared(FD, &Context) || FD->isAsyncSpecified()) { + return true; + } + // safe / unsafe func + if (FD->getSafeZoneSpecifier() != SZ_None) { + return true; + } + // generic function + if (FD->getParent() && isa(FD->getParent()) && + cast(FD->getParent())->getDescribedClassTemplate()) { + return true; + } + if (FD->isTemplateInstantiation()) { + return true; + } + + if (FD->isConstexpr()) { + return true; + } + + for (auto *Parameter : FD->parameters()) { + if (Visit(Parameter)) { + return true; + } + if (VisitQualType(Parameter->getType())) { + return true; + } + } + + if (FD->doesThisDeclarationHaveABody()) { + if (Visit(FD->getBody())) { + return true; + } + } + return false; + } + bool VisitVarDecl(VarDecl *D) { + if (VisitQualType(D->getType())) { + return true; + } + if (D->isConstexpr()) { + return true; + } + + if (D->hasInit()) { + if (Visit((D->getInit()))) { + return true; + } + if (VisitQualType(D->getInit()->getType())) { + return true; + } + } + return false; + } + + bool VisitRecordDecl(RecordDecl *RD) { + if (IsBSCDesugared(RD, &Context)) { + return true; + } + + if (RD->isTrait() || RD->getDesugaredTraitDecl()) { + return true; + } + if (RD->isOwnedDecl()) { + return true; + } + for (auto Member : RD->fields()) { + if (Visit(Member)) { + return true; + } + if (VisitQualType(Member->getType())) { + return true; + } + } + return false; + } + + bool VisitStaticAssertDecl(StaticAssertDecl *D) { + return Visit(D->getAssertExpr()); + } + + bool VisitTypeAliasDecl(TypeAliasDecl *D) { + return true; + } + + bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + return true; + } + + bool VisitStmt(Stmt *S) { + for (auto *C : S->children()) { + if (C) { + if (Visit(C)) { + return true; + } + } + } + return false; + } + + /*--------------Stmts--------------*/ + bool VisitDeclStmt(DeclStmt *DS) { + for (auto *D : DS->decls()) { + if (Visit(D)) { + return true; + } + } + return false; + } + + bool VisitCompoundStmt(CompoundStmt *CS) { + if (CS->getCompSafeZoneSpecifier() != SZ_None) { + return true; + } + for (auto *S : CS->body()) { + if (Visit(S)) { + return true; + } + } + return false; + } + + bool VisitIfStmt(IfStmt *IS) { + if (IS->isConstexpr()) { + return true; + } + Visit(IS->getCond()); + if (IS->getConditionVariable()) { + if (Visit(IS->getConditionVariable())) { + return true; + } + } + if (IS->getThen()) { + if (Visit(IS->getThen())) { + return true; + } + } + if (IS->getElse()) { + if (Visit(IS->getElse())) { + return true; + } + } + return false; + } + + bool VisitInitListExpr(InitListExpr *ILE) { + if (VisitQualType(ILE->getType())) { + return true; + } + for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i) { + if (ILE->getInit(i)) { + if (Visit(ILE->getInit(i))) { + return true; + } + } + } + return false; + } + + bool VisitCStyleCastExpr(CStyleCastExpr *E) { + if (VisitQualType(E->getType())) { + return true; + } + if (VisitExplicitCastExpr(E)) { + return true; + } + return false; + } + + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + if (VisitQualType(DRE->getType())) { + return true; + } + if (IsBSCDesugared(DRE->getDecl(), &Context)) { + return true; + } + + if (DRE->getDecl()->getKind() == Decl::BSCMethod) { + return true; + } + + if (DRE->getDecl()->getKind() == Decl::Function) { + FunctionDecl *FD = cast(DRE->getDecl()); + if (FD->isTemplateInstantiation() || FD->isConstexpr()) { + return true; + } + } + return false; + } + + bool VisitMemberExpr(MemberExpr *ME) { + if (VisitQualType(ME->getType())) { + return true; + } + if (Visit(ME->getBase())) { + return true; + } + if (IsBSCDesugared(ME->getMemberDecl(), &Context)) { + return true; + } + if (ME->getMemberDecl()->getKind() == Decl::BSCMethod) { + return true; + } + if (ME->getMemberDecl()->getKind() == Decl::Function) { + FunctionDecl *FD = cast(ME->getMemberDecl()); + if (FD->isTemplateInstantiation() || FD->isConstexpr()) { + return true; + } + } + return false; + } + +protected: + ASTContext &Context; + +private: + bool IsDesugaredFromTraitType(QualType T) { + while (T->isPointerType()) + T = T->getPointeeType(); + if (RecordDecl *RD = T->getAsRecordDecl()) { + if (auto *TST = dyn_cast_or_null(T)) { + TemplateDecl *TempT = TST->getTemplateName().getAsTemplateDecl(); + RD = dyn_cast_or_null(TempT->getTemplatedDecl()); + } + if (RD && RD->getDesugaredTraitDecl()) + return true; + } + return false; + } +}; + +} // namespace clang + +#endif // ENABLE_BSC + +#endif // LLVM_CLANG_AST_WALKERBSC_H \ No newline at end of file diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 432f48e52e2a7565ddd02b054c15137bac4b1263..f1ce081b980c28115e386c90c297ebd1f0100e59 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -12375,6 +12375,7 @@ public: AssignConvertType CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &RHS); + // BiShengC safety feature related APIs #if ENABLE_BSC bool CheckOwnedQualTypeCStyleCast(QualType LHSType, QualType RHSType); bool CheckOwnedQualTypeCStyleCast(QualType LHSType, QualType RHSType, SourceLocation RLoc); @@ -12425,6 +12426,7 @@ public: SourceLocation OpLoc); bool CheckOperatorDeclNeedAddToContext(Declarator &D); bool CheckOperatorFunReturnTypeIsLegal(FunctionDecl *FnDecl); + bool FindSafeFeatures(const FunctionDecl* FnDecl); #endif bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); diff --git a/clang/lib/Frontend/Rewrite/RewriteBSC.cpp b/clang/lib/Frontend/Rewrite/RewriteBSC.cpp index 6f197d96f53fa1d2f9cca97857d267ccb56860db..5397f13ed0de175e2a8331ab16b99d1745b5e7a5 100644 --- a/clang/lib/Frontend/Rewrite/RewriteBSC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteBSC.cpp @@ -14,9 +14,7 @@ #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/TypeVisitor.h" +#include "clang/AST/BSC/WalkerBSC.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Rewrite/Core/Rewriter.h" @@ -221,25 +219,11 @@ void RewriteBSC::RewriteDecls(DeclContext *DC) { ReplaceText(BeginLocOfFirstDecl, endBuf - startBuf + 1, Str); } -static bool IsDesugared(Decl *D, ASTContext *Context) { - for (auto DD : Context->BSCDesugaredMap) { - for (auto &DesugaredDecl : DD.second) { - if (isa(D)) { - NamedDecl *ND = cast(D); - if (ND == DesugaredDecl) { - return true; - } - } - } - } - return false; -} - void RewriteBSC::GetSourceLocationsOfFirstDeclAndLastDecl() { for (DeclContext::decl_iterator D = TUDecl->decls_begin(), DEnd = TUDecl->decls_end(); D != DEnd; ++D) { - if (IsDesugared(*D, Context)) { + if (IsBSCDesugared(*D, Context)) { continue; } @@ -294,312 +278,6 @@ static bool HasTemplateSpecType(QualType QT, return false; } -namespace { -class BSCFeatureFinder : public StmtVisitor, - public DeclVisitor, - public TypeVisitor { -public: - using TypeVisitor::Visit; - using DeclVisitor::Visit; - using StmtVisitor::Visit; - - BSCFeatureFinder(ASTContext &Context) : Context(Context) {} - - /*--------------Types--------------*/ - - bool VisitType(const Type *T) { - if (isa(T)) { - if (VisitQualType(cast(T)->getPointeeType())) { - return true; - } - } - - if (isa(T)) { - if (VisitQualType(cast(T)->getInnerType())) { - return true; - } - } - - if (const FunctionProtoType *FPT = dyn_cast(T)) { - if (VisitQualType(FPT->getReturnType())) { - return true; - } - for (auto &P : FPT->getParamTypes()) { - if (VisitQualType(P)) { - return true; - } - } - } - - if (T->isTraitType() || T->isTraitPointerType() || T->hasTraitType()) { - return true; - } - return false; - } - - bool VisitQualType(QualType QT) { - if (QT.isOwnedQualified() || QT.isBorrowQualified() || - QT->hasBorrowFields() || QT->hasOwnedFields()) { - return true; - } - if (IsDesugaredFromTraitType(QT)) { - return true; - } - if (QT->getAs()) { - return true; - } - if (auto *TT = QT->getAs()) { - if (auto *TD = TT->getDecl()) - if (isa(TD) || isa(TD)) - return true; - } - if (VisitType(QT.getTypePtr())) { - return true; - } - return false; - } - - /*--------------Decls--------------*/ - bool VisitBSCMethodDecl(BSCMethodDecl *MD) { return true; } - - bool VisitFunctionDecl(FunctionDecl *FD) { - if (VisitQualType(FD->getType())) { - return true; - } - - // async related funcs - if (IsDesugared(FD, &Context) || FD->isAsyncSpecified()) { - return true; - } - // safe / unsafe func - if (FD->getSafeZoneSpecifier() != SZ_None) { - return true; - } - // generic function - if (FD->getParent() && isa(FD->getParent()) && - cast(FD->getParent())->getDescribedClassTemplate()) { - return true; - } - if (FD->isTemplateInstantiation()) { - return true; - } - - if (FD->isConstexpr()) { - return true; - } - - for (auto *Parameter : FD->parameters()) { - if (Visit(Parameter)) { - return true; - } - if (VisitQualType(Parameter->getType())) { - return true; - } - } - - if (FD->doesThisDeclarationHaveABody()) { - if (Visit(FD->getBody())) { - return true; - } - } - return false; - } - bool VisitVarDecl(VarDecl *D) { - if (VisitQualType(D->getType())) { - return true; - } - if (D->isConstexpr()) { - return true; - } - - if (D->hasInit()) { - if (Visit((D->getInit()))) { - return true; - } - if (VisitQualType(D->getInit()->getType())) { - return true; - } - } - return false; - } - - bool VisitRecordDecl(RecordDecl *RD) { - if (IsDesugared(RD, &Context)) { - return true; - } - - if (RD->isTrait() || RD->getDesugaredTraitDecl()) { - return true; - } - if (RD->isOwnedDecl()) { - return true; - } - for (auto Member : RD->fields()) { - if (Visit(Member)) { - return true; - } - if (VisitQualType(Member->getType())) { - return true; - } - } - return false; - } - - bool VisitStaticAssertDecl(StaticAssertDecl *D) { - return Visit(D->getAssertExpr()); - } - - bool VisitTypeAliasDecl(TypeAliasDecl *D) { - return true; - } - - bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { - return true; - } - - bool VisitStmt(Stmt *S) { - for (auto *C : S->children()) { - if (C) { - if (Visit(C)) { - return true; - } - } - } - return false; - } - - /*--------------Stmts--------------*/ - bool VisitDeclStmt(DeclStmt *DS) { - for (auto *D : DS->decls()) { - if (Visit(D)) { - return true; - } - } - return false; - } - - bool VisitCompoundStmt(CompoundStmt *CS) { - if (CS->getCompSafeZoneSpecifier() != SZ_None) { - return true; - } - for (auto *S : CS->body()) { - if (Visit(S)) { - return true; - } - } - return false; - } - - bool VisitIfStmt(IfStmt *IS) { - if (IS->isConstexpr()) { - return true; - } - Visit(IS->getCond()); - if (IS->getConditionVariable()) { - if (Visit(IS->getConditionVariable())) { - return true; - } - } - if (IS->getThen()) { - if (Visit(IS->getThen())) { - return true; - } - } - if (IS->getElse()) { - if (Visit(IS->getElse())) { - return true; - } - } - return false; - } - - bool VisitInitListExpr(InitListExpr *ILE) { - if (VisitQualType(ILE->getType())) { - return true; - } - for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i) { - if (ILE->getInit(i)) { - if (Visit(ILE->getInit(i))) { - return true; - } - } - } - return false; - } - - bool VisitCStyleCastExpr(CStyleCastExpr *E) { - if (VisitQualType(E->getType())) { - return true; - } - if (VisitExplicitCastExpr(E)) { - return true; - } - return false; - } - - bool VisitDeclRefExpr(DeclRefExpr *DRE) { - if (VisitQualType(DRE->getType())) { - return true; - } - if (IsDesugared(DRE->getDecl(), &Context)) { - return true; - } - - if (DRE->getDecl()->getKind() == Decl::BSCMethod) { - return true; - } - - if (DRE->getDecl()->getKind() == Decl::Function) { - FunctionDecl *FD = cast(DRE->getDecl()); - if (FD->isTemplateInstantiation() || FD->isConstexpr()) { - return true; - } - } - return false; - } - - bool VisitMemberExpr(MemberExpr *ME) { - if (VisitQualType(ME->getType())) { - return true; - } - if (Visit(ME->getBase())) { - return true; - } - if (IsDesugared(ME->getMemberDecl(), &Context)) { - return true; - } - if (ME->getMemberDecl()->getKind() == Decl::BSCMethod) { - return true; - } - if (ME->getMemberDecl()->getKind() == Decl::Function) { - FunctionDecl *FD = cast(ME->getMemberDecl()); - if (FD->isTemplateInstantiation() || FD->isConstexpr()) { - return true; - } - } - return false; - } - -protected: - ASTContext &Context; - -private: - bool IsDesugaredFromTraitType(QualType T) { - while (T->isPointerType()) - T = T->getPointeeType(); - if (RecordDecl *RD = T->getAsRecordDecl()) { - if (auto *TST = dyn_cast_or_null(T)) { - TemplateDecl *TempT = TST->getTemplateName().getAsTemplateDecl(); - RD = dyn_cast_or_null(TempT->getTemplatedDecl()); - } - if (RD && RD->getDesugaredTraitDecl()) - return true; - } - return false; - } -}; -} // namespace - void RewriteBSC::FindDeclsWithoutBSCFeature() { BSCFeatureFinder finder = BSCFeatureFinder(*Context); for (DeclContext::decl_iterator D = TUDecl->decls_begin(), diff --git a/clang/lib/Sema/BSC/SemaDeclBSC.cpp b/clang/lib/Sema/BSC/SemaDeclBSC.cpp index 35507066b7445c372bd903c18bc6fe281e046c9a..184730d2bd6aa6aebb6e46fbcec62ff7a28ad3a4 100644 --- a/clang/lib/Sema/BSC/SemaDeclBSC.cpp +++ b/clang/lib/Sema/BSC/SemaDeclBSC.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" +#include "clang/AST/BSC/WalkerBSC.h" using namespace clang; using namespace sema; @@ -144,4 +145,14 @@ bool Sema::CheckOperatorFunReturnTypeIsLegal(FunctionDecl *FnDecl) { } return true; } + +// Return true if any memory safe features are found in a FunctionDecl. +bool Sema::FindSafeFeatures(const FunctionDecl* FnDecl) { + if (!FnDecl) return false; + BSCFeatureFinder finder = BSCFeatureFinder(Context); + if (finder.Visit(const_cast(FnDecl))) { + return true; + } + return false; +} #endif \ No newline at end of file diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 6bd0b666c41f47f21800486fca36d324da0a189c..148d167e209c2dbf8147de480e4667970d816a04 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2213,8 +2213,11 @@ Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP, #if ENABLE_BSC bool DisableOwnershipCheck = getLangOpts().DisableOwnershipCheck; - if (!DisableOwnershipCheck) { - if (LangOpts.BSC && !isBSCCoroutine && + // If D does not use memory safety features like "owned, borrow, &mut, &const", + // we do not do borrow checking. + bool useSafeFeature = LangOpts.BSC ? FindSafeFeatures(dyn_cast_or_null(D)) : false; + if (!DisableOwnershipCheck && useSafeFeature) { + if (!isBSCCoroutine && (getDiagnostics().getNumErrors() == getDiagnostics().getNumOwnershipErrors() + getDiagnostics().getNumBorrowCheckErrors()) && D)