aboutsummaryrefslogtreecommitdiff
path: root/llvm
diff options
context:
space:
mode:
authorSergei Barannikov <barannikov88@gmail.com>2023-06-29 17:22:41 +0300
committerSergei Barannikov <barannikov88@gmail.com>2023-07-01 04:33:28 +0300
commitaf20c1c1298d15f36470cd9d5b2cccb3b9b59c30 (patch)
treec53cfe4d72aa04582b2f5759240df170a6535bb6 /llvm
parent624813a4f41c5945dc8f8d998173960ad75db731 (diff)
downloadllvm-af20c1c1298d15f36470cd9d5b2cccb3b9b59c30.zip
llvm-af20c1c1298d15f36470cd9d5b2cccb3b9b59c30.tar.gz
llvm-af20c1c1298d15f36470cd9d5b2cccb3b9b59c30.tar.bz2
[MC] Add three-state parseDirective as a replacement for ParseDirective
Conventionally, parsing methods return false on success and true on error. However, directive parsing methods need a third state: the directive is not target specific. AsmParser::parseStatement detected this case by using a fragile heuristic: if the target parser did not consume any tokens, the directive is assumed to be not target-specific. Some targets fail to follow the convention: they return success after emitting an error or do not consume the entire line and return failure on successful parsing. This was partially worked around by checking for pending errors in parseStatement. This patch tries to improve the situation by introducing parseDirective method that returns ParseStatus -- three-state class. The new method should eventually replace the old one returning bool. ParseStatus is intentionally implicitly constructible from bool to allow uses like `return Error(Loc, "message")`. It also has a potential to replace OperandMatchResulTy as it is more convenient to use due to the implicit construction from bool and more type safe. Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D154101
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h41
-rw-r--r--llvm/lib/MC/MCParser/AsmParser.cpp18
-rw-r--r--llvm/lib/MC/MCParser/MCTargetAsmParser.cpp21
-rw-r--r--llvm/lib/MC/MCParser/MasmParser.cpp20
-rw-r--r--llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp30
-rw-r--r--llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp6
-rw-r--r--llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp20
-rw-r--r--llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp6
-rw-r--r--llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp4
-rw-r--r--llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp6
-rw-r--r--llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp33
-rw-r--r--llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp12
-rw-r--r--llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp23
-rw-r--r--llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp6
-rw-r--r--llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp65
-rw-r--r--llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp6
-rw-r--r--llvm/test/MC/CSKY/invalid-attribute.s15
-rw-r--r--llvm/test/MC/MSP430/directive-byte-word-long-invalid.s22
-rw-r--r--llvm/test/MC/MSP430/refsym-invalid.s10
-rw-r--r--llvm/test/MC/Sparc/sparc-directives.s5
-rw-r--r--llvm/test/MC/SystemZ/gnu-attributes-invalid.s13
-rw-r--r--llvm/test/MC/SystemZ/machine-directive-invalid.s10
-rw-r--r--llvm/test/MC/VE/data-size-error.s9
-rw-r--r--llvm/test/MC/WebAssembly/export-name-invalid.s13
-rw-r--r--llvm/test/MC/WebAssembly/functype-invalid.s28
-rw-r--r--llvm/test/MC/WebAssembly/globaltype-invalid.s31
-rw-r--r--llvm/test/MC/WebAssembly/import-module-invalid.s13
-rw-r--r--llvm/test/MC/WebAssembly/import-name-invalid.s13
-rw-r--r--llvm/test/MC/WebAssembly/tabletype-invalid.s28
-rw-r--r--llvm/test/MC/WebAssembly/tagtype-invalid.s10
30 files changed, 402 insertions, 135 deletions
diff --git a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h
index 6a060f3f..299f9b0 100644
--- a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h
+++ b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h
@@ -122,6 +122,32 @@ struct ParseInstructionInfo {
: AsmRewrites(rewrites) {}
};
+/// Ternary parse status returned by various parse* methods.
+class ParseStatus {
+ enum class StatusTy { Success, Failure, NoMatch } Status;
+
+public:
+#if __cplusplus >= 202002L
+ using enum StatusTy;
+#else
+ static constexpr StatusTy Success = StatusTy::Success;
+ static constexpr StatusTy Failure = StatusTy::Failure;
+ static constexpr StatusTy NoMatch = StatusTy::NoMatch;
+#endif
+
+ constexpr ParseStatus() : Status(NoMatch) {}
+
+ constexpr ParseStatus(StatusTy Status) : Status(Status) {}
+
+ constexpr ParseStatus(bool Error) : Status(Error ? Failure : Success) {}
+
+ template <typename T> constexpr ParseStatus(T) = delete;
+
+ constexpr bool isSuccess() const { return Status == StatusTy::Success; }
+ constexpr bool isFailure() const { return Status == StatusTy::Failure; }
+ constexpr bool isNoMatch() const { return Status == StatusTy::NoMatch; }
+};
+
enum OperandMatchResultTy {
MatchOperand_Success, // operand matched successfully
MatchOperand_NoMatch, // operand did not match
@@ -408,6 +434,7 @@ public:
}
/// ParseDirective - Parse a target specific assembler directive
+ /// This method is deprecated, use 'parseDirective' instead.
///
/// The parser is positioned following the directive name. The target
/// specific directive parser should parse the entire directive doing or
@@ -417,7 +444,19 @@ public:
/// end-of-statement token and false is returned.
///
/// \param DirectiveID - the identifier token of the directive.
- virtual bool ParseDirective(AsmToken DirectiveID) = 0;
+ virtual bool ParseDirective(AsmToken DirectiveID) { return true; }
+
+ /// Parses a target-specific assembler directive.
+ ///
+ /// The parser is positioned following the directive name. The target-specific
+ /// directive parser should parse the entire directive doing or recording any
+ /// target-specific work, or emit an error. On success, the entire line should
+ /// be parsed up to and including the end-of-statement token. On failure, the
+ /// parser is not required to read to the end of the line. If the directive is
+ /// not target-specific, no tokens should be consumed and NoMatch is returned.
+ ///
+ /// \param DirectiveID - The token identifying the directive.
+ virtual ParseStatus parseDirective(AsmToken DirectiveID);
/// MatchAndEmitInstruction - Recognize a series of operands of a parsed
/// instruction as an actual MCInst and emit it to the specified MCStreamer.
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
index 2c81c33..04590ed 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -1999,20 +1999,12 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
getTargetParser().flushPendingInstructions(getStreamer());
- SMLoc StartTokLoc = getTok().getLoc();
- bool TPDirectiveReturn = getTargetParser().ParseDirective(ID);
-
- if (hasPendingError())
- return true;
- // Currently the return value should be true if we are
- // uninterested but as this is at odds with the standard parsing
- // convention (return true = error) we have instances of a parsed
- // directive that fails returning true as an error. Catch these
- // cases as best as possible errors here.
- if (TPDirectiveReturn && StartTokLoc != getTok().getLoc())
+ ParseStatus TPDirectiveReturn = getTargetParser().parseDirective(ID);
+ assert(TPDirectiveReturn.isFailure() == hasPendingError() &&
+ "Should only return Failure iff there was an error");
+ if (TPDirectiveReturn.isFailure())
return true;
- // Return if we did some parsing or believe we succeeded.
- if (!TPDirectiveReturn || StartTokLoc != getTok().getLoc())
+ if (TPDirectiveReturn.isSuccess())
return false;
// Next, check the extension directive map to see if any extension has
diff --git a/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp b/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp
index 940f26d..0db5fb3 100644
--- a/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp
+++ b/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp
@@ -27,3 +27,24 @@ MCSubtargetInfo &MCTargetAsmParser::copySTI() {
const MCSubtargetInfo &MCTargetAsmParser::getSTI() const {
return *STI;
}
+
+ParseStatus MCTargetAsmParser::parseDirective(AsmToken DirectiveID) {
+ SMLoc StartTokLoc = getTok().getLoc();
+ // Delegate to ParseDirective by default for transition period. Once the
+ // transition is over, this method should just return NoMatch.
+ bool Res = ParseDirective(DirectiveID);
+
+ // Some targets erroneously report success after emitting an error.
+ if (getParser().hasPendingError())
+ return ParseStatus::Failure;
+
+ // ParseDirective returns true if there was an error or if the directive is
+ // not target-specific. Disambiguate the two cases by comparing position of
+ // the lexer before and after calling the method: if no tokens were consumed,
+ // there was no match, otherwise there was a failure.
+ if (!Res)
+ return ParseStatus::Success;
+ if (getTok().getLoc() != StartTokLoc)
+ return ParseStatus::Failure;
+ return ParseStatus::NoMatch;
+}
diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp
index d41df71..307256f 100644
--- a/llvm/lib/MC/MCParser/MasmParser.cpp
+++ b/llvm/lib/MC/MCParser/MasmParser.cpp
@@ -2304,21 +2304,15 @@ bool MasmParser::parseStatement(ParseStatementInfo &Info,
return (*Handler.second)(Handler.first, IDVal, IDLoc);
// Next, let the target-specific assembly parser try.
- SMLoc StartTokLoc = getTok().getLoc();
- bool TPDirectiveReturn =
- ID.is(AsmToken::Identifier) && getTargetParser().ParseDirective(ID);
+ if (ID.isNot(AsmToken::Identifier))
+ return false;
- if (hasPendingError())
- return true;
- // Currently the return value should be true if we are
- // uninterested but as this is at odds with the standard parsing
- // convention (return true = error) we have instances of a parsed
- // directive that fails returning true as an error. Catch these
- // cases as best as possible errors here.
- if (TPDirectiveReturn && StartTokLoc != getTok().getLoc())
+ ParseStatus TPDirectiveReturn = getTargetParser().parseDirective(ID);
+ assert(TPDirectiveReturn.isFailure() == hasPendingError() &&
+ "Should only return Failure iff there was an error");
+ if (TPDirectiveReturn.isFailure())
return true;
- // Return if we did some parsing or believe we succeeded.
- if (!TPDirectiveReturn || StartTokLoc != getTok().getLoc())
+ if (TPDirectiveReturn.isSuccess())
return false;
// Finally, if no one else is interested in this directive, it must be
diff --git a/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp b/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp
index 8d30b78..6c328ff 100644
--- a/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp
+++ b/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp
@@ -64,7 +64,7 @@ class AVRAsmParser : public MCTargetAsmParser {
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
- bool ParseDirective(AsmToken DirectiveID) override;
+ ParseStatus parseDirective(AsmToken DirectiveID) override;
OperandMatchResultTy parseMemriOperand(OperandVector &Operands);
@@ -90,7 +90,7 @@ class AVRAsmParser : public MCTargetAsmParser {
uint64_t const &ErrorInfo);
bool missingFeature(SMLoc const &Loc, uint64_t const &ErrorInfo);
- bool parseLiteralValues(unsigned SizeInBytes, SMLoc L);
+ ParseStatus parseLiteralValues(unsigned SizeInBytes, SMLoc L);
public:
AVRAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
@@ -674,19 +674,18 @@ bool AVRAsmParser::ParseInstruction(ParseInstructionInfo &Info,
return false;
}
-bool AVRAsmParser::ParseDirective(llvm::AsmToken DirectiveID) {
+ParseStatus AVRAsmParser::parseDirective(llvm::AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getIdentifier();
- if (IDVal.lower() == ".long") {
- parseLiteralValues(SIZE_LONG, DirectiveID.getLoc());
- } else if (IDVal.lower() == ".word" || IDVal.lower() == ".short") {
- parseLiteralValues(SIZE_WORD, DirectiveID.getLoc());
- } else if (IDVal.lower() == ".byte") {
- parseLiteralValues(1, DirectiveID.getLoc());
- }
- return true;
+ if (IDVal.lower() == ".long")
+ return parseLiteralValues(SIZE_LONG, DirectiveID.getLoc());
+ if (IDVal.lower() == ".word" || IDVal.lower() == ".short")
+ return parseLiteralValues(SIZE_WORD, DirectiveID.getLoc());
+ if (IDVal.lower() == ".byte")
+ return parseLiteralValues(1, DirectiveID.getLoc());
+ return ParseStatus::NoMatch;
}
-bool AVRAsmParser::parseLiteralValues(unsigned SizeInBytes, SMLoc L) {
+ParseStatus AVRAsmParser::parseLiteralValues(unsigned SizeInBytes, SMLoc L) {
MCAsmParser &Parser = getParser();
AVRMCELFStreamer &AVRStreamer =
static_cast<AVRMCELFStreamer &>(Parser.getStreamer());
@@ -698,7 +697,7 @@ bool AVRAsmParser::parseLiteralValues(unsigned SizeInBytes, SMLoc L) {
MCSymbol *Symbol = getContext().getOrCreateSymbol(".text");
AVRStreamer.emitValueForModiferKind(Symbol, SizeInBytes, L,
AVRMCExpr::VK_AVR_None);
- return false;
+ return ParseStatus::NoMatch;
}
if (Parser.getTok().getKind() == AsmToken::Identifier &&
@@ -715,7 +714,10 @@ bool AVRAsmParser::parseLiteralValues(unsigned SizeInBytes, SMLoc L) {
MCSymbol *Symbol =
getContext().getOrCreateSymbol(Parser.getTok().getString());
AVRStreamer.emitValueForModiferKind(Symbol, SizeInBytes, L, ModifierKind);
- return false;
+ Lex(); // Eat the symbol name.
+ if (parseToken(AsmToken::RParen))
+ return ParseStatus::Failure;
+ return parseEOL();
}
auto parseOne = [&]() -> bool {
diff --git a/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp b/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
index 85858b7..9896ddd 100644
--- a/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
+++ b/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
@@ -47,7 +47,7 @@ class BPFAsmParser : public MCTargetAsmParser {
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
- bool ParseDirective(AsmToken DirectiveID) override;
+ ParseStatus parseDirective(AsmToken DirectiveID) override;
// "=" is used as assignment operator for assembly statment, so can't be used
// for symbol assignment.
@@ -516,7 +516,9 @@ bool BPFAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
return false;
}
-bool BPFAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
+ParseStatus BPFAsmParser::parseDirective(AsmToken DirectiveID) {
+ return ParseStatus::NoMatch;
+}
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFAsmParser() {
RegisterMCAsmParser<BPFAsmParser> X(getTheBPFTarget());
diff --git a/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp b/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
index 413c331..c4d600757 100644
--- a/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
+++ b/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
@@ -77,7 +77,7 @@ class CSKYAsmParser : public MCTargetAsmParser {
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
- bool ParseDirective(AsmToken DirectiveID) override;
+ ParseStatus parseDirective(AsmToken DirectiveID) override;
// Helper to actually emit an instruction to the MCStreamer. Also, when
// possible, compression of the instruction is performed.
@@ -1573,17 +1573,13 @@ OperandMatchResultTy CSKYAsmParser::tryParseRegister(MCRegister &RegNo,
return MatchOperand_Success;
}
-bool CSKYAsmParser::ParseDirective(AsmToken DirectiveID) {
- // This returns false if this function recognizes the directive
- // regardless of whether it is successfully handles or reports an
- // error. Otherwise it returns true to give the generic parser a
- // chance at recognizing it.
+ParseStatus CSKYAsmParser::parseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getString();
if (IDVal == ".csky_attribute")
return parseDirectiveAttribute();
- return true;
+ return ParseStatus::NoMatch;
}
/// parseDirectiveAttribute
@@ -1597,10 +1593,8 @@ bool CSKYAsmParser::parseDirectiveAttribute() {
StringRef Name = Parser.getTok().getIdentifier();
std::optional<unsigned> Ret =
ELFAttrs::attrTypeFromString(Name, CSKYAttrs::getCSKYAttributeTags());
- if (!Ret) {
- Error(TagLoc, "attribute name not recognised: " + Name);
- return false;
- }
+ if (!Ret)
+ return Error(TagLoc, "attribute name not recognised: " + Name);
Tag = *Ret;
Parser.Lex();
} else {
@@ -1611,8 +1605,8 @@ bool CSKYAsmParser::parseDirectiveAttribute() {
return true;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(AttrExpr);
- if (check(!CE, TagLoc, "expected numeric constant"))
- return true;
+ if (!CE)
+ return Error(TagLoc, "expected numeric constant");
Tag = CE->getValue();
}
diff --git a/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp b/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
index 2c7013d..cf84e86 100644
--- a/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
+++ b/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
@@ -62,7 +62,7 @@ class LanaiAsmParser : public MCTargetAsmParser {
bool parsePrePost(StringRef Type, int *OffsetValue);
- bool ParseDirective(AsmToken DirectiveID) override;
+ ParseStatus parseDirective(AsmToken DirectiveID) override;
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
@@ -649,7 +649,9 @@ public:
} // end anonymous namespace
-bool LanaiAsmParser::ParseDirective(AsmToken /*DirectiveId*/) { return true; }
+ParseStatus LanaiAsmParser::parseDirective(AsmToken DirectiveID) {
+ return ParseStatus::NoMatch;
+}
bool LanaiAsmParser::MatchAndEmitInstruction(SMLoc IdLoc, unsigned &Opcode,
OperandVector &Operands,
diff --git a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
index a28e9e5..d3f4551 100644
--- a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
+++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
@@ -51,7 +51,9 @@ class LoongArchAsmParser : public MCTargetAsmParser {
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
- bool ParseDirective(AsmToken DirectiveID) override { return true; }
+ ParseStatus parseDirective(AsmToken DirectiveID) override {
+ return ParseStatus::NoMatch;
+ }
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands, MCStreamer &Out,
diff --git a/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp b/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp
index 89a5f02..1d9b505 100644
--- a/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp
+++ b/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp
@@ -72,7 +72,7 @@ public:
SMLoc &EndLoc) override;
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
- bool ParseDirective(AsmToken DirectiveID) override;
+ ParseStatus parseDirective(AsmToken DirectiveID) override;
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands, MCStreamer &Out,
uint64_t &ErrorInfo,
@@ -992,7 +992,9 @@ bool M68kAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
return false;
}
-bool M68kAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
+ParseStatus M68kAsmParser::parseDirective(AsmToken DirectiveID) {
+ return ParseStatus::NoMatch;
+}
bool M68kAsmParser::invalidOperand(SMLoc const &Loc,
OperandVector const &Operands,
diff --git a/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp b/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp
index 1389f0a..f2c90f5 100644
--- a/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp
+++ b/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp
@@ -53,7 +53,7 @@ class MSP430AsmParser : public MCTargetAsmParser {
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
- bool ParseDirective(AsmToken DirectiveID) override;
+ ParseStatus parseDirective(AsmToken DirectiveID) override;
bool ParseDirectiveRefSym(AsmToken DirectiveID);
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
@@ -424,27 +424,26 @@ bool MSP430AsmParser::ParseInstruction(ParseInstructionInfo &Info,
}
bool MSP430AsmParser::ParseDirectiveRefSym(AsmToken DirectiveID) {
- StringRef Name;
- if (getParser().parseIdentifier(Name))
- return TokError("expected identifier in directive");
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
- MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
- getStreamer().emitSymbolAttribute(Sym, MCSA_Global);
- return false;
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+ getStreamer().emitSymbolAttribute(Sym, MCSA_Global);
+ return parseEOL();
}
-bool MSP430AsmParser::ParseDirective(AsmToken DirectiveID) {
+ParseStatus MSP430AsmParser::parseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getIdentifier();
- if (IDVal.lower() == ".long") {
- ParseLiteralValues(4, DirectiveID.getLoc());
- } else if (IDVal.lower() == ".word" || IDVal.lower() == ".short") {
- ParseLiteralValues(2, DirectiveID.getLoc());
- } else if (IDVal.lower() == ".byte") {
- ParseLiteralValues(1, DirectiveID.getLoc());
- } else if (IDVal.lower() == ".refsym") {
+ if (IDVal.lower() == ".long")
+ return ParseLiteralValues(4, DirectiveID.getLoc());
+ if (IDVal.lower() == ".word" || IDVal.lower() == ".short")
+ return ParseLiteralValues(2, DirectiveID.getLoc());
+ if (IDVal.lower() == ".byte")
+ return ParseLiteralValues(1, DirectiveID.getLoc());
+ if (IDVal.lower() == ".refsym")
return ParseDirectiveRefSym(DirectiveID);
- }
- return true;
+ return ParseStatus::NoMatch;
}
bool MSP430AsmParser::ParseOperand(OperandVector &Operands) {
diff --git a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
index 6306fd1..9bfee26 100644
--- a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
+++ b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -76,7 +76,7 @@ class SparcAsmParser : public MCTargetAsmParser {
SMLoc &EndLoc) override;
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
- bool ParseDirective(AsmToken DirectiveID) override;
+ ParseStatus parseDirective(AsmToken DirectiveID) override;
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
unsigned Kind) override;
@@ -769,25 +769,23 @@ bool SparcAsmParser::ParseInstruction(ParseInstructionInfo &Info,
return false;
}
-bool SparcAsmParser::
-ParseDirective(AsmToken DirectiveID)
-{
+ParseStatus SparcAsmParser::parseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getString();
if (IDVal == ".register") {
// For now, ignore .register directive.
Parser.eatToEndOfStatement();
- return false;
+ return ParseStatus::Success;
}
if (IDVal == ".proc") {
// For compatibility, ignore this directive.
// (It's supposed to be an "optimization" in the Sun assembler)
Parser.eatToEndOfStatement();
- return false;
+ return ParseStatus::Success;
}
// Let the MC layer to handle other directives.
- return true;
+ return ParseStatus::NoMatch;
}
OperandMatchResultTy
diff --git a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
index 61831cc..4f8d16b 100644
--- a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
+++ b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp
@@ -494,7 +494,7 @@ public:
}
// Override MCTargetAsmParser.
- bool ParseDirective(AsmToken DirectiveID) override;
+ ParseStatus parseDirective(AsmToken DirectiveID) override;
bool parseRegister(MCRegister &RegNo, SMLoc &StartLoc,
SMLoc &EndLoc) override;
bool ParseRegister(MCRegister &RegNo, SMLoc &StartLoc, SMLoc &EndLoc,
@@ -1219,7 +1219,7 @@ SystemZAsmParser::parseAddress(OperandVector &Operands, MemoryKind MemKind,
return MatchOperand_Success;
}
-bool SystemZAsmParser::ParseDirective(AsmToken DirectiveID) {
+ParseStatus SystemZAsmParser::parseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getIdentifier();
if (IDVal == ".insn")
@@ -1229,7 +1229,7 @@ bool SystemZAsmParser::ParseDirective(AsmToken DirectiveID) {
if (IDVal.startswith(".gnu_attribute"))
return ParseGNUAttribute(DirectiveID.getLoc());
- return true;
+ return ParseStatus::NoMatch;
}
/// ParseDirectiveInsn
@@ -1346,12 +1346,12 @@ bool SystemZAsmParser::ParseDirectiveMachine(SMLoc L) {
MCAsmParser &Parser = getParser();
if (Parser.getTok().isNot(AsmToken::Identifier) &&
Parser.getTok().isNot(AsmToken::String))
- return Error(L, "unexpected token in '.machine' directive");
+ return TokError("unexpected token in '.machine' directive");
StringRef CPU = Parser.getTok().getIdentifier();
Parser.Lex();
- if (parseToken(AsmToken::EndOfStatement))
- return addErrorSuffix(" in '.machine' directive");
+ if (parseEOL())
+ return true;
MCSubtargetInfo &STI = copySTI();
STI.setDefaultFeatures(CPU, /*TuneCPU*/ CPU, "");
@@ -1366,18 +1366,15 @@ bool SystemZAsmParser::ParseGNUAttribute(SMLoc L) {
int64_t Tag;
int64_t IntegerValue;
if (!Parser.parseGNUAttribute(L, Tag, IntegerValue))
- return false;
+ return Error(L, "malformed .gnu_attribute directive");
// Tag_GNU_S390_ABI_Vector tag is '8' and can be 0, 1, or 2.
- if (Tag != 8 || (IntegerValue < 0 || IntegerValue > 2)) {
- Error(Parser.getTok().getLoc(),
- "Unrecognized .gnu_attribute tag/value pair.");
- return false;
- }
+ if (Tag != 8 || (IntegerValue < 0 || IntegerValue > 2))
+ return Error(L, "unrecognized .gnu_attribute tag/value pair.");
Parser.getStreamer().emitGNUAttribute(Tag, IntegerValue);
- return true;
+ return parseEOL();
}
bool SystemZAsmParser::ParseRegister(MCRegister &RegNo, SMLoc &StartLoc,
diff --git a/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp b/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp
index 0a72f29..a9cedf1 100644
--- a/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp
+++ b/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp
@@ -62,7 +62,7 @@ class VEAsmParser : public MCTargetAsmParser {
SMLoc &EndLoc) override;
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
- bool ParseDirective(AsmToken DirectiveID) override;
+ ParseStatus parseDirective(AsmToken DirectiveID) override;
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
unsigned Kind) override;
@@ -998,7 +998,7 @@ bool VEAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
return false;
}
-bool VEAsmParser::ParseDirective(AsmToken DirectiveID) {
+ParseStatus VEAsmParser::parseDirective(AsmToken DirectiveID) {
std::string IDVal = DirectiveID.getIdentifier().lower();
// Defines VE specific directives. Reference is "Vector Engine Assembly
@@ -1018,7 +1018,7 @@ bool VEAsmParser::ParseDirective(AsmToken DirectiveID) {
return parseLiteralValues(8, DirectiveID.getLoc());
// Let the MC layer to handle other directives.
- return true;
+ return ParseStatus::NoMatch;
}
/// parseLiteralValues
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index e8efb55..1e2d388 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -785,31 +785,23 @@ public:
// This function processes wasm-specific directives streamed to
// WebAssemblyTargetStreamer, all others go to the generic parser
// (see WasmAsmParser).
- bool ParseDirective(AsmToken DirectiveID) override {
- // This function has a really weird return value behavior that is different
- // from all the other parsing functions:
- // - return true && no tokens consumed -> don't know this directive / let
- // the generic parser handle it.
- // - return true && tokens consumed -> a parsing error occurred.
- // - return false -> processed this directive successfully.
+ ParseStatus parseDirective(AsmToken DirectiveID) override {
assert(DirectiveID.getKind() == AsmToken::Identifier);
auto &Out = getStreamer();
auto &TOut =
reinterpret_cast<WebAssemblyTargetStreamer &>(*Out.getTargetStreamer());
auto &Ctx = Out.getContext();
- // TODO: any time we return an error, at least one token must have been
- // consumed, otherwise this will not signal an error to the caller.
if (DirectiveID.getString() == ".globaltype") {
auto SymName = expectIdent();
if (SymName.empty())
- return true;
+ return ParseStatus::Failure;
if (expect(AsmToken::Comma, ","))
- return true;
+ return ParseStatus::Failure;
auto TypeTok = Lexer.getTok();
auto TypeName = expectIdent();
if (TypeName.empty())
- return true;
+ return ParseStatus::Failure;
auto Type = WebAssembly::parseType(TypeName);
if (!Type)
return error("Unknown type in .globaltype directive: ", TypeTok);
@@ -820,6 +812,8 @@ public:
if (isNext(AsmToken::Comma)) {
TypeTok = Lexer.getTok();
auto Id = expectIdent();
+ if (Id.empty())
+ return ParseStatus::Failure;
if (Id == "immutable")
Mutable = false;
else
@@ -839,14 +833,14 @@ public:
// .tabletype SYM, ELEMTYPE[, MINSIZE[, MAXSIZE]]
auto SymName = expectIdent();
if (SymName.empty())
- return true;
+ return ParseStatus::Failure;
if (expect(AsmToken::Comma, ","))
- return true;
+ return ParseStatus::Failure;
auto ElemTypeTok = Lexer.getTok();
auto ElemTypeName = expectIdent();
if (ElemTypeName.empty())
- return true;
+ return ParseStatus::Failure;
std::optional<wasm::ValType> ElemType =
WebAssembly::parseType(ElemTypeName);
if (!ElemType)
@@ -854,7 +848,7 @@ public:
wasm::WasmLimits Limits = DefaultLimits();
if (isNext(AsmToken::Comma) && parseLimits(&Limits))
- return true;
+ return ParseStatus::Failure;
// Now that we have the name and table type, we can actually create the
// symbol
@@ -874,7 +868,7 @@ public:
// parses the locals separately.
auto SymName = expectIdent();
if (SymName.empty())
- return true;
+ return ParseStatus::Failure;
auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
if (WasmSym->isDefined()) {
// We push 'Function' either when a label is parsed or a .functype
@@ -890,7 +884,7 @@ public:
if (CurrentState != FunctionLabel) {
// This .functype indicates a start of a function.
if (ensureEmptyNestingStack())
- return true;
+ return ParseStatus::Failure;
push(Function);
}
CurrentState = FunctionStart;
@@ -898,7 +892,7 @@ public:
}
auto Signature = std::make_unique<wasm::WasmSignature>();
if (parseSignature(Signature.get()))
- return true;
+ return ParseStatus::Failure;
TC.funcDecl(*Signature);
WasmSym->setSignature(Signature.get());
addSignature(std::move(Signature));
@@ -911,47 +905,56 @@ public:
if (DirectiveID.getString() == ".export_name") {
auto SymName = expectIdent();
if (SymName.empty())
- return true;
+ return ParseStatus::Failure;
if (expect(AsmToken::Comma, ","))
- return true;
+ return ParseStatus::Failure;
auto ExportName = expectIdent();
+ if (ExportName.empty())
+ return ParseStatus::Failure;
auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
WasmSym->setExportName(storeName(ExportName));
TOut.emitExportName(WasmSym, ExportName);
+ return expect(AsmToken::EndOfStatement, "EOL");
}
if (DirectiveID.getString() == ".import_module") {
auto SymName = expectIdent();
if (SymName.empty())
- return true;
+ return ParseStatus::Failure;
if (expect(AsmToken::Comma, ","))
- return true;
+ return ParseStatus::Failure;
auto ImportModule = expectIdent();
+ if (ImportModule.empty())
+ return ParseStatus::Failure;
auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
WasmSym->setImportModule(storeName(ImportModule));
TOut.emitImportModule(WasmSym, ImportModule);
+ return expect(AsmToken::EndOfStatement, "EOL");
}
if (DirectiveID.getString() == ".import_name") {
auto SymName = expectIdent();
if (SymName.empty())
- return true;
+ return ParseStatus::Failure;
if (expect(AsmToken::Comma, ","))
- return true;
+ return ParseStatus::Failure;
auto ImportName = expectIdent();
+ if (ImportName.empty())
+ return ParseStatus::Failure;
auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
WasmSym->setImportName(storeName(ImportName));
TOut.emitImportName(WasmSym, ImportName);
+ return expect(AsmToken::EndOfStatement, "EOL");
}
if (DirectiveID.getString() == ".tagtype") {
auto SymName = expectIdent();
if (SymName.empty())
- return true;
+ return ParseStatus::Failure;
auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
auto Signature = std::make_unique<wasm::WasmSignature>();
if (parseRegTypeList(Signature->Params))
- return true;
+ return ParseStatus::Failure;
WasmSym->setSignature(Signature.get());
addSignature(std::move(Signature));
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);
@@ -966,7 +969,7 @@ public:
Lexer.getTok());
SmallVector<wasm::ValType, 4> Locals;
if (parseRegTypeList(Locals))
- return true;
+ return ParseStatus::Failure;
TC.localDecl(Locals);
TOut.emitLocal(Locals);
CurrentState = FunctionLocals;
@@ -978,7 +981,7 @@ public:
DirectiveID.getString() == ".int32" ||
DirectiveID.getString() == ".int64") {
if (CheckDataSection())
- return true;
+ return ParseStatus::Failure;
const MCExpr *Val;
SMLoc End;
if (Parser.parseExpression(Val, End))
@@ -991,7 +994,7 @@ public:
if (DirectiveID.getString() == ".asciz") {
if (CheckDataSection())
- return true;
+ return ParseStatus::Failure;
std::string S;
if (Parser.parseEscapedString(S))
return error("Cannot parse string constant: ", Lexer.getTok());
@@ -999,7 +1002,7 @@ public:
return expect(AsmToken::EndOfStatement, "EOL");
}
- return true; // We didn't process this directive.
+ return ParseStatus::NoMatch; // We didn't process this directive.
}
// Called either when the first instruction is parsed of the function ends.
diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
index b8632d4..39998ff 100644
--- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
+++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
@@ -36,7 +36,7 @@ class XtensaAsmParser : public MCTargetAsmParser {
SMLoc getLoc() const { return getParser().getTok().getLoc(); }
// Override MCTargetAsmParser.
- bool ParseDirective(AsmToken DirectiveID) override;
+ ParseStatus parseDirective(AsmToken DirectiveID) override;
bool parseRegister(MCRegister &RegNo,
SMLoc &StartLoc, SMLoc &EndLoc) override;
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
@@ -697,7 +697,9 @@ bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info,
return false;
}
-bool XtensaAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
+ParseStatus XtensaAsmParser::parseDirective(AsmToken DirectiveID) {
+ return ParseStatus::NoMatch;
+}
// Force static initialization.
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaAsmParser() {
diff --git a/llvm/test/MC/CSKY/invalid-attribute.s b/llvm/test/MC/CSKY/invalid-attribute.s
index a6558e7..7123d8f 100644
--- a/llvm/test/MC/CSKY/invalid-attribute.s
+++ b/llvm/test/MC/CSKY/invalid-attribute.s
@@ -5,6 +5,21 @@
# RUN: not llvm-mc %s -triple=csky -filetype=asm 2>&1 | FileCheck %s
+.csky_attribute CSKY_UNKNOWN
+# CHECK: [[@LINE-1]]:17: error: attribute name not recognised: CSKY_UNKNOWN
+
+.csky_attribute CSKY_ARCH_NAME
+# CHECK: [[@LINE-1]]:31: error: expected comma
+
+.csky_attribute CSKY_ISA_FLAGS
+# CHECK: [[@LINE-1]]:31: error: expected comma
+
+.csky_attribute CSKY_ARCH_NAME, "foo",
+# CHECK: [[@LINE-1]]:38: error: expected newline
+
+.csky_attribute CSKY_ISA_FLAGS, 42,
+# CHECK: [[@LINE-1]]:35: error: expected newline
+
.csky_attribute CSKY_ARCH_NAME, "foo"
# CHECK: [[@LINE-1]]:33: error: unknown arch name
diff --git a/llvm/test/MC/MSP430/directive-byte-word-long-invalid.s b/llvm/test/MC/MSP430/directive-byte-word-long-invalid.s
new file mode 100644
index 0000000..c70fb48
--- /dev/null
+++ b/llvm/test/MC/MSP430/directive-byte-word-long-invalid.s
@@ -0,0 +1,22 @@
+# RUN: not llvm-mc -triple=msp430 %s 2>&1 | FileCheck %s
+
+# CHECK: [[#@LINE+3]]:6: error: unknown token in expression
+# CHECK: [[#@LINE+3]]:6: error: unknown token in expression
+# CHECK: [[#@LINE+3]]:6: error: unknown token in expression
+.byte, 42
+.word, 42
+.long, 42
+
+# CHECK: [[#@LINE+3]]:10: error: unknown token in expression
+# CHECK: [[#@LINE+3]]:10: error: unknown token in expression
+# CHECK: [[#@LINE+3]]:10: error: unknown token in expression
+.byte 42,
+.word 42,
+.long 42,
+
+# CHECK: [[#@LINE+3]]:10: error: unexpected token
+# CHECK: [[#@LINE+3]]:10: error: unexpected token
+# CHECK: [[#@LINE+3]]:10: error: unexpected token
+.byte 42 42
+.word 42 42
+.long 42 42
diff --git a/llvm/test/MC/MSP430/refsym-invalid.s b/llvm/test/MC/MSP430/refsym-invalid.s
new file mode 100644
index 0000000..5cbf707
--- /dev/null
+++ b/llvm/test/MC/MSP430/refsym-invalid.s
@@ -0,0 +1,10 @@
+# RUN: not llvm-mc -triple=msp430 %s 2>&1 | FileCheck %s
+
+# CHECK: [[#@LINE+1]]:8: error: expected identifier in directive
+.refsym
+
+# CHECK: [[#@LINE+1]]:9: error: expected identifier in directive
+.refsym 42
+
+# CHECK: [[#@LINE+1]]:12: error: expected newline
+.refsym sym,
diff --git a/llvm/test/MC/Sparc/sparc-directives.s b/llvm/test/MC/Sparc/sparc-directives.s
index 5c8cd00..1e1ce74 100644
--- a/llvm/test/MC/Sparc/sparc-directives.s
+++ b/llvm/test/MC/Sparc/sparc-directives.s
@@ -3,7 +3,10 @@
! '.proc' is documented to do nothing in the binutils assembler.
! so it should do nothing for clang either, i.e. not be an error.
- .proc 1
+ .proc 1 x (
+
+ ! '.register' is currently ignored.
+ .register 8-)
! SPARC32: .byte 24
! SPARC64: .byte 24
diff --git a/llvm/test/MC/SystemZ/gnu-attributes-invalid.s b/llvm/test/MC/SystemZ/gnu-attributes-invalid.s
new file mode 100644
index 0000000..c308053
--- /dev/null
+++ b/llvm/test/MC/SystemZ/gnu-attributes-invalid.s
@@ -0,0 +1,13 @@
+# RUN: not llvm-mc -triple s390x %s 2>&1 | FileCheck %s
+
+# CHECK: [[#@LINE+1]]:1: error: malformed .gnu_attribute directive
+.gnu_attribute tag, value
+
+# CHECK: [[#@LINE+1]]:1: error: unrecognized .gnu_attribute tag/value pair.
+.gnu_attribute 42, 8
+
+# CHECK: [[#@LINE+1]]:1: error: unrecognized .gnu_attribute tag/value pair.
+.gnu_attribute 8, 42
+
+# CHECK: [[#@LINE+1]]:20: error: expected newline
+.gnu_attribute 8, 1$
diff --git a/llvm/test/MC/SystemZ/machine-directive-invalid.s b/llvm/test/MC/SystemZ/machine-directive-invalid.s
new file mode 100644
index 0000000..8b3147e
--- /dev/null
+++ b/llvm/test/MC/SystemZ/machine-directive-invalid.s
@@ -0,0 +1,10 @@
+# RUN: not llvm-mc -triple=s390x %s 2>&1 | FileCheck %s
+
+# CHECK: [[#@LINE+1]]:9: error: unexpected token in '.machine' directive
+.machine
+
+# CHECK: [[#@LINE+1]]:10: error: unexpected token in '.machine' directive
+.machine 42
+
+# CHECK: [[#@LINE+1]]:13: error: expected newline
+.machine z13+
diff --git a/llvm/test/MC/VE/data-size-error.s b/llvm/test/MC/VE/data-size-error.s
index 0313944..c6188e0 100644
--- a/llvm/test/MC/VE/data-size-error.s
+++ b/llvm/test/MC/VE/data-size-error.s
@@ -34,3 +34,12 @@ a:
# CHECK-NEXT: .quad 0xff5588aadeadbeafde
# CHECK: data-size-error.s:15:8: error: literal value out of range for directive
# CHECK-NEXT: .llong 0xff5588aadeadbeafde
+
+# CHECK: [[#@LINE+1]]:17: error: unknown token in expression
+.word 0xd0bb1e +
+
+# CHECK: [[#@LINE+1]]:16: error: unexpected token
+.long 0xd0bb1e =
+
+# CHECK: [[#@LINE+1]]:10: error: unexpected token
+.llong 2 0xd0bb1e
diff --git a/llvm/test/MC/WebAssembly/export-name-invalid.s b/llvm/test/MC/WebAssembly/export-name-invalid.s
new file mode 100644
index 0000000..ad322ce
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/export-name-invalid.s
@@ -0,0 +1,13 @@
+# RUN: not llvm-mc -triple=wasm32 %s 2>&1 | FileCheck %s
+
+# CHECK: [[#@LINE+1]]:14: error: Expected identifier, got: 42
+.export_name 42
+
+# CHECK: [[#@LINE+1]]:17: error: Expected ,, instead got:
+.export_name foo
+
+# CHECK: [[#@LINE+1]]:18: error: Expected identifier, got:
+.export_name foo,
+
+# CHECK: [[#@LINE+1]]:22: error: Expected EOL, instead got: ,
+.export_name foo, bar,
diff --git a/llvm/test/MC/WebAssembly/functype-invalid.s b/llvm/test/MC/WebAssembly/functype-invalid.s
new file mode 100644
index 0000000..89b90c5
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/functype-invalid.s
@@ -0,0 +1,28 @@
+# RUN: not llvm-mc -triple=wasm32 %s 2>&1 | FileCheck %s
+
+# CHECK: [[#@LINE+1]]:10: error: Expected identifier, got:
+.functype
+
+# CHECK: [[#@LINE+1]]:13: error: Expected (, instead got:
+.functype fn
+
+# CHECK: [[#@LINE+1]]:15: error: Expected ), instead got:
+.functype fn (
+
+# CHECK: [[#@LINE+1]]:15: error: unknown type: i42
+.functype fn (i42
+
+# CHECK: [[#@LINE+1]]:19: error: Expected ), instead got: i32
+.functype fn (i32 i32
+
+# CHECK: [[#@LINE+1]]:16: error: Expected ->, instead got:
+.functype fn ()
+
+# CHECK: [[#@LINE+1]]:17: error: Expected ->, instead got: <
+.functype fn () <- ()
+
+# CHECK: [[#@LINE+1]]:21: error: Expected ), instead got:
+.functype fn () -> (
+
+# CHECK: [[#@LINE+1]]:23: error: Expected EOL, instead got: ->
+.functype fn () -> () -> ()
diff --git a/llvm/test/MC/WebAssembly/globaltype-invalid.s b/llvm/test/MC/WebAssembly/globaltype-invalid.s
new file mode 100644
index 0000000..26344e8
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/globaltype-invalid.s
@@ -0,0 +1,31 @@
+# RUN: not llvm-mc -triple=wasm32 %s 2>&1 | FileCheck %s
+
+# CHECK: [[#@LINE+1]]:12: error: Expected identifier, got:
+.globaltype
+
+# CHECK: [[#@LINE+1]]:13: error: Expected identifier, got: 42
+.globaltype 42
+
+# CHECK: [[#@LINE+1]]:16: error: Expected ,, instead got:
+.globaltype sym
+
+# CHECK: [[#@LINE+1]]:17: error: Expected identifier, got:
+.globaltype sym,
+
+# CHECK: [[#@LINE+1]]:18: error: Expected identifier, got: 42
+.globaltype sym, 42
+
+# CHECK: [[#@LINE+1]]:18: error: Unknown type in .globaltype directive: i42
+.globaltype sym, i42
+
+# CHECK: [[#@LINE+1]]:22: error: Expected identifier, got:
+.globaltype sym, i32,
+
+# CHECK: [[#@LINE+1]]:23: error: Expected identifier, got: 42
+.globaltype sym, i32, 42
+
+# CHECK: [[#@LINE+1]]:23: error: Unknown type in .globaltype modifier: unmutable
+.globaltype sym, i32, unmutable
+
+# CHECK: [[#@LINE+1]]:32: error: Expected EOL, instead got: ,
+.globaltype sym, i32, immutable,
diff --git a/llvm/test/MC/WebAssembly/import-module-invalid.s b/llvm/test/MC/WebAssembly/import-module-invalid.s
new file mode 100644
index 0000000..a9f93e8
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/import-module-invalid.s
@@ -0,0 +1,13 @@
+# RUN: not llvm-mc -triple=wasm32 %s 2>&1 | FileCheck %s
+
+# CHECK: [[#@LINE+1]]:16: error: Expected identifier, got: 42
+.import_module 42
+
+# CHECK: [[#@LINE+1]]:19: error: Expected ,, instead got:
+.import_module foo
+
+# CHECK: [[#@LINE+1]]:20: error: Expected identifier, got:
+.import_module foo,
+
+# CHECK: [[#@LINE+1]]:24: error: Expected EOL, instead got: ,
+.import_module foo, bar,
diff --git a/llvm/test/MC/WebAssembly/import-name-invalid.s b/llvm/test/MC/WebAssembly/import-name-invalid.s
new file mode 100644
index 0000000..da8ed0d
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/import-name-invalid.s
@@ -0,0 +1,13 @@
+# RUN: not llvm-mc -triple=wasm32 %s 2>&1 | FileCheck %s
+
+# CHECK: [[#@LINE+1]]:14: error: Expected identifier, got: 42
+.import_name 42
+
+# CHECK: [[#@LINE+1]]:17: error: Expected ,, instead got:
+.import_name foo
+
+# CHECK: [[#@LINE+1]]:18: error: Expected identifier, got:
+.import_name foo,
+
+# CHECK: [[#@LINE+1]]:22: error: Expected EOL, instead got: ,
+.import_name foo, bar,
diff --git a/llvm/test/MC/WebAssembly/tabletype-invalid.s b/llvm/test/MC/WebAssembly/tabletype-invalid.s
new file mode 100644
index 0000000..4e50d05
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/tabletype-invalid.s
@@ -0,0 +1,28 @@
+# RUN: not llvm-mc -triple=wasm32 %s 2>&1 | FileCheck %s
+
+# CHECK: [[#@LINE+1]]:11: error: Expected identifier, got:
+.tabletype
+
+# CHECK: [[#@LINE+1]]:12: error: Expected identifier, got: 42
+.tabletype 42
+
+# CHECK: [[#@LINE+1]]:15: error: Expected ,, instead got:
+.tabletype sym
+
+# CHECK: [[#@LINE+1]]:16: error: Expected identifier, got:
+.tabletype sym,
+
+# CHECK: [[#@LINE+1]]:17: error: Expected identifier, got: 42
+.tabletype sym, 42
+
+# CHECK: [[#@LINE+1]]:17: error: Unknown type in .tabletype directive: i42
+.tabletype sym, i42
+
+# CHECK: [[#@LINE+1]]:21: error: Expected integer constant, instead got:
+.tabletype sym, i32,
+
+# CHECK: [[#@LINE+1]]:25: error: Expected integer constant, instead got:
+.tabletype sym, i32, 42,
+
+# CHECK: [[#@LINE+1]]:28: error: Expected EOL, instead got: ,
+.tabletype sym, i32, 42, 42,
diff --git a/llvm/test/MC/WebAssembly/tagtype-invalid.s b/llvm/test/MC/WebAssembly/tagtype-invalid.s
new file mode 100644
index 0000000..6b562a4
--- /dev/null
+++ b/llvm/test/MC/WebAssembly/tagtype-invalid.s
@@ -0,0 +1,10 @@
+# RUN: not llvm-mc -triple=wasm32 %s 2>&1 | FileCheck %s
+
+# CHECK: [[#@LINE+1]]:10: error: Expected identifier, got: 42
+.tagtype 42
+
+# CHECK: [[#@LINE+1]]:13: error: Expected EOL, instead got: ,
+.tagtype foo, i32
+
+# CHECK: [[#@LINE+1]]:18: error: Expected EOL, instead got: pub
+.tagtype bar i32 pub