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