From 3c385e5f8d9008fff18597ca302be19fa86e51f6 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 14 Feb 2009 18:57:46 +0000 Subject: [PATCH] Add hook to add attributes to function declarations that we know about, whether they are builtins or not. Use this to add the appropriate "format" attribute to NSLog, NSLogv, asprintf, and vasprintf, and to translate builtin attributes (from Builtins.def) into actual attributes on the function declaration. Use the "printf" format attribute on function declarations to determine whether we should do format string checking, rather than looking at an ad hoc list of builtins and "known" function names. Be a bit more careful about when we consider a function a "builtin" in C++. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64561 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Attr.h | 1 + include/clang/AST/Decl.h | 2 +- include/clang/AST/Expr.h | 2 +- lib/AST/Decl.cpp | 36 ++++++++++++----- lib/AST/Expr.cpp | 8 ++-- lib/AST/ExprConstant.cpp | 7 ++-- lib/Analysis/GRExprEngine.cpp | 3 +- lib/CodeGen/CGExpr.cpp | 2 +- lib/CodeGen/CGExprConstant.cpp | 3 +- lib/Sema/Sema.cpp | 1 + lib/Sema/Sema.h | 10 +++-- lib/Sema/SemaChecking.cpp | 59 ++++++++++++--------------- lib/Sema/SemaDecl.cpp | 73 ++++++++++++++++++++++++++++++++-- lib/Sema/SemaExpr.cpp | 2 +- lib/Sema/SemaUtil.h | 36 ----------------- test/Sema/format-strings.c | 6 +++ 16 files changed, 152 insertions(+), 99 deletions(-) delete mode 100644 lib/Sema/SemaUtil.h 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(getDeclContext()) && - cast(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(getDeclContext()) && + cast(getDeclContext())->getLanguage() + == LinkageSpecDecl::lang_c && + !getAttr()) + 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(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(L)) { - if (unsigned id = cast(L).getDecl()->getBuiltinID()) + if (unsigned id + = cast(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(IcExpr->getSubExpr())) if (const FunctionDecl *FDecl = dyn_cast(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(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(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()) { + 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(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(E); return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg, - format_idx); + format_idx, firstDataArg); } case Stmt::ParenExprClass: { ParenExpr *Expr = dyn_cast(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(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(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(LeftExprSansParen)) - if (isCallBuiltin(CL)) + if (CL->isBuiltinCall(Context)) EmitWarning = false; if (EmitWarning) if (CallExpr* CR = dyn_cast(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()) { // 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(Init)->isBuiltinCall() == + if (cast(Init)->isBuiltinCall(Context) == Builtin::BI__builtin___CFStringMakeConstantString) return false; @@ -2071,7 +2072,7 @@ bool Sema::CheckArithmeticConstantExpression(const Expr* Init) { const CallExpr *CE = cast(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()) + FD->addAttr(new FormatAttr("printf", FormatIdx + 1, FormatIdx + 2)); + } + } + + IdentifierInfo *Name = FD->getIdentifier(); + if (!Name) + return; + if ((!getLangOptions().CPlusPlus && + FD->getDeclContext()->isTranslationUnit()) || + (isa(FD->getDeclContext()) && + cast(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()) { + // FIXME: We known better than our headers. + const_cast(Format)->setType("printf"); + } else + FD->addAttr(new FormatAttr("printf", 1, 2)); + break; + + case id_asprintf: + case id_vasprintf: + if (!FD->getAttr()) + 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(sub)) - if (FunctionDecl *Fn = dyn_cast(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 +} -- 2.40.0