diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 35 | ||||
-rw-r--r-- | test/Sema/block-sentinel-attribute.c | 24 | ||||
-rw-r--r-- | test/Sema/function-pointer-sentinel-attribute.c | 23 |
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 + +} + |