diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4091,7 +4091,9 @@ BothFlags<[CoreOption], " SYCL kernels compilation for device">, "f">, Group; def sycl_std_EQ : Joined<["-"], "sycl-std=">, Group, Flags<[CC1Option, NoArgumentUnused, CoreOption]>, - HelpText<"SYCL language standard to compile for.">, Values<"2017, 121, 1.2.1, sycl-1.2.1">; + HelpText<"SYCL language standard to compile for.">, Values<"2017,121,1.2.1,sycl-1.2.1">, + NormalizedValues<["SYCL_2017", "SYCL_2017", "SYCL_2017", "SYCL_2017"]>, NormalizedValuesScope<"LangOptions">, + MarshallingInfoString<"LangOpts->SYCLVersion", "SYCL_None">, ShouldParseIf, AutoNormalizeEnum; //===----------------------------------------------------------------------===// // FlangOption and FC1 Options diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2282,23 +2282,6 @@ } Opts.SYCLIsDevice = Opts.SYCL && Args.hasArg(options::OPT_fsycl_is_device); - if (Opts.SYCL) { - // -sycl-std applies to any SYCL source, not only those containing kernels, - // but also those using the SYCL API - if (const Arg *A = Args.getLastArg(OPT_sycl_std_EQ)) { - Opts.setSYCLVersion( - llvm::StringSwitch(A->getValue()) - .Cases("2017", "1.2.1", "121", "sycl-1.2.1", - LangOptions::SYCL_2017) - .Default(LangOptions::SYCL_None)); - - if (Opts.getSYCLVersion() == LangOptions::SYCL_None) { - // User has passed an invalid value to the flag, this is an error - Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(); - } - } - } llvm::Triple T(TargetOpts.Triple); CompilerInvocation::setLangDefaults(Opts, IK, T, PPOpts, LangStd); @@ -3003,16 +2986,17 @@ DiagnosticsEngine &Diags) { #define OPTION_WITH_MARSHALLING( \ PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, \ - TABLE_INDEX) \ + HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ + DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ + MERGER, EXTRACTOR, TABLE_INDEX) \ if ((FLAGS)&options::CC1Option) { \ this->KEYPATH = MERGER(this->KEYPATH, DEFAULT_VALUE); \ if (IMPLIED_CHECK) \ this->KEYPATH = MERGER(this->KEYPATH, IMPLIED_VALUE); \ - if (auto MaybeValue = NORMALIZER(OPT_##ID, TABLE_INDEX, Args, Diags)) \ - this->KEYPATH = MERGER( \ - this->KEYPATH, static_castKEYPATH)>(*MaybeValue)); \ + if (SHOULD_PARSE) \ + if (auto MaybeValue = NORMALIZER(OPT_##ID, TABLE_INDEX, Args, Diags)) \ + this->KEYPATH = MERGER( \ + this->KEYPATH, static_castKEYPATH)>(*MaybeValue)); \ } #include "clang/Driver/Options.inc" @@ -3265,9 +3249,9 @@ // with lifetime extension of the reference. #define OPTION_WITH_MARSHALLING( \ PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR, VALUES, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \ - IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, \ - TABLE_INDEX) \ + HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \ + DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \ + MERGER, EXTRACTOR, TABLE_INDEX) \ if ((FLAGS)&options::CC1Option) { \ [&](const auto &Extracted) { \ if (ALWAYS_EMIT || \ diff --git a/clang/unittests/Frontend/CompilerInvocationTest.cpp b/clang/unittests/Frontend/CompilerInvocationTest.cpp --- a/clang/unittests/Frontend/CompilerInvocationTest.cpp +++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp @@ -448,6 +448,68 @@ ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=b")), 1); } +// A flag that should be parsed only if a condition is met. + +TEST_F(CommandLineTest, ConditionalParsingIfFalseFlagNotPresent) { + const char *Args[] = {""}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_FALSE(Invocation.getLangOpts()->SYCL); + ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None); + + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + + ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl")))); + ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std=")))); +} + +TEST_F(CommandLineTest, ConditionalParsingIfFalseFlagPresent) { + const char *Args[] = {"-sycl-std=2017"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_FALSE(Invocation.getLangOpts()->SYCL); + ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None); + + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + + ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl")))); + ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std=")))); +} + +TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagNotPresent) { + const char *Args[] = {"-fsycl"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_TRUE(Invocation.getLangOpts()->SYCL); + ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None); + + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + + ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl"))); + ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std=")))); +} + +TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagPresent) { + const char *Args[] = {"-fsycl", "-sycl-std=2017"}; + + CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); + + ASSERT_FALSE(Diags->hasErrorOccurred()); + ASSERT_TRUE(Invocation.getLangOpts()->SYCL); + ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_2017); + + Invocation.generateCC1CommandLine(GeneratedArgs, *this); + + ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl"))); + ASSERT_THAT(GeneratedArgs, Contains(StrEq("-sycl-std=2017"))); +} + // Wide integer option. TEST_F(CommandLineTest, WideIntegerHighValue) { diff --git a/llvm/include/llvm/Option/OptParser.td b/llvm/include/llvm/Option/OptParser.td --- a/llvm/include/llvm/Option/OptParser.td +++ b/llvm/include/llvm/Option/OptParser.td @@ -101,6 +101,7 @@ code DefaultValue = ?; code ImpliedValue = ?; code ImpliedCheck = "false"; + code ShouldParse = "true"; bit ShouldAlwaysEmit = false; code NormalizerRetTy = ?; code NormalizedValuesScope = ""; @@ -202,6 +203,7 @@ // Mixins for additional marshalling attributes. +class ShouldParseIf { code ShouldParse = condition; } class AlwaysEmit { bit ShouldAlwaysEmit = true; } class Normalizer { code Normalizer = normalizer; } class Denormalizer { code Denormalizer = denormalizer; } diff --git a/llvm/utils/TableGen/OptParserEmitter.cpp b/llvm/utils/TableGen/OptParserEmitter.cpp --- a/llvm/utils/TableGen/OptParserEmitter.cpp +++ b/llvm/utils/TableGen/OptParserEmitter.cpp @@ -71,6 +71,7 @@ StringRef NormalizedValuesScope; StringRef ImpliedCheck; StringRef ImpliedValue; + StringRef ShouldParse; StringRef Normalizer; StringRef Denormalizer; StringRef ValueMerger; @@ -102,6 +103,8 @@ void emit(raw_ostream &OS) const { write_cstring(OS, StringRef(getOptionSpelling(R))); OS << ", "; + OS << ShouldParse; + OS << ", "; OS << ShouldAlwaysEmit; OS << ", "; OS << KeyPath; @@ -167,6 +170,7 @@ Ret.ImpliedValue = R.getValueAsOptionalString("ImpliedValue").getValueOr(Ret.DefaultValue); + Ret.ShouldParse = R.getValueAsString("ShouldParse"); Ret.Normalizer = R.getValueAsString("Normalizer"); Ret.Denormalizer = R.getValueAsString("Denormalizer"); Ret.ValueMerger = R.getValueAsString("ValueMerger");