+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
+