|
14 | 14 | #include "clang/AST/ASTContext.h" |
15 | 15 | #include "clang/AST/ASTMutationListener.h" |
16 | 16 | #include "clang/AST/CXXInheritance.h" |
| 17 | +#include "clang/AST/Decl.h" |
17 | 18 | #include "clang/AST/DeclCXX.h" |
18 | 19 | #include "clang/AST/DeclObjC.h" |
19 | 20 | #include "clang/AST/DeclTemplate.h" |
@@ -3753,6 +3754,113 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3753 | 3754 | S.Context, AL, EncodingIndices.data(), EncodingIndices.size())); |
3754 | 3755 | } |
3755 | 3756 |
|
| 3757 | +LifetimeCaptureByAttr *Sema::ParseLifetimeCaptureByAttr(const ParsedAttr &AL, |
| 3758 | + StringRef ParamName) { |
| 3759 | + // Atleast one capture by is required. |
| 3760 | + if (AL.getNumArgs() == 0) { |
| 3761 | + Diag(AL.getLoc(), diag::err_capture_by_attribute_no_entity) |
| 3762 | + << AL.getRange(); |
| 3763 | + return nullptr; |
| 3764 | + } |
| 3765 | + SmallVector<IdentifierInfo *, 1> ParamIdents; |
| 3766 | + SmallVector<SourceLocation, 1> ParamLocs; |
| 3767 | + for (unsigned I = 0; I < AL.getNumArgs(); ++I) { |
| 3768 | + if (AL.isArgExpr(I)) { |
| 3769 | + Expr *E = AL.getArgAsExpr(I); |
| 3770 | + Diag(E->getExprLoc(), diag::err_capture_by_attribute_argument_unknown) |
| 3771 | + << E << E->getExprLoc(); |
| 3772 | + continue; |
| 3773 | + } |
| 3774 | + assert(AL.isArgIdent(I)); |
| 3775 | + IdentifierLoc *IdLoc = AL.getArgAsIdent(I); |
| 3776 | + if (IdLoc->Ident->getName() == ParamName) { |
| 3777 | + Diag(IdLoc->Loc, diag::err_capture_by_references_itself) << IdLoc->Loc; |
| 3778 | + continue; |
| 3779 | + } |
| 3780 | + ParamIdents.push_back(IdLoc->Ident); |
| 3781 | + ParamLocs.push_back(IdLoc->Loc); |
| 3782 | + } |
| 3783 | + SmallVector<int, 1> FakeParamIndices(ParamIdents.size(), |
| 3784 | + LifetimeCaptureByAttr::INVALID); |
| 3785 | + LifetimeCaptureByAttr *CapturedBy = ::new (Context) LifetimeCaptureByAttr( |
| 3786 | + Context, AL, FakeParamIndices.data(), FakeParamIndices.size()); |
| 3787 | + CapturedBy->setArgs(std::move(ParamIdents), std::move(ParamLocs)); |
| 3788 | + return CapturedBy; |
| 3789 | +} |
| 3790 | + |
| 3791 | +static void HandleLifetimeCaptureByAttr(Sema &S, Decl *D, |
| 3792 | + const ParsedAttr &AL) { |
| 3793 | + // Do not allow multiple attributes. |
| 3794 | + if (D->hasAttr<LifetimeCaptureByAttr>()) { |
| 3795 | + S.Diag(AL.getLoc(), diag::err_capture_by_attribute_multiple) |
| 3796 | + << AL.getRange(); |
| 3797 | + return; |
| 3798 | + } |
| 3799 | + auto *PVD = dyn_cast<ParmVarDecl>(D); |
| 3800 | + assert(PVD); |
| 3801 | + auto *CaptureByAttr = S.ParseLifetimeCaptureByAttr(AL, PVD->getName()); |
| 3802 | + if (CaptureByAttr) |
| 3803 | + D->addAttr(CaptureByAttr); |
| 3804 | +} |
| 3805 | + |
| 3806 | +void Sema::LazyProcessLifetimeCaptureByParams(FunctionDecl *FD) { |
| 3807 | + bool HasImplicitThisParam = isInstanceMethod(FD); |
| 3808 | + |
| 3809 | + llvm::StringMap<int> NameIdxMapping; |
| 3810 | + NameIdxMapping["global"] = LifetimeCaptureByAttr::GLOBAL; |
| 3811 | + NameIdxMapping["unknown"] = LifetimeCaptureByAttr::UNKNOWN; |
| 3812 | + int Idx = 0; |
| 3813 | + if (HasImplicitThisParam) { |
| 3814 | + NameIdxMapping["this"] = 0; |
| 3815 | + Idx++; |
| 3816 | + } |
| 3817 | + for (const ParmVarDecl *PVD : FD->parameters()) |
| 3818 | + NameIdxMapping[PVD->getName()] = Idx++; |
| 3819 | + auto DisallowReservedParams = [&](StringRef Reserved) { |
| 3820 | + for (const ParmVarDecl *PVD : FD->parameters()) |
| 3821 | + if (PVD->getName() == Reserved) |
| 3822 | + Diag(PVD->getLocation(), diag::err_capture_by_param_uses_reserved_name) |
| 3823 | + << (PVD->getName() == "unknown"); |
| 3824 | + }; |
| 3825 | + auto HandleCaptureBy = [&](LifetimeCaptureByAttr *CapturedBy) { |
| 3826 | + if (!CapturedBy) |
| 3827 | + return; |
| 3828 | + const auto &Entities = CapturedBy->getArgIdents(); |
| 3829 | + for (size_t I = 0; I < Entities.size(); ++I) { |
| 3830 | + StringRef Name = Entities[I]->getName(); |
| 3831 | + auto It = NameIdxMapping.find(Name); |
| 3832 | + if (It == NameIdxMapping.end()) { |
| 3833 | + auto Loc = CapturedBy->getArgLocs()[I]; |
| 3834 | + if (!HasImplicitThisParam && Name == "this") |
| 3835 | + Diag(Loc, diag::err_capture_by_implicit_this_not_available) << Loc; |
| 3836 | + else |
| 3837 | + Diag(Loc, diag::err_capture_by_attribute_argument_unknown) |
| 3838 | + << Entities[I] << Loc; |
| 3839 | + continue; |
| 3840 | + } |
| 3841 | + if (Name == "unknown" || Name == "global") |
| 3842 | + DisallowReservedParams(Name); |
| 3843 | + CapturedBy->setParamIdx(I, It->second); |
| 3844 | + } |
| 3845 | + }; |
| 3846 | + for (ParmVarDecl *PVD : FD->parameters()) |
| 3847 | + HandleCaptureBy(PVD->getAttr<LifetimeCaptureByAttr>()); |
| 3848 | + if (!HasImplicitThisParam) |
| 3849 | + return; |
| 3850 | + TypeSourceInfo *TSI = FD->getTypeSourceInfo(); |
| 3851 | + if (!TSI) |
| 3852 | + return; |
| 3853 | + AttributedTypeLoc ATL; |
| 3854 | + for (TypeLoc TL = TSI->getTypeLoc(); |
| 3855 | + (ATL = TL.getAsAdjusted<AttributedTypeLoc>()); |
| 3856 | + TL = ATL.getModifiedLoc()) { |
| 3857 | + auto *A = ATL.getAttrAs<LifetimeCaptureByAttr>(); |
| 3858 | + if (!A) |
| 3859 | + continue; |
| 3860 | + HandleCaptureBy(const_cast<LifetimeCaptureByAttr *>(A)); |
| 3861 | + } |
| 3862 | +} |
| 3863 | + |
3756 | 3864 | static bool isFunctionLike(const Type &T) { |
3757 | 3865 | // Check for explicit function types. |
3758 | 3866 | // 'called_once' is only supported in Objective-C and it has |
@@ -6538,6 +6646,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, |
6538 | 6646 | case ParsedAttr::AT_Callback: |
6539 | 6647 | handleCallbackAttr(S, D, AL); |
6540 | 6648 | break; |
| 6649 | + case ParsedAttr::AT_LifetimeCaptureBy: |
| 6650 | + HandleLifetimeCaptureByAttr(S, D, AL); |
| 6651 | + break; |
6541 | 6652 | case ParsedAttr::AT_CalledOnce: |
6542 | 6653 | handleCalledOnceAttr(S, D, AL); |
6543 | 6654 | break; |
|
0 commit comments