]> granicus.if.org Git - clang/commitdiff
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@352540 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 7ca8e59095623c64029a4833b536d756d68bb856..643fb822f7f40926934a54bbdb7bb5cde84a822f 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 e743e23078a2641bf978be2f9fd0327accc0787e..578d5bc567338927a637dd831ef9d0789ddca1d0 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 df0a66456c3afdacb80dc83c4586d73199c548f6..a1207aae5aa25c397bd6d6f1cd07e15e987540e2 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 ff4883305a7df25cc18d87a6e158bf51bc8611b7..1a87de70f86b77385ab885df523600d2e576c977 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 e1349cbe199ac4953e625925c0e3dfbcb8d8b67b..0a36a84deb8575369494b992abc795a0829771ab 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 0598da214ecf3095ecd92fa17c2f909873de0dea..5a5e5616e801aa9625aeff98db245ce9f16d1791 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 a9af8ce5dee9ea0a5700211f7ada11fb868ec53c..e8acd40c8d2b42d81ecbf5738d80bbc9cfb95479 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 b9f949ffe2fcd5d1e9fedb88ff2128df000148d6..e1181e1e3e6a7b6dc54bf3278688d5455fc0bf20 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 39b859402702f39c5b3bc07d742e6d40b1bb1f0d..d08c95b6d8abdb12cf54d32545653e6acb960104 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 212e1f8981cbefa4fd39975f1905b28c7bb68a36..0cfeeb1357960083cdd15c0a4d7a75d95b12422f 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'}}
+}