aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r--lib/Sema/SemaDeclAttr.cpp93
1 files changed, 48 insertions, 45 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 50ebb49e7d5b..341d49ead418 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -1202,6 +1202,35 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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) {
@@ -1226,38 +1255,15 @@ 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()->getName();
// 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();
return;
@@ -1296,13 +1302,13 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// 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)) {
@@ -1340,7 +1346,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// 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();
@@ -1353,8 +1359,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
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,
@@ -1496,20 +1502,17 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
S.Diag(Attr.getLoc(), diag::err_attribute_missing_parameter_name);
return;
}
- const char *Str = Name->getName();
- unsigned Len = Name->getLength();
+
+ llvm::StringRef Str = Attr.getParameterName()->getName();
// Normalize the attribute name, __foo__ becomes foo.
- if (Len > 4 && Str[0] == '_' && Str[1] == '_' &&
- Str[Len - 2] == '_' && Str[Len - 1] == '_') {
- Str += 2;
- Len -= 4;
- }
+ if (Str.startswith("__") && Str.endswith("__"))
+ Str = Str.substr(2, Str.size() - 4);
unsigned DestWidth = 0;
bool IntegerMode = true;
bool ComplexMode = false;
- switch (Len) {
+ switch (Str.size()) {
case 2:
switch (Str[0]) {
case 'Q': DestWidth = 8; break;
@@ -1531,13 +1534,13 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) {
case 4:
// FIXME: glibc uses 'word' to define register_t; this is narrower than a
// pointer on PIC16 and other embedded platforms.
- if (!memcmp(Str, "word", 4))
+ if (Str == "word")
DestWidth = S.Context.Target.getPointerWidth(0);
- if (!memcmp(Str, "byte", 4))
+ else if (Str == "byte")
DestWidth = S.Context.Target.getCharWidth();
break;
case 7:
- if (!memcmp(Str, "pointer", 7))
+ if (Str == "pointer")
DestWidth = S.Context.Target.getPointerWidth(0);
break;
}