Fix PR8565.
authorRafael Espindola <rafael.espindola@gmail.com>
Mon, 15 Nov 2010 14:40:36 +0000 (14:40 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Mon, 15 Nov 2010 14:40:36 +0000 (14:40 +0000)
This moves most of the isUsed logic to the MCSymbol itself. With this we
get a bit more relaxed about allowing definitions after uses: uses that
don't evaluate their argument immediately (jmp foo) are accepted.

ddunbar, this was the smallest compromise I could think of that lets us
accept gcc (and clang!) assembly.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@119144 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/MC/MCSymbol.h
lib/MC/MCParser/AsmParser.cpp
lib/MC/MCSymbol.cpp
test/MC/ELF/set.s [new file with mode: 0644]

index 1b432c2b0a840105233106b301ba97e6dd1ccc76..99e705e596f130dc0537a49ea62e5841a06bcf31 100644 (file)
@@ -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;
     }
 
index 24b94d11cb072fb5ad20ab3bfdc6b3a3e423e434..3632c937402b24854cf143278c989ec111c0dc00 100644 (file)
@@ -485,9 +485,6 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
     std::pair<StringRef, StringRef> 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<const MCBinaryExpr*>(Value)->getLHS());
+    MarkUsed(static_cast<const MCBinaryExpr*>(Value)->getRHS());
+    break;
+  case MCExpr::Target:
+  case MCExpr::Constant:
+    break;
+  case MCExpr::SymbolRef: {
+    static_cast<const MCSymbolRefExpr*>(Value)->getSymbol().setUsed(true);
+    break;
+  }
+  case MCExpr::Unary:
+    MarkUsed(static_cast<const MCUnaryExpr*>(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<MCConstantExpr>(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);
 
index 07751f7298443e5de4e9e0ea432a954be66114bb..ebd3144a15389e01eb0b51b2dbd365464d8d681e 100644 (file)
@@ -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<MCConstantExpr>(Value))) &&
          "Invalid redefinition!");
diff --git a/test/MC/ELF/set.s b/test/MC/ELF/set.s
new file mode 100644 (file)
index 0000000..a782bed
--- /dev/null
@@ -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: ),