mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-02 19:24:25 +00:00
Change .thumb_set to have the same error checks as .set.
According to the documentation, .thumb_set is 'the equivalent of a .set directive'. We didn't have equivalent behaviour in terms of all the errors we could throw, for example, when a symbol is redefined. This change refactors parseAssignment so that it can be used by .set and .thumb_set and implements tests for .thumb_set for all the errors thrown by that method. Reviewed by Rafael Espíndola. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@240318 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -26,6 +26,7 @@
|
||||
#include "llvm/MC/MCParser/AsmCond.h"
|
||||
#include "llvm/MC/MCParser/AsmLexer.h"
|
||||
#include "llvm/MC/MCParser/MCAsmParser.h"
|
||||
#include "llvm/MC/MCParser/MCAsmParserUtils.h"
|
||||
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/MC/MCSectionMachO.h"
|
||||
@ -2178,82 +2179,20 @@ void AsmParser::handleMacroExit() {
|
||||
ActiveMacros.pop_back();
|
||||
}
|
||||
|
||||
static bool isUsedIn(const MCSymbol *Sym, const MCExpr *Value) {
|
||||
switch (Value->getKind()) {
|
||||
case MCExpr::Binary: {
|
||||
const MCBinaryExpr *BE = static_cast<const MCBinaryExpr *>(Value);
|
||||
return isUsedIn(Sym, BE->getLHS()) || isUsedIn(Sym, BE->getRHS());
|
||||
}
|
||||
case MCExpr::Target:
|
||||
case MCExpr::Constant:
|
||||
return false;
|
||||
case MCExpr::SymbolRef: {
|
||||
const MCSymbol &S =
|
||||
static_cast<const MCSymbolRefExpr *>(Value)->getSymbol();
|
||||
if (S.isVariable())
|
||||
return isUsedIn(Sym, S.getVariableValue());
|
||||
return &S == Sym;
|
||||
}
|
||||
case MCExpr::Unary:
|
||||
return isUsedIn(Sym, static_cast<const MCUnaryExpr *>(Value)->getSubExpr());
|
||||
}
|
||||
|
||||
llvm_unreachable("Unknown expr kind!");
|
||||
}
|
||||
|
||||
bool AsmParser::parseAssignment(StringRef Name, bool allow_redef,
|
||||
bool NoDeadStrip) {
|
||||
// FIXME: Use better location, we should use proper tokens.
|
||||
SMLoc EqualLoc = Lexer.getLoc();
|
||||
|
||||
MCSymbol *Sym;
|
||||
const MCExpr *Value;
|
||||
if (parseExpression(Value))
|
||||
if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym,
|
||||
Value))
|
||||
return true;
|
||||
|
||||
// Note: we don't count b as used in "a = b". This is to allow
|
||||
// a = b
|
||||
// b = c
|
||||
|
||||
if (Lexer.isNot(AsmToken::EndOfStatement))
|
||||
return TokError("unexpected token in assignment");
|
||||
|
||||
// Eat the end of statement marker.
|
||||
Lex();
|
||||
|
||||
// Validate that the LHS is allowed to be a variable (either it has not been
|
||||
// used as a symbol, or it is an absolute symbol).
|
||||
MCSymbol *Sym = getContext().lookupSymbol(Name);
|
||||
if (Sym) {
|
||||
// Diagnose assignment to a label.
|
||||
//
|
||||
// FIXME: Diagnostics. Note the location of the definition as a label.
|
||||
// FIXME: Diagnose assignment to protected identifier (e.g., register name).
|
||||
if (isUsedIn(Sym, Value))
|
||||
return Error(EqualLoc, "Recursive use of '" + Name + "'");
|
||||
else if (Sym->isUndefined() && !Sym->isUsed() && !Sym->isVariable())
|
||||
; // Allow redefinitions of undefined symbols only used in directives.
|
||||
else if (Sym->isVariable() && !Sym->isUsed() && allow_redef)
|
||||
; // Allow redefinitions of variables that haven't yet been used.
|
||||
else if (!Sym->isUndefined() && (!Sym->isVariable() || !allow_redef))
|
||||
return Error(EqualLoc, "redefinition of '" + Name + "'");
|
||||
else if (!Sym->isVariable())
|
||||
return Error(EqualLoc, "invalid assignment to '" + Name + "'");
|
||||
else if (!isa<MCConstantExpr>(Sym->getVariableValue()))
|
||||
return Error(EqualLoc, "invalid reassignment of non-absolute variable '" +
|
||||
Name + "'");
|
||||
|
||||
// Don't count these checks as uses.
|
||||
Sym->setUsed(false);
|
||||
} else if (Name == ".") {
|
||||
if (Out.EmitValueToOffset(Value, 0)) {
|
||||
Error(EqualLoc, "expected absolute expression");
|
||||
eatToEndOfStatement();
|
||||
}
|
||||
if (!Sym) {
|
||||
// In the case where we parse an expression starting with a '.', we will
|
||||
// not generate an error, nor will we create a symbol. In this case we
|
||||
// should just return out.
|
||||
return false;
|
||||
} else
|
||||
Sym = getContext().getOrCreateSymbol(Name);
|
||||
|
||||
Sym->setRedefinable(allow_redef);
|
||||
}
|
||||
|
||||
// Do the assignment.
|
||||
Out.EmitAssignment(Sym, Value);
|
||||
@ -4777,6 +4716,103 @@ bool AsmParser::parseMSInlineAsm(
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
namespace MCParserUtils {
|
||||
|
||||
/// Returns whether the given symbol is used anywhere in the given expression,
|
||||
/// or subexpressions.
|
||||
static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *Value) {
|
||||
switch (Value->getKind()) {
|
||||
case MCExpr::Binary: {
|
||||
const MCBinaryExpr *BE = static_cast<const MCBinaryExpr *>(Value);
|
||||
return isSymbolUsedInExpression(Sym, BE->getLHS()) ||
|
||||
isSymbolUsedInExpression(Sym, BE->getRHS());
|
||||
}
|
||||
case MCExpr::Target:
|
||||
case MCExpr::Constant:
|
||||
return false;
|
||||
case MCExpr::SymbolRef: {
|
||||
const MCSymbol &S =
|
||||
static_cast<const MCSymbolRefExpr *>(Value)->getSymbol();
|
||||
if (S.isVariable())
|
||||
return isSymbolUsedInExpression(Sym, S.getVariableValue());
|
||||
return &S == Sym;
|
||||
}
|
||||
case MCExpr::Unary:
|
||||
return isSymbolUsedInExpression(
|
||||
Sym, static_cast<const MCUnaryExpr *>(Value)->getSubExpr());
|
||||
}
|
||||
|
||||
llvm_unreachable("Unknown expr kind!");
|
||||
}
|
||||
|
||||
bool parseAssignmentExpression(StringRef Name, bool allow_redef,
|
||||
MCAsmParser &Parser, MCSymbol *&Sym,
|
||||
const MCExpr *&Value) {
|
||||
MCAsmLexer &Lexer = Parser.getLexer();
|
||||
|
||||
// FIXME: Use better location, we should use proper tokens.
|
||||
SMLoc EqualLoc = Lexer.getLoc();
|
||||
|
||||
if (Parser.parseExpression(Value)) {
|
||||
Parser.TokError("missing expression");
|
||||
Parser.eatToEndOfStatement();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Note: we don't count b as used in "a = b". This is to allow
|
||||
// a = b
|
||||
// b = c
|
||||
|
||||
if (Lexer.isNot(AsmToken::EndOfStatement))
|
||||
return Parser.TokError("unexpected token in assignment");
|
||||
|
||||
// Eat the end of statement marker.
|
||||
Parser.Lex();
|
||||
|
||||
// Validate that the LHS is allowed to be a variable (either it has not been
|
||||
// used as a symbol, or it is an absolute symbol).
|
||||
Sym = Parser.getContext().lookupSymbol(Name);
|
||||
if (Sym) {
|
||||
// Diagnose assignment to a label.
|
||||
//
|
||||
// FIXME: Diagnostics. Note the location of the definition as a label.
|
||||
// FIXME: Diagnose assignment to protected identifier (e.g., register name).
|
||||
if (isSymbolUsedInExpression(Sym, Value))
|
||||
return Parser.Error(EqualLoc, "Recursive use of '" + Name + "'");
|
||||
else if (Sym->isUndefined() && !Sym->isUsed() && !Sym->isVariable())
|
||||
; // Allow redefinitions of undefined symbols only used in directives.
|
||||
else if (Sym->isVariable() && !Sym->isUsed() && allow_redef)
|
||||
; // Allow redefinitions of variables that haven't yet been used.
|
||||
else if (!Sym->isUndefined() && (!Sym->isVariable() || !allow_redef))
|
||||
return Parser.Error(EqualLoc, "redefinition of '" + Name + "'");
|
||||
else if (!Sym->isVariable())
|
||||
return Parser.Error(EqualLoc, "invalid assignment to '" + Name + "'");
|
||||
else if (!isa<MCConstantExpr>(Sym->getVariableValue()))
|
||||
return Parser.Error(EqualLoc,
|
||||
"invalid reassignment of non-absolute variable '" +
|
||||
Name + "'");
|
||||
|
||||
// Don't count these checks as uses.
|
||||
Sym->setUsed(false);
|
||||
} else if (Name == ".") {
|
||||
if (Parser.getStreamer().EmitValueToOffset(Value, 0)) {
|
||||
Parser.Error(EqualLoc, "expected absolute expression");
|
||||
Parser.eatToEndOfStatement();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else
|
||||
Sym = Parser.getContext().getOrCreateSymbol(Name);
|
||||
|
||||
Sym->setRedefinable(allow_redef);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace MCParserUtils
|
||||
} // namespace llvm
|
||||
|
||||
/// \brief Create an MCAsmParser instance.
|
||||
MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C,
|
||||
MCStreamer &Out, const MCAsmInfo &MAI) {
|
||||
|
Reference in New Issue
Block a user