[cfe-commits] r64561 - in /cfe/trunk: include/clang/AST/Attr.h include/clang/AST/Decl.h include/clang/AST/Expr.h lib/AST/Decl.cpp lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/Analysis/GRExprEngine.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprConstant.cpp lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaChecking.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaUtil.h test/Sema/format-strings.c

Douglas Gregor dgregor at apple.com
Sat Feb 14 10:57:47 PST 2009


Author: dgregor
Date: Sat Feb 14 12:57:46 2009
New Revision: 64561

URL: http://llvm.org/viewvc/llvm-project?rev=64561&view=rev
Log:
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++.


Removed:
    cfe/trunk/lib/Sema/SemaUtil.h
Modified:
    cfe/trunk/include/clang/AST/Attr.h
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/Analysis/GRExprEngine.cpp
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/Sema/format-strings.c

Modified: cfe/trunk/include/clang/AST/Attr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Attr.h?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Attr.h (original)
+++ cfe/trunk/include/clang/AST/Attr.h Sat Feb 14 12:57:46 2009
@@ -347,6 +347,7 @@
              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; }
 

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Sat Feb 14 12:57:46 2009
@@ -600,7 +600,7 @@
     PreviousDeclaration = PrevDecl;
   }
 
-  unsigned getBuiltinID() const;
+  unsigned getBuiltinID(ASTContext &Context) const;
 
   // Iterator access to formal parameters.
   unsigned param_size() const { return getNumParams(); }

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Sat Feb 14 12:57:46 2009
@@ -834,7 +834,7 @@
 
   /// 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; }
 

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Sat Feb 14 12:57:46 2009
@@ -259,15 +259,33 @@
 /// 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;
 }
 

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Sat Feb 14 12:57:46 2009
@@ -173,7 +173,7 @@
 
 /// 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 @@
   if (!FDecl->getIdentifier())
     return 0;
 
-  return FDecl->getBuiltinID();
+  return FDecl->getBuiltinID(Context);
 }
 
 
@@ -922,7 +922,7 @@
     
     // 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 @@
     // 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;

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sat Feb 14 12:57:46 2009
@@ -350,7 +350,8 @@
 }  
 
 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 @@
 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 @@
 }
 
 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:

Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Sat Feb 14 12:57:46 2009
@@ -1263,7 +1263,8 @@
 
     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.

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Sat Feb 14 12:57:46 2009
@@ -964,7 +964,7 @@
         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())

Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Sat Feb 14 12:57:46 2009
@@ -582,7 +582,8 @@
     }
     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);

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Sat Feb 14 12:57:46 2009
@@ -132,6 +132,7 @@
   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");
 

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sat Feb 14 12:57:46 2009
@@ -181,6 +181,7 @@
   // Enum values used by KnownFunctionIDs (see below).
   enum {
     id_NSLog,
+    id_NSLogv,
     id_asprintf,
     id_vasprintf,
     id_num_known_functions
@@ -883,6 +884,7 @@
                                  SourceLocation Loc);
   NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
                                       Scope *S);
+  void AddKnownFunctionAttributes(FunctionDecl *FD);
 
   // More parsing and symbol table subroutines.
 
@@ -1986,12 +1988,12 @@
   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);

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Sat Feb 14 12:57:46 2009
@@ -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 @@
   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 @@
   // 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 @@
 
 // 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 @@
       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 @@
 /// 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 @@
   // 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 @@
 }
 
 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 @@
   //  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 @@
   // 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.

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Feb 14 12:57:46 2009
@@ -340,7 +340,7 @@
     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 @@
   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 @@
   // 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 @@
   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 @@
     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 @@
 
   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) {

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sat Feb 14 12:57:46 2009
@@ -1921,7 +1921,7 @@
 
   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.

Removed: cfe/trunk/lib/Sema/SemaUtil.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaUtil.h?rev=64560&view=auto

==============================================================================
--- cfe/trunk/lib/Sema/SemaUtil.h (original)
+++ cfe/trunk/lib/Sema/SemaUtil.h (removed)
@@ -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

Modified: cfe/trunk/test/Sema/format-strings.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings.c?rev=64561&r1=64560&r2=64561&view=diff

==============================================================================
--- cfe/trunk/test/Sema/format-strings.c (original)
+++ cfe/trunk/test/Sema/format-strings.c Sat Feb 14 12:57:46 2009
@@ -85,3 +85,9 @@
   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
+}





More information about the cfe-commits mailing list