From b0fe70451e23a2b5ef19399d286c6a1cdaf5e686 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 26 Apr 2017 23:44:33 +0000 Subject: [PATCH] Don't accept -std= values that would switch us to a different source language. We already prohibited this in most cases (in r130710), but had some bugs in our enforcement of this rule. Specifically, this prevents the following combinations: * -x c -std=clN.M, which would previously effectively act as if -x cl were used, despite the input being a C source file. (-x cl -std=cNN continues to be disallowed.) * -x c++ -std=cuda, which would previously select C++98 + CUDA, despite that not being a C++ standard. (-x cuda -std=c++NN is still permitted, and selects CUDA with the given C++ standard as its base language. -x cuda -std=cuda is still supported with the meaning of CUDA + C++98.) * -x renderscript -std=c++NN, which would previously form a hybrid "C++ with RenderScript extensions" language. We could support such a thing, but shouldn't do so by accident. llvm-svn: 301497 --- clang/include/clang/Frontend/LangStandard.h | 7 ++- clang/include/clang/Frontend/LangStandards.def | 84 +++++++++++++------------- clang/lib/Frontend/CompilerInvocation.cpp | 46 +++++++------- clang/lib/Frontend/LangStandards.cpp | 8 +-- clang/test/Driver/unknown-std.c | 9 +-- clang/test/Driver/unknown-std.cpp | 7 ++- clang/test/Frontend/gnu-inline.c | 4 +- 7 files changed, 87 insertions(+), 78 deletions(-) diff --git a/clang/include/clang/Frontend/LangStandard.h b/clang/include/clang/Frontend/LangStandard.h index 5ead90f..cd92b26 100644 --- a/clang/include/clang/Frontend/LangStandard.h +++ b/clang/include/clang/Frontend/LangStandard.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_FRONTEND_LANGSTANDARD_H #include "clang/Basic/LLVM.h" +#include "clang/Frontend/FrontendOptions.h" #include "llvm/ADT/StringRef.h" namespace clang { @@ -39,7 +40,7 @@ enum LangFeatures { /// standard. struct LangStandard { enum Kind { -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ lang_##id, #include "clang/Frontend/LangStandards.def" lang_unspecified @@ -48,6 +49,7 @@ struct LangStandard { const char *ShortName; const char *Description; unsigned Flags; + InputKind::Language Language; public: /// getName - Get the name of this standard. @@ -56,6 +58,9 @@ public: /// getDescription - Get the description of this standard. const char *getDescription() const { return Description; } + /// Get the language that this standard describes. + InputKind::Language getLanguage() const { return Language; } + /// Language supports '//' comments. bool hasLineComments() const { return Flags & frontend::LineComment; } diff --git a/clang/include/clang/Frontend/LangStandards.def b/clang/include/clang/Frontend/LangStandards.def index 425ac84..cc042bc 100644 --- a/clang/include/clang/Frontend/LangStandards.def +++ b/clang/include/clang/Frontend/LangStandards.def @@ -11,10 +11,11 @@ #error "LANGSTANDARD must be defined before including this file" #endif -/// LANGSTANDARD(IDENT, NAME, DESC, FEATURES) +/// LANGSTANDARD(IDENT, NAME, LANG, DESC, FEATURES) /// /// \param IDENT - The name of the standard as a C++ identifier. /// \param NAME - The name of the standard. +/// \param LANG - The InputKind::Language for which this is a standard. /// \param DESC - A short description of the standard. /// \param FEATURES - The standard features as flags, these are enums from the /// clang::frontend namespace, which is assumed to be be available. @@ -29,128 +30,128 @@ // C89-ish modes. LANGSTANDARD(c89, "c89", - "ISO C 1990", + C, "ISO C 1990", C89 | ImplicitInt) -LANGSTANDARD(c90, "c90", +LANGSTANDARD(c90, "c90", C, "ISO C 1990", C89 | ImplicitInt) LANGSTANDARD(iso9899_1990, "iso9899:1990", - "ISO C 1990", + C, "ISO C 1990", C89 | ImplicitInt) LANGSTANDARD(c94, "iso9899:199409", - "ISO C 1990 with amendment 1", + C, "ISO C 1990 with amendment 1", C89 | Digraphs | ImplicitInt) LANGSTANDARD(gnu89, "gnu89", - "ISO C 1990 with GNU extensions", + C, "ISO C 1990 with GNU extensions", LineComment | C89 | Digraphs | GNUMode | ImplicitInt) LANGSTANDARD(gnu90, "gnu90", - "ISO C 1990 with GNU extensions", + C, "ISO C 1990 with GNU extensions", LineComment | C89 | Digraphs | GNUMode | ImplicitInt) // C99-ish modes LANGSTANDARD(c99, "c99", - "ISO C 1999", + C, "ISO C 1999", LineComment | C99 | Digraphs | HexFloat) LANGSTANDARD(c9x, "c9x", - "ISO C 1999", + C, "ISO C 1999", LineComment | C99 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_1999, - "iso9899:1999", "ISO C 1999", +LANGSTANDARD(iso9899_1999, "iso9899:1999", + C, "ISO C 1999", LineComment | C99 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_199x, - "iso9899:199x", "ISO C 1999", +LANGSTANDARD(iso9899_199x, "iso9899:199x", + C, "ISO C 1999", LineComment | C99 | Digraphs | HexFloat) LANGSTANDARD(gnu99, "gnu99", - "ISO C 1999 with GNU extensions", + C, "ISO C 1999 with GNU extensions", LineComment | C99 | Digraphs | GNUMode | HexFloat) LANGSTANDARD(gnu9x, "gnu9x", - "ISO C 1999 with GNU extensions", + C, "ISO C 1999 with GNU extensions", LineComment | C99 | Digraphs | GNUMode | HexFloat) // C11 modes LANGSTANDARD(c11, "c11", - "ISO C 2011", + C, "ISO C 2011", LineComment | C99 | C11 | Digraphs | HexFloat) LANGSTANDARD(c1x, "c1x", - "ISO C 2011", + C, "ISO C 2011", LineComment | C99 | C11 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_2011, - "iso9899:2011", "ISO C 2011", +LANGSTANDARD(iso9899_2011, "iso9899:2011", + C, "ISO C 2011", LineComment | C99 | C11 | Digraphs | HexFloat) -LANGSTANDARD(iso9899_201x, - "iso9899:201x", "ISO C 2011", +LANGSTANDARD(iso9899_201x, "iso9899:201x", + C, "ISO C 2011", LineComment | C99 | C11 | Digraphs | HexFloat) LANGSTANDARD(gnu11, "gnu11", - "ISO C 2011 with GNU extensions", + C, "ISO C 2011 with GNU extensions", LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) LANGSTANDARD(gnu1x, "gnu1x", - "ISO C 2011 with GNU extensions", + C, "ISO C 2011 with GNU extensions", LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) // C++ modes LANGSTANDARD(cxx98, "c++98", - "ISO C++ 1998 with amendments", + CXX, "ISO C++ 1998 with amendments", LineComment | CPlusPlus | Digraphs) LANGSTANDARD(cxx03, "c++03", - "ISO C++ 1998 with amendments", + CXX, "ISO C++ 1998 with amendments", LineComment | CPlusPlus | Digraphs) LANGSTANDARD(gnucxx98, "gnu++98", - "ISO C++ 1998 with amendments and GNU extensions", + CXX, "ISO C++ 1998 with amendments and GNU extensions", LineComment | CPlusPlus | Digraphs | GNUMode) LANGSTANDARD(cxx0x, "c++0x", - "ISO C++ 2011 with amendments", + CXX, "ISO C++ 2011 with amendments", LineComment | CPlusPlus | CPlusPlus11 | Digraphs) LANGSTANDARD(cxx11, "c++11", - "ISO C++ 2011 with amendments", + CXX, "ISO C++ 2011 with amendments", LineComment | CPlusPlus | CPlusPlus11 | Digraphs) LANGSTANDARD(gnucxx0x, "gnu++0x", - "ISO C++ 2011 with amendments and GNU extensions", + CXX, "ISO C++ 2011 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode) -LANGSTANDARD(gnucxx11, "gnu++11", +LANGSTANDARD(gnucxx11, "gnu++11", CXX, "ISO C++ 2011 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode) LANGSTANDARD(cxx1y, "c++1y", - "ISO C++ 2014 with amendments", + CXX, "ISO C++ 2014 with amendments", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs) LANGSTANDARD(cxx14, "c++14", - "ISO C++ 2014 with amendments", + CXX, "ISO C++ 2014 with amendments", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs) LANGSTANDARD(gnucxx1y, "gnu++1y", - "ISO C++ 2014 with amendments and GNU extensions", + CXX, "ISO C++ 2014 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs | GNUMode) LANGSTANDARD(gnucxx14, "gnu++14", - "ISO C++ 2014 with amendments and GNU extensions", + CXX, "ISO C++ 2014 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs | GNUMode) LANGSTANDARD(cxx1z, "c++1z", - "Working draft for ISO C++ 2017", + CXX, "Working draft for ISO C++ 2017", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | Digraphs | HexFloat) LANGSTANDARD(gnucxx1z, "gnu++1z", - "Working draft for ISO C++ 2017 with GNU extensions", + CXX, "Working draft for ISO C++ 2017 with GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus1z | Digraphs | HexFloat | GNUMode) // OpenCL LANGSTANDARD(opencl, "cl", - "OpenCL 1.0", + OpenCL, "OpenCL 1.0", LineComment | C99 | Digraphs | HexFloat | OpenCL) LANGSTANDARD(opencl11, "cl1.1", - "OpenCL 1.1", + OpenCL, "OpenCL 1.1", LineComment | C99 | Digraphs | HexFloat | OpenCL) LANGSTANDARD(opencl12, "cl1.2", - "OpenCL 1.2", + OpenCL, "OpenCL 1.2", LineComment | C99 | Digraphs | HexFloat | OpenCL) LANGSTANDARD(opencl20, "cl2.0", - "OpenCL 2.0", + OpenCL, "OpenCL 2.0", LineComment | C99 | Digraphs | HexFloat | OpenCL) LANGSTANDARD_ALIAS(opencl, "CL") @@ -159,8 +160,7 @@ LANGSTANDARD_ALIAS(opencl12, "CL1.2") LANGSTANDARD_ALIAS(opencl20, "CL2.0") // CUDA -LANGSTANDARD(cuda, "cuda", - "NVIDIA CUDA(tm)", +LANGSTANDARD(cuda, "cuda", CUDA, "NVIDIA CUDA(tm)", LineComment | CPlusPlus | Digraphs) #undef LANGSTANDARD diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index d74c659..dbbe6af 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1620,7 +1620,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.ImplicitInt = Std.hasImplicitInt(); // Set OpenCL Version. - Opts.OpenCL = Std.isOpenCL() || IK.getLanguage() == InputKind::OpenCL; + Opts.OpenCL = Std.isOpenCL(); if (LangStd == LangStandard::lang_opencl) Opts.OpenCLVersion = 100; else if (LangStd == LangStandard::lang_opencl11) @@ -1644,8 +1644,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, } } - Opts.CUDA = IK.getLanguage() == InputKind::CUDA || - LangStd == LangStandard::lang_cuda; + Opts.CUDA = IK.getLanguage() == InputKind::CUDA; if (Opts.CUDA) // Set default FP_CONTRACT to FAST. Opts.setDefaultFPContractMode(LangOptions::FPC_Fast); @@ -1701,23 +1700,20 @@ static bool IsInputCompatibleWithStandard(InputKind IK, case InputKind::C: case InputKind::ObjC: - // FIXME: Should this really allow OpenCL standards? - return S.isC89() || S.isC99(); + case InputKind::RenderScript: + return S.getLanguage() == InputKind::C; case InputKind::OpenCL: - return S.isOpenCL(); - - case InputKind::RenderScript: - // FIXME: Should this really allow -std=c++98 etc? - return true; + return S.getLanguage() == InputKind::OpenCL; case InputKind::CXX: case InputKind::ObjCXX: - // FIXME: Should this really allow -std=cuda? - return S.isCPlusPlus(); + return S.getLanguage() == InputKind::CXX; case InputKind::CUDA: - return S.isCPlusPlus(); + // FIXME: What -std= values should be permitted for CUDA compilations? + return S.getLanguage() == InputKind::CUDA || + S.getLanguage() == InputKind::CXX; case InputKind::Asm: // Accept (and ignore) all -std= values. @@ -1733,21 +1729,29 @@ static bool IsInputCompatibleWithStandard(InputKind IK, static const StringRef GetInputKindName(InputKind IK) { switch (IK.getLanguage()) { case InputKind::C: + return "C"; case InputKind::ObjC: - // FIXME: Don't lump these together. - return "C/ObjC"; + return "Objective-C"; case InputKind::CXX: + return "C++"; case InputKind::ObjCXX: - // FIXME: Don't lump these together. - return "C++/ObjC++"; + return "Objective-C++"; case InputKind::OpenCL: return "OpenCL"; case InputKind::CUDA: return "CUDA"; - // FIXME: Include names for other options, and make this switch exhaustive. - default: - llvm_unreachable("Cannot decide on name for InputKind!"); + case InputKind::RenderScript: + return "RenderScript"; + + case InputKind::Asm: + return "Asm"; + case InputKind::LLVM_IR: + return "LLVM IR"; + + case InputKind::Unknown: + break; } + llvm_unreachable("unknown input language"); } static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, @@ -1758,7 +1762,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, LangStandard::Kind LangStd = LangStandard::lang_unspecified; if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { LangStd = llvm::StringSwitch(A->getValue()) -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ .Case(name, LangStandard::lang_##id) #define LANGSTANDARD_ALIAS(id, alias) \ .Case(alias, LangStandard::lang_##id) diff --git a/clang/lib/Frontend/LangStandards.cpp b/clang/lib/Frontend/LangStandards.cpp index f133327..47023e5 100644 --- a/clang/lib/Frontend/LangStandards.cpp +++ b/clang/lib/Frontend/LangStandards.cpp @@ -13,15 +13,15 @@ using namespace clang; using namespace clang::frontend; -#define LANGSTANDARD(id, name, desc, features) \ - static const LangStandard Lang_##id = { name, desc, features }; +#define LANGSTANDARD(id, name, lang, desc, features) \ +static const LangStandard Lang_##id = { name, desc, features, InputKind::lang }; #include "clang/Frontend/LangStandards.def" const LangStandard &LangStandard::getLangStandardForKind(Kind K) { switch (K) { case lang_unspecified: llvm::report_fatal_error("getLangStandardForKind() on unspecified kind"); -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ case lang_##id: return Lang_##id; #include "clang/Frontend/LangStandards.def" } @@ -30,7 +30,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) { const LangStandard *LangStandard::getLangStandardForName(StringRef Name) { Kind K = llvm::StringSwitch(Name) -#define LANGSTANDARD(id, name, desc, features) \ +#define LANGSTANDARD(id, name, lang, desc, features) \ .Case(name, lang_##id) #include "clang/Frontend/LangStandards.def" .Default(lang_unspecified); diff --git a/clang/test/Driver/unknown-std.c b/clang/test/Driver/unknown-std.c index ba3035fd..047726f 100644 --- a/clang/test/Driver/unknown-std.c +++ b/clang/test/Driver/unknown-std.c @@ -2,8 +2,9 @@ // 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 +// RUN: not %clang %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s +// RUN: not %clang -x objective-c %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s +// RUN: not %clang -x renderscript %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s // CHECK: error: invalid value 'foobar' in '-std=foobar' // CHECK-NEXT: note: use 'c89' for 'ISO C 1990' standard @@ -24,10 +25,6 @@ // 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: {{^.+$}} diff --git a/clang/test/Driver/unknown-std.cpp b/clang/test/Driver/unknown-std.cpp index faeb2cb..0ffc1e2 100644 --- a/clang/test/Driver/unknown-std.cpp +++ b/clang/test/Driver/unknown-std.cpp @@ -2,8 +2,9 @@ // 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 +// RUN: not %clang %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s +// RUN: not %clang -x objective-c++ %s -std=foobar -c 2>&1 | FileCheck --match-full-lines %s +// RUN: not %clang -x cuda -nocudainc -nocudalib %s -std=foobar -c 2>&1 | FileCheck --match-full-lines --check-prefix=CHECK --check-prefix=CUDA %s // CHECK: error: invalid value 'foobar' in '-std=foobar' // CHECK-NEXT: note: use 'c++98' for 'ISO C++ 1998 with amendments' standard @@ -19,7 +20,7 @@ // 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 +// CUDA-NEXT: note: use 'cuda' for 'NVIDIA CUDA(tm)' standard // Make sure that no other output is present. // CHECK-NOT: {{^.+$}} diff --git a/clang/test/Frontend/gnu-inline.c b/clang/test/Frontend/gnu-inline.c index 0272df7..75d4fe6 100644 --- a/clang/test/Frontend/gnu-inline.c +++ b/clang/test/Frontend/gnu-inline.c @@ -3,8 +3,10 @@ // RUN: %clang_cc1 -std=c99 -fgnu89-inline -fsyntax-only -x c -E -dM %s | FileCheck --check-prefix=GNU-INLINE %s // RUN: %clang_cc1 -fsyntax-only -x c++ -E -dM %s | FileCheck --check-prefix=GNU-INLINE %s // RUN: not %clang_cc1 -fgnu89-inline -fsyntax-only -x c++ %s 2>&1 | FileCheck --check-prefix=CXX %s +// RUN: not %clang_cc1 -fgnu89-inline -fsyntax-only -x objective-c++ %s 2>&1 | FileCheck --check-prefix=OBJCXX %s -// CXX: '-fgnu89-inline' not allowed with 'C++/ObjC++' +// CXX: '-fgnu89-inline' not allowed with 'C++' +// OBJCXX: '-fgnu89-inline' not allowed with 'Objective-C++' // STDC-INLINE-NOT: __GNUC_GNU_INLINE__ // STDC-INLINE: #define __GNUC_STDC_INLINE__ 1 -- 2.7.4