88 changes: 45 additions & 43 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ static Optional<bool> normalizeSimpleNegativeFlag(OptSpecifier Opt, unsigned,
/// argument.
static void denormalizeSimpleFlag(SmallVectorImpl<const char *> &Args,
const char *Spelling,
CompilerInvocation::StringAllocator, unsigned,
/*T*/...) {
CompilerInvocation::StringAllocator,
Option::OptionClass, unsigned, /*T*/...) {
Args.push_back(Spelling);
}

Expand Down Expand Up @@ -200,12 +200,41 @@ static auto makeBooleanOptionNormalizer(bool Value, bool OtherValue,

static auto makeBooleanOptionDenormalizer(bool Value) {
return [Value](SmallVectorImpl<const char *> &Args, const char *Spelling,
CompilerInvocation::StringAllocator, unsigned, bool KeyPath) {
CompilerInvocation::StringAllocator, Option::OptionClass,
unsigned, bool KeyPath) {
if (KeyPath == Value)
Args.push_back(Spelling);
};
}

static void denormalizeStringImpl(SmallVectorImpl<const char *> &Args,
const char *Spelling,
CompilerInvocation::StringAllocator SA,
Option::OptionClass OptClass, unsigned,
Twine Value) {
switch (OptClass) {
case Option::SeparateClass:
case Option::JoinedOrSeparateClass:
Args.push_back(Spelling);
Args.push_back(SA(Value));
break;
case Option::JoinedClass:
Args.push_back(SA(Twine(Spelling) + Value));
break;
default:
llvm_unreachable("Cannot denormalize an option with option class "
"incompatible with string denormalization.");
}
}

template <typename T>
static void
denormalizeString(SmallVectorImpl<const char *> &Args, const char *Spelling,
CompilerInvocation::StringAllocator SA,
Option::OptionClass OptClass, unsigned TableIndex, T Value) {
denormalizeStringImpl(Args, Spelling, SA, OptClass, TableIndex, Twine(Value));
}

static Optional<SimpleEnumValue>
findValueTableByName(const SimpleEnumValueTable &Table, StringRef Name) {
for (int I = 0, E = Table.Size; I != E; ++I)
Expand Down Expand Up @@ -247,12 +276,13 @@ static llvm::Optional<unsigned> normalizeSimpleEnum(OptSpecifier Opt,
static void denormalizeSimpleEnumImpl(SmallVectorImpl<const char *> &Args,
const char *Spelling,
CompilerInvocation::StringAllocator SA,
Option::OptionClass OptClass,
unsigned TableIndex, unsigned Value) {
assert(TableIndex < SimpleEnumValueTablesSize);
const SimpleEnumValueTable &Table = SimpleEnumValueTables[TableIndex];
if (auto MaybeEnumVal = findValueTableByValue(Table, Value)) {
Args.push_back(Spelling);
Args.push_back(MaybeEnumVal->Name);
denormalizeString(Args, Spelling, SA, OptClass, TableIndex,
MaybeEnumVal->Name);
} else {
llvm_unreachable("The simple enum value was not correctly defined in "
"the tablegen option description");
Expand All @@ -263,24 +293,12 @@ template <typename T>
static void denormalizeSimpleEnum(SmallVectorImpl<const char *> &Args,
const char *Spelling,
CompilerInvocation::StringAllocator SA,
Option::OptionClass OptClass,
unsigned TableIndex, T Value) {
return denormalizeSimpleEnumImpl(Args, Spelling, SA, TableIndex,
return denormalizeSimpleEnumImpl(Args, Spelling, SA, OptClass, TableIndex,
static_cast<unsigned>(Value));
}

static void denormalizeSimpleEnumJoined(SmallVectorImpl<const char *> &Args,
const char *Spelling,
CompilerInvocation::StringAllocator SA,
unsigned TableIndex, unsigned Value) {
assert(TableIndex < SimpleEnumValueTablesSize);
const SimpleEnumValueTable &Table = SimpleEnumValueTables[TableIndex];
if (auto MaybeEnumVal = findValueTableByValue(Table, Value))
Args.push_back(SA(Twine(Spelling) + MaybeEnumVal->Name));
else
llvm_unreachable("The simple enum value was not correctly defined in "
"the tablegen option description");
}

static Optional<std::string> normalizeString(OptSpecifier Opt, int TableIndex,
const ArgList &Args,
DiagnosticsEngine &Diags) {
Expand All @@ -290,25 +308,6 @@ static Optional<std::string> normalizeString(OptSpecifier Opt, int TableIndex,
return std::string(Arg->getValue());
}

static void denormalizeString(SmallVectorImpl<const char *> &Args,
const char *Spelling,
CompilerInvocation::StringAllocator SA, unsigned,
Twine Value) {
Args.push_back(Spelling);
Args.push_back(SA(Value));
}

template <typename T,
std::enable_if_t<!std::is_convertible<T, Twine>::value &&
std::is_constructible<Twine, T>::value,
bool> = false>
static void denormalizeString(SmallVectorImpl<const char *> &Args,
const char *Spelling,
CompilerInvocation::StringAllocator SA,
unsigned TableIndex, T Value) {
denormalizeString(Args, Spelling, SA, TableIndex, Twine(Value));
}

template <typename IntTy>
static Optional<IntTy> normalizeStringIntegral(OptSpecifier Opt, int,
const ArgList &Args,
Expand Down Expand Up @@ -2278,11 +2277,13 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
// -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.SYCLVersion = llvm::StringSwitch<unsigned>(A->getValue())
.Cases("2017", "1.2.1", "121", "sycl-1.2.1", 2017)
.Default(0U);
Opts.setSYCLVersion(
llvm::StringSwitch<LangOptions::SYCLMajorVersion>(A->getValue())
.Cases("2017", "1.2.1", "121", "sycl-1.2.1",
LangOptions::SYCL_2017)
.Default(LangOptions::SYCL_None));

if (Opts.SYCLVersion == 0U) {
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();
Expand Down Expand Up @@ -3267,7 +3268,8 @@ void CompilerInvocation::generateCC1CommandLine(
(Extracted != \
static_cast<decltype(this->KEYPATH)>( \
(IMPLIED_CHECK) ? (IMPLIED_VALUE) : (DEFAULT_VALUE)))) \
DENORMALIZER(Args, SPELLING, SA, TABLE_INDEX, Extracted); \
DENORMALIZER(Args, SPELLING, SA, Option::KIND##Class, TABLE_INDEX, \
Extracted); \
}(EXTRACTOR(this->KEYPATH)); \
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Frontend/InitPreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,

if (LangOpts.SYCL) {
// SYCL Version is set to a value when building SYCL applications
if (LangOpts.SYCLVersion == 2017)
if (LangOpts.getSYCLVersion() == LangOptions::SYCL_2017)
Builder.defineMacro("CL_SYCL_LANGUAGE_VERSION", "121");
}

Expand Down
44 changes: 42 additions & 2 deletions clang/unittests/Frontend/CompilerInvocationTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,30 +342,70 @@ TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredAbsent) {
ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str())));
}

TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateEnumNonDefault) {
TEST_F(CommandLineTest, SeparateEnumNonDefault) {
const char *Args[] = {"-mrelocation-model", "static"};

CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);

ASSERT_FALSE(Diags->hasErrorOccurred());
ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::Static);

Invocation.generateCC1CommandLine(GeneratedArgs, *this);

// Non default relocation model.
ASSERT_THAT(GeneratedArgs, Contains(StrEq("-mrelocation-model")));
ASSERT_THAT(GeneratedArgs, Contains(StrEq("static")));
ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=static"))));
}

TEST_F(CommandLineTest, CanGenerateCC1COmmandLineSeparateEnumDefault) {
TEST_F(CommandLineTest, SeparateEnumDefault) {
const char *Args[] = {"-mrelocation-model", "pic"};

CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);

ASSERT_FALSE(Diags->hasErrorOccurred());
ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::PIC_);

Invocation.generateCC1CommandLine(GeneratedArgs, *this);

// Default relocation model.
ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model"))));
ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("pic"))));
ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=pic"))));
}

TEST_F(CommandLineTest, JoinedEnumNonDefault) {
const char *Args[] = {"-fobjc-dispatch-method=non-legacy"};

CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);

ASSERT_FALSE(Diags->hasErrorOccurred());
ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(),
CodeGenOptions::NonLegacy);

Invocation.generateCC1CommandLine(GeneratedArgs, *this);

ASSERT_THAT(GeneratedArgs,
Contains(StrEq("-fobjc-dispatch-method=non-legacy")));
ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method="))));
ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("non-legacy"))));
}

TEST_F(CommandLineTest, JoinedEnumDefault) {
const char *Args[] = {"-fobjc-dispatch-method=legacy"};

CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);

ASSERT_FALSE(Diags->hasErrorOccurred());
ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(),
CodeGenOptions::Legacy);

Invocation.generateCC1CommandLine(GeneratedArgs, *this);

ASSERT_THAT(GeneratedArgs,
Not(Contains(StrEq("-fobjc-dispatch-method=legacy"))));
ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method="))));
ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("legacy"))));
}

// Tree of boolean options that can be (directly or transitively) implied by
Expand Down
12 changes: 6 additions & 6 deletions llvm/include/llvm/Option/OptParser.td
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ class MarshallingInfoFlag<code keypath, code defaultvalue = "false">
code Denormalizer = "denormalizeSimpleFlag";
}

class MarshallingInfoNegativeFlag<code keypath, code defaultvalue = "true">
: MarshallingInfo<keypath, defaultvalue> {
code Normalizer = "normalizeSimpleNegativeFlag";
code Denormalizer = "denormalizeSimpleFlag";
}

class MarshallingInfoBitfieldFlag<code keypath, code value>
: MarshallingInfoFlag<keypath, "0u"> {
code Normalizer = "makeFlagToValueNormalizer("#value#")";
Expand All @@ -190,9 +196,6 @@ class MarshallingInfoBooleanFlag<code keypath, code defaultvalue, code value, co

// Mixins for additional marshalling attributes.

class IsNegative {
code Normalizer = "normalizeSimpleNegativeFlag";
}
class AlwaysEmit { bit ShouldAlwaysEmit = true; }
class Normalizer<code normalizer> { code Normalizer = normalizer; }
class Denormalizer<code denormalizer> { code Denormalizer = denormalizer; }
Expand All @@ -202,9 +205,6 @@ class AutoNormalizeEnum {
code Normalizer = "normalizeSimpleEnum";
code Denormalizer = "denormalizeSimpleEnum";
}
class AutoNormalizeEnumJoined : AutoNormalizeEnum {
code Denormalizer = "denormalizeSimpleEnumJoined";
}
class ValueMerger<code merger> { code ValueMerger = merger; }
class ValueExtractor<code extractor> { code ValueExtractor = extractor; }

Expand Down