diff options
-rw-r--r-- | include/clang/AST/Builtins.def | 23 | ||||
-rw-r--r-- | include/clang/AST/Builtins.h | 21 | ||||
-rw-r--r-- | include/clang/AST/Decl.h | 2 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.def | 8 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 22 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 2 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGBuiltin.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 11 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 54 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 37 | ||||
-rw-r--r-- | lib/Sema/SemaUtil.h | 5 | ||||
-rw-r--r-- | test/Analysis/exercise-ps.c | 3 | ||||
-rw-r--r-- | test/CodeGen/merge-attrs.c | 4 | ||||
-rw-r--r-- | test/Sema/implicit-builtin-decl.c | 22 |
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 *)'}} +} |