aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-02-14 18:57:46 +0000
committerDouglas Gregor <dgregor@apple.com>2009-02-14 18:57:46 +0000
commit3c385e5f8d9008fff18597ca302be19fa86e51f6 (patch)
tree8daddebd1007dcd0f23f8a442032c584da996663 /lib/Sema
parentff975cfab9ada27df86038286d1678084aeb3428 (diff)
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
Diffstat (limited to 'lib/Sema')
-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
6 files changed, 103 insertions, 78 deletions
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