Clang driver. This involves a bunch of silly option parsing code to try to carefully emulate GCC's options. Currently, this takes a conservative approach, and unless all of the unsafe optimizations are enabled, none of them are. The fine grained control doesn't seem particularly useful. If it ever becomes useful, we can add that to LLVM first, and then expose it here. This also fixes a few tiny bugs in the flag management around -fhonor-infinities and -fhonor-nans; the flags now form proper sets both for enabling and disabling, with the last flag winning. I've also implemented a moderately terrifying GCC feature where a language change is also provided by the '-ffast-math' flag by defining the __FAST_MATH__ preprocessor macro. This feature is tracked and serialized in the frontend but it isn't used yet. A subsequent patch will add the preprocessor macro and tests for it. I've manually tested that codegen appears to respect this, but I've not dug in enough to see if there is an easy way to test codegen options w/o relying on the particulars of LLVM's optimizations. llvm-svn: 147434
332 lines
9.2 KiB
C++
332 lines
9.2 KiB
C++
//===--- ArgList.cpp - Argument List Management ---------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Driver/ArgList.h"
|
|
#include "clang/Driver/Arg.h"
|
|
#include "clang/Driver/DriverDiagnostic.h"
|
|
#include "clang/Driver/Option.h"
|
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace clang;
|
|
using namespace clang::driver;
|
|
|
|
void arg_iterator::SkipToNextArg() {
|
|
for (; Current != Args.end(); ++Current) {
|
|
// Done if there are no filters.
|
|
if (!Id0.isValid())
|
|
break;
|
|
|
|
// Otherwise require a match.
|
|
const Option &O = (*Current)->getOption();
|
|
if (O.matches(Id0) ||
|
|
(Id1.isValid() && O.matches(Id1)) ||
|
|
(Id2.isValid() && O.matches(Id2)))
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
|
|
ArgList::ArgList() {
|
|
}
|
|
|
|
ArgList::~ArgList() {
|
|
}
|
|
|
|
void ArgList::append(Arg *A) {
|
|
Args.push_back(A);
|
|
}
|
|
|
|
void ArgList::eraseArg(OptSpecifier Id) {
|
|
for (iterator it = begin(), ie = end(); it != ie; ) {
|
|
if ((*it)->getOption().matches(Id)) {
|
|
it = Args.erase(it);
|
|
ie = end();
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
Arg *ArgList::getLastArgNoClaim(OptSpecifier Id) const {
|
|
// FIXME: Make search efficient?
|
|
for (const_reverse_iterator it = rbegin(), ie = rend(); it != ie; ++it)
|
|
if ((*it)->getOption().matches(Id))
|
|
return *it;
|
|
return 0;
|
|
}
|
|
|
|
Arg *ArgList::getLastArg(OptSpecifier Id) const {
|
|
Arg *Res = 0;
|
|
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
|
|
if ((*it)->getOption().matches(Id)) {
|
|
Res = *it;
|
|
Res->claim();
|
|
}
|
|
}
|
|
|
|
return Res;
|
|
}
|
|
|
|
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1) const {
|
|
Arg *Res = 0;
|
|
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
|
|
if ((*it)->getOption().matches(Id0) ||
|
|
(*it)->getOption().matches(Id1)) {
|
|
Res = *it;
|
|
Res->claim();
|
|
|
|
}
|
|
}
|
|
|
|
return Res;
|
|
}
|
|
|
|
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
|
|
OptSpecifier Id2) const {
|
|
Arg *Res = 0;
|
|
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
|
|
if ((*it)->getOption().matches(Id0) ||
|
|
(*it)->getOption().matches(Id1) ||
|
|
(*it)->getOption().matches(Id2)) {
|
|
Res = *it;
|
|
Res->claim();
|
|
}
|
|
}
|
|
|
|
return Res;
|
|
}
|
|
|
|
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
|
|
OptSpecifier Id2, OptSpecifier Id3) const {
|
|
Arg *Res = 0;
|
|
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
|
|
if ((*it)->getOption().matches(Id0) ||
|
|
(*it)->getOption().matches(Id1) ||
|
|
(*it)->getOption().matches(Id2) ||
|
|
(*it)->getOption().matches(Id3)) {
|
|
Res = *it;
|
|
Res->claim();
|
|
}
|
|
}
|
|
|
|
return Res;
|
|
}
|
|
|
|
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
|
|
OptSpecifier Id2, OptSpecifier Id3,
|
|
OptSpecifier Id4) const {
|
|
Arg *Res = 0;
|
|
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
|
|
if ((*it)->getOption().matches(Id0) ||
|
|
(*it)->getOption().matches(Id1) ||
|
|
(*it)->getOption().matches(Id2) ||
|
|
(*it)->getOption().matches(Id3) ||
|
|
(*it)->getOption().matches(Id4)) {
|
|
Res = *it;
|
|
Res->claim();
|
|
}
|
|
}
|
|
|
|
return Res;
|
|
}
|
|
|
|
bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const {
|
|
if (Arg *A = getLastArg(Pos, Neg))
|
|
return A->getOption().matches(Pos);
|
|
return Default;
|
|
}
|
|
|
|
StringRef ArgList::getLastArgValue(OptSpecifier Id,
|
|
StringRef Default) const {
|
|
if (Arg *A = getLastArg(Id))
|
|
return A->getValue(*this);
|
|
return Default;
|
|
}
|
|
|
|
int ArgList::getLastArgIntValue(OptSpecifier Id, int Default,
|
|
clang::DiagnosticsEngine &Diags) const {
|
|
int Res = Default;
|
|
|
|
if (Arg *A = getLastArg(Id)) {
|
|
if (StringRef(A->getValue(*this)).getAsInteger(10, Res))
|
|
Diags.Report(diag::err_drv_invalid_int_value)
|
|
<< A->getAsString(*this) << A->getValue(*this);
|
|
}
|
|
|
|
return Res;
|
|
}
|
|
|
|
std::vector<std::string> ArgList::getAllArgValues(OptSpecifier Id) const {
|
|
SmallVector<const char *, 16> Values;
|
|
AddAllArgValues(Values, Id);
|
|
return std::vector<std::string>(Values.begin(), Values.end());
|
|
}
|
|
|
|
void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id) const {
|
|
if (Arg *A = getLastArg(Id)) {
|
|
A->claim();
|
|
A->render(*this, Output);
|
|
}
|
|
}
|
|
|
|
void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0,
|
|
OptSpecifier Id1, OptSpecifier Id2) const {
|
|
for (arg_iterator it = filtered_begin(Id0, Id1, Id2),
|
|
ie = filtered_end(); it != ie; ++it) {
|
|
(*it)->claim();
|
|
(*it)->render(*this, Output);
|
|
}
|
|
}
|
|
|
|
void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0,
|
|
OptSpecifier Id1, OptSpecifier Id2) const {
|
|
for (arg_iterator it = filtered_begin(Id0, Id1, Id2),
|
|
ie = filtered_end(); it != ie; ++it) {
|
|
(*it)->claim();
|
|
for (unsigned i = 0, e = (*it)->getNumValues(); i != e; ++i)
|
|
Output.push_back((*it)->getValue(*this, i));
|
|
}
|
|
}
|
|
|
|
void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0,
|
|
const char *Translation,
|
|
bool Joined) const {
|
|
for (arg_iterator it = filtered_begin(Id0),
|
|
ie = filtered_end(); it != ie; ++it) {
|
|
(*it)->claim();
|
|
|
|
if (Joined) {
|
|
Output.push_back(MakeArgString(StringRef(Translation) +
|
|
(*it)->getValue(*this, 0)));
|
|
} else {
|
|
Output.push_back(Translation);
|
|
Output.push_back((*it)->getValue(*this, 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
void ArgList::ClaimAllArgs(OptSpecifier Id0) const {
|
|
for (arg_iterator it = filtered_begin(Id0),
|
|
ie = filtered_end(); it != ie; ++it)
|
|
(*it)->claim();
|
|
}
|
|
|
|
void ArgList::ClaimAllArgs() const {
|
|
for (const_iterator it = begin(), ie = end(); it != ie; ++it)
|
|
if (!(*it)->isClaimed())
|
|
(*it)->claim();
|
|
}
|
|
|
|
const char *ArgList::MakeArgString(const Twine &T) const {
|
|
llvm::SmallString<256> Str;
|
|
T.toVector(Str);
|
|
return MakeArgString(Str.str());
|
|
}
|
|
|
|
const char *ArgList::GetOrMakeJoinedArgString(unsigned Index,
|
|
StringRef LHS,
|
|
StringRef RHS) const {
|
|
StringRef Cur = getArgString(Index);
|
|
if (Cur.size() == LHS.size() + RHS.size() &&
|
|
Cur.startswith(LHS) && Cur.endswith(RHS))
|
|
return Cur.data();
|
|
|
|
return MakeArgString(LHS + RHS);
|
|
}
|
|
|
|
//
|
|
|
|
InputArgList::InputArgList(const char* const *ArgBegin,
|
|
const char* const *ArgEnd)
|
|
: NumInputArgStrings(ArgEnd - ArgBegin) {
|
|
ArgStrings.append(ArgBegin, ArgEnd);
|
|
}
|
|
|
|
InputArgList::~InputArgList() {
|
|
// An InputArgList always owns its arguments.
|
|
for (iterator it = begin(), ie = end(); it != ie; ++it)
|
|
delete *it;
|
|
}
|
|
|
|
unsigned InputArgList::MakeIndex(StringRef String0) const {
|
|
unsigned Index = ArgStrings.size();
|
|
|
|
// Tuck away so we have a reliable const char *.
|
|
SynthesizedStrings.push_back(String0);
|
|
ArgStrings.push_back(SynthesizedStrings.back().c_str());
|
|
|
|
return Index;
|
|
}
|
|
|
|
unsigned InputArgList::MakeIndex(StringRef String0,
|
|
StringRef String1) const {
|
|
unsigned Index0 = MakeIndex(String0);
|
|
unsigned Index1 = MakeIndex(String1);
|
|
assert(Index0 + 1 == Index1 && "Unexpected non-consecutive indices!");
|
|
(void) Index1;
|
|
return Index0;
|
|
}
|
|
|
|
const char *InputArgList::MakeArgString(StringRef Str) const {
|
|
return getArgString(MakeIndex(Str));
|
|
}
|
|
|
|
//
|
|
|
|
DerivedArgList::DerivedArgList(const InputArgList &_BaseArgs)
|
|
: BaseArgs(_BaseArgs) {
|
|
}
|
|
|
|
DerivedArgList::~DerivedArgList() {
|
|
// We only own the arguments we explicitly synthesized.
|
|
for (iterator it = SynthesizedArgs.begin(), ie = SynthesizedArgs.end();
|
|
it != ie; ++it)
|
|
delete *it;
|
|
}
|
|
|
|
const char *DerivedArgList::MakeArgString(StringRef Str) const {
|
|
return BaseArgs.MakeArgString(Str);
|
|
}
|
|
|
|
Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option *Opt) const {
|
|
Arg *A = new Arg(Opt, BaseArgs.MakeIndex(Opt->getName()), BaseArg);
|
|
SynthesizedArgs.push_back(A);
|
|
return A;
|
|
}
|
|
|
|
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);
|
|
SynthesizedArgs.push_back(A);
|
|
return A;
|
|
}
|
|
|
|
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);
|
|
SynthesizedArgs.push_back(A);
|
|
return A;
|
|
}
|
|
|
|
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,
|
|
BaseArgs.getArgString(Index) + Opt->getName().size(),
|
|
BaseArg);
|
|
SynthesizedArgs.push_back(A);
|
|
return A;
|
|
}
|