Attr.getAttributeSpellingListIndex()));
}
+static const char *ownershipKindToDiagName(OwnershipAttr::OwnershipKind K) {
+ switch (K) {
+ case OwnershipAttr::Holds: return "'ownership_holds'";
+ case OwnershipAttr::Takes: return "'ownership_takes'";
+ case OwnershipAttr::Returns: return "'ownership_returns'";
+ }
+ llvm_unreachable("unknown ownership");
+}
+
static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
- // This attribute must be applied to a function declaration.
- // The first argument to the attribute must be a string,
- // the name of the resource, for example "malloc".
- // The following arguments must be argument indexes, the arguments must be
- // of integer type for Returns, otherwise of pointer type.
+ // This attribute must be applied to a function declaration. The first
+ // argument to the attribute must be an identifier, the name of the resource,
+ // for example: malloc. The following arguments must be argument indexes, the
+ // arguments must be of integer type for Returns, otherwise of pointer type.
// The difference between Holds and Takes is that a pointer may still be used
- // after being held. free() should be __attribute((ownership_takes)), whereas
+ // after being held. free() should be __attribute((ownership_takes)), whereas
// a list append function may well be __attribute((ownership_holds)).
if (!AL.isArgIdent(0)) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL.getName()->getName() << 1 << AANT_ArgumentString;
+ << AL.getName() << 1 << AANT_ArgumentIdentifier;
return;
}
+
// Figure out our Kind, and check arguments while we're at it.
OwnershipAttr::OwnershipKind K;
switch (AL.getKind()) {
case AttributeList::AT_ownership_takes:
K = OwnershipAttr::Takes;
if (AL.getNumArgs() < 2) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
- << AL.getName() << 2;
+ S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << 2;
return;
}
break;
case AttributeList::AT_ownership_holds:
K = OwnershipAttr::Holds;
if (AL.getNumArgs() < 2) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
- << AL.getName() << 2;
+ S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << 2;
return;
}
break;
case AttributeList::AT_ownership_returns:
K = OwnershipAttr::Returns;
+
if (AL.getNumArgs() > 2) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
- << AL.getName() << AL.getNumArgs() + 2;
+ S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << 1;
return;
}
break;
if (Module.startswith("__") && Module.endswith("__"))
Module = Module.substr(2, Module.size() - 4);
-
SmallVector<unsigned, 8> OwnershipArgs;
for (unsigned i = 1; i < AL.getNumArgs(); ++i) {
Expr *Ex = AL.getArgAsExpr(i);
AL.getLoc(), i, Ex, Idx))
return;
+ // Is the function argument a pointer type?
+ QualType T = getFunctionOrMethodArgType(D, Idx);
+ int Err = -1; // No error
switch (K) {
- case OwnershipAttr::Takes:
- case OwnershipAttr::Holds: {
- // Is the function argument a pointer type?
- QualType T = getFunctionOrMethodArgType(D, Idx);
- if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
- // FIXME: Should also highlight argument in decl.
- S.Diag(AL.getLoc(), diag::err_ownership_type)
- << ((K==OwnershipAttr::Takes)?"ownership_takes":"ownership_holds")
- << "pointer"
- << Ex->getSourceRange();
- continue;
- }
- break;
+ case OwnershipAttr::Takes:
+ case OwnershipAttr::Holds:
+ if (!T->isAnyPointerType() && !T->isBlockPointerType())
+ Err = 0;
+ break;
+ case OwnershipAttr::Returns:
+ if (!T->isIntegerType())
+ Err = 1;
+ break;
}
- case OwnershipAttr::Returns: {
- if (AL.getNumArgs() > 2) {
- // Is the function argument an integer type?
- Expr *IdxExpr = AL.getArgAsExpr(1);
- llvm::APSInt ArgNum(32);
- if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent()
- || !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) {
- S.Diag(AL.getLoc(), diag::err_ownership_type)
- << "ownership_returns" << "integer"
- << IdxExpr->getSourceRange();
- return;
- }
- }
- break;
+ if (-1 != Err) {
+ S.Diag(AL.getLoc(), diag::err_ownership_type) << AL.getName() << Err\r
+ << Ex->getSourceRange();
+ return;
}
- } // switch
// Check we don't have a conflict with another ownership attribute.
for (specific_attr_iterator<OwnershipAttr>
- i = D->specific_attr_begin<OwnershipAttr>(),
- e = D->specific_attr_end<OwnershipAttr>();
- i != e; ++i) {
- if ((*i)->getOwnKind() != K) {
- for (const unsigned *I = (*i)->args_begin(), *E = (*i)->args_end();
- I!=E; ++I) {
- if (Idx == *I) {
- S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
- << AL.getName()->getName() << "ownership_*";
- }
- }
+ i = D->specific_attr_begin<OwnershipAttr>(),
+ e = D->specific_attr_end<OwnershipAttr>(); i != e; ++i) {
+ if ((*i)->getOwnKind() != K && (*i)->args_end() !=
+ std::find((*i)->args_begin(), (*i)->args_end(), Idx)) {
+ S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
+ << AL.getName() << ownershipKindToDiagName((*i)->getOwnKind());
+ return;
}
}
OwnershipArgs.push_back(Idx);
unsigned size = OwnershipArgs.size();
llvm::array_pod_sort(start, start + size);
- if (K != OwnershipAttr::Returns && OwnershipArgs.empty()) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
- << AL.getName() << 2;
- return;
- }
-
D->addAttr(::new (S.Context)
OwnershipAttr(AL.getLoc(), S.Context, K, Module, start, size,
AL.getAttributeSpellingListIndex()));
--- /dev/null
+// RUN: %clang_cc1 %s -verify\r
+\r
+void f1(void) __attribute__((ownership_takes("foo"))); // expected-error {{'ownership_takes' attribute requires parameter 1 to be an identifier}}\r
+void *f2(void) __attribute__((ownership_returns(foo, 1, 2))); // expected-error {{attribute takes no more than 1 argument}}\r
+void f3(void) __attribute__((ownership_holds(foo, 1))); // expected-error {{'ownership_holds' attribute parameter 1 is out of bounds}}\r
+void *f4(void) __attribute__((ownership_returns(foo)));\r
+void f5(void) __attribute__((ownership_holds(foo))); // expected-error {{attribute takes at least 2 arguments}}\r
+void f6(void) __attribute__((ownership_holds(foo, 1, 2, 3))); // expected-error {{'ownership_holds' attribute parameter 1 is out of bounds}}\r
+void f7(void) __attribute__((ownership_takes(foo))); // expected-error {{attribute takes at least 2 arguments}}\r
+void f8(int *i, int *j, int k) __attribute__((ownership_holds(foo, 1, 2, 4))); // expected-error {{'ownership_holds' attribute parameter 3 is out of bounds}}\r
+\r
+int f9 __attribute__((ownership_takes(foo, 1))); // expected-warning {{'ownership_takes' attribute only applies to functions}}\r
+\r
+void f10(int i) __attribute__((ownership_holds(foo, 1))); // expected-error {{'ownership_holds' attribute only applies to pointer arguments}}\r
+void *f11(float i) __attribute__((ownership_returns(foo, 1))); // expected-error {{'ownership_returns' attribute only applies to integer arguments}}\r
+void *f12(float i, int k, int f, int *j) __attribute__((ownership_returns(foo, 4))); // expected-error {{'ownership_returns' attribute only applies to integer arguments}}\r
+\r
+void f13(int *i, int *j) __attribute__((ownership_holds(foo, 1))) __attribute__((ownership_takes(foo, 2)));\r
+void f14(int i, int j, int *k) __attribute__((ownership_holds(foo, 3))) __attribute__((ownership_takes(foo, 3))); // expected-error {{'ownership_holds' and 'ownership_takes' attributes are not compatible}}\r