Skip to content

Commit f8ce350

Browse files
committed
[clang] Move CCC_OVERRIDE_OPTIONS implementation to Driver (llvm#85425)
Move CCC_OVERRIDE_OPTIONS support to clangDriver so that it may be used outside of the clang driver binary. The override functionality will be used in LLDB, to apply adjustments to ClangImporter flags. This will be useful as an escape hatch when there are issues that can be fixed by adding or removing clang flags. The only thing changed is the name, from `ApplyQAOverride` to `applyOverrideOptions`. (cherry picked from commit 8d7ee46)
1 parent b047425 commit f8ce350

File tree

3 files changed

+144
-135
lines changed

3 files changed

+144
-135
lines changed

clang/include/clang/Driver/Driver.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
#include "llvm/Option/ArgList.h"
2929
#include "llvm/Support/StringSaver.h"
3030

31-
#include <list>
3231
#include <map>
32+
#include <set>
3333
#include <string>
3434
#include <vector>
3535

@@ -829,6 +829,13 @@ llvm::Error expandResponseFiles(SmallVectorImpl<const char *> &Args,
829829
/// Checks whether the value produced by getDriverMode is for 'cache' mode.
830830
bool isClangCache(StringRef DriverMode);
831831

832+
/// Apply a space separated list of edits to the input argument lists.
833+
/// See applyOneOverrideOption.
834+
void applyOverrideOptions(SmallVectorImpl<const char *> &Args,
835+
const char *OverrideOpts,
836+
llvm::StringSet<> &SavedStrings,
837+
raw_ostream *OS = nullptr);
838+
832839
} // end namespace driver
833840
} // end namespace clang
834841

clang/lib/Driver/Driver.cpp

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
#include "llvm/Support/PrettyStackTrace.h"
9292
#include "llvm/Support/Process.h"
9393
#include "llvm/Support/Program.h"
94+
#include "llvm/Support/Regex.h"
9495
#include "llvm/Support/StringSaver.h"
9596
#include "llvm/Support/VirtualFileSystem.h"
9697
#include "llvm/Support/raw_ostream.h"
@@ -6673,3 +6674,131 @@ llvm::Error driver::expandResponseFiles(SmallVectorImpl<const char *> &Args,
66736674
bool driver::isClangCache(StringRef DriverMode) {
66746675
return DriverMode == "cache";
66756676
}
6677+
6678+
static const char *GetStableCStr(llvm::StringSet<> &SavedStrings, StringRef S) {
6679+
return SavedStrings.insert(S).first->getKeyData();
6680+
}
6681+
6682+
/// Apply a list of edits to the input argument lists.
6683+
///
6684+
/// The input string is a space separated list of edits to perform,
6685+
/// they are applied in order to the input argument lists. Edits
6686+
/// should be one of the following forms:
6687+
///
6688+
/// '#': Silence information about the changes to the command line arguments.
6689+
///
6690+
/// '^': Add FOO as a new argument at the beginning of the command line.
6691+
///
6692+
/// '+': Add FOO as a new argument at the end of the command line.
6693+
///
6694+
/// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
6695+
/// line.
6696+
///
6697+
/// 'xOPTION': Removes all instances of the literal argument OPTION.
6698+
///
6699+
/// 'XOPTION': Removes all instances of the literal argument OPTION,
6700+
/// and the following argument.
6701+
///
6702+
/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
6703+
/// at the end of the command line.
6704+
///
6705+
/// \param OS - The stream to write edit information to.
6706+
/// \param Args - The vector of command line arguments.
6707+
/// \param Edit - The override command to perform.
6708+
/// \param SavedStrings - Set to use for storing string representations.
6709+
static void applyOneOverrideOption(raw_ostream &OS,
6710+
SmallVectorImpl<const char *> &Args,
6711+
StringRef Edit,
6712+
llvm::StringSet<> &SavedStrings) {
6713+
// This does not need to be efficient.
6714+
6715+
if (Edit[0] == '^') {
6716+
const char *Str = GetStableCStr(SavedStrings, Edit.substr(1));
6717+
OS << "### Adding argument " << Str << " at beginning\n";
6718+
Args.insert(Args.begin() + 1, Str);
6719+
} else if (Edit[0] == '+') {
6720+
const char *Str = GetStableCStr(SavedStrings, Edit.substr(1));
6721+
OS << "### Adding argument " << Str << " at end\n";
6722+
Args.push_back(Str);
6723+
} else if (Edit[0] == 's' && Edit[1] == '/' && Edit.ends_with("/") &&
6724+
Edit.slice(2, Edit.size() - 1).contains('/')) {
6725+
StringRef MatchPattern = Edit.substr(2).split('/').first;
6726+
StringRef ReplPattern = Edit.substr(2).split('/').second;
6727+
ReplPattern = ReplPattern.slice(0, ReplPattern.size() - 1);
6728+
6729+
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
6730+
// Ignore end-of-line response file markers
6731+
if (Args[i] == nullptr)
6732+
continue;
6733+
std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
6734+
6735+
if (Repl != Args[i]) {
6736+
OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
6737+
Args[i] = GetStableCStr(SavedStrings, Repl);
6738+
}
6739+
}
6740+
} else if (Edit[0] == 'x' || Edit[0] == 'X') {
6741+
auto Option = Edit.substr(1);
6742+
for (unsigned i = 1; i < Args.size();) {
6743+
if (Option == Args[i]) {
6744+
OS << "### Deleting argument " << Args[i] << '\n';
6745+
Args.erase(Args.begin() + i);
6746+
if (Edit[0] == 'X') {
6747+
if (i < Args.size()) {
6748+
OS << "### Deleting argument " << Args[i] << '\n';
6749+
Args.erase(Args.begin() + i);
6750+
} else
6751+
OS << "### Invalid X edit, end of command line!\n";
6752+
}
6753+
} else
6754+
++i;
6755+
}
6756+
} else if (Edit[0] == 'O') {
6757+
for (unsigned i = 1; i < Args.size();) {
6758+
const char *A = Args[i];
6759+
// Ignore end-of-line response file markers
6760+
if (A == nullptr)
6761+
continue;
6762+
if (A[0] == '-' && A[1] == 'O' &&
6763+
(A[2] == '\0' || (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
6764+
('0' <= A[2] && A[2] <= '9'))))) {
6765+
OS << "### Deleting argument " << Args[i] << '\n';
6766+
Args.erase(Args.begin() + i);
6767+
} else
6768+
++i;
6769+
}
6770+
OS << "### Adding argument " << Edit << " at end\n";
6771+
Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
6772+
} else {
6773+
OS << "### Unrecognized edit: " << Edit << "\n";
6774+
}
6775+
}
6776+
6777+
void driver::applyOverrideOptions(SmallVectorImpl<const char *> &Args,
6778+
const char *OverrideStr,
6779+
llvm::StringSet<> &SavedStrings,
6780+
raw_ostream *OS) {
6781+
if (!OS)
6782+
OS = &llvm::nulls();
6783+
6784+
if (OverrideStr[0] == '#') {
6785+
++OverrideStr;
6786+
OS = &llvm::nulls();
6787+
}
6788+
6789+
*OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";
6790+
6791+
// This does not need to be efficient.
6792+
6793+
const char *S = OverrideStr;
6794+
while (*S) {
6795+
const char *End = ::strchr(S, ' ');
6796+
if (!End)
6797+
End = S + strlen(S);
6798+
if (End != S)
6799+
applyOneOverrideOption(*OS, Args, std::string(S, End), SavedStrings);
6800+
S = End;
6801+
if (*S != '\0')
6802+
++S;
6803+
}
6804+
}

clang/tools/driver/driver.cpp

Lines changed: 7 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "llvm/ADT/ArrayRef.h"
3131
#include "llvm/ADT/SmallString.h"
3232
#include "llvm/ADT/SmallVector.h"
33+
#include "llvm/ADT/StringSet.h"
3334
#include "llvm/Option/ArgList.h"
3435
#include "llvm/Option/OptTable.h"
3536
#include "llvm/Option/Option.h"
@@ -45,7 +46,6 @@
4546
#include "llvm/Support/PrettyStackTrace.h"
4647
#include "llvm/Support/Process.h"
4748
#include "llvm/Support/Program.h"
48-
#include "llvm/Support/Regex.h"
4949
#include "llvm/Support/Signals.h"
5050
#include "llvm/Support/StringSaver.h"
5151
#include "llvm/Support/TargetSelect.h"
@@ -82,136 +82,8 @@ std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
8282
return llvm::sys::fs::getMainExecutable(Argv0, P);
8383
}
8484

85-
static const char *GetStableCStr(std::set<std::string> &SavedStrings,
86-
StringRef S) {
87-
return SavedStrings.insert(std::string(S)).first->c_str();
88-
}
89-
90-
/// ApplyQAOverride - Apply a list of edits to the input argument lists.
91-
///
92-
/// The input string is a space separate list of edits to perform,
93-
/// they are applied in order to the input argument lists. Edits
94-
/// should be one of the following forms:
95-
///
96-
/// '#': Silence information about the changes to the command line arguments.
97-
///
98-
/// '^': Add FOO as a new argument at the beginning of the command line.
99-
///
100-
/// '+': Add FOO as a new argument at the end of the command line.
101-
///
102-
/// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
103-
/// line.
104-
///
105-
/// 'xOPTION': Removes all instances of the literal argument OPTION.
106-
///
107-
/// 'XOPTION': Removes all instances of the literal argument OPTION,
108-
/// and the following argument.
109-
///
110-
/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
111-
/// at the end of the command line.
112-
///
113-
/// \param OS - The stream to write edit information to.
114-
/// \param Args - The vector of command line arguments.
115-
/// \param Edit - The override command to perform.
116-
/// \param SavedStrings - Set to use for storing string representations.
117-
static void ApplyOneQAOverride(raw_ostream &OS,
118-
SmallVectorImpl<const char*> &Args,
119-
StringRef Edit,
120-
std::set<std::string> &SavedStrings) {
121-
// This does not need to be efficient.
122-
123-
if (Edit[0] == '^') {
124-
const char *Str =
125-
GetStableCStr(SavedStrings, Edit.substr(1));
126-
OS << "### Adding argument " << Str << " at beginning\n";
127-
Args.insert(Args.begin() + 1, Str);
128-
} else if (Edit[0] == '+') {
129-
const char *Str =
130-
GetStableCStr(SavedStrings, Edit.substr(1));
131-
OS << "### Adding argument " << Str << " at end\n";
132-
Args.push_back(Str);
133-
} else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
134-
Edit.slice(2, Edit.size() - 1).contains('/')) {
135-
StringRef MatchPattern = Edit.substr(2).split('/').first;
136-
StringRef ReplPattern = Edit.substr(2).split('/').second;
137-
ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
138-
139-
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
140-
// Ignore end-of-line response file markers
141-
if (Args[i] == nullptr)
142-
continue;
143-
std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
144-
145-
if (Repl != Args[i]) {
146-
OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
147-
Args[i] = GetStableCStr(SavedStrings, Repl);
148-
}
149-
}
150-
} else if (Edit[0] == 'x' || Edit[0] == 'X') {
151-
auto Option = Edit.substr(1);
152-
for (unsigned i = 1; i < Args.size();) {
153-
if (Option == Args[i]) {
154-
OS << "### Deleting argument " << Args[i] << '\n';
155-
Args.erase(Args.begin() + i);
156-
if (Edit[0] == 'X') {
157-
if (i < Args.size()) {
158-
OS << "### Deleting argument " << Args[i] << '\n';
159-
Args.erase(Args.begin() + i);
160-
} else
161-
OS << "### Invalid X edit, end of command line!\n";
162-
}
163-
} else
164-
++i;
165-
}
166-
} else if (Edit[0] == 'O') {
167-
for (unsigned i = 1; i < Args.size();) {
168-
const char *A = Args[i];
169-
// Ignore end-of-line response file markers
170-
if (A == nullptr)
171-
continue;
172-
if (A[0] == '-' && A[1] == 'O' &&
173-
(A[2] == '\0' ||
174-
(A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
175-
('0' <= A[2] && A[2] <= '9'))))) {
176-
OS << "### Deleting argument " << Args[i] << '\n';
177-
Args.erase(Args.begin() + i);
178-
} else
179-
++i;
180-
}
181-
OS << "### Adding argument " << Edit << " at end\n";
182-
Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
183-
} else {
184-
OS << "### Unrecognized edit: " << Edit << "\n";
185-
}
186-
}
187-
188-
/// ApplyQAOverride - Apply a comma separate list of edits to the
189-
/// input argument lists. See ApplyOneQAOverride.
190-
static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
191-
const char *OverrideStr,
192-
std::set<std::string> &SavedStrings) {
193-
raw_ostream *OS = &llvm::errs();
194-
195-
if (OverrideStr[0] == '#') {
196-
++OverrideStr;
197-
OS = &llvm::nulls();
198-
}
199-
200-
*OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";
201-
202-
// This does not need to be efficient.
203-
204-
const char *S = OverrideStr;
205-
while (*S) {
206-
const char *End = ::strchr(S, ' ');
207-
if (!End)
208-
End = S + strlen(S);
209-
if (End != S)
210-
ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
211-
S = End;
212-
if (*S != '\0')
213-
++S;
214-
}
85+
static const char *GetStableCStr(llvm::StringSet<> &SavedStrings, StringRef S) {
86+
return SavedStrings.insert(S).first->getKeyData();
21587
}
21688

21789
extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
@@ -230,7 +102,7 @@ extern int cc1gen_reproducer_main(ArrayRef<const char *> Argv,
230102

231103
static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
232104
SmallVectorImpl<const char *> &ArgVector,
233-
std::set<std::string> &SavedStrings) {
105+
llvm::StringSet<> &SavedStrings) {
234106
// Put target and mode arguments at the start of argument list so that
235107
// arguments specified in command line could override them. Avoid putting
236108
// them at index 0, as an option like '-cc1' must remain the first.
@@ -482,12 +354,13 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
482354
}
483355
}
484356

485-
std::set<std::string> SavedStrings;
357+
llvm::StringSet<> SavedStrings;
486358
// Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
487359
// scenes.
488360
if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) {
489361
// FIXME: Driver shouldn't take extra initial argument.
490-
ApplyQAOverride(Args, OverrideStr, SavedStrings);
362+
driver::applyOverrideOptions(Args, OverrideStr, SavedStrings,
363+
&llvm::errs());
491364
}
492365

493366
std::string Path = GetExecutablePath(ToolContext.Path, CanonicalPrefixes);

0 commit comments

Comments
 (0)