aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Builtins.def23
-rw-r--r--include/clang/AST/Builtins.h21
-rw-r--r--include/clang/AST/Decl.h2
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.def8
-rw-r--r--lib/AST/Decl.cpp22
-rw-r--r--lib/AST/Expr.cpp2
-rw-r--r--lib/Analysis/GRExprEngine.cpp4
-rw-r--r--lib/CodeGen/CGBuiltin.cpp3
-rw-r--r--lib/CodeGen/CGExpr.cpp2
-rw-r--r--lib/CodeGen/CodeGenModule.cpp10
-rw-r--r--lib/Sema/Sema.h11
-rw-r--r--lib/Sema/SemaChecking.cpp2
-rw-r--r--lib/Sema/SemaDecl.cpp54
-rw-r--r--lib/Sema/SemaExpr.cpp8
-rw-r--r--lib/Sema/SemaLookup.cpp37
-rw-r--r--lib/Sema/SemaUtil.h5
-rw-r--r--test/Analysis/exercise-ps.c3
-rw-r--r--test/CodeGen/merge-attrs.c4
-rw-r--r--test/Sema/implicit-builtin-decl.c22
19 files changed, 191 insertions, 52 deletions
diff --git a/include/clang/AST/Builtins.def b/include/clang/AST/Builtins.def
index 7d8f27a236..e3c64bb0b8 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 @@ 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
diff --git a/include/clang/AST/Builtins.h b/include/clang/AST/Builtins.h
index c1771924ba..f1b63bc843 100644
--- a/include/clang/AST/Builtins.h
+++ b/include/clang/AST/Builtins.h
@@ -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 {
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index ac4b630f18..a4e30653b2 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -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;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def
index bf83fd3ff9..871d03762b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.def
+++ b/include/clang/Basic/DiagnosticSemaKinds.def
@@ -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")
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 04ee44a480..13b40e8afe 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -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();
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 7b06a3c1ce..e294f48029 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -192,7 +192,7 @@ unsigned CallExpr::isBuiltinCall() const {
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 c8861ac774..a52437c343 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -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.
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 9cd344fb7e..e14c9f01c6 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -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());
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 83fbd72f90..ddecbebded 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -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())
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 503cc2ace5..03de730f65 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -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);
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index a0fa0c7f3d..fdd4c304fb 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -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);
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index e52c730442..e058861283 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -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");
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 0dbd6d3804..d0997b03eb 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -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
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 6b82eadaea..cec771d4e5 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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.
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index f4bfe5ca3c..d1bb99acc5 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -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);
}
diff --git a/lib/Sema/SemaUtil.h b/lib/Sema/SemaUtil.h
index 35452b18e6..5c64c76e29 100644
--- a/lib/Sema/SemaUtil.h
+++ b/lib/Sema/SemaUtil.h
@@ -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;
}
diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c
index 4aaba8e8dd..217135ec06 100644
--- a/test/Analysis/exercise-ps.c
+++ b/test/Analysis/exercise-ps.c
@@ -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'}}
}
diff --git a/test/CodeGen/merge-attrs.c b/test/CodeGen/merge-attrs.c
index c3349d8e97..3c1d62aeca 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 0000000000..3faef0b719
--- /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 *)'}}
+}