diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index 1692b2f19000..f73e56ade2d7 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -58,6 +58,9 @@ typedef std::vector MCAsmMacroArguments; struct MCAsmMacroParameter { StringRef Name; MCAsmMacroArgument Value; + bool Required; + + MCAsmMacroParameter() : Required(false) { } }; typedef std::vector MCAsmMacroParameters; @@ -1940,26 +1943,23 @@ bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA) { bool AsmParser::parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A) { const unsigned NParameters = M ? M->Parameters.size() : 0; + bool NamedParametersFound = false; + SmallVector FALocs; A.resize(NParameters); - for (unsigned PI = 0; PI < NParameters; ++PI) - if (!M->Parameters[PI].Value.empty()) - A[PI] = M->Parameters[PI].Value; - - bool NamedParametersFound = false; + FALocs.resize(NParameters); // Parse two kinds of macro invocations: // - macros defined without any parameters accept an arbitrary number of them // - macros defined with parameters accept at most that many of them for (unsigned Parameter = 0; !NParameters || Parameter < NParameters; ++Parameter) { + SMLoc IDLoc = Lexer.getLoc(); MCAsmMacroParameter FA; - SMLoc L; if (Lexer.is(AsmToken::Identifier) && Lexer.peekTok().is(AsmToken::Equal)) { - L = Lexer.getLoc(); if (parseIdentifier(FA.Name)) { - Error(L, "invalid argument identifier for formal argument"); + Error(IDLoc, "invalid argument identifier for formal argument"); eatToEndOfStatement(); return true; } @@ -1975,7 +1975,7 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M, } if (NamedParametersFound && FA.Name.empty()) { - Error(Lexer.getLoc(), "cannot mix positional and keyword arguments"); + Error(IDLoc, "cannot mix positional and keyword arguments"); eatToEndOfStatement(); return true; } @@ -1989,8 +1989,9 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M, for (FAI = 0; FAI < NParameters; ++FAI) if (M->Parameters[FAI].Name == FA.Name) break; + if (FAI >= NParameters) { - Error(L, + Error(IDLoc, "parameter named '" + FA.Name + "' does not exist for macro '" + M->Name + "'"); return true; @@ -2002,13 +2003,33 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M, if (A.size() <= PI) A.resize(PI + 1); A[PI] = FA.Value; + + if (FALocs.size() <= PI) + FALocs.resize(PI + 1); + + FALocs[PI] = Lexer.getLoc(); } // At the end of the statement, fill in remaining arguments that have // default values. If there aren't any, then the next argument is // required but missing - if (Lexer.is(AsmToken::EndOfStatement)) - return false; + if (Lexer.is(AsmToken::EndOfStatement)) { + bool Failure = false; + for (unsigned FAI = 0; FAI < NParameters; ++FAI) { + if (A[FAI].empty()) { + if (M->Parameters[FAI].Required) { + Error(FALocs[FAI].isValid() ? FALocs[FAI] : Lexer.getLoc(), + "missing value for required parameter " + "'" + M->Parameters[FAI].Name + "' in macro '" + M->Name + "'"); + Failure = true; + } + + if (!M->Parameters[FAI].Value.empty()) + A[FAI] = M->Parameters[FAI].Value; + } + } + return Failure; + } if (Lexer.is(AsmToken::Comma)) Lex(); @@ -3210,10 +3231,36 @@ bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) { if (parseIdentifier(Parameter.Name)) return TokError("expected identifier in '.macro' directive"); + if (Lexer.is(AsmToken::Colon)) { + Lex(); // consume ':' + + SMLoc QualLoc; + StringRef Qualifier; + + QualLoc = Lexer.getLoc(); + if (parseIdentifier(Qualifier)) + return Error(QualLoc, "missing parameter qualifier for " + "'" + Parameter.Name + "' in macro '" + Name + "'"); + + if (Qualifier == "req") + Parameter.Required = true; + else + return Error(QualLoc, Qualifier + " is not a valid parameter qualifier " + "for '" + Parameter.Name + "' in macro '" + Name + "'"); + } + if (getLexer().is(AsmToken::Equal)) { Lex(); + + SMLoc ParamLoc; + + ParamLoc = Lexer.getLoc(); if (parseMacroArgument(Parameter.Value)) return true; + + if (Parameter.Required) + Warning(ParamLoc, "pointless default value for required parameter " + "'" + Parameter.Name + "' in macro '" + Name + "'"); } Parameters.push_back(Parameter); diff --git a/llvm/test/MC/AsmParser/macro-qualifier-diagnostics.s b/llvm/test/MC/AsmParser/macro-qualifier-diagnostics.s new file mode 100644 index 000000000000..4ebad2b69e48 --- /dev/null +++ b/llvm/test/MC/AsmParser/macro-qualifier-diagnostics.s @@ -0,0 +1,64 @@ +# RUN: not llvm-mc -triple i386 -o /dev/null %s 2>&1 | FileCheck %s + + .macro missing_qualifier parameter: + +# CHECK: error: missing parameter qualifier for 'parameter' in macro 'missing_qualifier' +# CHECK: .macro missing_qualifier parameter: +# CHECK: ^ + + .macro non_identifier_qualifier parameter:0 + +# CHECK: error: missing parameter qualifier for 'parameter' in macro 'non_identifier_qualifier' +# CHECK: .macro non_identifier_qualifier parameter:0 +# CHECK: ^ + + .macro invalid_qualifier parameter:invalid_qualifier + +# CHECK: error: invalid_qualifier is not a valid parameter qualifier for 'parameter' in macro 'invalid_qualifier' +# CHECK: .macro invalid_qualifier parameter:invalid_qualifier +# CHECK: ^ + + .macro pointless_default parameter:req=default + .endm + +# CHECK: warning: pointless default value for required parameter 'parameter' in macro 'pointless_default' +# CHECK: .macro pointless_default parameter:req=default +# CHECK: ^ + + .macro missing_required_parameter parameter:req + .endm + + missing_required_parameter + +# CHECK: error: missing value for required parameter 'parameter' in macro 'missing_required_parameter' +# CHECK: missing_required_parameter +# CHECK: ^ + + .macro missing_second_required_argument first=0 second:req + .endm + + missing_second_required_argument + +# CHECK: error: missing value for required parameter 'second' in macro 'missing_second_required_argument' +# CHECK: missing_second_required_argument +# CHECK: ^ + + .macro second_third_required first=0 second:req third:req + .endm + + second_third_required 0 + +# CHECK: error: missing value for required parameter 'second' in macro 'second_third_required' +# CHECK: second_third_required 0 +# CHECK: ^ + +# CHECK: error: missing value for required parameter 'third' in macro 'second_third_required' +# CHECK: second_third_required 0 +# CHECK: ^ + + second_third_required third=3 first=1 + +# CHECK: error: missing value for required parameter 'second' in macro 'second_third_required' +# CHECK: second_third_required third=3 first=1 +# CHECK: ^ + diff --git a/llvm/test/MC/AsmParser/macro-qualifier.s b/llvm/test/MC/AsmParser/macro-qualifier.s new file mode 100644 index 000000000000..7714e5cfa936 --- /dev/null +++ b/llvm/test/MC/AsmParser/macro-qualifier.s @@ -0,0 +1,16 @@ +# RUN: llvm-mc -triple i386 -o - %s | FileCheck %s + + .macro required parameter:req + .long \parameter + .endm + + required 0 +# CHECK: .long 0 + + .macro required_with_default parameter:req=0 + .long \parameter + .endm + + required 1 +# CHECK: .long 1 +