diff options
author | Anders Carlsson <andersca@mac.com> | 2008-10-05 18:05:59 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2008-10-05 18:05:59 +0000 |
commit | 770918281c5bdc7b5b3942285c407e3d62270053 (patch) | |
tree | 8098d6fb2d8b845d738df9bc8655df11e3502c0d | |
parent | 9a9683b585696119ea8f57598634f647468f41aa (diff) | |
download | clang-770918281c5bdc7b5b3942285c407e3d62270053.tar.gz |
Add parsing of the sentinel attribute. Still need to create the attribute.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@57121 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 6 | ||||
-rw-r--r-- | include/clang/Parse/AttributeList.h | 1 | ||||
-rw-r--r-- | lib/Parse/AttributeList.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 66 | ||||
-rw-r--r-- | test/Sema/sentinel-attribute.c | 13 |
5 files changed, 87 insertions, 0 deletions
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 0a453dd455..03acd3c980 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -733,6 +733,12 @@ DIAG(warn_attribute_nonnull_no_pointers, WARNING, 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, diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h index 2cc786369b..8ca78a34b8 100644 --- a/include/clang/Parse/AttributeList.h +++ b/include/clang/Parse/AttributeList.h @@ -72,6 +72,7 @@ public: AT_weak, AT_objc_gc, AT_blocks, + AT_sentinel, UnknownAttribute }; diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index b39dbe8c01..825570dce2 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -80,6 +80,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { if (!memcmp(Str, "noinline", 8)) return AT_noinline; if (!memcmp(Str, "fastcall", 8)) return AT_fastcall; if (!memcmp(Str, "iboutlet", 8)) return AT_IBOutlet; + if (!memcmp(Str, "sentinel", 8)) return AT_sentinel; break; case 9: if (!memcmp(Str, "dllimport", 9)) return AT_dllimport; diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 2bdb885f53..fd79a10bf4 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -586,6 +586,71 @@ static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) { 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) { @@ -1052,6 +1117,7 @@ static void ProcessDeclAttribute(Decl *D, const AttributeList &Attr, Sema &S) { 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. diff --git a/test/Sema/sentinel-attribute.c b/test/Sema/sentinel-attribute.c new file mode 100644 index 0000000000..a83cda771d --- /dev/null +++ b/test/Sema/sentinel-attribute.c @@ -0,0 +1,13 @@ +// 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}} + |