aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Attr.h1
-rw-r--r--include/clang/AST/Decl.h2
-rw-r--r--include/clang/AST/Expr.h2
-rw-r--r--lib/AST/Decl.cpp36
-rw-r--r--lib/AST/Expr.cpp8
-rw-r--r--lib/AST/ExprConstant.cpp7
-rw-r--r--lib/Analysis/GRExprEngine.cpp3
-rw-r--r--lib/CodeGen/CGExpr.cpp2
-rw-r--r--lib/CodeGen/CGExprConstant.cpp3
-rw-r--r--lib/Sema/Sema.cpp1
-rw-r--r--lib/Sema/Sema.h10
-rw-r--r--lib/Sema/SemaChecking.cpp59
-rw-r--r--lib/Sema/SemaDecl.cpp73
-rw-r--r--lib/Sema/SemaExpr.cpp2
-rw-r--r--lib/Sema/SemaUtil.h36
-rw-r--r--test/Sema/format-strings.c6
16 files changed, 152 insertions, 99 deletions
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 288a1c4a32..8d4e1090cf 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -347,6 +347,7 @@ public:
Type(type), formatIdx(idx), firstArg(first) {}
const std::string& getType() const { return Type; }
+ void setType(const std::string &type) { Type = type; }
int getFormatIdx() const { return formatIdx; }
int getFirstArg() const { return firstArg; }
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index a4e30653b2..b39467a55f 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -600,7 +600,7 @@ public:
PreviousDeclaration = PrevDecl;
}
- unsigned getBuiltinID() const;
+ unsigned getBuiltinID(ASTContext &Context) const;
// Iterator access to formal parameters.
unsigned param_size() const { return getNumParams(); }
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 2baaa438d0..b7c5c8920d 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -834,7 +834,7 @@ public:
/// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If
/// not, return 0.
- unsigned isBuiltinCall() const;
+ unsigned isBuiltinCall(ASTContext &Context) const;
SourceLocation getRParenLoc() const { return RParenLoc; }
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 13b40e8afe..ca1fa0c1e1 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -259,15 +259,33 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
/// will be 0 for functions that do not correspond to a builtin, a
/// value of type \c Builtin::ID if in the target-independent range
/// \c [1,Builtin::First), or a target-specific builtin value.
-unsigned FunctionDecl::getBuiltinID() const {
- if (getIdentifier() &&
- (getDeclContext()->isTranslationUnit() ||
- (isa<LinkageSpecDecl>(getDeclContext()) &&
- cast<LinkageSpecDecl>(getDeclContext())->getLanguage()
- == LinkageSpecDecl::lang_c)))
- return getIdentifier()->getBuiltinID();
-
- // Not a builtin.
+unsigned FunctionDecl::getBuiltinID(ASTContext &Context) const {
+ if (!getIdentifier() || !getIdentifier()->getBuiltinID())
+ return 0;
+
+ unsigned BuiltinID = getIdentifier()->getBuiltinID();
+ if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+ return BuiltinID;
+
+ // This function has the name of a known C library
+ // function. Determine whether it actually refers to the C library
+ // function or whether it just has the same name.
+
+ // If this function is at translation-unit scope and we're not in
+ // C++, it refers to the C library function.
+ if (!Context.getLangOptions().CPlusPlus &&
+ getDeclContext()->isTranslationUnit())
+ return BuiltinID;
+
+ // If the function is in an extern "C" linkage specification and is
+ // not marked "overloadable", it's the real function.
+ if (isa<LinkageSpecDecl>(getDeclContext()) &&
+ cast<LinkageSpecDecl>(getDeclContext())->getLanguage()
+ == LinkageSpecDecl::lang_c &&
+ !getAttr<OverloadableAttr>())
+ return BuiltinID;
+
+ // Not a builtin
return 0;
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 7063b768c5..7a04ffcedc 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -173,7 +173,7 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) {
/// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If
/// not, return 0.
-unsigned CallExpr::isBuiltinCall() const {
+unsigned CallExpr::isBuiltinCall(ASTContext &Context) const {
// All simple function calls (e.g. func()) are implicitly cast to pointer to
// function. As a result, we try and obtain the DeclRefExpr from the
// ImplicitCastExpr.
@@ -192,7 +192,7 @@ unsigned CallExpr::isBuiltinCall() const {
if (!FDecl->getIdentifier())
return 0;
- return FDecl->getBuiltinID();
+ return FDecl->getBuiltinID(Context);
}
@@ -922,7 +922,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
// If this is a call to a builtin function, constant fold it otherwise
// reject it.
- if (CE->isBuiltinCall()) {
+ if (CE->isBuiltinCall(Ctx)) {
EvalResult EvalResult;
if (CE->Evaluate(EvalResult, Ctx)) {
assert(!EvalResult.HasSideEffects &&
@@ -1205,7 +1205,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
// expression, and it is fully evaluated. This is an important GNU
// extension. See GCC PR38377 for discussion.
if (const CallExpr *CallCE = dyn_cast<CallExpr>(Cond->IgnoreParenCasts()))
- if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p) {
+ if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) {
EvalResult EVResult;
if (!Evaluate(EVResult, Ctx) || EVResult.HasSideEffects)
return false;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index c7cc85425c..3a3b1527fa 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -350,7 +350,8 @@ APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
}
APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
- if (E->isBuiltinCall() == Builtin::BI__builtin___CFStringMakeConstantString)
+ if (E->isBuiltinCall(Info.Ctx) ==
+ Builtin::BI__builtin___CFStringMakeConstantString)
return APValue(E, 0);
return APValue();
}
@@ -646,7 +647,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) {
bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
Result.zextOrTrunc(getIntTypeSizeInBits(E->getType()));
- switch (E->isBuiltinCall()) {
+ switch (E->isBuiltinCall(Info.Ctx)) {
default:
return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
case Builtin::BI__builtin_classify_type:
@@ -1173,7 +1174,7 @@ static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
}
bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
- switch (E->isBuiltinCall()) {
+ switch (E->isBuiltinCall(Info.Ctx)) {
default: return false;
case Builtin::BI__builtin_huge_val:
case Builtin::BI__builtin_huge_valf:
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index a48b18c9c6..1a7f35960c 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -1263,7 +1263,8 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred,
if (isa<loc::FuncVal>(L)) {
- if (unsigned id = cast<loc::FuncVal>(L).getDecl()->getBuiltinID())
+ if (unsigned id
+ = cast<loc::FuncVal>(L).getDecl()->getBuiltinID(getContext()))
switch (id) {
case Builtin::BI__builtin_expect: {
// For __builtin_expect, just return the value of the subexpression.
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index ddecbebded..3e44c0079b 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -964,7 +964,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) {
dyn_cast<const DeclRefExpr>(IcExpr->getSubExpr()))
if (const FunctionDecl *FDecl =
dyn_cast<const FunctionDecl>(DRExpr->getDecl()))
- if (unsigned builtinID = FDecl->getBuiltinID())
+ if (unsigned builtinID = FDecl->getBuiltinID(getContext()))
return EmitBuiltinExpr(builtinID, E);
if (E->getCallee()->getType()->isBlockPointerType())
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 91153f796b..bfb523bb32 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -582,7 +582,8 @@ public:
}
case Expr::CallExprClass: {
CallExpr* CE = cast<CallExpr>(E);
- if (CE->isBuiltinCall() != Builtin::BI__builtin___CFStringMakeConstantString)
+ if (CE->isBuiltinCall(CGM.getContext()) !=
+ Builtin::BI__builtin___CFStringMakeConstantString)
break;
const Expr *Arg = CE->getArg(0)->IgnoreParenCasts();
const StringLiteral *Literal = cast<StringLiteral>(Arg);
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 4666250c4a..539457f8a6 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -132,6 +132,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
IdentifierTable &IT = PP.getIdentifierTable();
KnownFunctionIDs[id_NSLog] = &IT.get("NSLog");
+ KnownFunctionIDs[id_NSLogv] = &IT.get("NSLogv");
KnownFunctionIDs[id_asprintf] = &IT.get("asprintf");
KnownFunctionIDs[id_vasprintf] = &IT.get("vasprintf");
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 68c425cd60..7c2d3b67ad 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -181,6 +181,7 @@ public:
// Enum values used by KnownFunctionIDs (see below).
enum {
id_NSLog,
+ id_NSLogv,
id_asprintf,
id_vasprintf,
id_num_known_functions
@@ -883,6 +884,7 @@ public:
SourceLocation Loc);
NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
Scope *S);
+ void AddKnownFunctionAttributes(FunctionDecl *FD);
// More parsing and symbol table subroutines.
@@ -1986,12 +1988,12 @@ private:
bool SemaBuiltinPrefetch(CallExpr *TheCall);
bool SemaBuiltinObjectSize(CallExpr *TheCall);
bool SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
- unsigned format_idx);
+ unsigned format_idx, unsigned firstDataArg);
void CheckPrintfString(StringLiteral *FExpr, Expr *OrigFormatExpr,
CallExpr *TheCall, bool HasVAListArg,
- unsigned format_idx);
- void CheckPrintfArguments(CallExpr *TheCall,
- bool HasVAListArg, unsigned format_idx);
+ unsigned format_idx, unsigned firstDataArg);
+ void CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
+ unsigned format_idx, unsigned firstDataArg);
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc);
void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 7ecc304fc9..e2ec2676c7 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -18,7 +18,6 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/Preprocessor.h"
-#include "SemaUtil.h"
using namespace clang;
/// CheckFunctionCall - Check a direct function call for various correctness
@@ -34,7 +33,7 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
if (!FnInfo)
return move(TheCallResult);
- switch (FDecl->getBuiltinID()) {
+ switch (FDecl->getBuiltinID(Context)) {
case Builtin::BI__builtin___CFStringMakeConstantString:
assert(TheCall->getNumArgs() == 1 &&
"Wrong # arguments to builtin CFStringMakeConstantString");
@@ -78,27 +77,17 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
// handlers.
// Printf checking.
- unsigned format_idx = 0;
- bool HasVAListArg = false;
- if (FDecl->getBuiltinID() &&
- Context.BuiltinInfo.isPrintfLike(FDecl->getBuiltinID(), format_idx,
- HasVAListArg)) {
- // Found a printf builtin.
- } else if (FnInfo == KnownFunctionIDs[id_NSLog]) {
- format_idx = 0;
- HasVAListArg = false;
- } else if (FnInfo == KnownFunctionIDs[id_asprintf]) {
- format_idx = 1;
- HasVAListArg = false;
- } else if (FnInfo == KnownFunctionIDs[id_vasprintf]) {
- format_idx = 1;
- HasVAListArg = true;
- } else {
- return move(TheCallResult);
+ if (const FormatAttr *Format = FDecl->getAttr<FormatAttr>()) {
+ if (Format->getType() == "printf") {
+ bool HasVAListArg = false;
+ if (const FunctionTypeProto *Proto
+ = FDecl->getType()->getAsFunctionTypeProto())
+ HasVAListArg = !Proto->isVariadic();
+ CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1,
+ Format->getFirstArg() - 1);
+ }
}
- CheckPrintfArguments(TheCall, HasVAListArg, format_idx);
-
return move(TheCallResult);
}
@@ -364,27 +353,27 @@ bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
// Handle i > 1 ? "x" : "y", recursivelly
bool Sema::SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
- unsigned format_idx) {
+ unsigned format_idx, unsigned firstDataArg) {
switch (E->getStmtClass()) {
case Stmt::ConditionalOperatorClass: {
ConditionalOperator *C = cast<ConditionalOperator>(E);
return SemaCheckStringLiteral(C->getLHS(), TheCall,
- HasVAListArg, format_idx)
+ HasVAListArg, format_idx, firstDataArg)
&& SemaCheckStringLiteral(C->getRHS(), TheCall,
- HasVAListArg, format_idx);
+ HasVAListArg, format_idx, firstDataArg);
}
case Stmt::ImplicitCastExprClass: {
ImplicitCastExpr *Expr = dyn_cast<ImplicitCastExpr>(E);
return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg,
- format_idx);
+ format_idx, firstDataArg);
}
case Stmt::ParenExprClass: {
ParenExpr *Expr = dyn_cast<ParenExpr>(E);
return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg,
- format_idx);
+ format_idx, firstDataArg);
}
default: {
@@ -397,7 +386,8 @@ bool Sema::SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
StrE = dyn_cast<StringLiteral>(E);
if (StrE) {
- CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx);
+ CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx,
+ firstDataArg);
return true;
}
@@ -458,7 +448,7 @@ bool Sema::SemaCheckStringLiteral(Expr *E, CallExpr *TheCall, bool HasVAListArg,
/// For now, we ONLY do (1), (3), (5), (6), (7), and (8).
void
Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
- unsigned format_idx) {
+ unsigned format_idx, unsigned firstDataArg) {
Expr *Fn = TheCall->getCallee();
// CHECK: printf-like function is called with no format string.
@@ -482,7 +472,9 @@ Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
// C string (e.g. "%d")
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
- bool isFExpr = SemaCheckStringLiteral(OrigFormatExpr, TheCall, HasVAListArg, format_idx);
+ bool isFExpr = SemaCheckStringLiteral(OrigFormatExpr, TheCall,
+ HasVAListArg, format_idx,
+ firstDataArg);
if (!isFExpr) {
// For vprintf* functions (i.e., HasVAListArg==true), we add a
@@ -516,7 +508,8 @@ Sema::CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg,
}
void Sema::CheckPrintfString(StringLiteral *FExpr, Expr *OrigFormatExpr,
- CallExpr *TheCall, bool HasVAListArg, unsigned format_idx) {
+ CallExpr *TheCall, bool HasVAListArg, unsigned format_idx,
+ unsigned firstDataArg) {
ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(OrigFormatExpr);
// CHECK: is the format string a wide literal?
@@ -554,7 +547,7 @@ void Sema::CheckPrintfString(StringLiteral *FExpr, Expr *OrigFormatExpr,
// string. This can only be determined for non vprintf-like
// functions. For those functions, this value is 1 (the sole
// va_arg argument).
- unsigned numDataArgs = TheCall->getNumArgs()-(format_idx+1);
+ unsigned numDataArgs = TheCall->getNumArgs()-firstDataArg;
// Inspect the format string.
unsigned StrIdx = 0;
@@ -1025,12 +1018,12 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) {
// Check for comparisons with builtin types.
if (EmitWarning)
if (CallExpr* CL = dyn_cast<CallExpr>(LeftExprSansParen))
- if (isCallBuiltin(CL))
+ if (CL->isBuiltinCall(Context))
EmitWarning = false;
if (EmitWarning)
if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen))
- if (isCallBuiltin(CR))
+ if (CR->isBuiltinCall(Context))
EmitWarning = false;
// Emit the diagnostic.
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 16e8691f10..37e1f54f7f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -340,7 +340,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
New->setParams(Context, &Params[0], Params.size());
}
-
+ AddKnownFunctionAttributes(New);
// TUScope is the translation-unit scope to insert this function into.
// FIXME: This is hideous. We need to teach PushOnScopeChains to
@@ -522,7 +522,7 @@ Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, bool &Redeclaration) {
if (Old->isThisDeclarationADefinition())
PrevDiag = diag::note_previous_definition;
else if (Old->isImplicit()) {
- if (Old->getBuiltinID())
+ if (Old->getBuiltinID(Context))
PrevDiag = diag::note_previous_builtin_declaration;
else
PrevDiag = diag::note_previous_implicit_declaration;
@@ -1771,6 +1771,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Handle attributes. We need to have merged decls when handling attributes
// (for example to check for conflicts, etc).
ProcessDeclAttributes(NewFD, D);
+ AddKnownFunctionAttributes(NewFD);
if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) {
// If a function name is overloadable in C, then every function
@@ -1872,7 +1873,7 @@ bool Sema::CheckAddressConstantExpression(const Expr* Init) {
case Expr::CallExprClass:
case Expr::CXXOperatorCallExprClass:
// __builtin___CFStringMakeConstantString is a valid constant l-value.
- if (cast<CallExpr>(Init)->isBuiltinCall() ==
+ if (cast<CallExpr>(Init)->isBuiltinCall(Context) ==
Builtin::BI__builtin___CFStringMakeConstantString)
return false;
@@ -2071,7 +2072,7 @@ bool Sema::CheckArithmeticConstantExpression(const Expr* Init) {
const CallExpr *CE = cast<CallExpr>(Init);
// Allow any constant foldable calls to builtins.
- if (CE->isBuiltinCall() && CE->isEvaluatable(Context))
+ if (CE->isBuiltinCall(Context) && CE->isEvaluatable(Context))
return false;
InitializerElementNotConstant(Init);
@@ -2856,9 +2857,73 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
CurContext = PrevDC;
+ AddKnownFunctionAttributes(FD);
+
return FD;
}
+/// \brief Adds any function attributes that we know a priori based on
+/// the declaration of this function.
+///
+/// These attributes can apply both to implicitly-declared builtins
+/// (like __builtin___printf_chk) or to library-declared functions
+/// like NSLog or printf.
+void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
+ if (FD->isInvalidDecl())
+ return;
+
+ // If this is a built-in function, map its builtin attributes to
+ // actual attributes.
+ if (unsigned BuiltinID = FD->getBuiltinID(Context)) {
+ // Handle printf-formatting attributes.
+ unsigned FormatIdx;
+ bool HasVAListArg;
+ if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) {
+ if (!FD->getAttr<FormatAttr>())
+ FD->addAttr(new FormatAttr("printf", FormatIdx + 1, FormatIdx + 2));
+ }
+ }
+
+ IdentifierInfo *Name = FD->getIdentifier();
+ if (!Name)
+ return;
+ if ((!getLangOptions().CPlusPlus &&
+ FD->getDeclContext()->isTranslationUnit()) ||
+ (isa<LinkageSpecDecl>(FD->getDeclContext()) &&
+ cast<LinkageSpecDecl>(FD->getDeclContext())->getLanguage() ==
+ LinkageSpecDecl::lang_c)) {
+ // Okay: this could be a libc/libm/Objective-C function we know
+ // about.
+ } else
+ return;
+
+ unsigned KnownID;
+ for (KnownID = 0; KnownID != id_num_known_functions; ++KnownID)
+ if (KnownFunctionIDs[KnownID] == Name)
+ break;
+
+ switch (KnownID) {
+ case id_NSLog:
+ case id_NSLogv:
+ if (const FormatAttr *Format = FD->getAttr<FormatAttr>()) {
+ // FIXME: We known better than our headers.
+ const_cast<FormatAttr *>(Format)->setType("printf");
+ } else
+ FD->addAttr(new FormatAttr("printf", 1, 2));
+ break;
+
+ case id_asprintf:
+ case id_vasprintf:
+ if (!FD->getAttr<FormatAttr>())
+ FD->addAttr(new FormatAttr("printf", 2, 3));
+ break;
+
+ default:
+ // Unknown function or known function without any attributes to
+ // add. Do nothing.
+ break;
+ }
+}
TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
Decl *LastDeclarator) {
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index ee3ef04084..ef4ae54b86 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1921,7 +1921,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
if (Ovl || (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
// We don't perform ADL for implicit declarations of builtins.
- if (FDecl && FDecl->getBuiltinID() && FDecl->isImplicit())
+ if (FDecl && FDecl->getBuiltinID(Context) && FDecl->isImplicit())
ADL = false;
// We don't perform ADL in C.
diff --git a/lib/Sema/SemaUtil.h b/lib/Sema/SemaUtil.h
deleted file mode 100644
index 5c64c76e29..0000000000
--- a/lib/Sema/SemaUtil.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//===--- SemaUtil.h - Utility functions for semantic analysis -------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file provides a few static inline functions that are useful for
-// performing semantic analysis.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_SEMA_UTIL_H
-#define LLVM_CLANG_SEMA_UTIL_H
-
-#include "clang/AST/Expr.h"
-
-namespace clang {
-
-/// Utility method to determine if a CallExpr is a call to a builtin.
-static inline bool isCallBuiltin(CallExpr* cexp) {
- Expr* sub = cexp->getCallee()->IgnoreParenCasts();
-
- if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(sub))
- if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(E->getDecl()))
- if (Fn->getBuiltinID() > 0)
- return true;
-
- return false;
-}
-
-} // end namespace clang
-
-#endif
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index 9e558e93ac..707873feaf 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -85,3 +85,9 @@ void check_asterisk_precision_width(int x) {
printf("%*d","foo",x); // expected-warning {{field width should have type 'int', but argument has type 'char *'}}
printf("%.*d","foo",x); // expected-warning {{field precision should have type 'int', but argument has type 'char *'}}
}
+
+void __attribute__((format(printf,1,3))) myprintf(const char*, int blah, ...);
+
+void test_myprintf() {
+ myprintf("%d", 17, 18); // okay
+}