r295113 - [Driver] Report available language standards on user error

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 14 14:44:20 PST 2017


Author: rsmith
Date: Tue Feb 14 16:44:20 2017
New Revision: 295113

URL: http://llvm.org/viewvc/llvm-project?rev=295113&view=rev
Log:
[Driver] Report available language standards on user error

In case user did not provide valid standard name for -std option, available
values (with short description) will be reported.

Patch by Paweł Żukowski!

Added:
    cfe/trunk/test/Driver/unknown-std.c
    cfe/trunk/test/Driver/unknown-std.cl
    cfe/trunk/test/Driver/unknown-std.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
    cfe/trunk/include/clang/Frontend/LangStandard.h
    cfe/trunk/include/clang/Frontend/LangStandards.def
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td?rev=295113&r1=295112&r2=295113&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td Tue Feb 14 16:44:20 2017
@@ -230,6 +230,7 @@ def note_drv_t_option_is_global : Note<
   "The last /TC or /TP option takes precedence over earlier instances">;
 def note_drv_address_sanitizer_debug_runtime : Note<
   "AddressSanitizer doesn't support linking with debug runtime libraries yet">;
+def note_drv_use_standard : Note<"use '%0' for '%1' standard">;
 
 def err_analyzer_config_no_value : Error<
   "analyzer-config option '%0' has a key but no value">;

Modified: cfe/trunk/include/clang/Frontend/LangStandard.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/LangStandard.h?rev=295113&r1=295112&r2=295113&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/LangStandard.h (original)
+++ cfe/trunk/include/clang/Frontend/LangStandard.h Tue Feb 14 16:44:20 2017
@@ -29,7 +29,8 @@ enum LangFeatures {
   Digraphs = (1 << 8),
   GNUMode = (1 << 9),
   HexFloat = (1 << 10),
-  ImplicitInt = (1 << 11)
+  ImplicitInt = (1 << 11),
+  OpenCL = (1 << 12)
 };
 
 }
@@ -91,6 +92,9 @@ public:
   /// hasImplicitInt - Language allows variables to be typed as int implicitly.
   bool hasImplicitInt() const { return Flags & frontend::ImplicitInt; }
 
+  /// isOpenCL - Language is a OpenCL variant.
+  bool isOpenCL() const { return Flags & frontend::OpenCL; }
+
   static const LangStandard &getLangStandardForKind(Kind K);
   static const LangStandard *getLangStandardForName(StringRef Name);
 };

Modified: cfe/trunk/include/clang/Frontend/LangStandards.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/LangStandards.def?rev=295113&r1=295112&r2=295113&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/LangStandards.def (original)
+++ cfe/trunk/include/clang/Frontend/LangStandards.def Tue Feb 14 16:44:20 2017
@@ -142,16 +142,16 @@ LANGSTANDARD(gnucxx1z, "gnu++1z",
 // OpenCL
 LANGSTANDARD(opencl, "cl",
              "OpenCL 1.0",
-             LineComment | C99 | Digraphs | HexFloat)
+             LineComment | C99 | Digraphs | HexFloat | OpenCL)
 LANGSTANDARD(opencl11, "cl1.1",
              "OpenCL 1.1",
-             LineComment | C99 | Digraphs | HexFloat)
+             LineComment | C99 | Digraphs | HexFloat | OpenCL)
 LANGSTANDARD(opencl12, "cl1.2",
              "OpenCL 1.2",
-             LineComment | C99 | Digraphs | HexFloat)
+             LineComment | C99 | Digraphs | HexFloat | OpenCL)
 LANGSTANDARD(opencl20, "cl2.0",
              "OpenCL 2.0",
-             LineComment | C99 | Digraphs | HexFloat)
+             LineComment | C99 | Digraphs | HexFloat | OpenCL)
 
 LANGSTANDARD_ALIAS(opencl, "CL")
 LANGSTANDARD_ALIAS(opencl11, "CL1.1")

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=295113&r1=295112&r2=295113&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Tue Feb 14 16:44:20 2017
@@ -1535,13 +1535,6 @@ static void ParseHeaderSearchArgs(Header
     Opts.AddVFSOverlayFile(A->getValue());
 }
 
-static bool isOpenCL(LangStandard::Kind LangStd) {
-  return LangStd == LangStandard::lang_opencl ||
-         LangStd == LangStandard::lang_opencl11 ||
-         LangStd == LangStandard::lang_opencl12 ||
-         LangStd == LangStandard::lang_opencl20;
-}
-
 void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
                                          const llvm::Triple &T,
                                          PreprocessorOptions &PPOpts,
@@ -1612,7 +1605,7 @@ void CompilerInvocation::setLangDefaults
   Opts.ImplicitInt = Std.hasImplicitInt();
 
   // Set OpenCL Version.
-  Opts.OpenCL = isOpenCL(LangStd) || IK == IK_OpenCL;
+  Opts.OpenCL = Std.isOpenCL() || IK == IK_OpenCL;
   if (LangStd == LangStandard::lang_opencl)
     Opts.OpenCLVersion = 100;
   else if (LangStd == LangStandard::lang_opencl11)
@@ -1681,6 +1674,63 @@ static Visibility parseVisibility(Arg *a
   return DefaultVisibility;
 }
 
+/// Check if input file kind and language standard are compatible.
+static bool IsInputCompatibleWithStandard(InputKind IK,
+                                          const LangStandard &S) {
+  switch (IK) {
+  case IK_C:
+  case IK_ObjC:
+  case IK_PreprocessedC:
+  case IK_PreprocessedObjC:
+    if (S.isC89() || S.isC99())
+      return true;
+    break;
+  case IK_CXX:
+  case IK_ObjCXX:
+  case IK_PreprocessedCXX:
+  case IK_PreprocessedObjCXX:
+    if (S.isCPlusPlus())
+      return true;
+    break;
+  case IK_OpenCL:
+    if (S.isOpenCL())
+      return true;
+    break;
+  case IK_CUDA:
+  case IK_PreprocessedCuda:
+    if (S.isCPlusPlus())
+      return true;
+    break;
+  default:
+    llvm_unreachable("Cannot decide whether language standard and "
+        "input file kind are compatible!");
+  }
+  return false;
+}
+
+/// Get language name for given input kind.
+static const StringRef GetInputKindName(InputKind IK) {
+  switch (IK) {
+  case IK_C:
+  case IK_ObjC:
+  case IK_PreprocessedC:
+  case IK_PreprocessedObjC:
+    return "C/ObjC";
+  case IK_CXX:
+  case IK_ObjCXX:
+  case IK_PreprocessedCXX:
+  case IK_PreprocessedObjCXX:
+    return "C++/ObjC++";
+  case IK_OpenCL:
+    return "OpenCL";
+  case IK_CUDA:
+  case IK_PreprocessedCuda:
+    return "CUDA";
+  default:
+    llvm_unreachable("Cannot decide on name for InputKind!");
+  }
+}
+
 static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
                           const TargetOptions &TargetOpts,
                           PreprocessorOptions &PPOpts,
@@ -1695,43 +1745,27 @@ static void ParseLangArgs(LangOptions &O
       .Case(alias, LangStandard::lang_##id)
 #include "clang/Frontend/LangStandards.def"
       .Default(LangStandard::lang_unspecified);
-    if (LangStd == LangStandard::lang_unspecified)
+    if (LangStd == LangStandard::lang_unspecified) {
       Diags.Report(diag::err_drv_invalid_value)
         << A->getAsString(Args) << A->getValue();
-    else {
+      // Report supported standards with short description.
+      for (unsigned KindValue = 0;
+           KindValue != LangStandard::lang_unspecified;
+           ++KindValue) {
+        const LangStandard &Std = LangStandard::getLangStandardForKind(
+          static_cast<LangStandard::Kind>(KindValue));
+        if (IsInputCompatibleWithStandard(IK, Std)) {
+          Diags.Report(diag::note_drv_use_standard)
+            << Std.getName() << Std.getDescription();
+        }
+      }
+    } else {
       // Valid standard, check to make sure language and standard are
       // compatible.
       const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
-      switch (IK) {
-      case IK_C:
-      case IK_ObjC:
-      case IK_PreprocessedC:
-      case IK_PreprocessedObjC:
-        if (!(Std.isC89() || Std.isC99()))
-          Diags.Report(diag::err_drv_argument_not_allowed_with)
-            << A->getAsString(Args) << "C/ObjC";
-        break;
-      case IK_CXX:
-      case IK_ObjCXX:
-      case IK_PreprocessedCXX:
-      case IK_PreprocessedObjCXX:
-        if (!Std.isCPlusPlus())
-          Diags.Report(diag::err_drv_argument_not_allowed_with)
-            << A->getAsString(Args) << "C++/ObjC++";
-        break;
-      case IK_OpenCL:
-        if (!isOpenCL(LangStd))
-          Diags.Report(diag::err_drv_argument_not_allowed_with)
-            << A->getAsString(Args) << "OpenCL";
-        break;
-      case IK_CUDA:
-      case IK_PreprocessedCuda:
-        if (!Std.isCPlusPlus())
-          Diags.Report(diag::err_drv_argument_not_allowed_with)
-            << A->getAsString(Args) << "CUDA";
-        break;
-      default:
-        break;
+      if (!IsInputCompatibleWithStandard(IK, Std)) {
+        Diags.Report(diag::err_drv_argument_not_allowed_with)
+          << A->getAsString(Args) << GetInputKindName(IK);
       }
     }
   }
@@ -1740,16 +1774,16 @@ static void ParseLangArgs(LangOptions &O
   // Override the -std option in this case.
   if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) {
     LangStandard::Kind OpenCLLangStd
-    = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
-    .Cases("cl", "CL", LangStandard::lang_opencl)
-    .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11)
-    .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12)
-    .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20)
-    .Default(LangStandard::lang_unspecified);
+      = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
+        .Cases("cl", "CL", LangStandard::lang_opencl)
+        .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11)
+        .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12)
+        .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20)
+        .Default(LangStandard::lang_unspecified);
 
     if (OpenCLLangStd == LangStandard::lang_unspecified) {
       Diags.Report(diag::err_drv_invalid_value)
-      << A->getAsString(Args) << A->getValue();
+        << A->getAsString(Args) << A->getValue();
     }
     else
       LangStd = OpenCLLangStd;
@@ -1850,8 +1884,8 @@ static void ParseLangArgs(LangOptions &O
 
   if (Args.hasArg(OPT_fgnu89_inline)) {
     if (Opts.CPlusPlus)
-      Diags.Report(diag::err_drv_argument_not_allowed_with) << "-fgnu89-inline"
-                                                            << "C++/ObjC++";
+      Diags.Report(diag::err_drv_argument_not_allowed_with)
+        << "-fgnu89-inline" << GetInputKindName(IK);
     else
       Opts.GNUInline = 1;
   }

Added: cfe/trunk/test/Driver/unknown-std.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/unknown-std.c?rev=295113&view=auto
==============================================================================
--- cfe/trunk/test/Driver/unknown-std.c (added)
+++ cfe/trunk/test/Driver/unknown-std.c Tue Feb 14 16:44:20 2017
@@ -0,0 +1,34 @@
+// This file checks output given when processing C/ObjC files.
+// When user selects invalid language standard
+// print out supported values with short description.
+
+// RUN: not %clang %s -std=foobar -c 2>&1 | \
+// RUN: FileCheck --match-full-lines %s
+
+// CHECK: error: invalid value 'foobar' in '-std=foobar'
+// CHECK-NEXT: note: use 'c89' for 'ISO C 1990' standard
+// CHECK-NEXT: note: use 'c90' for 'ISO C 1990' standard
+// CHECK-NEXT: note: use 'iso9899:1990' for 'ISO C 1990' standard
+// CHECK-NEXT: note: use 'iso9899:199409' for 'ISO C 1990 with amendment 1' standard
+// CHECK-NEXT: note: use 'gnu89' for 'ISO C 1990 with GNU extensions' standard
+// CHECK-NEXT: note: use 'gnu90' for 'ISO C 1990 with GNU extensions' standard
+// CHECK-NEXT: note: use 'c99' for 'ISO C 1999' standard
+// CHECK-NEXT: note: use 'c9x' for 'ISO C 1999' standard
+// CHECK-NEXT: note: use 'iso9899:1999' for 'ISO C 1999' standard
+// CHECK-NEXT: note: use 'iso9899:199x' for 'ISO C 1999' standard
+// CHECK-NEXT: note: use 'gnu99' for 'ISO C 1999 with GNU extensions' standard
+// CHECK-NEXT: note: use 'gnu9x' for 'ISO C 1999 with GNU extensions' standard
+// CHECK-NEXT: note: use 'c11' for 'ISO C 2011' standard
+// CHECK-NEXT: note: use 'c1x' for 'ISO C 2011' standard
+// CHECK-NEXT: note: use 'iso9899:2011' for 'ISO C 2011' standard
+// CHECK-NEXT: note: use 'iso9899:201x' for 'ISO C 2011' standard
+// CHECK-NEXT: note: use 'gnu11' for 'ISO C 2011 with GNU extensions' standard
+// CHECK-NEXT: note: use 'gnu1x' for 'ISO C 2011 with GNU extensions' standard
+// CHECK-NEXT: note: use 'cl' for 'OpenCL 1.0' standard
+// CHECK-NEXT: note: use 'cl1.1' for 'OpenCL 1.1' standard
+// CHECK-NEXT: note: use 'cl1.2' for 'OpenCL 1.2' standard
+// CHECK-NEXT: note: use 'cl2.0' for 'OpenCL 2.0' standard
+
+// Make sure that no other output is present.
+// CHECK-NOT: {{^.+$}}
+

Added: cfe/trunk/test/Driver/unknown-std.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/unknown-std.cl?rev=295113&view=auto
==============================================================================
--- cfe/trunk/test/Driver/unknown-std.cl (added)
+++ cfe/trunk/test/Driver/unknown-std.cl Tue Feb 14 16:44:20 2017
@@ -0,0 +1,16 @@
+// This file checks output given when processing OpenCL files.
+// When user selects invalid language standard
+// print out supported values with short description.
+
+// RUN: not %clang %s -std=foobar -c 2>&1 | \
+// RUN: FileCheck --match-full-lines %s
+
+// CHECK: error: invalid value 'foobar' in '-std=foobar'
+// CHECK-NEXT: note: use 'cl' for 'OpenCL 1.0' standard
+// CHECK-NEXT: note: use 'cl1.1' for 'OpenCL 1.1' standard
+// CHECK-NEXT: note: use 'cl1.2' for 'OpenCL 1.2' standard
+// CHECK-NEXT: note: use 'cl2.0' for 'OpenCL 2.0' standard
+
+// Make sure that no other output is present.
+// CHECK-NOT: {{^.+$}}
+

Added: cfe/trunk/test/Driver/unknown-std.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/unknown-std.cpp?rev=295113&view=auto
==============================================================================
--- cfe/trunk/test/Driver/unknown-std.cpp (added)
+++ cfe/trunk/test/Driver/unknown-std.cpp Tue Feb 14 16:44:20 2017
@@ -0,0 +1,26 @@
+// This file checks output given when processing C++/ObjC++ files.
+// When user selects invalid language standard
+// print out supported values with short description.
+
+// RUN: not %clang %s -std=foobar -c 2>&1 | \
+// RUN: FileCheck --match-full-lines %s
+
+// CHECK: error: invalid value 'foobar' in '-std=foobar'
+// CHECK-NEXT: note: use 'c++98' for 'ISO C++ 1998 with amendments' standard
+// CHECK-NEXT: note: use 'c++03' for 'ISO C++ 1998 with amendments' standard
+// CHECK-NEXT: note: use 'gnu++98' for 'ISO C++ 1998 with amendments and GNU extensions' standard
+// CHECK-NEXT: note: use 'c++0x' for 'ISO C++ 2011 with amendments' standard
+// CHECK-NEXT: note: use 'c++11' for 'ISO C++ 2011 with amendments' standard
+// CHECK-NEXT: note: use 'gnu++0x' for 'ISO C++ 2011 with amendments and GNU extensions' standard
+// CHECK-NEXT: note: use 'gnu++11' for 'ISO C++ 2011 with amendments and GNU extensions' standard
+// CHECK-NEXT: note: use 'c++1y' for 'ISO C++ 2014 with amendments' standard
+// CHECK-NEXT: note: use 'c++14' for 'ISO C++ 2014 with amendments' standard
+// CHECK-NEXT: note: use 'gnu++1y' for 'ISO C++ 2014 with amendments and GNU extensions' standard
+// CHECK-NEXT: note: use 'gnu++14' for 'ISO C++ 2014 with amendments and GNU extensions' standard
+// CHECK-NEXT: note: use 'c++1z' for 'Working draft for ISO C++ 2017' standard
+// CHECK-NEXT: note: use 'gnu++1z' for 'Working draft for ISO C++ 2017 with GNU extensions' standard
+// CHECK-NEXT: note: use 'cuda' for 'NVIDIA CUDA(tm)' standard
+
+// Make sure that no other output is present.
+// CHECK-NOT: {{^.+$}}
+




More information about the cfe-commits mailing list