Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -104,6 +104,11 @@ class elf::ScriptParser { typedef void (ScriptParser::*Handler)(); + struct Token { + StringRef Val; + size_t Line; + }; + public: ScriptParser(BumpPtrAllocator *A, StringRef S, bool B) : Saver(*A), Tokens(tokenize(S)), IsUnderSysroot(B) {} @@ -112,7 +117,7 @@ private: void setError(const Twine &Msg); - static std::vector tokenize(StringRef S); + static std::vector tokenize(StringRef S); static StringRef skipSpace(StringRef S); bool atEOF(); StringRef next(); @@ -140,9 +145,10 @@ std::vector parseHex(StringRef S); StringSaver Saver; - std::vector Tokens; + std::vector Tokens; const static StringMap Cmd; size_t Pos = 0; + size_t Line = 0; bool IsUnderSysroot; bool Error = false; }; @@ -174,15 +180,22 @@ void ScriptParser::setError(const Twine &Msg) { if (Error) return; - error(Msg); + error("line " + Twine(Line) + ": " + Msg); Error = true; } // Split S into linker script tokens. -std::vector ScriptParser::tokenize(StringRef S) { - std::vector Ret; +std::vector ScriptParser::tokenize(StringRef S) { + std::vector Ret; + size_t Line = 0; for (;;) { - S = skipSpace(S); + StringRef Clip = skipSpace(S); + size_t Space = S.size() - Clip.size(); + if (Space) { + Line += S.substr(0, Space).count('\n'); + S = Clip; + } + if (S.empty()) return Ret; @@ -193,7 +206,7 @@ error("unclosed quote"); return {}; } - Ret.push_back(S.substr(1, E - 1)); + Ret.push_back({S.substr(1, E - 1), Line}); S = S.substr(E + 1); continue; } @@ -206,7 +219,7 @@ // punctuation) forms a single character token. if (Pos == 0) Pos = 1; - Ret.push_back(S.substr(0, Pos)); + Ret.push_back({S.substr(0, Pos), Line}); S = S.substr(Pos); } } @@ -240,7 +253,8 @@ setError("unexpected EOF"); return ""; } - return Tokens[Pos++]; + Line = Tokens[Pos].Line; + return Tokens[Pos++].Val; } StringRef ScriptParser::peek() { @@ -258,7 +272,7 @@ setError("unexpected EOF"); return false; } - if (Tok != Tokens[Pos]) + if (Tok != Tokens[Pos].Val) return false; ++Pos; return true; @@ -357,7 +371,7 @@ } std::unique_ptr &MB = *MBOrErr; StringRef S = Saver.save(MB->getMemBufferRef().getBuffer()); - std::vector V = tokenize(S); + std::vector V = tokenize(S); Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end()); } Index: test/ELF/linkerscript-diagnostic.s =================================================================== --- test/ELF/linkerscript-diagnostic.s +++ test/ELF/linkerscript-diagnostic.s @@ -0,0 +1,48 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +## Take some valid script with multiline comments +## and check it actually works: +# RUN: rm -f %t.script +# RUN: echo "SECTIONS {" >> %t.script +# RUN: echo ".text : { *(.text) }" >> %t.script +# RUN: echo ".keep : { *(.keep) } /*" >> %t.script +# RUN: echo "comment line 1" >> %t.script +# RUN: echo "comment line 2 */" >> %t.script +# RUN: echo ".temp : { *(.temp) } }" >> %t.script +# RUN: ld.lld -shared %t -o %t1 --script %t.script + +## Change ":" to "+" at line 1, check that error +## message starts from correct line number: +# RUN: rm -f %t.script +# RUN: echo "SECTIONS {" >> %t.script +# RUN: echo ".text + { *(.text) }" >> %t.script +# RUN: echo ".keep : { *(.keep) } /*" >> %t.script +# RUN: echo "comment line 1" >> %t.script +# RUN: echo "comment line 2 */" >> %t.script +# RUN: echo ".temp : { *(.temp) } }" >> %t.script +# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR1 %s +# ERR1: line 1: + +## Change ":" to "+" at line 2 now, check correct error line number: +# RUN: rm -f %t.script +# RUN: echo "SECTIONS {" >> %t.script +# RUN: echo ".text : { *(.text) }" >> %t.script +# RUN: echo ".keep + { *(.keep) } /*" >> %t.script +# RUN: echo "comment line 1" >> %t.script +# RUN: echo "comment line 2 */" >> %t.script +# RUN: echo ".temp : { *(.temp) } }" >> %t.script +# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR2 %s +# ERR2: line 2: + +## Change ":" to "+" at line 5, after multiline comment, +## check correct error line number: +# RUN: rm -f %t.script +# RUN: echo "SECTIONS {" >> %t.script +# RUN: echo ".text : { *(.text) }" >> %t.script +# RUN: echo ".keep : { *(.keep) } /*" >> %t.script +# RUN: echo "comment line 1" >> %t.script +# RUN: echo "comment line 2 */" >> %t.script +# RUN: echo ".temp + { *(.temp) } }" >> %t.script +# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR5 %s +# ERR5: line 5: