/// maps assembly-time variable names to variables.
struct Variable {
+ enum RedefinableKind { NOT_REDEFINABLE, WARN_ON_REDEFINITION, REDEFINABLE };
+
StringRef Name;
- bool Redefinable = true;
+ RedefinableKind Redefinable = REDEFINABLE;
bool IsText = false;
int64_t NumericValue = 0;
std::string TextValue;
// "=", "equ", "textequ"
bool parseDirectiveEquate(StringRef IDVal, StringRef Name,
- DirectiveKind DirKind);
+ DirectiveKind DirKind, SMLoc NameLoc);
bool parseDirectiveOrg(); // ".org"
bool parseDirectiveAlign(); // "align"
case DK_EQU:
case DK_TEXTEQU:
Lex();
- return parseDirectiveEquate(nextVal, IDVal, DirKind);
+ return parseDirectiveEquate(nextVal, IDVal, DirKind, IDLoc);
case DK_BYTE:
if (afterNextTok.is(AsmToken::Identifier) &&
afterNextTok.getString().equals_lower("ptr")) {
/// | name "equ" text-list
/// | name "textequ" text-list (redefinability unspecified)
bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef Name,
- DirectiveKind DirKind) {
+ DirectiveKind DirKind, SMLoc NameLoc) {
Variable &Var = Variables[Name.lower()];
if (Var.Name.empty()) {
Var.Name = Name;
if (parseOptionalToken(AsmToken::Comma) && parseMany(parseItem))
return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
- if (!Var.Redefinable && (!Var.IsText || Var.TextValue != Value))
- return Error(getTok().getLoc(), "invalid variable redefinition");
+ if (!Var.IsText || Var.TextValue != Value) {
+ switch (Var.Redefinable) {
+ case Variable::NOT_REDEFINABLE:
+ return Error(getTok().getLoc(), "invalid variable redefinition");
+ case Variable::WARN_ON_REDEFINITION:
+ if (Warning(NameLoc, "redefining '" + Name +
+ "', already defined on the command line")) {
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
Var.IsText = true;
Var.TextValue = Value;
- Var.Redefinable = true;
+ Var.Redefinable = Variable::REDEFINABLE;
return false;
}
// Not an absolute expression; define as a text replacement.
StringRef ExprAsString = StringRef(
StartLoc.getPointer(), EndLoc.getPointer() - StartLoc.getPointer());
- if (!Var.Redefinable && (!Var.IsText && Var.TextValue != ExprAsString))
- return Error(getTok().getLoc(), "invalid variable redefinition");
+ if (!Var.IsText || Var.TextValue != ExprAsString) {
+ switch (Var.Redefinable) {
+ case Variable::NOT_REDEFINABLE:
+ return Error(getTok().getLoc(), "invalid variable redefinition");
+ case Variable::WARN_ON_REDEFINITION:
+ if (Warning(NameLoc, "redefining '" + Name +
+ "', already defined on the command line")) {
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
Var.IsText = true;
Var.TextValue = ExprAsString.str();
} else {
- if (!Var.Redefinable && (Var.IsText || Var.NumericValue != Value))
- return Error(getTok().getLoc(), "invalid variable redefinition");
+ if (Var.IsText || Var.NumericValue != Value) {
+ switch (Var.Redefinable) {
+ case Variable::NOT_REDEFINABLE:
+ return Error(getTok().getLoc(), "invalid variable redefinition");
+ case Variable::WARN_ON_REDEFINITION:
+ if (Warning(NameLoc, "redefining '" + Name +
+ "', already defined on the command line")) {
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
Var.NumericValue = Value;
}
- Var.Redefinable = (DirKind == DK_ASSIGN);
+ Var.Redefinable = (DirKind == DK_ASSIGN) ? Variable::REDEFINABLE
+ : Variable::NOT_REDEFINABLE;
MCSymbol *Sym = getContext().getOrCreateSymbol(Var.Name);
- Sym->setRedefinable(Var.Redefinable);
+ Sym->setRedefinable(Var.Redefinable != Variable::NOT_REDEFINABLE);
Sym->setVariableValue(Expr);
Sym->setExternal(false);
Variable &Var = Variables[Name.lower()];
if (Var.Name.empty()) {
Var.Name = Name;
- } else if (!Var.Redefinable) {
- return TokError("invalid variable redefinition");
+ } else if (Var.Redefinable == Variable::NOT_REDEFINABLE) {
+ return Error(SMLoc(), "invalid variable redefinition");
+ } else if (Var.Redefinable == Variable::WARN_ON_REDEFINITION &&
+ Warning(SMLoc(), "redefining '" + Name +
+ "', already defined on the command line")) {
+ return true;
}
- Var.Redefinable = true;
+ Var.Redefinable = Variable::WARN_ON_REDEFINITION;
Var.IsText = true;
Var.TextValue = Value.str();
return false;