Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -1079,6 +1079,7 @@ void readVersionDeclaration(StringRef VerStr); std::vector readSymbols(); void readLocals(); + bool isNextLocal(); ScriptConfiguration &Opt = *ScriptConfig; bool IsUnderSysroot; @@ -1944,8 +1945,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")) + if (!isNextLocal()) { + if (!consume("global:") && consume("global")) expect(":"); for (SymbolVersion V : readSymbols()) Config->VersionScriptGlobals.push_back(V); @@ -1956,9 +1957,11 @@ } void ScriptParser::readLocals() { - if (!consume("local")) + if (!isNextLocal()) return; - expect(":"); + + if (!consume("local:") && consume("local")) + expect(":"); std::vector Locals = readSymbols(); for (SymbolVersion V : Locals) { if (V.Name == "*") { @@ -1969,6 +1972,10 @@ } } +bool ScriptParser::isNextLocal() { + return peek() == "local:" || (peek() == "local" && peek(1) == ":"); +} + // 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 @@ -1977,8 +1984,8 @@ Config->VersionDefinitions.push_back({VerStr, VersionId}); // Read global symbols. - if (peek() != "local") { - if (consume("global")) + if (!isNextLocal()) { + if (!consume("global:") && consume("global")) expect(":"); Config->VersionDefinitions.back().Globals = readSymbols(); } @@ -2005,7 +2012,7 @@ continue; } - if (peek() == "}" || (peek() == "local" && peek(1) == ":") || Error) + if (peek() == "}" || Error || isNextLocal()) break; StringRef Tok = next(); Ret.push_back({unquote(Tok), false, hasWildcard(Tok)}); 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("\"")) 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: