|
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" |
@@ -3867,6 +3868,113 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) { |
3867 | 3868 | S.Context, AL, EncodingIndices.data(), EncodingIndices.size())); |
3868 | 3869 | } |
3869 | 3870 |
|
| 3871 | +LifetimeCaptureByAttr *Sema::ParseLifetimeCaptureByAttr(const ParsedAttr &AL, |
| 3872 | + StringRef ParamName) { |
| 3873 | + // Atleast one capture by is required. |
| 3874 | + if (AL.getNumArgs() == 0) { |
| 3875 | + Diag(AL.getLoc(), diag::err_capture_by_attribute_no_entity) |
| 3876 | + << AL.getRange(); |
| 3877 | + return nullptr; |
| 3878 | + } |
| 3879 | + SmallVector<IdentifierInfo *, 1> ParamIdents; |
| 3880 | + SmallVector<SourceLocation, 1> ParamLocs; |
| 3881 | + for (unsigned I = 0; I < AL.getNumArgs(); ++I) { |
| 3882 | + if (AL.isArgExpr(I)) { |
| 3883 | + Expr *E = AL.getArgAsExpr(I); |
| 3884 | + Diag(E->getExprLoc(), diag::err_capture_by_attribute_argument_unknown) |
| 3885 | + << E << E->getExprLoc(); |
| 3886 | + continue; |
| 3887 | + } |
| 3888 | + assert(AL.isArgIdent(I)); |
| 3889 | + IdentifierLoc *IdLoc = AL.getArgAsIdent(I); |
| 3890 | + if (IdLoc->Ident->getName() == ParamName) { |
| 3891 | + Diag(IdLoc->Loc, diag::err_capture_by_references_itself) << IdLoc->Loc; |
| 3892 | + continue; |
| 3893 | + } |
| 3894 | + ParamIdents.push_back(IdLoc->Ident); |
| 3895 | + ParamLocs.push_back(IdLoc->Loc); |
| 3896 | + } |
| 3897 | + SmallVector<int, 1> FakeParamIndices(ParamIdents.size(), |
| 3898 | + LifetimeCaptureByAttr::INVALID); |
| 3899 | + LifetimeCaptureByAttr *CapturedBy = ::new (Context) LifetimeCaptureByAttr( |
| 3900 | + Context, AL, FakeParamIndices.data(), FakeParamIndices.size()); |
| 3901 | + CapturedBy->setArgs(std::move(ParamIdents), std::move(ParamLocs)); |
| 3902 | + return CapturedBy; |
| 3903 | +} |
| 3904 | + |
| 3905 | +static void HandleLifetimeCaptureByAttr(Sema &S, Decl *D, |
| 3906 | + const ParsedAttr &AL) { |
| 3907 | + // Do not allow multiple attributes. |
| 3908 | + if (D->hasAttr<LifetimeCaptureByAttr>()) { |
| 3909 | + S.Diag(AL.getLoc(), diag::err_capture_by_attribute_multiple) |
| 3910 | + << AL.getRange(); |
| 3911 | + return; |
| 3912 | + } |
| 3913 | + auto *PVD = dyn_cast<ParmVarDecl>(D); |
| 3914 | + assert(PVD); |
| 3915 | + auto *CaptureByAttr = S.ParseLifetimeCaptureByAttr(AL, PVD->getName()); |
| 3916 | + if (CaptureByAttr) |
| 3917 | + D->addAttr(CaptureByAttr); |
| 3918 | +} |
| 3919 | + |
| 3920 | +void Sema::LazyProcessLifetimeCaptureByParams(FunctionDecl *FD) { |
| 3921 | + bool HasImplicitThisParam = isInstanceMethod(FD); |
| 3922 | + |
| 3923 | + llvm::StringMap<int> NameIdxMapping; |
| 3924 | + NameIdxMapping["global"] = LifetimeCaptureByAttr::GLOBAL; |
| 3925 | + NameIdxMapping["unknown"] = LifetimeCaptureByAttr::UNKNOWN; |
| 3926 | + int Idx = 0; |
| 3927 | + if (HasImplicitThisParam) { |
| 3928 | + NameIdxMapping["this"] = 0; |
| 3929 | + Idx++; |
| 3930 | + } |
| 3931 | + for (const ParmVarDecl *PVD : FD->parameters()) |
| 3932 | + NameIdxMapping[PVD->getName()] = Idx++; |
| 3933 | + auto DisallowReservedParams = [&](StringRef Reserved) { |
| 3934 | + for (const ParmVarDecl *PVD : FD->parameters()) |
| 3935 | + if (PVD->getName() == Reserved) |
| 3936 | + Diag(PVD->getLocation(), diag::err_capture_by_param_uses_reserved_name) |
| 3937 | + << (PVD->getName() == "unknown"); |
| 3938 | + }; |
| 3939 | + auto HandleCaptureBy = [&](LifetimeCaptureByAttr *CapturedBy) { |
| 3940 | + if (!CapturedBy) |
| 3941 | + return; |
| 3942 | + const auto &Entities = CapturedBy->getArgIdents(); |
| 3943 | + for (size_t I = 0; I < Entities.size(); ++I) { |
| 3944 | + StringRef Name = Entities[I]->getName(); |
| 3945 | + auto It = NameIdxMapping.find(Name); |
| 3946 | + if (It == NameIdxMapping.end()) { |
| 3947 | + auto Loc = CapturedBy->getArgLocs()[I]; |
| 3948 | + if (!HasImplicitThisParam && Name == "this") |
| 3949 | + Diag(Loc, diag::err_capture_by_implicit_this_not_available) << Loc; |
| 3950 | + else |
| 3951 | + Diag(Loc, diag::err_capture_by_attribute_argument_unknown) |
| 3952 | + << Entities[I] << Loc; |
| 3953 | + continue; |
| 3954 | + } |
| 3955 | + if (Name == "unknown" || Name == "global") |
| 3956 | + DisallowReservedParams(Name); |
| 3957 | + CapturedBy->setParamIdx(I, It->second); |
| 3958 | + } |
| 3959 | + }; |
| 3960 | + for (ParmVarDecl *PVD : FD->parameters()) |
| 3961 | + HandleCaptureBy(PVD->getAttr<LifetimeCaptureByAttr>()); |
| 3962 | + if (!HasImplicitThisParam) |
| 3963 | + return; |
| 3964 | + TypeSourceInfo *TSI = FD->getTypeSourceInfo(); |
| 3965 | + if (!TSI) |
| 3966 | + return; |
| 3967 | + AttributedTypeLoc ATL; |
| 3968 | + for (TypeLoc TL = TSI->getTypeLoc(); |
| 3969 | + (ATL = TL.getAsAdjusted<AttributedTypeLoc>()); |
| 3970 | + TL = ATL.getModifiedLoc()) { |
| 3971 | + auto *A = ATL.getAttrAs<LifetimeCaptureByAttr>(); |
| 3972 | + if (!A) |
| 3973 | + continue; |
| 3974 | + HandleCaptureBy(const_cast<LifetimeCaptureByAttr *>(A)); |
| 3975 | + } |
| 3976 | +} |
| 3977 | + |
3870 | 3978 | static bool isFunctionLike(const Type &T) { |
3871 | 3979 | // Check for explicit function types. |
3872 | 3980 | // 'called_once' is only supported in Objective-C and it has |
@@ -6644,6 +6752,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, |
6644 | 6752 | case ParsedAttr::AT_Callback: |
6645 | 6753 | handleCallbackAttr(S, D, AL); |
6646 | 6754 | break; |
| 6755 | + case ParsedAttr::AT_LifetimeCaptureBy: |
| 6756 | + HandleLifetimeCaptureByAttr(S, D, AL); |
| 6757 | + break; |
6647 | 6758 | case ParsedAttr::AT_CalledOnce: |
6648 | 6759 | handleCalledOnceAttr(S, D, AL); |
6649 | 6760 | break; |
|
0 commit comments