Add builtin definition for scanf, including extending the builtin encoding to
represent builtins that have the "scanf" attribution (via the format attribute) just like we do with printf functions. Follow-up work is needed to add similar support for fscanf et al. This is to support format-string checking for scanf functions. llvm-svn: 108499
This commit is contained in:
parent
103c4ebea5
commit
5932c35138
|
@ -66,6 +66,11 @@
|
|||
// P:N: -> similar to the p:N: attribute, but the function is like vprintf
|
||||
// in that it accepts its arguments as a va_list rather than
|
||||
// through an ellipsis
|
||||
// s:N: -> this is a scanf-like function whose Nth argument is the format
|
||||
// string.
|
||||
// S:N: -> similar to the s:N: attribute, but the function is like vscanf
|
||||
// in that it accepts its arguments as a va_list rather than
|
||||
// through an ellipsis
|
||||
// e -> const, but only when -fmath-errno=0
|
||||
// FIXME: gcc has nonnull
|
||||
|
||||
|
@ -516,6 +521,7 @@ LIBBUILTIN(vprintf, "icC*a", "fP:0:", "stdio.h")
|
|||
LIBBUILTIN(vfprintf, "i.", "fP:1:", "stdio.h")
|
||||
LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h")
|
||||
LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h")
|
||||
LIBBUILTIN(scanf, "icC*.", "fs:0:", "stdio.h")
|
||||
// C99
|
||||
LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h")
|
||||
|
||||
|
|
|
@ -119,6 +119,11 @@ public:
|
|||
/// argument and whether this function as a va_list argument.
|
||||
bool isPrintfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg);
|
||||
|
||||
/// \brief Determine whether this builtin is like scanf in its
|
||||
/// formatting rules and, if so, set the index to the format string
|
||||
/// argument and whether this function as a va_list argument.
|
||||
bool isScanfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg);
|
||||
|
||||
/// hasVAListUse - Return true of the specified builtin uses __builtin_va_list
|
||||
/// as an operand or return type.
|
||||
bool hasVAListUse(unsigned ID) const {
|
||||
|
|
|
@ -93,3 +93,23 @@ Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx,
|
|||
return true;
|
||||
}
|
||||
|
||||
// FIXME: Refactor with isPrintfLike.
|
||||
bool
|
||||
Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx,
|
||||
bool &HasVAListArg) {
|
||||
const char *Scanf = strpbrk(GetRecord(ID).Attributes, "sS");
|
||||
if (!Scanf)
|
||||
return false;
|
||||
|
||||
HasVAListArg = (*Scanf == 'S');
|
||||
|
||||
++Scanf;
|
||||
assert(*Scanf == ':' && "s or S specifier must have be followed by a ':'");
|
||||
++Scanf;
|
||||
|
||||
assert(strchr(Scanf, ':') && "printf specifier must end with a ':'");
|
||||
FormatIdx = strtol(Scanf, 0, 10);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4905,6 +4905,12 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
|
|||
FD->addAttr(::new (Context) FormatAttr(Context, "printf", FormatIdx+1,
|
||||
HasVAListArg ? 0 : FormatIdx+2));
|
||||
}
|
||||
if (Context.BuiltinInfo.isScanfLike(BuiltinID, FormatIdx,
|
||||
HasVAListArg)) {
|
||||
if (!FD->getAttr<FormatAttr>())
|
||||
FD->addAttr(::new (Context) FormatAttr(Context, "scanf", FormatIdx+1,
|
||||
HasVAListArg ? 0 : FormatIdx+2));
|
||||
}
|
||||
|
||||
// Mark const if we don't care about errno and that is the only
|
||||
// thing preventing the function from being const. This allows
|
||||
|
|
Loading…
Reference in New Issue