[Options] Add prefixes to options.
Each option has a set of prefixes. When matching an argument such as
-funroll-loops. First the leading - is removed as it is a prefix. Then
a lower_bound search for "funroll-loops" is done against the option table by
option name. From there each option prefix + option name combination is tested
against the argument.
This allows us to support Microsoft style options where both / and - are valid
prefixes. It also simplifies the cases we already have where options come in
both - and -- forms. Almost every option for gnu-ld happens to have this form.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166444 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp
index b156d7c..2431051 100644
--- a/lib/Driver/Arg.cpp
+++ b/lib/Driver/Arg.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Arg.h"
+#include "clang/Basic/LLVM.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Option.h"
#include "llvm/ADT/SmallString.h"
@@ -15,22 +16,23 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang::driver;
+using clang::StringRef;
-Arg::Arg(const Option _Opt, unsigned _Index, const Arg *_BaseArg)
- : Opt(_Opt), BaseArg(_BaseArg), Index(_Index),
+Arg::Arg(const Option _Opt, StringRef S, unsigned _Index, const Arg *_BaseArg)
+ : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
Claimed(false), OwnsValues(false) {
}
-Arg::Arg(const Option _Opt, unsigned _Index,
+Arg::Arg(const Option _Opt, StringRef S, unsigned _Index,
const char *Value0, const Arg *_BaseArg)
- : Opt(_Opt), BaseArg(_BaseArg), Index(_Index),
+ : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
Claimed(false), OwnsValues(false) {
Values.push_back(Value0);
}
-Arg::Arg(const Option _Opt, unsigned _Index,
+Arg::Arg(const Option _Opt, StringRef S, unsigned _Index,
const char *Value0, const char *Value1, const Arg *_BaseArg)
- : Opt(_Opt), BaseArg(_BaseArg), Index(_Index),
+ : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
Claimed(false), OwnsValues(false) {
Values.push_back(Value0);
Values.push_back(Value1);
@@ -96,7 +98,7 @@
case Option::RenderCommaJoinedStyle: {
SmallString<256> Res;
llvm::raw_svector_ostream OS(Res);
- OS << getOption().getName();
+ OS << getSpelling();
for (unsigned i = 0, e = getNumValues(); i != e; ++i) {
if (i) OS << ',';
OS << getValue(Args, i);
@@ -107,13 +109,13 @@
case Option::RenderJoinedStyle:
Output.push_back(Args.GetOrMakeJoinedArgString(
- getIndex(), getOption().getName(), getValue(Args, 0)));
+ getIndex(), getSpelling(), getValue(Args, 0)));
for (unsigned i = 1, e = getNumValues(); i != e; ++i)
Output.push_back(getValue(Args, i));
break;
case Option::RenderSeparateStyle:
- Output.push_back(getOption().getName().data());
+ Output.push_back(Args.MakeArgString(getSpelling()));
for (unsigned i = 0, e = getNumValues(); i != e; ++i)
Output.push_back(getValue(Args, i));
break;
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index 3b824f7..28d6b1e 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -363,7 +363,9 @@
}
Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option Opt) const {
- Arg *A = new Arg(Opt, BaseArgs.MakeIndex(Opt.getName()), BaseArg);
+ Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
+ Twine(Opt.getName())),
+ BaseArgs.MakeIndex(Opt.getName()), BaseArg);
SynthesizedArgs.push_back(A);
return A;
}
@@ -371,7 +373,9 @@
Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const {
unsigned Index = BaseArgs.MakeIndex(Value);
- Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index), BaseArg);
+ Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
+ Twine(Opt.getName())),
+ Index, BaseArgs.getArgString(Index), BaseArg);
SynthesizedArgs.push_back(A);
return A;
}
@@ -379,7 +383,9 @@
Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const {
unsigned Index = BaseArgs.MakeIndex(Opt.getName(), Value);
- Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index + 1), BaseArg);
+ Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
+ Twine(Opt.getName())),
+ Index, BaseArgs.getArgString(Index + 1), BaseArg);
SynthesizedArgs.push_back(A);
return A;
}
@@ -387,7 +393,8 @@
Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const {
unsigned Index = BaseArgs.MakeIndex(Opt.getName().str() + Value.str());
- Arg *A = new Arg(Opt, Index,
+ Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
+ Twine(Opt.getName())), Index,
BaseArgs.getArgString(Index) + Opt.getName().size(),
BaseArg);
SynthesizedArgs.push_back(A);
diff --git a/lib/Driver/CC1AsOptions.cpp b/lib/Driver/CC1AsOptions.cpp
index cc7c7a4..4f89b73 100644
--- a/lib/Driver/CC1AsOptions.cpp
+++ b/lib/Driver/CC1AsOptions.cpp
@@ -15,11 +15,19 @@
using namespace clang::driver::options;
using namespace clang::driver::cc1asoptions;
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR)
+#include "clang/Driver/CC1AsOptions.inc"
+#undef OPTION
+#undef PREFIX
+
static const OptTable::Info CC1AsInfoTable[] = {
-#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#define PREFIX(NAME, VALUE)
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
- { NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, FLAGS, \
- OPT_##GROUP, OPT_##ALIAS },
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
+ FLAGS, OPT_##GROUP, OPT_##ALIAS },
#include "clang/Driver/CC1AsOptions.inc"
};
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 59cebf5..31492a7 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -608,7 +608,7 @@
it != ie; ++it, ++i) {
Arg *A = *it;
llvm::errs() << "Option " << i << " - "
- << "Name: \"" << A->getOption().getName() << "\", "
+ << "Name: \"" << A->getOption().getPrefixedName() << "\", "
<< "Values: {";
for (unsigned j = 0; j < A->getNumValues(); ++j) {
if (j)
diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index f9d36cf..3925b8a 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -14,11 +14,19 @@
using namespace clang::driver;
using namespace clang::driver::options;
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR)
+#include "clang/Driver/Options.inc"
+#undef OPTION
+#undef PREFIX
+
static const OptTable::Info InfoTable[] = {
-#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+#define PREFIX(NAME, VALUE)
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
- { NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, FLAGS, \
- OPT_##GROUP, OPT_##ALIAS },
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
+ FLAGS, OPT_##GROUP, OPT_##ALIAS },
#include "clang/Driver/Options.inc"
};
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
index a1c5ecd..db59298 100644
--- a/lib/Driver/OptTable.cpp
+++ b/lib/Driver/OptTable.cpp
@@ -55,6 +55,13 @@
if (int N = StrCmpOptionName(A.Name, B.Name))
return N == -1;
+ for (const char * const *APre = A.Prefixes,
+ * const *BPre = B.Prefixes;
+ *APre != 0 && *BPre != 0; ++APre, ++BPre) {
+ if (int N = StrCmpOptionName(*APre, *BPre))
+ return N == -1;
+ }
+
// Names are the same, check that classes are in order; exactly one
// should be joined, and it should succeed the other.
assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
@@ -123,6 +130,26 @@
}
}
#endif
+
+ // Build prefixes.
+ for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) {
+ if (const char *const *P = getInfo(i).Prefixes) {
+ for (; *P != 0; ++P) {
+ PrefixesUnion.insert(*P);
+ }
+ }
+ }
+
+ // Build prefix chars.
+ for (llvm::StringSet<>::const_iterator I = PrefixesUnion.begin(),
+ E = PrefixesUnion.end(); I != E; ++I) {
+ StringRef Prefix = I->getKey();
+ for (StringRef::const_iterator C = Prefix.begin(), CE = Prefix.end();
+ C != CE; ++C)
+ if (std::find(PrefixChars.begin(), PrefixChars.end(), *C)
+ == PrefixChars.end())
+ PrefixChars.push_back(*C);
+ }
}
OptTable::~OptTable() {
@@ -140,19 +167,41 @@
return getInfo(id).Flags & options::HelpHidden;
}
+static bool isInput(const llvm::StringSet<> &Prefixes, StringRef Arg) {
+ if (Arg == "-")
+ return true;
+ for (llvm::StringSet<>::const_iterator I = Prefixes.begin(),
+ E = Prefixes.end(); I != E; ++I)
+ if (Arg.startswith(I->getKey()))
+ return false;
+ return true;
+}
+
+/// \returns Matched size. 0 means no match.
+static unsigned matchOption(const OptTable::Info *I, StringRef Str) {
+ for (const char * const *Pre = I->Prefixes; *Pre != 0; ++Pre) {
+ StringRef Prefix(*Pre);
+ if (Str.startswith(Prefix) && Str.substr(Prefix.size()).startswith(I->Name))
+ return Prefix.size() + StringRef(I->Name).size();
+ }
+ return 0;
+}
+
Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
unsigned Prev = Index;
const char *Str = Args.getArgString(Index);
- // Anything that doesn't start with '-' is an input, as is '-' itself.
- if (Str[0] != '-' || Str[1] == '\0')
- return new Arg(getOption(TheInputOptionID), Index++, Str);
+ // Anything that doesn't start with PrefixesUnion is an input, as is '-'
+ // itself.
+ if (isInput(PrefixesUnion, Str))
+ return new Arg(getOption(TheInputOptionID), Str, Index++, Str);
const Info *Start = OptionInfos + FirstSearchableIndex;
const Info *End = OptionInfos + getNumOptions();
+ StringRef Name = StringRef(Str).ltrim(PrefixChars);
// Search for the first next option which could be a prefix.
- Start = std::lower_bound(Start, End, Str);
+ Start = std::lower_bound(Start, End, Name.data());
// Options are stored in sorted order, with '\0' at the end of the
// alphabet. Since the only options which can accept a string must
@@ -162,17 +211,17 @@
// FIXME: This is searching much more than necessary, but I am
// blanking on the simplest way to make it fast. We can solve this
// problem when we move to TableGen.
- StringRef StrRef(Str);
for (; Start != End; ++Start) {
+ unsigned ArgSize = 0;
// Scan for first option which is a proper prefix.
for (; Start != End; ++Start)
- if (StrRef.startswith(Start->Name))
+ if ((ArgSize = matchOption(Start, Str)))
break;
if (Start == End)
break;
// See if this option matches.
- if (Arg *A = getOption(Start - OptionInfos + 1).accept(Args, Index))
+ if (Arg *A = Option(Start, this).accept(Args, Index, ArgSize))
return A;
// Otherwise, see if this argument was missing values.
@@ -180,7 +229,7 @@
return 0;
}
- return new Arg(getOption(TheUnknownOptionID), Index++, Str);
+ return new Arg(getOption(TheUnknownOptionID), Str, Index++, Str);
}
InputArgList *OptTable::ParseArgs(const char* const *ArgBegin,
@@ -220,10 +269,11 @@
}
static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
- std::string Name = Opts.getOptionName(Id);
+ const Option O = Opts.getOption(Id);
+ std::string Name = O.getPrefixedName();
// Add metavar, if used.
- switch (Opts.getOptionKind(Id)) {
+ switch (O.getKind()) {
case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
llvm_unreachable("Invalid option with help text.");
diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp
index e9440c5..a22cb15 100644
--- a/lib/Driver/Option.cpp
+++ b/lib/Driver/Option.cpp
@@ -48,6 +48,12 @@
#undef P
}
+ llvm::errs() << " Prefixes:[";
+ for (const char * const *Pre = Info->Prefixes; *Pre != 0; ++Pre) {
+ llvm::errs() << '"' << *Pre << (*(Pre + 1) == 0 ? "\"" : "\", ");
+ }
+ llvm::errs() << ']';
+
llvm::errs() << " Name:\"" << getName() << '"';
const Option Group = getGroup();
@@ -84,21 +90,24 @@
return false;
}
-Arg *Option::accept(const ArgList &Args, unsigned &Index) const {
+Arg *Option::accept(const ArgList &Args,
+ unsigned &Index,
+ unsigned ArgSize) const {
+ StringRef Spelling(Args.getArgString(Index), ArgSize);
switch (getKind()) {
case FlagClass:
- if (getName().size() != strlen(Args.getArgString(Index)))
+ if (ArgSize != strlen(Args.getArgString(Index)))
return 0;
- return new Arg(getUnaliasedOption(), Index++);
+ return new Arg(getUnaliasedOption(), Spelling, Index++);
case JoinedClass: {
- const char *Value = Args.getArgString(Index) + getName().size();
- return new Arg(getUnaliasedOption(), Index++, Value);
+ const char *Value = Args.getArgString(Index) + ArgSize;
+ return new Arg(getUnaliasedOption(), Spelling, Index++, Value);
}
case CommaJoinedClass: {
// Always matches.
- const char *Str = Args.getArgString(Index) + getName().size();
- Arg *A = new Arg(getUnaliasedOption(), Index++);
+ const char *Str = Args.getArgString(Index) + ArgSize;
+ Arg *A = new Arg(getUnaliasedOption(), Spelling, Index++);
// Parse out the comma separated values.
const char *Prev = Str;
@@ -126,26 +135,26 @@
case SeparateClass:
// Matches iff this is an exact match.
// FIXME: Avoid strlen.
- if (getName().size() != strlen(Args.getArgString(Index)))
+ if (ArgSize != strlen(Args.getArgString(Index)))
return 0;
Index += 2;
if (Index > Args.getNumInputArgStrings())
return 0;
- return new Arg(getUnaliasedOption(),
+ return new Arg(getUnaliasedOption(), Spelling,
Index - 2, Args.getArgString(Index - 1));
case MultiArgClass: {
// Matches iff this is an exact match.
// FIXME: Avoid strlen.
- if (getName().size() != strlen(Args.getArgString(Index)))
+ if (ArgSize != strlen(Args.getArgString(Index)))
return 0;
Index += 1 + getNumArgs();
if (Index > Args.getNumInputArgStrings())
return 0;
- Arg *A = new Arg(getUnaliasedOption(), Index - 1 - getNumArgs(),
+ Arg *A = new Arg(getUnaliasedOption(), Spelling, Index - 1 - getNumArgs(),
Args.getArgString(Index - getNumArgs()));
for (unsigned i = 1; i != getNumArgs(); ++i)
A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
@@ -154,9 +163,9 @@
case JoinedOrSeparateClass: {
// If this is not an exact match, it is a joined arg.
// FIXME: Avoid strlen.
- if (getName().size() != strlen(Args.getArgString(Index))) {
- const char *Value = Args.getArgString(Index) + getName().size();
- return new Arg(*this, Index++, Value);
+ if (ArgSize != strlen(Args.getArgString(Index))) {
+ const char *Value = Args.getArgString(Index) + ArgSize;
+ return new Arg(*this, Spelling, Index++, Value);
}
// Otherwise it must be separate.
@@ -164,7 +173,7 @@
if (Index > Args.getNumInputArgStrings())
return 0;
- return new Arg(getUnaliasedOption(),
+ return new Arg(getUnaliasedOption(), Spelling,
Index - 2, Args.getArgString(Index - 1));
}
case JoinedAndSeparateClass:
@@ -173,9 +182,9 @@
if (Index > Args.getNumInputArgStrings())
return 0;
- return new Arg(getUnaliasedOption(), Index - 2,
- Args.getArgString(Index-2)+getName().size(),
- Args.getArgString(Index-1));
+ return new Arg(getUnaliasedOption(), Spelling, Index - 2,
+ Args.getArgString(Index - 2) + ArgSize,
+ Args.getArgString(Index - 1));
default:
llvm_unreachable("Invalid option kind!");
}
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 7848b48..54ec0cb 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1175,8 +1175,8 @@
(*it)->claim();
// Skip over "-m".
- assert(Name.startswith("-m") && "Invalid feature name.");
- Name = Name.substr(2);
+ assert(Name.startswith("m") && "Invalid feature name.");
+ Name = Name.substr(1);
bool IsNegative = Name.startswith("no-");
if (IsNegative)
@@ -2283,7 +2283,7 @@
CmdArgs.push_back("-fbounds-checking=1");
}
- if (Args.hasArg(options::OPT__relocatable_pch))
+ if (Args.hasArg(options::OPT_relocatable_pch))
CmdArgs.push_back("-relocatable-pch");
if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) {
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 4f0cfa8..1de547d 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1001,10 +1001,10 @@
for (arg_iterator I = Args.filtered_begin(OPT_W_Group),
E = Args.filtered_end(); I != E; ++I) {
Arg *A = *I;
- // If the argument is a pure flag, add its name (minus the "-W" at the beginning)
+ // If the argument is a pure flag, add its name (minus the "W" at the beginning)
// to the warning list. Else, add its value (for the OPT_W case).
if (A->getOption().getKind() == Option::FlagClass) {
- Warnings.push_back(A->getOption().getName().substr(2));
+ Warnings.push_back(A->getOption().getName().substr(1));
} else {
for (unsigned Idx = 0, End = A->getNumValues();
Idx < End; ++Idx) {