/// 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>
//===----------------------------------------------------------------------===//
// 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) {
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()) {
case ParsedAttr::AT_NSReturnsRetained:
case ParsedAttr::AT_NSReturnsAutoreleased:
case ParsedAttr::AT_NSReturnsNotRetained:
+ case ParsedAttr::AT_OSReturnsRetained:
+ case ParsedAttr::AT_OSReturnsNotRetained:
ExpectedDeclKind = ExpectedFunctionOrMethod;
break;
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;
}
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;
};
}
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);