diff options
author | George Karpenkov <ekarpenkov@apple.com> | 2018-11-30 02:18:37 +0000 |
---|---|---|
committer | George Karpenkov <ekarpenkov@apple.com> | 2018-11-30 02:18:37 +0000 |
commit | 1657f36c7f48a008ef435949b6457034894745e0 (patch) | |
tree | 600487ee5c9e64d99a0e279af39b01f2d736daeb /clang/lib/Sema/SemaDeclAttr.cpp | |
parent | 62db886062f841cb84fca6d32ec7cc91931400a2 (diff) | |
download | bcm5719-llvm-1657f36c7f48a008ef435949b6457034894745e0.tar.gz bcm5719-llvm-1657f36c7f48a008ef435949b6457034894745e0.zip |
[attributes] Add a family of OS_CONSUMED, OS_RETURNS and OS_RETURNS_RETAINED attributes
The addition adds three attributes for communicating ownership,
analogous to existing NS_ and CF_ attributes.
The attributes are meant to be used for communicating ownership of all
objects in XNU (Darwin kernel) and all of the kernel modules.
The ownership model there is very similar, but still different from the
Foundation model, so we think that introducing a new family of
attributes is appropriate.
The addition required a sizeable refactoring of the existing code for
CF_ and NS_ ownership attributes, due to tight coupling and the fact
that differentiating between the types was previously done using a
boolean.
Differential Revision: https://reviews.llvm.org/D54912
llvm-svn: 347947
Diffstat (limited to 'clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 190 |
1 files changed, 129 insertions, 61 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index be662b9b914..a2520c03cb3 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -392,9 +392,49 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum, /// Applies the given attribute to the Decl without performing any /// additional semantic checking. template <typename AttrType> +static void handleSimpleAttribute(Sema &S, Decl *D, SourceRange SR, + unsigned SpellingIndex) { + D->addAttr(::new (S.Context) AttrType(SR, S.Context, SpellingIndex)); +} + +template <typename AttrType> static void handleSimpleAttribute(Sema &S, Decl *D, const ParsedAttr &AL) { - D->addAttr(::new (S.Context) AttrType(AL.getRange(), S.Context, - AL.getAttributeSpellingListIndex())); + handleSimpleAttribute<AttrType>(S, D, AL.getRange(), + AL.getAttributeSpellingListIndex()); +} + + +template <typename... DiagnosticArgs> +static const Sema::SemaDiagnosticBuilder& +appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr) { + return Bldr; +} + +template <typename T, typename... DiagnosticArgs> +static const Sema::SemaDiagnosticBuilder& +appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr, T &&ExtraArg, + DiagnosticArgs &&... ExtraArgs) { + return appendDiagnostics(Bldr << std::forward<T>(ExtraArg), + std::forward<DiagnosticArgs>(ExtraArgs)...); +} + +/// Add an attribute {@code AttrType} to declaration {@code D}, +/// provided the given {@code Check} function returns {@code true} +/// on type of {@code D}. +/// If check does not pass, emit diagnostic {@code DiagID}, +/// passing in all parameters specified in {@code ExtraArgs}. +template <typename AttrType, typename... DiagnosticArgs> +static void +handleSimpleAttributeWithCheck(Sema &S, ValueDecl *D, SourceRange SR, + unsigned SpellingIndex, + llvm::function_ref<bool(QualType)> Check, + unsigned DiagID, DiagnosticArgs... ExtraArgs) { + if (!Check(D->getType())) { + Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID); + appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...); + return; + } + handleSimpleAttribute<AttrType>(S, D, SR, SpellingIndex); } template <typename AttrType> @@ -4711,58 +4751,70 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// - static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType QT) { return QT->isDependentType() || QT->isObjCRetainableType(); } -static bool isValidSubjectOfNSAttribute(Sema &S, QualType QT) { +static bool isValidSubjectOfNSAttribute(QualType QT) { return QT->isDependentType() || QT->isObjCObjectPointerType() || - S.Context.isObjCNSObjectType(QT); + QT->isObjCNSObjectType(); } -static bool isValidSubjectOfCFAttribute(Sema &S, QualType QT) { +static bool isValidSubjectOfCFAttribute(QualType QT) { return QT->isDependentType() || QT->isPointerType() || - isValidSubjectOfNSAttribute(S, QT); + isValidSubjectOfNSAttribute(QT); } -static void handleNSConsumedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - S.AddNSConsumedAttr(AL.getRange(), D, AL.getAttributeSpellingListIndex(), - AL.getKind() == ParsedAttr::AT_NSConsumed, - /*template instantiation*/ false); +static bool isValidSubjectOfOSAttribute(QualType QT) { + return QT->isDependentType() || QT->isPointerType(); } -void Sema::AddNSConsumedAttr(SourceRange AttrRange, Decl *D, - unsigned SpellingIndex, bool IsNSConsumed, - bool IsTemplateInstantiation) { - const auto *Param = cast<ParmVarDecl>(D); - bool TypeOK; - - if (IsNSConsumed) - TypeOK = isValidSubjectOfNSAttribute(*this, Param->getType()); - else - TypeOK = isValidSubjectOfCFAttribute(*this, Param->getType()); +void Sema::AddXConsumedAttr(Decl *D, SourceRange SR, unsigned SpellingIndex, + RetainOwnershipKind K, + bool IsTemplateInstantiation) { + ValueDecl *VD = cast<ValueDecl>(D); + switch (K) { + case RetainOwnershipKind::OS: + handleSimpleAttributeWithCheck<OSConsumedAttr>( + *this, VD, SR, SpellingIndex, &isValidSubjectOfOSAttribute, + diag::warn_ns_attribute_wrong_parameter_type, + /*ExtraArgs=*/SR, "os_consumed", /*pointers*/ 1); + return; + case RetainOwnershipKind::NS: + handleSimpleAttributeWithCheck<NSConsumedAttr>( + *this, VD, SR, SpellingIndex, &isValidSubjectOfNSAttribute, - if (!TypeOK) { - // These attributes are normally just advisory, but in ARC, ns_consumed - // is significant. Allow non-dependent code to contain inappropriate - // attributes even in ARC, but require template instantiations to be - // set up correctly. - Diag(D->getBeginLoc(), (IsTemplateInstantiation && IsNSConsumed && - getLangOpts().ObjCAutoRefCount - ? diag::err_ns_attribute_wrong_parameter_type - : diag::warn_ns_attribute_wrong_parameter_type)) - << AttrRange << (IsNSConsumed ? "ns_consumed" : "cf_consumed") - << (IsNSConsumed ? /*objc pointers*/ 0 : /*cf pointers*/ 1); + // These attributes are normally just advisory, but in ARC, ns_consumed + // is significant. Allow non-dependent code to contain inappropriate + // attributes even in ARC, but require template instantiations to be + // set up correctly. + ((IsTemplateInstantiation && getLangOpts().ObjCAutoRefCount) + ? diag::err_ns_attribute_wrong_parameter_type + : diag::warn_ns_attribute_wrong_parameter_type), + /*ExtraArgs=*/SR, "ns_consumed", /*objc pointers*/ 0); + return; + case RetainOwnershipKind::CF: + handleSimpleAttributeWithCheck<CFConsumedAttr>( + *this, VD, SR, SpellingIndex, + &isValidSubjectOfCFAttribute, + diag::warn_ns_attribute_wrong_parameter_type, + /*ExtraArgs=*/SR, "cf_consumed", /*pointers*/1); return; } +} - if (IsNSConsumed) - D->addAttr(::new (Context) - NSConsumedAttr(AttrRange, Context, SpellingIndex)); - else - D->addAttr(::new (Context) - CFConsumedAttr(AttrRange, Context, SpellingIndex)); +static Sema::RetainOwnershipKind +parsedAttrToRetainOwnershipKind(const ParsedAttr &AL) { + switch (AL.getKind()) { + case ParsedAttr::AT_CFConsumed: + return Sema::RetainOwnershipKind::CF; + case ParsedAttr::AT_OSConsumed: + return Sema::RetainOwnershipKind::OS; + case ParsedAttr::AT_NSConsumed: + return Sema::RetainOwnershipKind::NS; + default: + llvm_unreachable("Wrong argument supplied"); + } } bool Sema::checkNSReturnsRetainedReturnType(SourceLocation Loc, QualType QT) { @@ -4774,24 +4826,26 @@ bool Sema::checkNSReturnsRetainedReturnType(SourceLocation Loc, QualType QT) { return true; } -static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, +static void handleXReturnsXRetainedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType ReturnType; - if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { ReturnType = MD->getReturnType(); - else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) && - (AL.getKind() == ParsedAttr::AT_NSReturnsRetained)) + } else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) && + (AL.getKind() == ParsedAttr::AT_NSReturnsRetained)) { return; // ignore: was handled as a type attribute - else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) + } else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) { ReturnType = PD->getType(); - else if (const auto *FD = dyn_cast<FunctionDecl>(D)) + } else if (const auto *FD = dyn_cast<FunctionDecl>(D)) { ReturnType = FD->getReturnType(); - else if (const auto *Param = dyn_cast<ParmVarDecl>(D)) { + } else if (const auto *Param = dyn_cast<ParmVarDecl>(D)) { + // Attributes on parameters are used for out-parameters, + // passed as pointers-to-pointers. ReturnType = Param->getType()->getPointeeType(); if (ReturnType.isNull()) { S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type) - << AL << /*pointer-to-CF*/ 2 << AL.getRange(); + << AL << /*pointer-to-CF-pointer*/ 2 << AL.getRange(); return; } } else if (AL.isUsedAsTypeAttr()) { @@ -4803,6 +4857,8 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, case ParsedAttr::AT_NSReturnsRetained: case ParsedAttr::AT_NSReturnsAutoreleased: case ParsedAttr::AT_NSReturnsNotRetained: + case ParsedAttr::AT_OSReturnsRetained: + case ParsedAttr::AT_OSReturnsNotRetained: ExpectedDeclKind = ExpectedFunctionOrMethod; break; @@ -4827,13 +4883,19 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, case ParsedAttr::AT_NSReturnsAutoreleased: case ParsedAttr::AT_NSReturnsNotRetained: - TypeOK = isValidSubjectOfNSAttribute(S, ReturnType); + TypeOK = isValidSubjectOfNSAttribute(ReturnType); Cf = false; break; case ParsedAttr::AT_CFReturnsRetained: case ParsedAttr::AT_CFReturnsNotRetained: - TypeOK = isValidSubjectOfCFAttribute(S, ReturnType); + TypeOK = isValidSubjectOfCFAttribute(ReturnType); + Cf = true; + break; + + case ParsedAttr::AT_OSReturnsRetained: + case ParsedAttr::AT_OSReturnsNotRetained: + TypeOK = isValidSubjectOfOSAttribute(ReturnType); Cf = true; break; } @@ -4866,24 +4928,25 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, default: llvm_unreachable("invalid ownership attribute"); case ParsedAttr::AT_NSReturnsAutoreleased: - D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + handleSimpleAttribute<NSReturnsAutoreleasedAttr>(S, D, AL); return; case ParsedAttr::AT_CFReturnsNotRetained: - D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + handleSimpleAttribute<CFReturnsNotRetainedAttr>(S, D, AL); return; case ParsedAttr::AT_NSReturnsNotRetained: - D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + handleSimpleAttribute<NSReturnsNotRetainedAttr>(S, D, AL); return; case ParsedAttr::AT_CFReturnsRetained: - D->addAttr(::new (S.Context) CFReturnsRetainedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + handleSimpleAttribute<CFReturnsRetainedAttr>(S, D, AL); return; case ParsedAttr::AT_NSReturnsRetained: - D->addAttr(::new (S.Context) NSReturnsRetainedAttr( - AL.getRange(), S.Context, AL.getAttributeSpellingListIndex())); + handleSimpleAttribute<NSReturnsRetainedAttr>(S, D, AL); + return; + case ParsedAttr::AT_OSReturnsRetained: + handleSimpleAttribute<OSReturnsRetainedAttr>(S, D, AL); + return; + case ParsedAttr::AT_OSReturnsNotRetained: + handleSimpleAttribute<OSReturnsNotRetainedAttr>(S, D, AL); return; }; } @@ -6337,17 +6400,22 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, break; case ParsedAttr::AT_CFConsumed: case ParsedAttr::AT_NSConsumed: - handleNSConsumedAttr(S, D, AL); + case ParsedAttr::AT_OSConsumed: + S.AddXConsumedAttr(D, AL.getRange(), AL.getAttributeSpellingListIndex(), + parsedAttrToRetainOwnershipKind(AL), + /*IsTemplateInstantiation=*/false); break; case ParsedAttr::AT_NSConsumesSelf: handleSimpleAttribute<NSConsumesSelfAttr>(S, D, AL); break; case ParsedAttr::AT_NSReturnsAutoreleased: case ParsedAttr::AT_NSReturnsNotRetained: - case ParsedAttr::AT_CFReturnsNotRetained: case ParsedAttr::AT_NSReturnsRetained: + case ParsedAttr::AT_CFReturnsNotRetained: case ParsedAttr::AT_CFReturnsRetained: - handleNSReturnsRetainedAttr(S, D, AL); + case ParsedAttr::AT_OSReturnsNotRetained: + case ParsedAttr::AT_OSReturnsRetained: + handleXReturnsXRetainedAttr(S, D, AL); break; case ParsedAttr::AT_WorkGroupSizeHint: handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, AL); |