forked from OSchip/llvm-project
MCAsmParser: support required parameters
This enhances the macro parser to parse and handle parameter qualifications, which is needed to support required formal parameters in macro definitions. A required parameter may not be defaulted (though providing a default value is accepted with a warning). This improves GAS compatibility. Partially addresses PR9248. llvm-svn: 201630
This commit is contained in:
parent
a08585b233
commit
f903a44728
|
@ -58,6 +58,9 @@ typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments;
|
|||
struct MCAsmMacroParameter {
|
||||
StringRef Name;
|
||||
MCAsmMacroArgument Value;
|
||||
bool Required;
|
||||
|
||||
MCAsmMacroParameter() : Required(false) { }
|
||||
};
|
||||
|
||||
typedef std::vector<MCAsmMacroParameter> 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<SMLoc, 4> 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);
|
||||
|
|
|
@ -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: ^
|
||||
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue