OpenCL: Use length modifier for warning on vector printf arguments
authorMatt Arsenault <Matthew.Arsenault@amd.com>
Tue, 29 Jan 2019 20:49:54 +0000 (20:49 +0000)
committerMatt Arsenault <Matthew.Arsenault@amd.com>
Tue, 29 Jan 2019 20:49:54 +0000 (20:49 +0000)
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

clang/include/clang/AST/FormatString.h
clang/lib/AST/FormatString.cpp
clang/lib/AST/PrintfFormatString.cpp
clang/lib/AST/ScanfFormatString.cpp
clang/lib/Headers/opencl-c.h
clang/lib/Sema/SemaChecking.cpp
clang/test/Sema/format-strings.c
clang/test/SemaOpenCL/format-strings-fixit.cl
clang/test/SemaOpenCL/printf-format-string-warnings.cl
clang/test/SemaOpenCL/printf-format-strings.cl

index 7ca8e59..643fb82 100644 (file)
@@ -67,6 +67,7 @@ public:
     None,
     AsChar,       // 'hh'
     AsShort,      // 'h'
+    AsShortLong,  // 'hl' (OpenCL float/int vector element)
     AsLong,       // 'l'
     AsLongLong,   // 'll'
     AsQuad,       // 'q' (BSD, deprecated, for 64-bit integer types)
@@ -436,7 +437,8 @@ public:
 
   bool usesPositionalArg() const { return UsesPositionalArg; }
 
-  bool hasValidLengthModifier(const TargetInfo &Target) const;
+  bool hasValidLengthModifier(const TargetInfo &Target,
+                              const LangOptions &LO) const;
 
   bool hasStandardLengthModifier() const;
 
index e743e23..578d5bc 100644 (file)
@@ -223,6 +223,9 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
       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::matchesType(ASTContext &C, QualType argTy) const {
 }
 
 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 @@ analyze_format_string::LengthModifier::toString() const {
     return "hh";
   case AsShort:
     return "h";
+  case AsShortLong:
+    return "hl";
   case AsLong: // or AsWideChar
     return "l";
   case AsLongLong:
@@ -707,13 +713,18 @@ void OptionalAmount::toString(raw_ostream &os) const {
   }
 }
 
-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 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
           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 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {
         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 @@ bool FormatSpecifier::hasStandardLengthModifier() const {
     case LengthModifier::AsInt3264:
     case LengthModifier::AsInt64:
     case LengthModifier::AsWide:
+    case LengthModifier::AsShortLong: // ???
       return false;
   }
   llvm_unreachable("Invalid LengthModifier Kind!");
index df0a664..a1207aa 100644 (file)
@@ -315,7 +315,11 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
     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 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
         // 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 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
         // 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 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
     }
 
   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 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
       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 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
   case BuiltinType::UInt:
   case BuiltinType::Int:
   case BuiltinType::Float:
+    LM.setKind(VectorNumElts.isInvalid() ?
+               LengthModifier::None : LengthModifier::AsShortLong);
+    break;
   case BuiltinType::Double:
-    LM.setKind(LengthModifier::None);
+    LM.setKind(VectorNumElts.isInvalid() ?
+               LengthModifier::None : LengthModifier::AsLong);
     break;
-
   case BuiltinType::Char_U:
   case BuiltinType::UChar:
   case BuiltinType::Char_S:
@@ -796,7 +820,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
     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:
index ff48833..1a87de7 100644 (file)
@@ -261,9 +261,10 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
         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 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
         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 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
         case LengthModifier::AsInt32:
         case LengthModifier::AsInt3264:
         case LengthModifier::AsWide:
+        case LengthModifier::AsShortLong:
           return ArgType::Invalid();
         }
 
@@ -501,7 +504,7 @@ bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
     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;
index e1349cb..0a36a84 100644 (file)
@@ -14469,7 +14469,7 @@ half16 __ovld __cnfn shuffle2(half16 x, half16 y, ushort16 mask);
 #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
index 0598da2..5a5e561 100644 (file)
@@ -7650,7 +7650,8 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
             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 @@ bool CheckScanfHandler::HandleScanfSpecifier(
   }
 
   // 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())
index a9af8ce..e8acd40 100644 (file)
@@ -617,6 +617,8 @@ void test_opencl_vector_format(int x) {
   printf("%v4d", x); // expected-warning{{invalid conversion specifier 'v'}}
   printf("%vd", x); // expected-warning{{invalid conversion specifier 'v'}}
   printf("%0vd", x); // expected-warning{{invalid conversion specifier 'v'}}
+  printf("%hlf", x); // expected-warning{{invalid conversion specifier 'l'}}
+  printf("%hld", x); // expected-warning{{invalid conversion specifier 'l'}}
 }
 
 // Test that we correctly merge the format in both orders.
index b9f949f..e1181e1 100644 (file)
@@ -3,22 +3,72 @@
 // RUN: %clang_cc1 -cl-std=CL1.2 -fsyntax-only -pedantic -Wall -Werror %t
 // RUN: %clang_cc1 -cl-std=CL1.2 -E -o - %t | FileCheck %s
 
+typedef __attribute__((ext_vector_type(4))) char char4;
+typedef __attribute__((ext_vector_type(4))) short short4;
 typedef __attribute__((ext_vector_type(4))) int int4;
+typedef __attribute__((ext_vector_type(4))) unsigned int uint4;
 typedef __attribute__((ext_vector_type(8))) int int8;
+typedef __attribute__((ext_vector_type(4))) long long4;
+typedef __attribute__((ext_vector_type(4))) float float4;
+typedef __attribute__((ext_vector_type(4))) double double4;
 
 int printf(__constant const char* st, ...) __attribute__((format(printf, 1, 2)));
 
 
 void vector_fixits() {
   printf("%v4f", (int4) 123);
-  // CHECK: printf("%v4d", (int4) 123);
+  // CHECK: printf("%v4hld", (int4) 123);
 
   printf("%v8d", (int4) 123);
-  // CHECK: printf("%v4d", (int4) 123);
+  // CHECK: printf("%v4hld", (int4) 123);
 
   printf("%v4d", (int8) 123);
-  // CHECK: printf("%v8d", (int8) 123);
+  // CHECK: printf("%v8hld", (int8) 123);
 
   printf("%v4f", (int8) 123);
-  // CHECK: printf("%v8d", (int8) 123);
+  // CHECK: printf("%v8hld", (int8) 123);
+
+  printf("%v4ld", (int8) 123);
+  // CHECK: printf("%v8hld", (int8) 123);
+
+  printf("%v4hlf", (int4) 123);
+  // CHECK: printf("%v4hld", (int4) 123);
+
+  printf("%v8hld", (int4) 123);
+  // CHECK: printf("%v4hld", (int4) 123);
+
+  printf("%v4hld", (int8) 123);
+  // CHECK: printf("%v8hld", (int8) 123);
+
+  printf("%v4hlf", (int8) 123);
+  // CHECK: printf("%v8hld", (int8) 123);
+
+  printf("%v4hd", (int4) 123);
+  // CHECK: printf("%v4hld", (int4) 123);
+
+  printf("%v4hld", (short4) 123);
+  // CHECK: printf("%v4hd", (short4) 123);
+
+  printf("%v4ld", (short4) 123);
+  // CHECK: printf("%v4hd", (short4) 123);
+
+  printf("%v4hld", (long4) 123);
+  // CHECK: printf("%v4ld", (long4) 123);
+
+  printf("%v8f", (float4) 2.0f);
+  // CHECK: printf("%v4hlf", (float4) 2.0f);
+
+  printf("%v4f", (float4) 2.0f);
+  // CHECK: printf("%v4hlf", (float4) 2.0f);
+
+  printf("%v4lf", (double4) 2.0);
+  // CHECK: printf("%v4lf", (double4) 2.0);
+
+  /// FIXME: This should be fixed
+  printf("%v4hhd", (int4) 123);
+  // CHECK: printf("%v4hhd", (int4) 123);
+
+  /// FIXME: This should be fixed
+  printf("%v4hhd", (int8) 123);
+  // CHECK: printf("%v4hhd", (int8) 123);
 }
index 39b8594..d08c95b 100644 (file)
@@ -1,14 +1,12 @@
 // RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0 -finclude-default-header
 
-// FIXME: Make sure warnings are produced based on printf format strings.
-
-// expected-no-diagnostics
+// Make sure warnings are produced based on printf format strings.
 
 kernel void format_string_warnings(__constant char* arg) {
 
-  printf("%d", arg);
+  printf("%d", arg); // expected-warning {{format specifies type 'int' but the argument has type '__constant char *'}}
 
-  printf("not enough arguments %d %d", 4);
+  printf("not enough arguments %d %d", 4); // expected-warning {{more '%' conversions than data arguments}}
 
-  printf("too many arguments", 4);
+  printf("too many arguments", 4); // expected-warning {{data argument not used by format string}}
 }
index 212e1f8..0cfeeb1 100644 (file)
@@ -1,22 +1,90 @@
 // RUN: %clang_cc1 -cl-std=CL1.2 -cl-ext=+cl_khr_fp64 -fsyntax-only -verify %s
 // RUN: %clang_cc1 -cl-std=CL1.2 -cl-ext=-cl_khr_fp64 -fsyntax-only -verify %s
 
+typedef __attribute__((ext_vector_type(4))) half half4;
+
 typedef __attribute__((ext_vector_type(2))) float float2;
 typedef __attribute__((ext_vector_type(4))) float float4;
 
+#ifdef cl_khr_fp64
+typedef __attribute__((ext_vector_type(4))) double double4;
+#endif
+
+typedef __attribute__((ext_vector_type(4))) char char4;
+typedef __attribute__((ext_vector_type(4))) unsigned char uchar4;
+
+typedef __attribute__((ext_vector_type(4))) short short4;
+typedef __attribute__((ext_vector_type(4))) unsigned short ushort4;
+
 typedef __attribute__((ext_vector_type(2))) int int2;
 typedef __attribute__((ext_vector_type(4))) int int4;
 typedef __attribute__((ext_vector_type(16))) int int16;
 
+typedef __attribute__((ext_vector_type(4))) long long4;
+typedef __attribute__((ext_vector_type(4))) unsigned int uint4;
+typedef __attribute__((ext_vector_type(4))) unsigned long ulong4;
+
 int printf(__constant const char* st, ...) __attribute__((format(printf, 1, 2)));
 
+
+#ifdef cl_khr_fp64
+kernel void format_v4f64(half4 arg_h, float4 arg_f, double4 arg_d)
+{
+  printf("%v4lf", arg_d);
+  printf("%v4lf", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4lf", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4lF", arg_d);
+  printf("%v4lF", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4lF", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4le", arg_d);
+  printf("%v4le", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4le", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4lE", arg_d);
+  printf("%v4lE", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4lE", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4lg", arg_d);
+  printf("%v4lg", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4lg", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4lG", arg_d);
+  printf("%v4lG", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4lG", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4la", arg_d);
+  printf("%v4la", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4la", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+
+  printf("%v4lA", arg_d);
+  printf("%v4lA", arg_f); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4lA", arg_h); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'half4' (vector of 4 'half' values)}}
+}
+
+kernel void format_v4f16(half4 arg_h, float4 arg_f, double4 arg_d)
+{
+  printf("%v4hf\n", arg_d); // expected-warning{{format specifies type '__fp16 __attribute__((ext_vector_type(4)))' but the argument has type 'double4' (vector of 4 'double' values)}}
+  printf("%v4hf\n", arg_f); // expected-warning{{format specifies type '__fp16 __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+  printf("%v4hf\n", arg_h);
+}
+
+kernel void no_length_modifier_scalar_fp(float f) {
+  printf("%hf", f); // expected-warning{{length modifier 'h' results in undefined behavior or no effect with 'f' conversion specifier}}
+  printf("%hlf", f); // expected-warning{{length modifier 'hl' results in undefined behavior or no effect with 'f' conversion specifier}}
+  printf("%lf", f); // expected-warning{{length modifier 'l' results in undefined behavior or no effect with 'f' conversion specifier}}
+}
+
+#endif
+
 kernel void format_v4f32(float4 arg)
 {
 #ifdef cl_khr_fp64
     printf("%v4f\n", arg); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
 
     // Precision modifier
-    printf("%.2v4f\n", arg); // expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
+    printf("%.2v4f\n", arg); //expected-warning{{format specifies type 'double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
 #else
     // FIXME: These should not warn, and the type should be expected to be float.
     printf("%v4f\n", arg);  // expected-warning {{double __attribute__((ext_vector_type(4)))' but the argument has type 'float4' (vector of 4 'float' values)}}
@@ -92,3 +160,52 @@ kernel void crash_on_s(int4 arg)
 {
     printf("%v4s\n", arg);
 }
+
+
+kernel void printf_int_length_modifiers(char4 arg_c, short4 arg_s, int4 arg_i, long4 arg_l, uchar4 arg_uc, ushort4 arg_us, uint4 arg_ui, ulong4 arg_ul) {
+  printf("%v4hhd", arg_c);
+  printf("%v4hhd", arg_s);
+  printf("%v4hhd", arg_i);
+  printf("%v4hhd", arg_l);
+
+  printf("%v4hd", arg_c); // expected-warning{{format specifies type 'short __attribute__((ext_vector_type(4)))' but the argument has type 'char4' (vector of 4 'char' values)}}
+  printf("%v4hd", arg_s);
+  printf("%v4hd", arg_i); // expected-warning{{format specifies type 'short __attribute__((ext_vector_type(4)))' but the argument has type 'int4' (vector of 4 'int' values)}}
+  printf("%v4hd", arg_l); // expected-warning{{format specifies type 'short __attribute__((ext_vector_type(4)))' but the argument has type 'long4' (vector of 4 'long' values)}}
+
+  printf("%v4hld", arg_c); // expected-warning{{format specifies type 'int __attribute__((ext_vector_type(4)))' but the argument has type 'char4' (vector of 4 'char' values)}}
+  printf("%v4hld", arg_s); // expected-warning{{format specifies type 'int __attribute__((ext_vector_type(4)))' but the argument has type 'short4' (vector of 4 'short' values)}}
+  printf("%v4hld", arg_i);
+  printf("%v4hld", arg_l); // expected-warning{{format specifies type 'int __attribute__((ext_vector_type(4)))' but the argument has type 'long4' (vector of 4 'long' values)}}
+
+  printf("%v4ld", arg_c); // expected-warning{{format specifies type 'long __attribute__((ext_vector_type(4)))' but the argument has type 'char4' (vector of 4 'char' values)}}
+  printf("%v4ld", arg_s); // expected-warning{{format specifies type 'long __attribute__((ext_vector_type(4)))' but the argument has type 'short4' (vector of 4 'short' values)}}
+  printf("%v4ld", arg_i); // expected-warning{{format specifies type 'long __attribute__((ext_vector_type(4)))' but the argument has type 'int4' (vector of 4 'int' values)}}
+  printf("%v4ld", arg_l);
+
+
+
+  printf("%v4hhu", arg_uc);
+  printf("%v4hhu", arg_us); // expected-warning{{format specifies type 'unsigned char __attribute__((ext_vector_type(4)))' but the argument has type 'ushort4' (vector of 4 'unsigned short' values)}}
+  printf("%v4hhu", arg_ui); // expected-warning{{format specifies type 'unsigned char __attribute__((ext_vector_type(4)))' but the argument has type 'uint4' (vector of 4 'unsigned int' values)}}
+  printf("%v4hhu", arg_ul); // expected-warning{{format specifies type 'unsigned char __attribute__((ext_vector_type(4)))' but the argument has type 'ulong4' (vector of 4 'unsigned long' values)}}
+
+  printf("%v4hu", arg_uc); // expected-warning{{format specifies type 'unsigned short __attribute__((ext_vector_type(4)))' but the argument has type 'uchar4' (vector of 4 'unsigned char' values)}}
+  printf("%v4hu", arg_us);
+  printf("%v4hu", arg_ui); // expected-warning{{format specifies type 'unsigned short __attribute__((ext_vector_type(4)))' but the argument has type 'uint4' (vector of 4 'unsigned int' values)}}
+  printf("%v4hu", arg_ul); // expected-warning{{format specifies type 'unsigned short __attribute__((ext_vector_type(4)))' but the argument has type 'ulong4' (vector of 4 'unsigned long' values)}}
+
+  printf("%v4hlu", arg_uc); // expected-warning{{format specifies type 'unsigned int __attribute__((ext_vector_type(4)))' but the argument has type 'uchar4' (vector of 4 'unsigned char' values)}}
+  printf("%v4hlu", arg_us); // expected-warning{{format specifies type 'unsigned int __attribute__((ext_vector_type(4)))' but the argument has type 'ushort4' (vector of 4 'unsigned short' values)}}
+  printf("%v4hlu", arg_ui);
+  printf("%v4hlu", arg_ul); // expected-warning{{format specifies type 'unsigned int __attribute__((ext_vector_type(4)))' but the argument has type 'ulong4' (vector of 4 'unsigned long' values)}}
+
+  printf("%v4lu", arg_uc); // expected-warning{{format specifies type 'unsigned long __attribute__((ext_vector_type(4)))' but the argument has type 'uchar4' (vector of 4 'unsigned char' values)}}
+  printf("%v4lu", arg_us); // expected-warning{{format specifies type 'unsigned long __attribute__((ext_vector_type(4)))' but the argument has type 'ushort4' (vector of 4 'unsigned short' values)}}
+  printf("%v4lu", arg_ui); // expected-warning{{format specifies type 'unsigned long __attribute__((ext_vector_type(4)))' but the argument has type 'uint4' (vector of 4 'unsigned int' values)}}
+  printf("%v4lu", arg_ul);
+
+
+  printf("%v4n", &arg_i); // expected-warning{{invalid conversion specifier 'n'}}
+  printf("%v4hln", &arg_i); // expected-warning{{invalid conversion specifier 'n'}}
+}