OpenCL: Use length modifier for warning on vector printf arguments
Re-enable format string warnings on printf.
The warnings are still incomplete. Apparently it is undefined to use a
vector specifier without a length modifier, which is not currently
warned on. Additionally, type warnings appear to not be working with
the hh modifier, and aren't warning on all of the special restrictions
from c99 printf.
llvm-svn: 352540
diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp
index e743e23..578d5bc 100644
--- a/clang/lib/AST/FormatString.cpp
+++ b/clang/lib/AST/FormatString.cpp
@@ -223,6 +223,9 @@
if (I != E && *I == 'h') {
++I;
lmKind = LengthModifier::AsChar;
+ } else if (I != E && *I == 'l' && LO.OpenCL) {
+ ++I;
+ lmKind = LengthModifier::AsShortLong;
} else {
lmKind = LengthModifier::AsShort;
}
@@ -487,7 +490,8 @@
}
ArgType ArgType::makeVectorType(ASTContext &C, unsigned NumElts) const {
- if (K != SpecificTy) // Won't be a valid vector element type.
+ // Check for valid vector element types.
+ if (T.isNull())
return ArgType::Invalid();
QualType Vec = C.getExtVectorType(T, NumElts);
@@ -572,6 +576,8 @@
return "hh";
case AsShort:
return "h";
+ case AsShortLong:
+ return "hl";
case AsLong: // or AsWideChar
return "l";
case AsLongLong:
@@ -707,13 +713,18 @@
}
}
-bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
+bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
+ const LangOptions &LO) const {
switch (LM.getKind()) {
case LengthModifier::None:
return true;
// Handle most integer flags
case LengthModifier::AsShort:
+ // Length modifier only applies to FP vectors.
+ if (LO.OpenCL && CS.isDoubleArg())
+ return !VectorNumElts.isInvalid();
+
if (Target.getTriple().isOSMSVCRT()) {
switch (CS.getKind()) {
case ConversionSpecifier::cArg:
@@ -752,8 +763,18 @@
return false;
}
+ case LengthModifier::AsShortLong:
+ return LO.OpenCL && !VectorNumElts.isInvalid();
+
// Handle 'l' flag
case LengthModifier::AsLong: // or AsWideChar
+ if (CS.isDoubleArg()) {
+ // Invalid for OpenCL FP scalars.
+ if (LO.OpenCL && VectorNumElts.isInvalid())
+ return false;
+ return true;
+ }
+
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
case ConversionSpecifier::DArg:
@@ -764,14 +785,6 @@
case ConversionSpecifier::UArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
- case ConversionSpecifier::aArg:
- case ConversionSpecifier::AArg:
- case ConversionSpecifier::fArg:
- case ConversionSpecifier::FArg:
- case ConversionSpecifier::eArg:
- case ConversionSpecifier::EArg:
- case ConversionSpecifier::gArg:
- case ConversionSpecifier::GArg:
case ConversionSpecifier::nArg:
case ConversionSpecifier::cArg:
case ConversionSpecifier::sArg:
@@ -878,6 +891,7 @@
case LengthModifier::AsInt3264:
case LengthModifier::AsInt64:
case LengthModifier::AsWide:
+ case LengthModifier::AsShortLong: // ???
return false;
}
llvm_unreachable("Invalid LengthModifier Kind!");
diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp
index df0a664..a1207aa 100644
--- a/clang/lib/AST/PrintfFormatString.cpp
+++ b/clang/lib/AST/PrintfFormatString.cpp
@@ -315,7 +315,11 @@
case 'f': k = ConversionSpecifier::fArg; break;
case 'g': k = ConversionSpecifier::gArg; break;
case 'i': k = ConversionSpecifier::iArg; break;
- case 'n': k = ConversionSpecifier::nArg; break;
+ case 'n':
+ // Not handled, but reserved in OpenCL.
+ if (!LO.OpenCL)
+ k = ConversionSpecifier::nArg;
+ break;
case 'o': k = ConversionSpecifier::oArg; break;
case 'p': k = ConversionSpecifier::pArg; break;
case 's': k = ConversionSpecifier::sArg; break;
@@ -486,10 +490,12 @@
// GNU extension.
return Ctx.LongLongTy;
case LengthModifier::None:
+ case LengthModifier::AsShortLong:
return Ctx.IntTy;
case LengthModifier::AsInt32:
return ArgType(Ctx.IntTy, "__int32");
- case LengthModifier::AsChar: return ArgType::AnyCharTy;
+ case LengthModifier::AsChar:
+ return ArgType::AnyCharTy;
case LengthModifier::AsShort: return Ctx.ShortTy;
case LengthModifier::AsLong: return Ctx.LongTy;
case LengthModifier::AsLongLong:
@@ -520,6 +526,7 @@
// GNU extension.
return Ctx.UnsignedLongLongTy;
case LengthModifier::None:
+ case LengthModifier::AsShortLong:
return Ctx.UnsignedIntTy;
case LengthModifier::AsInt32:
return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
@@ -549,6 +556,18 @@
}
if (CS.isDoubleArg()) {
+ if (!VectorNumElts.isInvalid()) {
+ switch (LM.getKind()) {
+ case LengthModifier::AsShort:
+ return Ctx.HalfTy;
+ case LengthModifier::AsShortLong:
+ return Ctx.FloatTy;
+ case LengthModifier::AsLong:
+ default:
+ return Ctx.DoubleTy;
+ }
+ }
+
if (LM.getKind() == LengthModifier::AsLongDouble)
return Ctx.LongDoubleTy;
return Ctx.DoubleTy;
@@ -582,6 +601,8 @@
case LengthModifier::AsInt64:
case LengthModifier::AsWide:
return ArgType::Invalid();
+ case LengthModifier::AsShortLong:
+ llvm_unreachable("only used for OpenCL which doesn not handle nArg");
}
}
@@ -760,10 +781,13 @@
case BuiltinType::UInt:
case BuiltinType::Int:
case BuiltinType::Float:
- case BuiltinType::Double:
- LM.setKind(LengthModifier::None);
+ LM.setKind(VectorNumElts.isInvalid() ?
+ LengthModifier::None : LengthModifier::AsShortLong);
break;
-
+ case BuiltinType::Double:
+ LM.setKind(VectorNumElts.isInvalid() ?
+ LengthModifier::None : LengthModifier::AsLong);
+ break;
case BuiltinType::Char_U:
case BuiltinType::UChar:
case BuiltinType::Char_S:
@@ -796,7 +820,7 @@
namedTypeToLengthModifier(QT, LM);
// If fixing the length modifier was enough, we might be done.
- if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
// If we're going to offer a fix anyway, make sure the sign matches.
switch (CS.getKind()) {
case ConversionSpecifier::uArg:
diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp
index ff48833..1a87de7 100644
--- a/clang/lib/AST/ScanfFormatString.cpp
+++ b/clang/lib/AST/ScanfFormatString.cpp
@@ -261,9 +261,10 @@
case LengthModifier::AsInt32:
case LengthModifier::AsInt3264:
case LengthModifier::AsWide:
+ case LengthModifier::AsShortLong:
return ArgType::Invalid();
}
- llvm_unreachable("Unsupported LenghtModifier Type");
+ llvm_unreachable("Unsupported LengthModifier Type");
// Unsigned int.
case ConversionSpecifier::oArg:
@@ -301,9 +302,10 @@
case LengthModifier::AsInt32:
case LengthModifier::AsInt3264:
case LengthModifier::AsWide:
+ case LengthModifier::AsShortLong:
return ArgType::Invalid();
}
- llvm_unreachable("Unsupported LenghtModifier Type");
+ llvm_unreachable("Unsupported LengthModifier Type");
// Float.
case ConversionSpecifier::aArg:
@@ -396,6 +398,7 @@
case LengthModifier::AsInt32:
case LengthModifier::AsInt3264:
case LengthModifier::AsWide:
+ case LengthModifier::AsShortLong:
return ArgType::Invalid();
}
@@ -501,7 +504,7 @@
namedTypeToLengthModifier(PT, LM);
// If fixing the length modifier was enough, we are done.
- if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
const analyze_scanf::ArgType &AT = getArgType(Ctx);
if (AT.isValid() && AT.matchesType(Ctx, QT))
return true;
diff --git a/clang/lib/Headers/opencl-c.h b/clang/lib/Headers/opencl-c.h
index e1349cb..0a36a84 100644
--- a/clang/lib/Headers/opencl-c.h
+++ b/clang/lib/Headers/opencl-c.h
@@ -14469,7 +14469,7 @@
#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2
// OpenCL v1.2 s6.12.13, v2.0 s6.13.13 - printf
-int printf(__constant const char* st, ...);
+int printf(__constant const char* st, ...) __attribute__((format(printf, 1, 2)));
#endif
// OpenCL v1.1 s6.11.3, v1.2 s6.12.14, v2.0 s6.13.14 - Image Read and Write Functions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 0598da2..5a5e561 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -7650,7 +7650,8 @@
startSpecifier, specifierLen);
// Check the length modifier is valid with the given conversion specifier.
- if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo()))
+ if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(),
+ S.getLangOpts()))
HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
diag::warn_format_nonsensical_length);
else if (!FS.hasStandardLengthModifier())
@@ -8154,7 +8155,8 @@
}
// Check the length modifier is valid with the given conversion specifier.
- if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo()))
+ if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(),
+ S.getLangOpts()))
HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
diag::warn_format_nonsensical_length);
else if (!FS.hasStandardLengthModifier())