d->addAttr(::new (S.Context) FormatArgAttr(Idx.getZExtValue()));
}
+enum FormatAttrKind {
+ CFStringFormat,
+ NSStringFormat,
+ StrftimeFormat,
+ SupportedFormat,
+ InvalidFormat
+};
+
+/// getFormatAttrKind - Map from format attribute names to supported format
+/// types.
+static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) {
+ // Check for formats that get handled specially.
+ if (Format == "NSString")
+ return NSStringFormat;
+ if (Format == "CFString")
+ return CFStringFormat;
+ if (Format == "strftime")
+ return StrftimeFormat;
+
+ // Otherwise, check for supported formats.
+ if (Format == "scanf" || Format == "printf" || Format == "printf0" ||
+ Format == "strfmon" || Format == "cmn_err" || Format == "strftime" ||
+ Format == "NSString" || Format == "CFString" || Format == "vcmn_err" ||
+ Format == "zcmn_err")
+ return SupportedFormat;
+
+ return InvalidFormat;
+}
+
/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
/// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
unsigned NumArgs = getFunctionOrMethodNumArgs(d);
unsigned FirstIdx = 1;
- const char *Format = Attr.getParameterName()->getName();
- unsigned FormatLen = Attr.getParameterName()->getLength();
+ llvm::StringRef Format = Attr.getParameterName()->getNameStr();
// Normalize the argument, __foo__ becomes foo.
- if (FormatLen > 4 && Format[0] == '_' && Format[1] == '_' &&
- Format[FormatLen - 2] == '_' && Format[FormatLen - 1] == '_') {
- Format += 2;
- FormatLen -= 4;
- }
-
- bool Supported = false;
- bool is_NSString = false;
- bool is_strftime = false;
- bool is_CFString = false;
-
- switch (FormatLen) {
- default: break;
- case 5: Supported = !memcmp(Format, "scanf", 5); break;
- case 6: Supported = !memcmp(Format, "printf", 6); break;
- case 7: Supported = !memcmp(Format, "printf0", 7) ||
- !memcmp(Format, "strfmon", 7) ||
- !memcmp(Format, "cmn_err", 7); break;
- case 8:
- Supported = (is_strftime = !memcmp(Format, "strftime", 8)) ||
- (is_NSString = !memcmp(Format, "NSString", 8)) ||
- !memcmp(Format, "vcmn_err", 8) ||
- !memcmp(Format, "zcmn_err", 8) ||
- (is_CFString = !memcmp(Format, "CFString", 8));
- break;
- }
+ if (Format.startswith("__") && Format.endswith("__"))
+ Format = Format.substr(2, Format.size() - 4);
- if (!Supported) {
+ // Check for supported formats.
+ FormatAttrKind Kind = getFormatAttrKind(Format);
+ if (Kind == InvalidFormat) {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
- << "format" << Attr.getParameterName()->getName();
+ << "format" << Attr.getParameterName()->getNameStr();
return;
}
// make sure the format string is really a string
QualType Ty = getFunctionOrMethodArgType(d, ArgIdx);
- if (is_CFString) {
+ if (Kind == CFStringFormat) {
if (!isCFStringType(Ty, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_format_attribute_not)
<< "a CFString" << IdxExpr->getSourceRange();
return;
}
- } else if (is_NSString) {
+ } else if (Kind == NSStringFormat) {
// FIXME: do we need to check if the type is NSString*? What are the
// semantics?
if (!isNSStringType(Ty, S.Context)) {
// strftime requires FirstArg to be 0 because it doesn't read from any
// variable the input is just the current time + the format string.
- if (is_strftime) {
+ if (Kind == StrftimeFormat) {
if (FirstArg != 0) {
S.Diag(Attr.getLoc(), diag::err_format_strftime_third_parameter)
<< FirstArgExpr->getSourceRange();
return;
}
- d->addAttr(::new (S.Context) FormatAttr(std::string(Format, FormatLen),
- Idx.getZExtValue(), FirstArg.getZExtValue()));
+ d->addAttr(::new (S.Context) FormatAttr(Format, Idx.getZExtValue(),
+ FirstArg.getZExtValue()));
}
static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,