diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 287d80f93f49..feed54b7ecd5 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -66,6 +66,7 @@ public: Pure, Regparm, Section, + Sentinel, StdCall, TransparentUnion, Unavailable, @@ -359,6 +360,23 @@ public: static bool classof(const FormatAttr *A) { return true; } }; +class SentinelAttr : public Attr { + int sentinel, NullPos; +public: + SentinelAttr(int sentinel_val, int nullPos) : Attr(Sentinel), + sentinel(sentinel_val), NullPos(nullPos) {} + int getSentinel() const { return sentinel; } + int getNullPos() const { return NullPos; } + + virtual Attr *clone(ASTContext &C) const { + return ::new (C) SentinelAttr(sentinel, NullPos); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { return A->getKind() == Sentinel; } + static bool classof(const SentinelAttr *A) { return true; } +}; + class VisibilityAttr : public Attr { public: /// @brief An enumeration for the kinds of visibility of symbols. diff --git a/clang/lib/Frontend/PCHReaderDecl.cpp b/clang/lib/Frontend/PCHReaderDecl.cpp index e623b6f1d7d6..3db00ec1b71f 100644 --- a/clang/lib/Frontend/PCHReaderDecl.cpp +++ b/clang/lib/Frontend/PCHReaderDecl.cpp @@ -452,6 +452,13 @@ Attr *PCHReader::ReadAttributes() { New = ::new (*Context) FormatAttr(Type, FormatIdx, FirstArg); break; } + + case Attr::Sentinel: { + int sentinel = Record[Idx++]; + int nullPos = Record[Idx++]; + New = ::new (*Context) SentinelAttr(sentinel, nullPos); + break; + } SIMPLE_ATTR(GNUInline); diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index dbe0e536e557..e05a73568f4e 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -1556,6 +1556,13 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { break; } + case Attr::Sentinel : { + const SentinelAttr *Sentinel = cast(Attr); + Record.push_back(Sentinel->getSentinel()); + Record.push_back(Sentinel->getNullPos()); + break; + } + case Attr::GNUInline: case Attr::IBOutletKind: case Attr::NoReturn: diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 2e617f573bec..8c38c2bfd2bb 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1274,6 +1274,8 @@ public: bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, ObjCMethodDecl *Getter, SourceLocation Loc); + void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, + Expr **Args, unsigned NumArgs); // Primary Expressions. virtual SourceRange getExprRange(ExprTy *E) const; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d2e84c10e222..f1da408669ca 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -88,6 +88,15 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { return false; } +/// DiagnoseSentinelCalls - This routine checks on method dispatch calls +/// (and other functions in future), which have been declared with sentinel +/// attribute. It warns if call does not have the sentinel argument. +/// +void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, + Expr **Args, unsigned NumArgs) +{ +} + SourceRange Sema::getExprRange(ExprTy *E) const { Expr *Ex = (Expr *)E; return Ex? Ex->getSourceRange() : SourceRange(); diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index de6b69f90fbe..0073fd9f28f2 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -626,6 +626,8 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, return true; } + if (Method) + DiagnoseSentinelCalls(Method, receiverLoc, ArgExprs, NumArgs); if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, lbrac, rbrac, returnType)) return true;