]> granicus.if.org Git - clang/commitdiff
Implicitly declare certain C library functions (malloc, strcpy, memmove,
authorDouglas Gregor <dgregor@apple.com>
Fri, 13 Feb 2009 23:20:09 +0000 (23:20 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 13 Feb 2009 23:20:09 +0000 (23:20 +0000)
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

19 files changed:
include/clang/AST/Builtins.def
include/clang/AST/Builtins.h
include/clang/AST/Decl.h
include/clang/Basic/DiagnosticSemaKinds.def
lib/AST/Decl.cpp
lib/AST/Expr.cpp
lib/Analysis/GRExprEngine.cpp
lib/CodeGen/CGBuiltin.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CodeGenModule.cpp
lib/Sema/Sema.h
lib/Sema/SemaChecking.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaUtil.h
test/Analysis/exercise-ps.c
test/CodeGen/merge-attrs.c
test/Sema/implicit-builtin-decl.c [new file with mode: 0644]

index 7d8f27a23687eb5eaac2c83f49d7751e4024f444..e3c64bb0b8a01346215f7962bdee0c600976dbd9 100644 (file)
 //  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 @@ BUILTIN(__sync_val_compare_and_swap,"ii*ii", "n")
 // 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
index c1771924ba35a5019fe323814810ddff9bd465f0..f1b63bc8437c29f0c556f4de9dd8b0b61c01fa19 100644 (file)
@@ -78,6 +78,27 @@ public:
     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 {
index ac4b630f1849f87c490b14880dd30437219e354d..a4e30653b2c2128971ff2553c1181cf321490134 100644 (file)
@@ -600,6 +600,8 @@ public:
     PreviousDeclaration = PrevDecl;
   }
 
+  unsigned getBuiltinID() const;
+
   // Iterator access to formal parameters.
   unsigned param_size() const { return getNumParams(); }
   typedef ParmVarDecl **param_iterator;
index bf83fd3ff9b216059c1cbc69c22d1a8ba83fc5d8..871d03762bd83f1d67eff5c143b9275959097957 100644 (file)
@@ -84,6 +84,14 @@ DIAG(err_declarator_need_ident, ERROR,
 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")
index 04ee44a480a86c5826d233a0ab78e2fc3db1ecb7..13b40e8afe2732c7adae111d807aadc39e73a916 100644 (file)
@@ -250,6 +250,28 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
   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();
index 7b06a3c1ce693ee4fd36e91b4a11cf66a7ce0793..e294f480299d8523ecf7b1319fd8f4514a303272 100644 (file)
@@ -192,7 +192,7 @@ unsigned CallExpr::isBuiltinCall() const {
   if (!FDecl->getIdentifier())
     return 0;
 
-  return FDecl->getIdentifier()->getBuiltinID();
+  return FDecl->getBuiltinID();
 }
 
 
index c8861ac774a52c84f46cf37f165f97ddf7f8f1ef..a52437c343ebab2ec557275f662080a6cce3999a 100644 (file)
@@ -1269,9 +1269,7 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred,
 
     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.
index 9cd344fb7e2b85693a270b7fda01f8ba78436865..e14c9f01c611230d9b0bdb19197eb9a3d4673bf8 100644 (file)
@@ -327,7 +327,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
   
   // 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());
index 83fbd72f9090588315ebbdb64c9924482eae236b..ddecbebded1599c5d6f03e7e73ec09f414d1e809 100644 (file)
@@ -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->getIdentifier()->getBuiltinID())
+        if (unsigned builtinID = FDecl->getBuiltinID())
           return EmitBuiltinExpr(builtinID, E);
 
   if (E->getCallee()->getType()->isBlockPointerType())
index 503cc2ace56ef31255b437c1cd01465dd4370e0d..03de730f655f0776fdce8918f5f77a6c19bfdffb 100644 (file)
@@ -842,10 +842,14 @@ llvm::Function *CodeGenModule::getBuiltinLibFunction(unsigned BuiltinID) {
   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);
index a0fa0c7f3dab512be6d9814867f8dcdbee84ccdc..fdd4c304fb259a39952350b4a8b6e79fb9dc1c36 100644 (file)
@@ -864,14 +864,18 @@ public:
 
   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 @@ public:
   
   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);
 
index e52c73044232747742ecea6341a859424257c055..e058861283f69171ef95c6b57d661a00ebbd2470 100644 (file)
@@ -34,7 +34,7 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
   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");
index 0dbd6d3804e1ec7da7e38b5f1f812aef96a5198b..d0997b03ebe0096b516304cf1ba3e652c2b19875 100644 (file)
@@ -45,7 +45,8 @@ using namespace clang;
 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 @@ void Sema::InitBuiltinVaListType() {
   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 @@ Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, bool &Redeclaration) {
   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 @@ Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, bool &Redeclaration) {
       = 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 @@ Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, bool &Redeclaration) {
       //       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 @@ Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, bool &Redeclaration) {
           NewDiag = diag::err_member_redeclared;
 
         Diag(New->getLocation(), NewDiag);
-        Diag(Old->getLocation(), PrevDiag);
+        Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
       }
     }
 
@@ -577,7 +598,7 @@ Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, bool &Redeclaration) {
   // 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 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
   // 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
index 6b82eadaea2cff7ffdf01d24b30379d50e921cc4..cec771d4e5145e051a06db59e2cf770fd358efce 100644 (file)
@@ -547,7 +547,8 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
   // 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 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
   }
 
   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.
index f4bfe5ca3c8ccb332ed210344e166317dfe2401f..d1bb99acc520d476410a9b6b1c5a77cf2de2aa75 100644 (file)
@@ -728,21 +728,17 @@ Sema::CppLookupName(Scope *S, DeclarationName Name,
 ///
 /// @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 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind,
   // 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 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
 /// @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 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS,
                                  Name, NameKind, RedeclarationOnly);
   }
 
-  return LookupName(S, Name, NameKind, RedeclarationOnly);
+  return LookupName(S, Name, NameKind, RedeclarationOnly, 
+                    AllowBuiltinCreation, Loc);
 }
 
 
index 35452b18e6f145953d264925e0e3c0882c71687f..5c64c76e2956bb803f208b7aa4ff9215d5a3f3f4 100644 (file)
@@ -24,8 +24,9 @@ static inline bool isCallBuiltin(CallExpr* cexp) {
   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;
 }
index 4aaba8e8dd053c2c97bc6998491cdfccf937085a..217135ec06e2787dc88ff4d564431ead5dec04bb 100644 (file)
@@ -20,5 +20,6 @@ void_typedef f2_helper();
 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'}}
 }
index c3349d8e97b7b05839a32a96e8a2b8633281a10e..3c1d62aeca3c36a56fc476f197a45325e82a884d 100644 (file)
@@ -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 (file)
index 0000000..3faef0b
--- /dev/null
@@ -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 *)'}}
+}