diff --git a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h --- a/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h +++ b/llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h @@ -122,6 +122,32 @@ : 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 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 @@ } /// 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 @@ /// 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 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -1999,20 +1999,12 @@ 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 --- a/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp +++ b/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp @@ -27,3 +27,24 @@ 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 --- a/llvm/lib/MC/MCParser/MasmParser.cpp +++ b/llvm/lib/MC/MCParser/MasmParser.cpp @@ -2304,21 +2304,15 @@ 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 --- a/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp +++ b/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp @@ -64,7 +64,7 @@ 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 @@ 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 @@ 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(Parser.getStreamer()); @@ -698,7 +697,7 @@ 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 @@ 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 --- a/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp +++ b/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp @@ -47,7 +47,7 @@ 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 @@ 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 X(getTheBPFTarget()); diff --git a/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp b/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp --- a/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp +++ b/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp @@ -77,7 +77,7 @@ 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 @@ 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 @@ StringRef Name = Parser.getTok().getIdentifier(); std::optional 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 @@ return true; const MCConstantExpr *CE = dyn_cast(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 --- a/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp +++ b/llvm/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp @@ -62,7 +62,7 @@ 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 @@ } // 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 --- a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp +++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp @@ -51,7 +51,9 @@ 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 --- a/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp +++ b/llvm/lib/Target/M68k/AsmParser/M68kAsmParser.cpp @@ -72,7 +72,7 @@ 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 @@ 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 --- a/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp +++ b/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp @@ -53,7 +53,7 @@ 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::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 --- a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -76,7 +76,7 @@ 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 @@ 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 --- a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -494,7 +494,7 @@ } // 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 @@ return MatchOperand_Success; } -bool SystemZAsmParser::ParseDirective(AsmToken DirectiveID) { +ParseStatus SystemZAsmParser::parseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getIdentifier(); if (IDVal == ".insn") @@ -1229,7 +1229,7 @@ if (IDVal.startswith(".gnu_attribute")) return ParseGNUAttribute(DirectiveID.getLoc()); - return true; + return ParseStatus::NoMatch; } /// ParseDirectiveInsn @@ -1346,12 +1346,12 @@ 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 @@ 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 --- a/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp +++ b/llvm/lib/Target/VE/AsmParser/VEAsmParser.cpp @@ -62,7 +62,7 @@ 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 @@ 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 @@ 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 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -785,31 +785,23 @@ // 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(*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 @@ 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 @@ // .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 ElemType = WebAssembly::parseType(ElemTypeName); if (!ElemType) @@ -854,7 +848,7 @@ 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 @@ // parses the locals separately. auto SymName = expectIdent(); if (SymName.empty()) - return true; + return ParseStatus::Failure; auto WasmSym = cast(Ctx.getOrCreateSymbol(SymName)); if (WasmSym->isDefined()) { // We push 'Function' either when a label is parsed or a .functype @@ -890,7 +884,7 @@ 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 @@ } auto Signature = std::make_unique(); if (parseSignature(Signature.get())) - return true; + return ParseStatus::Failure; TC.funcDecl(*Signature); WasmSym->setSignature(Signature.get()); addSignature(std::move(Signature)); @@ -911,47 +905,56 @@ 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(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(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(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(Ctx.getOrCreateSymbol(SymName)); auto Signature = std::make_unique(); 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 @@ Lexer.getTok()); SmallVector Locals; if (parseRegTypeList(Locals)) - return true; + return ParseStatus::Failure; TC.localDecl(Locals); TOut.emitLocal(Locals); CurrentState = FunctionLocals; @@ -978,7 +981,7 @@ 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 @@ 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 @@ 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 --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -36,7 +36,7 @@ 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 @@ 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 --- 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 --- /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 --- /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 --- 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 --- /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 --- /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 --- a/llvm/test/MC/VE/data-size-error.s +++ b/llvm/test/MC/VE/data-size-error.s @@ -34,3 +34,12 @@ # 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 --- /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 --- /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 --- /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 --- /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 --- /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 --- /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 --- /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