aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-12-05 18:44:40 +0000
committerJordan Rose <jordan_rose@apple.com>2012-12-05 18:44:40 +0000
commit448ac3e6d1f10264cea86c89cc14c266ba2da4a2 (patch)
tree560ff3048ebb19540ab93e94c778bfdbe6260f14 /lib/Sema/SemaChecking.cpp
parentff7be48165548c9c01492010609d166973607068 (diff)
Format strings: a character literal should be printed with %c, not %d.
The type of a character literal is 'int' in C, but if the user writes a character /as/ a literal, we should assume they meant it to be a character and not a numeric value, and thus offer %c as a correction rather than %d. There's a special case for multi-character literals (like 'MooV'), which have implementation-defined value and usually cannot be printed with %c. These still use %d as the suggestion. In C++, the type of a character literal is 'char', and so this problem doesn't exist. <rdar://problem/12282316> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@169398 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaChecking.cpp')
-rw-r--r--lib/Sema/SemaChecking.cpp28
1 files changed, 18 insertions, 10 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index f1ffd788b9..ce44eafa04 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -2717,8 +2717,8 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (!AT.isValid())
return true;
- QualType IntendedTy = E->getType();
- if (AT.matchesType(S.Context, IntendedTy))
+ QualType ExprTy = E->getType();
+ if (AT.matchesType(S.Context, ExprTy))
return true;
// Look through argument promotions for our error message's reported type.
@@ -2729,7 +2729,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (ICE->getCastKind() == CK_IntegralCast ||
ICE->getCastKind() == CK_FloatingCast) {
E = ICE->getSubExpr();
- IntendedTy = E->getType();
+ ExprTy = E->getType();
// Check if we didn't match because of an implicit cast from a 'char'
// or 'short' to an 'int'. This is done because printf is a varargs
@@ -2737,12 +2737,20 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (ICE->getType() == S.Context.IntTy ||
ICE->getType() == S.Context.UnsignedIntTy) {
// All further checking is done on the subexpression.
- if (AT.matchesType(S.Context, IntendedTy))
+ if (AT.matchesType(S.Context, ExprTy))
return true;
}
}
+ } else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) {
+ // Special case for 'a', which has type 'int' in C.
+ // Note, however, that we do /not/ want to treat multibyte constants like
+ // 'MooV' as characters! This form is deprecated but still exists.
+ if (ExprTy == S.Context.IntTy)
+ if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue()))
+ ExprTy = S.Context.CharTy;
}
+ QualType IntendedTy = ExprTy;
if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
// Special-case some of Darwin's platform-independence types.
if (const TypedefType *UserTy = IntendedTy->getAs<TypedefType>()) {
@@ -2769,7 +2777,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
- if (IntendedTy != E->getType()) {
+ if (IntendedTy != ExprTy) {
// The canonical type for formatting this value is different from the
// actual type of the expression. (This occurs, for example, with Darwin's
// NSInteger on 32-bit platforms, where it is typedef'd as 'int', but
@@ -2809,7 +2817,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// We extract the name from the typedef because we don't want to show
// the underlying type in the diagnostic.
- const TypedefType *UserTy = cast<TypedefType>(E->getType());
+ const TypedefType *UserTy = cast<TypedefType>(ExprTy);
StringRef Name = UserTy->getDecl()->getName();
// Finally, emit the diagnostic.
@@ -2834,9 +2842,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// Since the warning for passing non-POD types to variadic functions
// was deferred until now, we emit a warning for non-POD
// arguments here.
- if (S.isValidVarArgType(E->getType()) == Sema::VAK_Invalid) {
+ if (S.isValidVarArgType(ExprTy) == Sema::VAK_Invalid) {
unsigned DiagKind;
- if (E->getType()->isObjCObjectType())
+ if (ExprTy->isObjCObjectType())
DiagKind = diag::err_cannot_pass_objc_interface_to_vararg_format;
else
DiagKind = diag::warn_non_pod_vararg_with_format_string;
@@ -2844,7 +2852,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
EmitFormatDiagnostic(
S.PDiag(DiagKind)
<< S.getLangOpts().CPlusPlus0x
- << E->getType()
+ << ExprTy
<< CallType
<< AT.getRepresentativeTypeName(S.Context)
<< CSR
@@ -2855,7 +2863,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
} else
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << E->getType()
+ << AT.getRepresentativeTypeName(S.Context) << ExprTy
<< CSR
<< E->getSourceRange(),
E->getLocStart(), /*IsStringLocation*/false, CSR);