diff --git a/include/llvm/MC/MCSymbol.h b/include/llvm/MC/MCSymbol.h index 1b432c2b0a8..99e705e596f 100644 --- a/include/llvm/MC/MCSymbol.h +++ b/include/llvm/MC/MCSymbol.h @@ -52,15 +52,14 @@ namespace llvm { /// "Lfoo" or ".foo". unsigned IsTemporary : 1; - /// IsUsedInExpr - True if this symbol has been used in an expression and - /// cannot be redefined. - unsigned IsUsedInExpr : 1; + /// IsUsed - True if this symbol has been used. + mutable unsigned IsUsed : 1; private: // MCContext creates and uniques these. friend class MCContext; MCSymbol(StringRef name, bool isTemporary) : Name(name), Section(0), Value(0), - IsTemporary(isTemporary), IsUsedInExpr(false) {} + IsTemporary(isTemporary), IsUsed(false) {} MCSymbol(const MCSymbol&); // DO NOT IMPLEMENT void operator=(const MCSymbol&); // DO NOT IMPLEMENT @@ -74,9 +73,9 @@ namespace llvm { /// isTemporary - Check if this is an assembler temporary symbol. bool isTemporary() const { return IsTemporary; } - /// isUsedInExpr - Check if this is an assembler temporary symbol. - bool isUsedInExpr() const { return IsUsedInExpr; } - void setUsedInExpr(bool Value) { IsUsedInExpr = Value; } + /// isUsed - Check if this is used. + bool isUsed() const { return IsUsed; } + void setUsed(bool Value) const { IsUsed = Value; } /// @} /// @name Associated Sections @@ -135,6 +134,7 @@ namespace llvm { /// getValue() - Get the value for variable symbols. const MCExpr *getVariableValue() const { assert(isVariable() && "Invalid accessor!"); + IsUsed = true; return Value; } diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 24b94d11cb0..3632c937402 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -485,9 +485,6 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { std::pair Split = Identifier.split('@'); MCSymbol *Sym = getContext().GetOrCreateSymbol(Split.first); - // Mark the symbol as used in an expression. - Sym->setUsedInExpr(true); - // Lookup the symbol variant if used. MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; if (Split.first.size() != Identifier.size()) { @@ -1191,6 +1188,25 @@ void AsmParser::HandleMacroExit() { ActiveMacros.pop_back(); } +static void MarkUsed(const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Binary: + MarkUsed(static_cast(Value)->getLHS()); + MarkUsed(static_cast(Value)->getRHS()); + break; + case MCExpr::Target: + case MCExpr::Constant: + break; + case MCExpr::SymbolRef: { + static_cast(Value)->getSymbol().setUsed(true); + break; + } + case MCExpr::Unary: + MarkUsed(static_cast(Value)->getSubExpr()); + break; + } +} + bool AsmParser::ParseAssignment(StringRef Name) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Lexer.getLoc(); @@ -1199,6 +1215,8 @@ bool AsmParser::ParseAssignment(StringRef Name) { if (ParseExpression(Value)) return true; + MarkUsed(Value); + if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in assignment"); @@ -1213,7 +1231,7 @@ bool AsmParser::ParseAssignment(StringRef Name) { // // FIXME: Diagnostics. Note the location of the definition as a label. // FIXME: Diagnose assignment to protected identifier (e.g., register name). - if (Sym->isUndefined() && !Sym->isUsedInExpr()) + if (Sym->isUndefined() && !Sym->isUsed() && !Sym->isVariable()) ; // Allow redefinitions of undefined symbols only used in directives. else if (!Sym->isUndefined() && !Sym->isAbsolute()) return Error(EqualLoc, "redefinition of '" + Name + "'"); @@ -1222,13 +1240,14 @@ bool AsmParser::ParseAssignment(StringRef Name) { else if (!isa(Sym->getVariableValue())) return Error(EqualLoc, "invalid reassignment of non-absolute variable '" + Name + "'"); + + // Don't count these checks as uses. + Sym->setUsed(false); } else Sym = getContext().GetOrCreateSymbol(Name); // FIXME: Handle '.'. - Sym->setUsedInExpr(true); - // Do the assignment. Out.EmitAssignment(Sym, Value); diff --git a/lib/MC/MCSymbol.cpp b/lib/MC/MCSymbol.cpp index 07751f72984..ebd3144a153 100644 --- a/lib/MC/MCSymbol.cpp +++ b/lib/MC/MCSymbol.cpp @@ -40,6 +40,7 @@ static bool NameNeedsQuoting(StringRef Str) { } void MCSymbol::setVariableValue(const MCExpr *Value) { + assert(!IsUsed && "Cannot set a variable that has already been used."); assert(Value && "Invalid variable value!"); assert((isUndefined() || (isAbsolute() && isa(Value))) && "Invalid redefinition!"); diff --git a/test/MC/ELF/set.s b/test/MC/ELF/set.s new file mode 100644 index 00000000000..a782bedfdbf --- /dev/null +++ b/test/MC/ELF/set.s @@ -0,0 +1,21 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | elf-dump --dump-section-data | FileCheck %s + +// Test that we accept .set of a symbol after it has been used in a statement. + + jmp foo + .set foo, bar + +// or a .quad + + .quad foo2 + .set foo2,bar2 + +// Test that there is an undefined reference to bar +// CHECK: (('st_name', 0x00000001) # 'bar' +// CHECK-NEXT: ('st_bind', 0x00000001) +// CHECK-NEXT: ('st_type', 0x00000000) +// CHECK-NEXT: ('st_other', 0x00000000) +// CHECK-NEXT: ('st_shndx', 0x00000000) +// CHECK-NEXT: ('st_value', 0x00000000) +// CHECK-NEXT: ('st_size', 0x00000000) +// CHECK-NEXT: ),