Implicitly declare certain C library functions (malloc, strcpy, memmove,
etc.) when we perform name lookup on them. This ensures that we
produce the correct signature for these functions, which has two
practical impacts:

  1) When we're supporting the "implicit function declaration" feature
  of C99, these functions will be implicitly declared with the right
  signature rather than as a function returning "int" with no
  prototype. See PR3541 for the reason why this is important (hint:
  GCC always predeclares these functions).
 
  2) If users attempt to redeclare one of these library functions with
  an incompatible signature, we produce a hard error.

This patch does a little bit of work to give reasonable error
messages. For example, when we hit case #1 we complain that we're
implicitly declaring this function with a specific signature, and then
we give a note that asks the user to include the appropriate header
(e.g., "please include <stdlib.h> or explicitly declare 'malloc'"). In
case #2, we show the type of the implicit builtin that was incorrectly
declared, so the user can see the problem. We could do better here:
for example, when displaying this latter error message we say
something like:

  'strcpy' was implicitly declared here with type 'char *(char *, char
  const *)'

but we should really print out a fake code line showing the
declaration, like this:

  'strcpy' was implicitly declared here as:

    char *strcpy(char *, char const *)

This would also be good for printing built-in candidates with C++
operator overloading.

The set of C library functions supported by this patch includes all
functions from the C99 specification's <stdlib.h> and <string.h> that
(a) are predefined by GCC and (b) have signatures that could cause
codegen issues if they are treated as functions with no prototype
returning and int. Future work could extend this set of functions to
other C library functions that we know about.




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64504 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Builtins.def b/include/clang/AST/Builtins.def
index 7d8f27a..e3c64bb 100644
--- a/include/clang/AST/Builtins.def
+++ b/include/clang/AST/Builtins.def
@@ -54,6 +54,10 @@
 //  n -> nothrow
 //  c -> const
 //  F -> this is a libc/libm function with a '__builtin_' prefix added.
+//  f -> this is a libc/libm function without the '__builtin_' prefix. It can
+//       be followed by ':headername' to state which header this function
+//       comes from, but only if 'f:headername' is the last part of the
+//       string.
 //  FIXME: gcc has nonnull
 
 // Standard libc/libm functions:
@@ -172,4 +176,23 @@
 // LLVM instruction builtin
 BUILTIN(__builtin_llvm_memory_barrier,"vbbbbb", "n")
 
+// Builtin library functions
+BUILTIN(alloca, "v*z", "f:stdlib.h")
+BUILTIN(calloc, "v*zz", "f:stdlib.h")
+BUILTIN(malloc, "v*z", "f:stdlib.h")
+BUILTIN(memcpy, "v*v*vC*z", "f:string.h")
+BUILTIN(memmove, "v*v*vC*z", "f:string.h")
+BUILTIN(memset, "v*v*iz", "f:string.h")
+BUILTIN(strcat, "c*c*cC*", "f:string.h")
+BUILTIN(strchr, "c*cC*i", "f:string.h")
+BUILTIN(strcpy, "c*c*cC*", "f:string.h")
+BUILTIN(strcspn, "zcC*cC*", "f:string.h")
+BUILTIN(strlen, "zcC*", "f:string.h")
+BUILTIN(strncat, "c*c*cC*z", "f:string.h")
+BUILTIN(strncpy, "c*c*cC*z", "f:string.h")
+BUILTIN(strpbrk, "c*cC*cC*", "f:string.h")
+BUILTIN(strrchr, "c*cC*i", "f:string.h")
+BUILTIN(strspn, "zcC*cC*", "f:string.h")
+BUILTIN(strstr, "c*cC*cC*", "f:string.h")
+
 #undef BUILTIN
diff --git a/include/clang/AST/Builtins.h b/include/clang/AST/Builtins.h
index c177192..f1b63bc 100644
--- a/include/clang/AST/Builtins.h
+++ b/include/clang/AST/Builtins.h
@@ -78,6 +78,27 @@
     return strchr(GetRecord(ID).Attributes, 'F') != 0;
   }
   
+  /// \brief Determines whether this builtin is a predefined libc/libm
+  /// function, such as "malloc", where we know the signature a
+  /// priori.
+  bool isPredefinedLibFunction(unsigned ID) const {
+    return strchr(GetRecord(ID).Attributes, 'f') != 0;
+  }
+
+  /// \brief If this is a library function that comes from a specific
+  /// header, retrieve that header name.
+  const char *getHeaderName(unsigned ID) const {
+    char *Name = strchr(GetRecord(ID).Attributes, 'f');
+    if (!Name)
+      return 0;
+    ++Name;
+
+    if (*Name != ':')
+      return 0;
+
+    return ++Name;
+  }
+
   /// hasVAListUse - Return true of the specified builtin uses __builtin_va_list
   /// as an operand or return type.
   bool hasVAListUse(unsigned ID) const {
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index ac4b630..a4e3065 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -600,6 +600,8 @@
     PreviousDeclaration = PrevDecl;
   }
 
+  unsigned getBuiltinID() const;
+
   // Iterator access to formal parameters.
   unsigned param_size() const { return getNumParams(); }
   typedef ParmVarDecl **param_iterator;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def
index bf83fd3..871d037 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.def
+++ b/include/clang/Basic/DiagnosticSemaKinds.def
@@ -84,6 +84,14 @@
 DIAG(err_bad_language, ERROR,
      "unknown linkage language")
 
+/// Built-in functions.
+DIAG(ext_implicit_lib_function_decl, EXTWARN,
+     "implicitly declaring C library function '%0' with type %1")
+DIAG(note_please_include_header, NOTE,
+     "please include the header <%0> or explicitly provide a declaration for '%1'")
+DIAG(note_previous_builtin_declaration, NOTE,
+     "%0 was implicitly declared here with type %1")
+
 /// parser diagnostics
 DIAG(ext_typedef_without_a_name, EXTWARN,
      "typedef requires a name")
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 04ee44a..13b40e8 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -250,6 +250,28 @@
   return 0;
 }
 
+/// \brief Returns a value indicating whether this function
+/// corresponds to a builtin function.
+///
+/// The function corresponds to a built-in function if it is
+/// declared at translation scope or within an extern "C" block and
+/// its name matches with the name of a builtin. The returned value
+/// 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.
+  return 0;
+}
+
+
 // Helper function for FunctionDecl::getNumParams and FunctionDecl::setParams()
 static unsigned getNumTypeParams(QualType T) {
   const FunctionType *FT = T->getAsFunctionType();
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 7b06a3c..e294f48 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -192,7 +192,7 @@
   if (!FDecl->getIdentifier())
     return 0;
 
-  return FDecl->getIdentifier()->getBuiltinID();
+  return FDecl->getBuiltinID();
 }
 
 
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index c8861ac..a52437c 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -1269,9 +1269,7 @@
 
     if (isa<loc::FuncVal>(L)) {
       
-      IdentifierInfo* Info = cast<loc::FuncVal>(L).getDecl()->getIdentifier();
-      
-      if (unsigned id = Info->getBuiltinID())
+      if (unsigned id = cast<loc::FuncVal>(L).getDecl()->getBuiltinID())
         switch (id) {
           case Builtin::BI__builtin_expect: {
             // For __builtin_expect, just return the value of the subexpression.
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 9cd344f..e14c9f0 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -327,7 +327,8 @@
   
   // If this is an alias for a libm function (e.g. __builtin_sin) turn it into
   // that function.
-  if (getContext().BuiltinInfo.isLibFunction(BuiltinID))
+  if (getContext().BuiltinInfo.isLibFunction(BuiltinID) ||
+      getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
     return EmitCallExpr(CGM.getBuiltinLibFunction(BuiltinID), 
                         E->getCallee()->getType(), E->arg_begin(),
                         E->arg_end());
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 83fbd72..ddecbeb 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -964,7 +964,7 @@
         dyn_cast<const DeclRefExpr>(IcExpr->getSubExpr()))
       if (const FunctionDecl *FDecl = 
           dyn_cast<const FunctionDecl>(DRExpr->getDecl()))
-        if (unsigned builtinID = FDecl->getIdentifier()->getBuiltinID())
+        if (unsigned builtinID = FDecl->getBuiltinID())
           return EmitBuiltinExpr(builtinID, E);
 
   if (E->getCallee()->getType()->isBlockPointerType())
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 503cc2a..03de730 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -842,10 +842,14 @@
   if (FunctionSlot)
     return FunctionSlot;
   
-  assert(Context.BuiltinInfo.isLibFunction(BuiltinID) && "isn't a lib fn");
+  assert((Context.BuiltinInfo.isLibFunction(BuiltinID) ||
+          Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) && 
+         "isn't a lib fn");
   
-  // Get the name, skip over the __builtin_ prefix.
-  const char *Name = Context.BuiltinInfo.GetName(BuiltinID)+10;
+  // Get the name, skip over the __builtin_ prefix (if necessary).
+  const char *Name = Context.BuiltinInfo.GetName(BuiltinID);
+  if (Context.BuiltinInfo.isLibFunction(BuiltinID))
+    Name += 10;
   
   // Get the type for the builtin.
   QualType Type = Context.BuiltinInfo.GetBuiltinType(BuiltinID, Context);
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index a0fa0c7..fdd4c30 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -864,14 +864,18 @@
 
   LookupResult LookupName(Scope *S, DeclarationName Name, 
                           LookupNameKind NameKind, 
-                          bool RedeclarationOnly = false);
+                          bool RedeclarationOnly = false,
+                          bool AllowBuiltinCreation = true,
+                          SourceLocation Loc = SourceLocation());
   LookupResult LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
                                    LookupNameKind NameKind, 
                                    bool RedeclarationOnly = false);
   LookupResult LookupParsedName(Scope *S, const CXXScopeSpec *SS, 
                                 DeclarationName Name,
                                 LookupNameKind NameKind, 
-                                bool RedeclarationOnly = false);
+                                bool RedeclarationOnly = false,
+                                bool AllowBuiltinCreation = true,
+                                SourceLocation Loc = SourceLocation());
   
   typedef llvm::SmallPtrSet<NamespaceDecl *, 16> AssociatedNamespaceSet;
   typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
@@ -887,7 +891,8 @@
   
   ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
   NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, 
-                                 Scope *S);
+                                 Scope *S, bool ForRedeclaration,
+                                 SourceLocation Loc);
   NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
                                       Scope *S);
 
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index e52c730..e058861 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -34,7 +34,7 @@
   if (!FnInfo)
     return move(TheCallResult);
 
-  switch (FnInfo->getBuiltinID()) {
+  switch (FDecl->getBuiltinID()) {
   case Builtin::BI__builtin___CFStringMakeConstantString:
     assert(TheCall->getNumArgs() == 1 &&
            "Wrong # arguments to builtin CFStringMakeConstantString");
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 0dbd6d3..d0997b0 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -45,7 +45,8 @@
 Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
                                 Scope *S, const CXXScopeSpec *SS) {
   Decl *IIDecl = 0;
-  LookupResult Result = LookupParsedName(S, SS, &II, LookupOrdinaryName, false);
+  LookupResult Result = LookupParsedName(S, SS, &II, LookupOrdinaryName, 
+                                         false, false);
   switch (Result.getKind()) {
     case LookupResult::NotFound:
     case LookupResult::FoundOverloaded:
@@ -285,21 +286,38 @@
   Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef));
 }
 
-/// LazilyCreateBuiltin - The specified Builtin-ID was first used at file scope.
-/// lazily create a decl for it.
+/// LazilyCreateBuiltin - The specified Builtin-ID was first used at
+/// file scope.  lazily create a decl for it. ForRedeclaration is true
+/// if we're creating this built-in in anticipation of redeclaring the
+/// built-in.
 NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
-                                     Scope *S) {
+                                     Scope *S, bool ForRedeclaration,
+                                     SourceLocation Loc) {
   Builtin::ID BID = (Builtin::ID)bid;
 
   if (Context.BuiltinInfo.hasVAListUse(BID))
     InitBuiltinVaListType();
-    
+
   QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context);  
+
+  if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
+    Diag(Loc, diag::ext_implicit_lib_function_decl)
+      << Context.BuiltinInfo.GetName(BID)
+      << R;
+    if (Context.BuiltinInfo.getHeaderName(BID) &&
+        Diags.getDiagnosticMapping(diag::ext_implicit_lib_function_decl)
+          != diag::MAP_IGNORE)
+      Diag(Loc, diag::note_please_include_header)
+        << Context.BuiltinInfo.getHeaderName(BID)
+        << Context.BuiltinInfo.GetName(BID);
+  }
+
   FunctionDecl *New = FunctionDecl::Create(Context,
                                            Context.getTranslationUnitDecl(),
-                                           SourceLocation(), II, R,
+                                           Loc, II, R,
                                            FunctionDecl::Extern, false);
-  
+  New->setImplicit();
+
   // Create Decl objects for each parameter, adding them to the
   // FunctionDecl.
   if (FunctionTypeProto *FT = dyn_cast<FunctionTypeProto>(R)) {
@@ -491,9 +509,12 @@
   diag::kind PrevDiag;
   if (Old->isThisDeclarationADefinition())
     PrevDiag = diag::note_previous_definition;
-  else if (Old->isImplicit())
-    PrevDiag = diag::note_previous_implicit_declaration;
-  else 
+  else if (Old->isImplicit()) {
+    if (Old->getBuiltinID())
+      PrevDiag = diag::note_previous_builtin_declaration;
+    else
+      PrevDiag = diag::note_previous_implicit_declaration;
+  } else 
     PrevDiag = diag::note_previous_declaration;
   
   QualType OldQType = Context.getCanonicalType(Old->getType());
@@ -510,7 +531,7 @@
       = cast<FunctionType>(NewQType.getTypePtr())->getResultType();
     if (OldReturnType != NewReturnType) {
       Diag(New->getLocation(), diag::err_ovl_diff_return_type);
-      Diag(Old->getLocation(), PrevDiag);
+      Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
       Redeclaration = true;
       return New;
     }
@@ -523,7 +544,7 @@
       //       is a static member function declaration.
       if (OldMethod->isStatic() || NewMethod->isStatic()) {
         Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member);
-        Diag(Old->getLocation(), PrevDiag);
+        Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
         return New;
       }
 
@@ -544,7 +565,7 @@
           NewDiag = diag::err_member_redeclared;
 
         Diag(New->getLocation(), NewDiag);
-        Diag(Old->getLocation(), PrevDiag);
+        Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
       }
     }
 
@@ -577,7 +598,7 @@
   // TODO: This is totally simplistic.  It should handle merging functions
   // together etc, merging extern int X; int X; ...
   Diag(New->getLocation(), diag::err_conflicting_types) << New->getDeclName();
-  Diag(Old->getLocation(), PrevDiag);
+  Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
   return New;
 }
 
@@ -1217,10 +1238,11 @@
   // See if this is a redefinition of a variable in the same scope.
   if (!D.getCXXScopeSpec().isSet() && !D.getCXXScopeSpec().isInvalid()) {
     DC = CurContext;
-    PrevDecl = LookupName(S, Name, LookupOrdinaryName);
+    PrevDecl = LookupName(S, Name, LookupOrdinaryName, true, true,
+                          D.getIdentifierLoc());
   } else { // Something like "int foo::x;"
     DC = static_cast<DeclContext*>(D.getCXXScopeSpec().getScopeRep());
-    PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName);
+    PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
 
     // C++ 7.3.1.2p2:
     // Members (including explicit specializations of templates) of a named
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 6b82ead..cec771d 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -547,7 +547,8 @@
   // Could be enum-constant, value decl, instance variable, etc.
   if (SS && SS->isInvalid())
     return ExprError();
-  LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName);
+  LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName,
+                                         false, true, Loc);
 
   if (getLangOptions().CPlusPlus && (!SS || !SS->isSet()) && 
       HasTrailingLParen && Lookup.getKind() == LookupResult::NotFound) {
@@ -1922,9 +1923,8 @@
   }
 
   if (Ovl || (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
-    // We don't perform ADL for builtins.
-    if (FDecl && FDecl->getIdentifier() && 
-        FDecl->getIdentifier()->getBuiltinID())
+    // We don't perform ADL for implicit declarations of builtins.
+    if (FDecl && FDecl->getBuiltinID() && FDecl->isImplicit())
       ADL = false;
 
     // We don't perform ADL in C.
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index f4bfe5c..d1bb99a 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -728,21 +728,17 @@
 ///
 /// @param Name     The name of the entity that we are searching for.
 ///
-/// @param Criteria The criteria that this routine will use to
-/// determine which names are visible and which names will be
-/// found. Note that name lookup will find a name that is visible by
-/// the given criteria, but the entity itself may not be semantically
-/// correct or even the kind of entity expected based on the
-/// lookup. For example, searching for a nested-name-specifier name
-/// might result in an EnumDecl, which is visible but is not permitted
-/// as a nested-name-specifier in C++03.
+/// @param Loc      If provided, the source location where we're performing
+/// name lookup. At present, this is only used to produce diagnostics when 
+/// C library functions (like "malloc") are implicitly declared.
 ///
 /// @returns The result of name lookup, which includes zero or more
 /// declarations and possibly additional information used to diagnose
 /// ambiguities.
 Sema::LookupResult 
 Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
-                 bool RedeclarationOnly) {
+                 bool RedeclarationOnly, bool AllowBuiltinCreation,
+                 SourceLocation Loc) {
   if (!Name) return LookupResult::CreateLookupResult(Context, 0);
 
   if (!getLangOptions().CPlusPlus) {
@@ -812,12 +808,19 @@
   // now, injecting it into translation unit scope, and return it.
   if (NameKind == LookupOrdinaryName) {
     IdentifierInfo *II = Name.getAsIdentifierInfo();
-    if (II) {
+    if (II && AllowBuiltinCreation) {
       // If this is a builtin on this (or all) targets, create the decl.
-      if (unsigned BuiltinID = II->getBuiltinID())
+      if (unsigned BuiltinID = II->getBuiltinID()) {
+        // In C++, we don't have any predefined library functions like
+        // 'malloc'. Instead, we'll just error.
+        if (getLangOptions().CPlusPlus && 
+            Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+          return LookupResult::CreateLookupResult(Context, 0);
+
         return LookupResult::CreateLookupResult(Context,
                             LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
-                                                S));
+                                                S, RedeclarationOnly, Loc));
+      }
     }
     if (getLangOptions().ObjC1 && II) {
       // @interface and @compatibility_alias introduce typedef-like names.
@@ -995,11 +998,16 @@
 /// @param Name     The name of the entity that name lookup will
 /// search for.
 ///
+/// @param Loc      If provided, the source location where we're performing
+/// name lookup. At present, this is only used to produce diagnostics when 
+/// C library functions (like "malloc") are implicitly declared.
+///
 /// @returns The result of qualified or unqualified name lookup.
 Sema::LookupResult
 Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS, 
                        DeclarationName Name, LookupNameKind NameKind,
-                       bool RedeclarationOnly) {
+                       bool RedeclarationOnly, bool AllowBuiltinCreation,
+                       SourceLocation Loc) {
   if (SS) {
     if (SS->isInvalid())
       return LookupResult::CreateLookupResult(Context, 0);
@@ -1009,7 +1017,8 @@
                                  Name, NameKind, RedeclarationOnly);
   }
 
-  return LookupName(S, Name, NameKind, RedeclarationOnly);
+  return LookupName(S, Name, NameKind, RedeclarationOnly, 
+                    AllowBuiltinCreation, Loc);
 }
 
 
diff --git a/lib/Sema/SemaUtil.h b/lib/Sema/SemaUtil.h
index 35452b1..5c64c76 100644
--- a/lib/Sema/SemaUtil.h
+++ b/lib/Sema/SemaUtil.h
@@ -24,8 +24,9 @@
   Expr* sub = cexp->getCallee()->IgnoreParenCasts();
   
   if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(sub))
-    if (E->getDecl()->getIdentifier()->getBuiltinID() > 0)
-      return true;
+    if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(E->getDecl()))
+      if (Fn->getBuiltinID() > 0)
+        return true;
   
   return false;
 }
diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c
index 4aaba8e..217135e 100644
--- a/test/Analysis/exercise-ps.c
+++ b/test/Analysis/exercise-ps.c
@@ -20,5 +20,6 @@
 static void f2(void *buf) {
   F12_typedef* x;
   x = f2_helper();
-  memcpy((&x[1]), (buf), 1);
+  memcpy((&x[1]), (buf), 1); // expected-warning{{implicitly declaring C library function 'memcpy' with type 'void *(void *, void const *}} \
+  // expected-note{{please include the header <string.h> or explicitly provide a declaration for 'memcpy'}}
 }
diff --git a/test/CodeGen/merge-attrs.c b/test/CodeGen/merge-attrs.c
index c3349d8..3c1d62a 100644
--- a/test/CodeGen/merge-attrs.c
+++ b/test/CodeGen/merge-attrs.c
@@ -1,12 +1,12 @@
 // RUN: clang %s -emit-llvm -o %t
 
-void *malloc(int size) __attribute__ ((__nothrow__));
+void *malloc(__SIZE_TYPE__ size) __attribute__ ((__nothrow__));
 
 inline static void __zend_malloc() {
     malloc(1);
 }
 
-void *malloc(int size) __attribute__ ((__nothrow__));
+void *malloc(__SIZE_TYPE__ size) __attribute__ ((__nothrow__));
 
 void fontFetch() {
     __zend_malloc(1);
diff --git a/test/Sema/implicit-builtin-decl.c b/test/Sema/implicit-builtin-decl.c
new file mode 100644
index 0000000..3faef0b
--- /dev/null
+++ b/test/Sema/implicit-builtin-decl.c
@@ -0,0 +1,22 @@
+// RUN: clang -fsyntax-only -verify %s
+void f() {
+  int *ptr = malloc(sizeof(int) * 10); // expected-warning{{implicitly declaring C library function 'malloc' with type}} \
+  // expected-note{{please include the header <stdlib.h> or explicitly provide a declaration for 'malloc'}} \
+  // expected-note{{'malloc' was implicitly declared here with type 'void *}}
+}
+
+void *alloca(__SIZE_TYPE__); // redeclaration okay
+
+int *calloc(__SIZE_TYPE__, __SIZE_TYPE__); // expected-error{{conflicting types for 'calloc'}} \
+                    // expected-note{{'calloc' was implicitly declared here with type 'void *}}
+
+
+void g(int malloc) { // okay: these aren't functions
+  int calloc = 1;
+}
+
+void h() {
+  int malloc(int); // expected-error{{conflicting types for 'malloc'}}
+  int strcpy(int); // expected-error{{conflicting types for 'strcpy'}} \
+  // expected-note{{'strcpy' was implicitly declared here with type 'char *(char *, char const *)'}}
+}