]> granicus.if.org Git - clang/commitdiff
Make it possible for builtins to expression FILE* arguments, so that
authorDouglas Gregor <dgregor@apple.com>
Sat, 14 Feb 2009 01:52:53 +0000 (01:52 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 14 Feb 2009 01:52:53 +0000 (01:52 +0000)
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
include/clang/AST/Builtins.h
include/clang/Basic/DiagnosticSemaKinds.def
lib/AST/Builtins.cpp
lib/CodeGen/CodeGenModule.cpp
lib/Sema/Sema.cpp
lib/Sema/Sema.h
lib/Sema/SemaChecking.cpp
lib/Sema/SemaDecl.cpp
test/Sema/implicit-builtin-decl.c

index 5e009d27aaf95a4a0e96ddda558269d91c8c6df4..3cfe2d340f26442739ba715146402ab835c64374 100644 (file)
@@ -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, "i<FIXME:FILEPTR>cC*.", "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, "i<FIXME:FILEPTR>cC*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:")
 
index 045e2ecf1b7fb8099d2c7cc0779f7b5a5e01a095..6fbd16624abf70e9f4e92e7383a6d11541099671 100644 (file)
@@ -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 <stdio.h>
+  };
+  QualType GetBuiltinType(unsigned ID, ASTContext &Context,
+                          GetBuiltinTypeError &Error) const;
 private:
   const Info &GetRecord(unsigned ID) const;
 };
index 871d03762bd83f1d67eff5c143b9275959097957..d109539d0e7a25b7c21be8609cf1a9e6bd4a24d3 100644 (file)
@@ -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 <stdio.h>")
 
 /// parser diagnostics
 DIAG(ext_typedef_without_a_name, EXTWARN,
index e7ec1372a8eecf44ae70d50b187726bdbeff3cac..e345898b79cde5af4bc6adcfd22d65b69ccb28ca 100644 (file)
@@ -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<TypeDecl>(*Lookup.first)) {
+      Type = Context.getTypeDeclType(cast<TypeDecl>(*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<QualType, 8> 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);
index 03de730f655f0776fdce8918f5f77a6c19bfdffb..ba77e44288ca38dad84160d23ce6869f7d756561 100644 (file)
@@ -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<llvm::FunctionType>(getTypes().ConvertType(Type));
 
index 45ef03506f296a123671d325bebad0d891a394b8..4666250c4a7683791a53573b4c9252d93fa1a7d4 100644 (file)
@@ -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;
index db0837710f65e71c8ba7f48d73274a7bc8eb4ea7..f202ad409a1d292922365cc8a2076c15d8c1988d 100644 (file)
@@ -182,9 +182,7 @@ public:
   enum {
     id_NSLog,
     id_asprintf,
-    id_fprintf,
     id_vasprintf,
-    id_vfprintf,
     id_num_known_functions
   };
   
index ab7125549654095d82f9c30935ecd4445d3d221b..7ecc304fc90966f8348ed71125fa7869c841afcf 100644 (file)
@@ -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 {
index 3c02d4b29465f5968e13de79212cf881d8bb50d7..16e8691f10babb73d389d1b25b69146bff78f407 100644 (file)
@@ -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)
index 3faef0b719f4bc678e7a3bbd60d1b53bf3bd4c1d..e9b0556f3e5854cc1460db97849fe0c242e642a8 100644 (file)
@@ -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 <stdio.h>}}
+}