aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2009-05-15 20:33:25 +0000
committerFariborz Jahanian <fjahanian@apple.com>2009-05-15 20:33:25 +0000
commitdaf0415583e33d5d279197c65e9227c1ed92474b (patch)
tree2f0bbb1fd3db3edb7e166dabbcf0c884f214f7b2
parente28be4386b3b2af45462339fc04c0924ffa78e93 (diff)
This patch finishes off the sentinel attribute handling for
blocks and function pointers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71888 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td4
-rw-r--r--lib/Sema/SemaDeclAttr.cpp8
-rw-r--r--lib/Sema/SemaExpr.cpp35
-rw-r--r--test/Sema/block-sentinel-attribute.c24
-rw-r--r--test/Sema/function-pointer-sentinel-attribute.c23
5 files changed, 83 insertions, 11 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 5fefa2d69f..7bb9a38422 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -799,9 +799,9 @@ def note_unavailable_here : Note<
def warn_not_enough_argument : Warning<
"not enough variable arguments in %0 declaration to fit a sentinel">;
def warn_missing_sentinel : Warning <
- "missing sentinel in %select{function|method}0 %select{call|dispatch}1">;
+ "missing sentinel in %select{function call|method dispatch|block call}0">;
def note_sentinel_here : Note<
- "%select{function|method}0 has been explicitly marked sentinel here">;
+ "%select{function|method|block}0 has been explicitly marked sentinel here">;
def warn_missing_prototype : Warning<
"no previous prototype for function %0">,
InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore;
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index c253b40bfe..f5b6595b18 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -726,11 +726,9 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
;
} else if (const VarDecl *V = dyn_cast<VarDecl>(d)) {
QualType Ty = V->getType();
- if (Ty->isBlockPointerType()) {
- const BlockPointerType *BPT = Ty->getAsBlockPointerType();
- QualType FnType = BPT->getPointeeType();
- const FunctionType *FT = FnType->getAsFunctionType();
- assert(FT && "Block has non-function type?");
+ if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
+ const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d)
+ : Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType();
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic);
return;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 2bc7461962..8aaa8b1399 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -130,6 +130,30 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
}
warnNotEnoughArgs = (P != E || i >= NumArgs);
}
+ else if (VarDecl *V = dyn_cast<VarDecl>(D)) {
+ // block or function pointer call.
+ QualType Ty = V->getType();
+ if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
+ const FunctionType *FT = Ty->isFunctionPointerType()
+ ? Ty->getAsPointerType()->getPointeeType()->getAsFunctionType()
+ : Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType();
+ if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) {
+ unsigned NumArgsInProto = Proto->getNumArgs();
+ unsigned k;
+ for (k = 0; (k != NumArgsInProto && i < NumArgs); k++) {
+ if (nullPos)
+ --nullPos;
+ else
+ ++i;
+ }
+ warnNotEnoughArgs = (k != NumArgsInProto || i >= NumArgs);
+ }
+ if (Ty->isBlockPointerType())
+ isMethod = 2;
+ }
+ else
+ return;
+ }
else
return;
@@ -155,7 +179,7 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
Expr *sentinelExpr = Args[sentinel];
if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() ||
!sentinelExpr->isNullPointerConstant(Context))) {
- Diag(Loc, diag::warn_missing_sentinel) << isMethod << isMethod;
+ Diag(Loc, diag::warn_missing_sentinel) << isMethod;
Diag(D->getLocation(), diag::note_sentinel_here) << isMethod;
}
return;
@@ -2466,6 +2490,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
Expr **Args = reinterpret_cast<Expr**>(args.release());
assert(Fn && "no function call expression");
FunctionDecl *FDecl = NULL;
+ NamedDecl *NDecl = NULL;
DeclarationName UnqualifiedName;
if (getLangOptions().CPlusPlus) {
@@ -2531,6 +2556,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
if (DRExpr) {
FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl());
+ NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl());
}
if (Ovl || (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
@@ -2638,11 +2664,12 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
return ExprError(Diag(LParenLoc, diag::err_member_call_without_object)
<< Fn->getSourceRange());
+ // Check for sentinels
+ if (NDecl)
+ DiagnoseSentinelCalls(NDecl, LParenLoc, Args, NumArgs);
// Do special checking on direct calls to functions.
- if (FDecl) {
- DiagnoseSentinelCalls(FDecl, LParenLoc, Args, NumArgs);
+ if (FDecl)
return CheckFunctionCall(FDecl, TheCall.take());
- }
return Owned(TheCall.take());
}
diff --git a/test/Sema/block-sentinel-attribute.c b/test/Sema/block-sentinel-attribute.c
new file mode 100644
index 0000000000..68d3614eee
--- /dev/null
+++ b/test/Sema/block-sentinel-attribute.c
@@ -0,0 +1,24 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void (^e) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (1,1)));
+
+int main()
+{
+ void (^b) (int arg, const char * format, ...) __attribute__ ((__sentinel__)) = // expected-note {{block has been explicitly marked sentinel here}}
+ ^ __attribute__ ((__sentinel__)) (int arg, const char * format, ...) {};
+ void (^z) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (2))) = ^ __attribute__ ((__sentinel__ (2))) (int arg, const char * format, ...) {}; // expected-note {{block has been explicitly marked sentinel here}}
+
+
+ void (^y) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (5))) = ^ __attribute__ ((__sentinel__ (5))) (int arg, const char * format, ...) {}; // expected-note {{block has been explicitly marked sentinel here}}
+
+ b(1, "%s", (void*)0); // OK
+ b(1, "%s", 0); // expected-warning {{missing sentinel in block call}}
+ z(1, "%s",4 ,1,0); // expected-warning {{missing sentinel in block call}}
+ z(1, "%s", (void*)0, 1, 0); // OK
+
+ y(1, "%s", 1,2,3,4,5,6,7); // expected-warning {{missing sentinel in block call}}
+
+ y(1, "%s", (void*)0,3,4,5,6,7); // OK
+
+}
+
diff --git a/test/Sema/function-pointer-sentinel-attribute.c b/test/Sema/function-pointer-sentinel-attribute.c
new file mode 100644
index 0000000000..0de02fa536
--- /dev/null
+++ b/test/Sema/function-pointer-sentinel-attribute.c
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void (*e) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (1,1)));
+
+int main()
+{
+ void (*b) (int arg, const char * format, ...) __attribute__ ((__sentinel__)); // expected-note {{function has been explicitly marked sentinel here}}
+ void (*z) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (2))); // expected-note {{function has been explicitly marked sentinel here}}
+
+
+ void (*y) (int arg, const char * format, ...) __attribute__ ((__sentinel__ (5))); // expected-note {{function has been explicitly marked sentinel here}}
+
+ b(1, "%s", (void*)0); // OK
+ b(1, "%s", 0); // expected-warning {{missing sentinel in function call}}
+ z(1, "%s",4 ,1,0); // expected-warning {{missing sentinel in function call}}
+ z(1, "%s", (void*)0, 1, 0); // OK
+
+ y(1, "%s", 1,2,3,4,5,6,7); // expected-warning {{missing sentinel in function call}}
+
+ y(1, "%s", (void*)0,3,4,5,6,7); // OK
+
+}
+