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. llvm-svn: 64526
This commit is contained in:
parent
e68c0fcfb2
commit
538c3d8459
|
@ -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:")
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -182,9 +182,7 @@ public:
|
|||
enum {
|
||||
id_NSLog,
|
||||
id_asprintf,
|
||||
id_fprintf,
|
||||
id_vasprintf,
|
||||
id_vfprintf,
|
||||
id_num_known_functions
|
||||
};
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue