diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp --- a/llvm/lib/MC/MCParser/MasmParser.cpp +++ b/llvm/lib/MC/MCParser/MasmParser.cpp @@ -491,7 +491,8 @@ bool Warning(SMLoc L, const Twine &Msg, SMRange Range = None) override; bool printError(SMLoc L, const Twine &Msg, SMRange Range = None) override; - const AsmToken &Lex() override; + const AsmToken &Lex(bool ExpandNextToken); + const AsmToken &Lex() override { return Lex(/*ExpandNextToken=*/true); } void setParsingMSInlineAsm(bool V) override { ParsingMSInlineAsm = V; @@ -534,7 +535,10 @@ /// Parse an identifier or string (as a quoted identifier) /// and set \p Res to the identifier contents. - bool parseIdentifier(StringRef &Res) override; + bool parseIdentifier(StringRef &Res, bool StartOfStatement); + bool parseIdentifier(StringRef &Res) override { + return parseIdentifier(Res, false); + } void eatToEndOfStatement() override; bool checkForValidSection() override; @@ -542,6 +546,7 @@ /// } private: + bool expandCurrentToken(); const AsmToken peekTok(bool ShouldSkipSpace = true); bool parseStatement(ParseStatementInfo &Info, @@ -1003,7 +1008,7 @@ bool parseDirectiveRadix(SMLoc DirectiveLoc); // "echo" - bool parseDirectiveEcho(); + bool parseDirectiveEcho(SMLoc DirectiveLoc); void initializeDirectiveKindMap(); void initializeCVDefRangeTypeMap(); @@ -1111,7 +1116,37 @@ Loc.getPointer(), EndStatementAtEOF); } -const AsmToken &MasmParser::Lex() { +bool MasmParser::expandCurrentToken() { + const AsmToken *tok = &getTok(); + auto it = Variables.find(tok->getIdentifier().lower()); + const llvm::MCAsmMacro *M = + getContext().lookupMacro(tok->getIdentifier().lower()); + if (it != Variables.end() && it->second.IsText) { + std::unique_ptr Instantiation = + MemoryBuffer::getMemBufferCopy(it->second.TextValue, ""); + + // Jump to the macro instantiation and prime the lexer. + CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), + getTok().getEndLoc()); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr, + /*EndStatementAtEOF=*/false); + EndStatementAtEOFStack.push_back(false); + Lexer.Lex(); + return false; + } else if (M && M->IsFunction && peekTok().is(AsmToken::LParen)) { + // This is a macro function invocation; expand it in place. + const AsmToken MacroTok = *tok; + Lexer.Lex(); + if (handleMacroInvocation(M, MacroTok.getLoc())) { + Lexer.UnLex(AsmToken(AsmToken::Error, MacroTok.getIdentifier())); + Lexer.Lex(); + } + return false; + } + return true; +} + +const AsmToken &MasmParser::Lex(bool ExpandNextToken) { if (Lexer.getTok().is(AsmToken::Error)) Error(Lexer.getErrLoc(), Lexer.getErr()); @@ -1126,10 +1161,9 @@ const AsmToken *tok = &Lexer.Lex(); bool StartOfStatement = Lexer.isAtStartOfStatement(); - while (tok->is(AsmToken::Identifier)) { + while (ExpandNextToken && tok->is(AsmToken::Identifier)) { if (StartOfStatement) { AsmToken NextTok; - MutableArrayRef Buf(NextTok); size_t ReadCount = Lexer.peekTokens(Buf); if (ReadCount && NextTok.is(AsmToken::Identifier) && @@ -1140,34 +1174,8 @@ break; } } - auto it = Variables.find(tok->getIdentifier().lower()); - const llvm::MCAsmMacro *M = - getContext().lookupMacro(tok->getIdentifier().lower()); - if (it != Variables.end() && it->second.IsText) { - // This is a textmacro; expand it in place. - std::unique_ptr Instantiation = - MemoryBuffer::getMemBufferCopy(it->second.TextValue, - ""); - - // Jump to the macro instantiation and prime the lexer. - CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), - getTok().getEndLoc()); - Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr, - /*EndStatementAtEOF=*/false); - EndStatementAtEOFStack.push_back(false); - tok = &Lexer.Lex(); - } else if (M && M->IsFunction && peekTok().is(AsmToken::LParen)) { - // This is a macro function invocation; expand it in place. - const AsmToken MacroTok = *tok; - tok = &Lexer.Lex(); - if (handleMacroInvocation(M, MacroTok.getLoc())) { - Lexer.UnLex(AsmToken(AsmToken::Error, MacroTok.getIdentifier())); - tok = &Lexer.Lex(); - } - continue; - } else { + if (expandCurrentToken()) break; - } } // Parse comments here to be deferred until end of next statement. @@ -2081,12 +2089,7 @@ Lex(); // always eat a token if (!IDVal.startswith(".")) return Error(IDLoc, "unexpected token at start of statement"); - } else if (Lexer.is(AsmToken::Identifier) && - getTok().getString().equals_lower("echo")) { - // Intercept echo early to avoid lexical substitution in its message, and - // delegate all handling to the appropriate function. - return parseDirectiveEcho(); - } else if (parseIdentifier(IDVal)) { + } else if (parseIdentifier(IDVal, /*StartOfStatement=*/true)) { if (!TheCondState.Ignore) { Lex(); // always eat a token return Error(IDLoc, "unexpected token at start of statement"); @@ -2465,6 +2468,8 @@ return parseDirectiveErrorIfe(IDLoc, false); case DK_RADIX: return parseDirectiveRadix(IDLoc); + case DK_ECHO: + return parseDirectiveEcho(IDLoc); } return Error(IDLoc, "unknown directive"); @@ -3300,7 +3305,7 @@ /// parseIdentifier: /// ::= identifier /// ::= string -bool MasmParser::parseIdentifier(StringRef &Res) { +bool MasmParser::parseIdentifier(StringRef &Res, bool StartOfStatement) { // The assembler has relaxed rules for accepting identifiers, in particular we // allow things like '.globl $foo' and '.def @feat.00', which would normally // be separate tokens. At this level, we have already lexed so we cannot @@ -3334,7 +3339,15 @@ Res = getTok().getIdentifier(); - Lex(); // Consume the identifier token. + // Consume the identifier token - but if parsing certain directives, avoid + // lexical expansion of the next token. + const bool ExpandNextToken = + !StartOfStatement || + StringSwitch(Res) + .CaseLower("echo", false) + .CasesLower("ifdef", "ifndef", "elseifdef", "elseifndef", false) + .Default(true); + Lex(ExpandNextToken); return false; } @@ -7005,14 +7018,7 @@ /// parseDirectiveEcho /// ::= "echo" message -bool MasmParser::parseDirectiveEcho() { - // We're called before the directive is parsed, to avoid triggering lexical - // substitutions in the message. Assert that the next token is the directive, - // then eat it without using the Parser's Lex method. - assert(getTok().is(AsmToken::Identifier) && - getTok().getString().equals_lower("echo")); - Lexer.Lex(); - +bool MasmParser::parseDirectiveEcho(SMLoc DirectiveLoc) { std::string Message = parseStringTo(AsmToken::EndOfStatement); llvm::outs() << Message; if (!StringRef(Message).endswith("\n")) diff --git a/llvm/test/tools/llvm-ml/command_line_defines.asm b/llvm/test/tools/llvm-ml/command_line_defines.asm --- a/llvm/test/tools/llvm-ml/command_line_defines.asm +++ b/llvm/test/tools/llvm-ml/command_line_defines.asm @@ -1,4 +1,4 @@ -; RUN: llvm-ml -filetype=s %s /Fo - /DT1=test1 /D T2=test2 /Dtest5=def | FileCheck %s +; RUN: llvm-ml -filetype=s %s /Fo - /DT1=test1 /D T2=test2 /Dtest5=def /Dtest6 | FileCheck %s .code @@ -51,4 +51,13 @@ ; CHECK-NEXT: .byte 101 ; CHECK-NEXT: .byte 102 +t6: +ifdef test6 + xor eax, eax +endif + ret +; CHECK-LABEL: t6: +; CHECK: xor eax, eax +; CHECK: ret + end