Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -1940,9 +1940,8 @@ void ScriptParser::readAnonymousDeclaration() { // Read global symbols first. "global:" is default, so if there's // no label, we assume global symbols. - if (peek() != "local") { - if (consume("global")) - expect(":"); + if (!peekLabel("local:")) { + consumeLabel("global:"); for (SymbolVersion V : readSymbols()) Config->VersionScriptGlobals.push_back(V); } @@ -1952,9 +1951,8 @@ } void ScriptParser::readLocals() { - if (!consume("local")) + if (!consumeLabel("local:")) return; - expect(":"); std::vector Locals = readSymbols(); for (SymbolVersion V : Locals) { if (V.Name == "*") { @@ -1973,9 +1971,8 @@ Config->VersionDefinitions.push_back({VerStr, VersionId}); // Read global symbols. - if (peek() != "local") { - if (consume("global")) - expect(":"); + if (!peekLabel("local:")) { + consumeLabel("global:"); Config->VersionDefinitions.back().Globals = readSymbols(); } readLocals(); @@ -2001,7 +1998,7 @@ continue; } - if (peek() == "}" || (peek() == "local" && peek(1) == ":") || Error) + if (peek() == "}" || Error || peekLabel("local:")) break; StringRef Tok = next(); Ret.push_back({unquote(Tok), false, hasWildcard(Tok)}); Index: ELF/ScriptLexer.h =================================================================== --- ELF/ScriptLexer.h +++ ELF/ScriptLexer.h @@ -29,11 +29,17 @@ bool atEOF(); StringRef next(); StringRef peek(unsigned N = 0); - void skip(); + void skip(unsigned N = 1); bool consume(StringRef Tok); void expect(StringRef Expect); std::string getCurrentLocation(); + // These are the only methods that use LL(2) grammar. + // Required to parse labels that may consist of + // one or two tokens, ex: "local :" vs "local:". + bool peekLabel(StringRef Tok); + bool consumeLabel(StringRef Tok); + std::vector MBs; std::vector Tokens; bool InExpr = false; Index: ELF/ScriptLexer.cpp =================================================================== --- ELF/ScriptLexer.cpp +++ ELF/ScriptLexer.cpp @@ -124,7 +124,7 @@ // so that you can write "file-name.cpp" as one bare token, for example. size_t Pos = S.find_first_not_of( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789_.$/\\~=+[]*?-!<>^"); + "0123456789_.$/\\~=+[]*?-!<>^:"); // A character that cannot start a word (which is usually a // punctuation) forms a single character token. @@ -169,7 +169,7 @@ // Split a given string as an expression. // This function returns "3", "*" and "5" for "3*5" for example. static std::vector tokenizeExpr(StringRef S) { - StringRef Ops = "+-*/"; // List of operators + StringRef Ops = "+-*/:"; // List of operators // Quoted strings are literal strings, so we don't want to split it. if (S.startswith("\"")) @@ -248,7 +248,23 @@ return false; } -void ScriptLexer::skip() { (void)next(); } +bool ScriptLexer::consumeLabel(StringRef Tok) { + if (!peekLabel(Tok)) + return false; + skip(peek() == Tok ? 1 : 2); + return true; +} + +bool ScriptLexer::peekLabel(StringRef Tok) { + if (peek() == Tok) + return true; + return peek() == Tok.drop_back(1) && peek(1) == Tok.take_back(1); +} + +void ScriptLexer::skip(unsigned N) { + while (N--) + (void)next(); +} void ScriptLexer::expect(StringRef Expect) { if (Error) Index: test/ELF/version-script-extern-wildcards-anon.s =================================================================== --- test/ELF/version-script-extern-wildcards-anon.s +++ test/ELF/version-script-extern-wildcards-anon.s @@ -7,6 +7,7 @@ # RUN: extern "C++" { \ # RUN: "foo(int)"; \ # RUN: z*; \ +# RUN: std::q*; \ # RUN: }; \ # RUN: local: *; \ # RUN: }; ' > %t.script @@ -50,6 +51,15 @@ # CHECK-NEXT: Other: # CHECK-NEXT: Section: # CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _ZSt3qux +# CHECK-NEXT: Value: +# CHECK-NEXT: Size: +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: +# CHECK-NEXT: Other: +# CHECK-NEXT: Section: +# CHECK-NEXT: } # CHECK-NEXT: ] .global _Z3fooi @@ -60,3 +70,5 @@ _Z3zedi: .global _Z3bazi _Z3bazi: +.global _ZSt3qux +_ZSt3qux: