Split ScriptParser::readVersionDeclaration.

readVersionDeclaration was to read anonymous version definition and
named version definition. Splitting it into two functions should
improve readability as the two cases are different enough.

I also changed a few helper functions to return values instead of
mutating given references.

llvm-svn: 287319
This commit is contained in:
Rui Ueyama 2016-11-18 06:30:09 +00:00
parent 8980c92dde
commit 12450b20b4
1 changed files with 58 additions and 39 deletions

View File

@ -1004,11 +1004,10 @@ private:
Expr readParenExpr();
// For parsing version script.
void readVersionExtern(std::vector<SymbolVersion> *Globals);
std::vector<SymbolVersion> readVersionExtern();
void readAnonymousDeclaration();
void readVersionDeclaration(StringRef VerStr);
void readGlobal(StringRef VerStr);
void readLocal(StringRef VerStr);
void readSymbols(std::vector<SymbolVersion> &V);
std::vector<SymbolVersion> readSymbols();
ScriptConfiguration &Opt = *ScriptConfig;
bool IsUnderSysroot;
@ -1022,7 +1021,7 @@ void ScriptParser::readVersionScript() {
void ScriptParser::readVersionScriptCommand() {
if (consume("{")) {
readVersionDeclaration("");
readAnonymousDeclaration();
return;
}
@ -1812,73 +1811,93 @@ unsigned ScriptParser::readPhdrType() {
return Ret;
}
// Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };".
void ScriptParser::readAnonymousDeclaration() {
// Read global symbols first. "global:" is default, so if there's
// no label, we assume global symbols.
if (consume("global:") || peek() != "local:")
Config->VersionScriptGlobals = readSymbols();
// Next, read local symbols.
if (consume("local:")) {
if (consume("*")) {
Config->DefaultSymbolVersion = VER_NDX_LOCAL;
expect(";");
} else {
setError("local symbol list for anonymous version is not supported");
}
}
expect("}");
expect(";");
}
// Reads a list of symbols, e.g. "VerStr { global: foo; bar; local: *; };".
void ScriptParser::readVersionDeclaration(StringRef VerStr) {
// Identifiers start at 2 because 0 and 1 are reserved
// for VER_NDX_LOCAL and VER_NDX_GLOBAL constants.
uint16_t VersionId = Config->VersionDefinitions.size() + 2;
Config->VersionDefinitions.push_back({VerStr, VersionId});
// Read global symbols.
if (consume("global:") || peek() != "local:")
readGlobal(VerStr);
if (consume("local:"))
readLocal(VerStr);
Config->VersionDefinitions.back().Globals = readSymbols();
// Read local symbols.
if (consume("local:")) {
if (consume("*")) {
Config->DefaultSymbolVersion = VER_NDX_LOCAL;
expect(";");
} else {
for (SymbolVersion V : readSymbols())
Config->VersionScriptLocals.push_back(V);
}
}
expect("}");
// Each version may have a parent version. For example, "Ver2" defined as
// "Ver2 { global: foo; local: *; } Ver1;" has "Ver1" as a parent. This
// version hierarchy is, probably against your instinct, purely for human; the
// runtime doesn't care about them at all. In LLD, we simply skip the token.
if (!VerStr.empty() && peek() != ";")
// Each version may have a parent version. For example, "Ver2"
// defined as "Ver2 { global: foo; local: *; } Ver1;" has "Ver1"
// as a parent. This version hierarchy is, probably against your
// instinct, purely for hint; the runtime doesn't care about it
// at all. In LLD, we simply ignore it.
if (peek() != ";")
skip();
expect(";");
}
void ScriptParser::readSymbols(std::vector<SymbolVersion> &V) {
// Reads a list of symbols for a versions cript.
std::vector<SymbolVersion> ScriptParser::readSymbols() {
std::vector<SymbolVersion> Ret;
for (;;) {
if (consume("extern"))
readVersionExtern(&V);
for (SymbolVersion V : readVersionExtern())
Ret.push_back(V);
if (peek() == "}" || peek() == "local:" || Error)
return;
break;
StringRef Tok = next();
V.push_back({unquote(Tok), false, hasWildcard(Tok)});
Ret.push_back({unquote(Tok), false, hasWildcard(Tok)});
expect(";");
}
return Ret;
}
void ScriptParser::readLocal(StringRef VerStr) {
if (consume("*")) {
Config->DefaultSymbolVersion = VER_NDX_LOCAL;
expect(";");
return;
}
if (VerStr.empty())
setError("locals list for anonymous version is not supported");
readSymbols(Config->VersionScriptLocals);
}
void ScriptParser::readVersionExtern(std::vector<SymbolVersion> *V) {
// Reads an "extern C++" directive, e.g.,
// "extern "C++" { ns::*; "f(int, double)"; };"
std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
expect("\"C++\"");
expect("{");
std::vector<SymbolVersion> Ret;
while (!Error && peek() != "}") {
StringRef Tok = next();
bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok);
V->push_back({unquote(Tok), true, HasWildcard});
Ret.push_back({unquote(Tok), true, HasWildcard});
expect(";");
}
expect("}");
expect(";");
}
void ScriptParser::readGlobal(StringRef VerStr) {
if (VerStr.empty())
readSymbols(Config->VersionScriptGlobals);
else
readSymbols(Config->VersionDefinitions.back().Globals);
return Ret;
}
static bool isUnderSysroot(StringRef Path) {