DIAG(warn_transparent_union_nonpointer, WARNING,
"'transparent_union' attribute support incomplete; only supported for"
"pointer unions")
+DIAG(warn_attribute_sentinel_not_variadic, WARNING,
+ "'sentinel' attribute only supported for variadic functions")
+DIAG(err_attribute_sentinel_less_than_zero, ERROR,
+ "'sentinel' parameter 1 less than zero")
+DIAG(err_attribute_sentinel_not_zero_or_one, ERROR,
+ "'sentinel' parameter 2 not 0 or 1")
// Clang-Specific Attributes
DIAG(err_attribute_iboutlet_non_ivar, ERROR,
d->addAttr(new BlocksAttr(type));
}
+static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.getNumArgs() > 2) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments, "0, 1 or 2");
+ return;
+ }
+
+ int sentinel = 0;
+ if (Attr.getNumArgs() > 0) {
+ Expr *E = static_cast<Expr *>(Attr.getArg(0));
+ llvm::APSInt Idx(32);
+ if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int,
+ "sentinel", "1", E->getSourceRange());
+ return;
+ }
+ sentinel = Idx.getZExtValue();
+
+ if (sentinel < 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero,
+ E->getSourceRange());
+ return;
+ }
+ }
+
+ int nullPos = 0;
+ if (Attr.getNumArgs() > 1) {
+ Expr *E = static_cast<Expr *>(Attr.getArg(1));
+ llvm::APSInt Idx(32);
+ if (!E->isIntegerConstantExpr(Idx, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int,
+ "sentinel", "2", E->getSourceRange());
+ return;
+ }
+ nullPos = Idx.getZExtValue();
+
+ if (nullPos > 1 || nullPos < 0) {
+ // FIXME: This error message could be improved, it would be nice
+ // to say what the bounds actually are.
+ S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_not_zero_or_one,
+ E->getSourceRange());
+ return;
+ }
+ }
+
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) {
+ QualType FT = FD->getType();
+ if (!FT->getAsFunctionTypeProto()->isVariadic()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic);
+ return;
+ }
+ } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) {
+ if (!MD->isVariadic()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic);
+ return;
+ }
+ } else {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type,
+ "sentinel", "function or method");
+ return;
+ }
+
+ // FIXME: Actually create the attribute.
+}
+
static void HandleWeakAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments.
if (Attr.getNumArgs() != 0) {
break;
case AttributeList::AT_objc_gc: HandleObjCGCAttr (D, Attr, S); break;
case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break;
+ case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break;
default:
#if 0
// TODO: when we have the full set of attributes, warn about unknown ones.
--- /dev/null
+// RUN: clang -fsyntax-only -verify %s
+int x __attribute__((sentinel)); //expected-warning{{'sentinel' attribute only applies to function or method types}}
+
+void f1(int a, ...) __attribute__ ((sentinel));
+void f2(int a, ...) __attribute__ ((sentinel(1)));
+
+void f3(int a, ...) __attribute__ ((sentinel("hello"))); //expected-error{{'sentinel' attribute requires parameter 1 to be an integer constant}}
+void f4(int a, ...) __attribute__ ((sentinel(1, 2, 3))); //expected-error{{attribute requires 0, 1 or 2 argument(s)}}
+void f4(int a, ...) __attribute__ ((sentinel(-1))); //expected-error{{parameter 1 less than zero}}
+void f4(int a, ...) __attribute__ ((sentinel(0, 2))); // expected-error{{parameter 2 not 0 or 1}}
+
+void f5(int a) __attribute__ ((sentinel)); //expected-warning{{'sentinel' attribute only supported for variadic functions}}
+