From 370ab3f1373841d70582feac9e35c3c6b3489f63 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 14 Feb 2009 01:52:53 +0000 Subject: [PATCH] Make it possible for builtins to expression FILE* arguments, so that we can define builtins such as fprintf, vfprintf, and __builtin___fprintf_chk. Give a nice error message when we need to implicitly declare a function like fprintf. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64526 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Builtins.def | 13 +++++---- include/clang/AST/Builtins.h | 7 ++++- include/clang/Basic/DiagnosticSemaKinds.def | 2 ++ lib/AST/Builtins.cpp | 31 +++++++++++++++++---- lib/CodeGen/CodeGenModule.cpp | 5 +++- lib/Sema/Sema.cpp | 2 -- lib/Sema/Sema.h | 2 -- lib/Sema/SemaChecking.cpp | 6 ++-- lib/Sema/SemaDecl.cpp | 14 +++++++++- test/Sema/implicit-builtin-decl.c | 4 +++ 10 files changed, 63 insertions(+), 23 deletions(-) diff --git a/include/clang/AST/Builtins.def b/include/clang/AST/Builtins.def index 5e009d27aa..3cfe2d340f 100644 --- a/include/clang/AST/Builtins.def +++ b/include/clang/AST/Builtins.def @@ -35,6 +35,7 @@ // a -> __builtin_va_list // A -> "reference" to __builtin_va_list // V -> Vector, following num elements and a base type. +// P -> FILE // . -> "...". This may only occur at the end of the function list. // // Types maybe prefixed with the following modifiers: @@ -151,10 +152,10 @@ BUILTIN(__builtin___snprintf_chk, "ic*zizcC*.", "Fp:4:") BUILTIN(__builtin___sprintf_chk, "ic*izcC*.", "Fp:3:") BUILTIN(__builtin___vsnprintf_chk, "ic*zizcC*a", "FP:4:") BUILTIN(__builtin___vsprintf_chk, "ic*izcC*a", "FP:3:") -//BUILTIN(__builtin___fprintf_chk, "i(FIXME:FILEPTR)icC*.", "F") // FIXME: format printf attribute -BUILTIN(__builtin___printf_chk, "iicC*.", "F") // FIXME: format printf attribute -//BUILTIN(__builtin___vfprintf_chk, "i(FIXME:FILEPTR)icC*a", "F") // FIXME: format printf attribute -BUILTIN(__builtin___vprintf_chk, "iicC*a", "F") // FIXME: format printf attribute +BUILTIN(__builtin___fprintf_chk, "iP*icC*.", "Fp:2:") +BUILTIN(__builtin___printf_chk, "iicC*.", "Fp:1:") +BUILTIN(__builtin___vfprintf_chk, "iP*icC*a", "FP:2:") +BUILTIN(__builtin___vprintf_chk, "iicC*a", "FP:1:") BUILTIN(__builtin_expect, "iii" , "nc") BUILTIN(__builtin_prefetch, "vCv*.", "nc") @@ -199,11 +200,11 @@ BUILTIN(strrchr, "c*cC*i", "f:string.h:") BUILTIN(strspn, "zcC*cC*", "f:string.h:") BUILTIN(strstr, "c*cC*cC*", "f:string.h:") BUILTIN(printf, "icC*.", "f:stdio.h:p:0:") -//BUILTIN(fprintf, "icC*.", "f:stdio.h:p:1:") +BUILTIN(fprintf, "iP*cC*.", "f:stdio.h:p:1:") BUILTIN(snprintf, "ic*zcC*.", "f:stdio.h:p:2:") BUILTIN(sprintf, "ic*cC*.", "f:stdio.h:p:1:") BUILTIN(vprintf, "icC*a", "f:stdio.h:P:0:") -//BUILTIN(vfprintf, "icC*a", "f:stdio.h:P:1:") +BUILTIN(vfprintf, "iP*cC*a", "f:stdio.h:P:1:") BUILTIN(vsnprintf, "ic*zcC*a", "f:stdio.h:P:2:") BUILTIN(vsprintf, "ic*cC*a", "f:stdio.h:P:1:") diff --git a/include/clang/AST/Builtins.h b/include/clang/AST/Builtins.h index 045e2ecf1b..6fbd16624a 100644 --- a/include/clang/AST/Builtins.h +++ b/include/clang/AST/Builtins.h @@ -102,7 +102,12 @@ public: } /// GetBuiltinType - Return the type for the specified builtin. - QualType GetBuiltinType(unsigned ID, ASTContext &Context) const; + enum GetBuiltinTypeError { + GE_None, //< No error + GE_Missing_FILE //< Missing the FILE type from + }; + QualType GetBuiltinType(unsigned ID, ASTContext &Context, + GetBuiltinTypeError &Error) const; private: const Info &GetRecord(unsigned ID) const; }; diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 871d03762b..d109539d0e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -91,6 +91,8 @@ 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") +DIAG(err_implicit_decl_requires_stdio, ERROR, + "implicit declaration of '%0' requires inclusion of the header ") /// parser diagnostics DIAG(ext_typedef_without_a_name, EXTWARN, diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index e7ec1372a8..e345898b79 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -87,6 +87,7 @@ Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, /// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the /// pointer over the consumed characters. This returns the resultant type. static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, + Builtin::Context::GetBuiltinTypeError &Error, bool AllowTypeModifiers = true) { // Modifiers. bool Long = false, LongLong = false, Signed = false, Unsigned = false; @@ -202,10 +203,23 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, Str = End; - QualType ElementType = DecodeTypeFromStr(Str, Context, false); + QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); Type = Context.getVectorType(ElementType, NumElements); break; } + case 'P': { + IdentifierInfo *II = &Context.Idents.get("FILE"); + DeclContext::lookup_result Lookup + = Context.getTranslationUnitDecl()->lookup(II); + if (Lookup.first != Lookup.second && isa(*Lookup.first)) { + Type = Context.getTypeDeclType(cast(*Lookup.first)); + break; + } + else { + Error = Builtin::Context::GE_Missing_FILE; + return QualType(); + } + } } if (!AllowTypeModifiers) @@ -231,16 +245,21 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, } /// GetBuiltinType - Return the type for the specified builtin. -QualType Builtin::Context::GetBuiltinType(unsigned id, - ASTContext &Context) const { +QualType Builtin::Context::GetBuiltinType(unsigned id, ASTContext &Context, + GetBuiltinTypeError &Error) const { const char *TypeStr = GetRecord(id).Type; llvm::SmallVector ArgTypes; - QualType ResType = DecodeTypeFromStr(TypeStr, Context); + Error = GE_None; + QualType ResType = DecodeTypeFromStr(TypeStr, Context, Error); + if (Error != GE_None) + return QualType(); while (TypeStr[0] && TypeStr[0] != '.') { - QualType Ty = DecodeTypeFromStr(TypeStr, Context); - + QualType Ty = DecodeTypeFromStr(TypeStr, Context, Error); + if (Error != GE_None) + return QualType(); + // Do array -> pointer decay. The builtin should use the decayed type. if (Ty->isArrayType()) Ty = Context.getArrayDecayedType(Ty); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 03de730f65..ba77e44288 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -852,7 +852,10 @@ llvm::Function *CodeGenModule::getBuiltinLibFunction(unsigned BuiltinID) { Name += 10; // Get the type for the builtin. - QualType Type = Context.BuiltinInfo.GetBuiltinType(BuiltinID, Context); + Builtin::Context::GetBuiltinTypeError Error; + QualType Type = Context.BuiltinInfo.GetBuiltinType(BuiltinID, Context, Error); + assert(Error == Builtin::Context::GE_None && "Can't get builtin type"); + const llvm::FunctionType *Ty = cast(getTypes().ConvertType(Type)); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 45ef03506f..4666250c4a 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -133,9 +133,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer) KnownFunctionIDs[id_NSLog] = &IT.get("NSLog"); KnownFunctionIDs[id_asprintf] = &IT.get("asprintf"); - KnownFunctionIDs[id_fprintf] = &IT.get("fprintf"); KnownFunctionIDs[id_vasprintf] = &IT.get("vasprintf"); - KnownFunctionIDs[id_vfprintf] = &IT.get("vfprintf"); StdNamespace = 0; TUScope = 0; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index db0837710f..f202ad409a 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -182,9 +182,7 @@ public: enum { id_NSLog, id_asprintf, - id_fprintf, id_vasprintf, - id_vfprintf, id_num_known_functions }; diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index ab71255496..7ecc304fc9 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -87,12 +87,10 @@ Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { } else if (FnInfo == KnownFunctionIDs[id_NSLog]) { format_idx = 0; HasVAListArg = false; - } else if (FnInfo == KnownFunctionIDs[id_asprintf] || - FnInfo == KnownFunctionIDs[id_fprintf]) { + } else if (FnInfo == KnownFunctionIDs[id_asprintf]) { format_idx = 1; HasVAListArg = false; - } else if (FnInfo == KnownFunctionIDs[id_vasprintf] || - FnInfo == KnownFunctionIDs[id_vfprintf]) { + } else if (FnInfo == KnownFunctionIDs[id_vasprintf]) { format_idx = 1; HasVAListArg = true; } else { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 3c02d4b294..16e8691f10 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -298,7 +298,19 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, if (Context.BuiltinInfo.hasVAListUse(BID)) InitBuiltinVaListType(); - QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context); + Builtin::Context::GetBuiltinTypeError Error; + QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context, Error); + switch (Error) { + case Builtin::Context::GE_None: + // Okay + break; + + case Builtin::Context::GE_Missing_FILE: + if (ForRedeclaration) + Diag(Loc, diag::err_implicit_decl_requires_stdio) + << Context.BuiltinInfo.GetName(BID); + return 0; + } if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) { Diag(Loc, diag::ext_implicit_lib_function_decl) diff --git a/test/Sema/implicit-builtin-decl.c b/test/Sema/implicit-builtin-decl.c index 3faef0b719..e9b0556f3e 100644 --- a/test/Sema/implicit-builtin-decl.c +++ b/test/Sema/implicit-builtin-decl.c @@ -20,3 +20,7 @@ void h() { int strcpy(int); // expected-error{{conflicting types for 'strcpy'}} \ // expected-note{{'strcpy' was implicitly declared here with type 'char *(char *, char const *)'}} } + +void f2() { + fprintf(0, "foo"); // expected-error{{implicit declaration of 'fprintf' requires inclusion of the header }} +} -- 2.40.0