Index: ELF/Driver.cpp
===================================================================
--- ELF/Driver.cpp
+++ ELF/Driver.cpp
@@ -1293,7 +1293,7 @@
       if (!S->getFile<ELFT>().IsNeeded) {
         bool Used = S->Used;
         replaceSymbol<Undefined>(S, nullptr, S->getName(), STB_WEAK, S->StOther,
-                                 S->Type);
+                                 S->Type, 0);
         S->Used = Used;
       }
     }
@@ -1366,7 +1366,7 @@
 
 template <class ELFT> static Symbol *addUndefined(StringRef Name) {
   return Symtab->addUndefined<ELFT>(Name, STB_GLOBAL, STV_DEFAULT, 0, false,
-                                    nullptr);
+                                    nullptr, 0);
 }
 
 // The --wrap option is a feature to rename symbols so that you can write
Index: ELF/InputFiles.h
===================================================================
--- ELF/InputFiles.h
+++ ELF/InputFiles.h
@@ -184,17 +184,18 @@
   typedef typename ELFT::Word Elf_Word;
   typedef typename ELFT::CGProfile Elf_CGProfile;
 
+public:
+  static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; }
+
   StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
                                  const Elf_Shdr &Sec);
 
-public:
-  static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; }
-
   ArrayRef<Symbol *> getLocalSymbols();
   ArrayRef<Symbol *> getGlobalSymbols();
 
   ObjFile(MemoryBufferRef M, StringRef ArchiveName);
-  void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
+  void parse(llvm::DenseMap<llvm::CachedHashStringRef, const InputFile *>
+                 &ComdatGroups);
 
   Symbol &getSymbol(uint32_t SymbolIndex) const {
     if (SymbolIndex >= this->Symbols.size())
@@ -235,8 +236,8 @@
   ArrayRef<Elf_CGProfile> CGProfile;
 
 private:
-  void
-  initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
+  void initializeSections(llvm::DenseMap<llvm::CachedHashStringRef,
+                                         const InputFile *> &ComdatGroups);
   void initializeSymbols();
   void initializeJustSymbols();
   void initializeDwarf();
@@ -315,7 +316,8 @@
               uint64_t OffsetInArchive);
   static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
   template <class ELFT>
-  void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
+  void parse(llvm::DenseMap<llvm::CachedHashStringRef, const InputFile *>
+                 &ComdatGroups);
   std::unique_ptr<llvm::lto::InputFile> Obj;
 };
 
Index: ELF/InputFiles.cpp
===================================================================
--- ELF/InputFiles.cpp
+++ ELF/InputFiles.cpp
@@ -292,7 +292,8 @@
 }
 
 template <class ELFT>
-void ObjFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
+void ObjFile<ELFT>::parse(
+    DenseMap<CachedHashStringRef, const InputFile *> &ComdatGroups) {
   // Read a section table. JustSymbols is usually false.
   if (this->JustSymbols)
     initializeJustSymbols();
@@ -398,7 +399,7 @@
 
 template <class ELFT>
 void ObjFile<ELFT>::initializeSections(
-    DenseSet<CachedHashStringRef> &ComdatGroups) {
+    DenseMap<CachedHashStringRef, const InputFile *> &ComdatGroups) {
   const ELFFile<ELFT> &Obj = this->getObj();
 
   ArrayRef<Elf_Shdr> ObjSections = CHECK(Obj.sections(), this);
@@ -457,7 +458,8 @@
       if (Entries[0] != GRP_COMDAT)
         fatal(toString(this) + ": unsupported SHT_GROUP format");
 
-      bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second;
+      bool IsNew =
+          ComdatGroups.try_emplace(CachedHashStringRef(Signature), this).second;
       if (IsNew) {
         if (Config->Relocatable)
           this->Sections[I] = createInputSection(Sec);
@@ -801,7 +803,7 @@
 
     StringRefZ Name = this->StringTable.data() + Sym->st_name;
     if (Sym->st_shndx == SHN_UNDEF)
-      return make<Undefined>(this, Name, Binding, StOther, Type);
+      return make<Undefined>(this, Name, Binding, StOther, Type, 0);
 
     return make<Defined>(this, Name, Binding, StOther, Type, Value, Size, Sec);
   }
@@ -811,7 +813,7 @@
   switch (Sym->st_shndx) {
   case SHN_UNDEF:
     return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type,
-                                      /*CanOmitFromDynSym=*/false, this);
+                                      /*CanOmitFromDynSym=*/false, this, 0);
   case SHN_COMMON:
     if (Value == 0 || Value >= UINT32_MAX)
       fatal(toString(this) + ": common symbol '" + Name +
@@ -825,9 +827,11 @@
   case STB_GLOBAL:
   case STB_WEAK:
   case STB_GNU_UNIQUE:
-    if (Sec == &InputSection::Discarded)
+    if (Sec == &InputSection::Discarded) {
       return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type,
-                                        /*CanOmitFromDynSym=*/false, this);
+                                        /*CanOmitFromDynSym=*/false, this,
+                                        SecIdx);
+    }
     return Symtab->addDefined(Name, StOther, Type, Value, Size, Binding, Sec,
                               this);
   }
@@ -1030,9 +1034,9 @@
     }
 
     if (Sym.isUndefined()) {
-      Symbol *S = Symtab->addUndefined<ELFT>(Name, Sym.getBinding(),
-                                             Sym.st_other, Sym.getType(),
-                                             /*CanOmitFromDynSym=*/false, this);
+      Symbol *S = Symtab->addUndefined<ELFT>(
+          Name, Sym.getBinding(), Sym.st_other, Sym.getType(),
+          /*CanOmitFromDynSym=*/false, this, 0);
       S->ExportDynamic = true;
       continue;
     }
@@ -1163,11 +1167,11 @@
   int C = ObjSym.getComdatIndex();
   if (C != -1 && !KeptComdats[C])
     return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type,
-                                      CanOmitFromDynSym, &F);
+                                      CanOmitFromDynSym, &F, 0);
 
   if (ObjSym.isUndefined())
     return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type,
-                                      CanOmitFromDynSym, &F);
+                                      CanOmitFromDynSym, &F, 0);
 
   if (ObjSym.isCommon())
     return Symtab->addCommon(Name, ObjSym.getCommonSize(),
@@ -1179,10 +1183,12 @@
 }
 
 template <class ELFT>
-void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
+void BitcodeFile::parse(
+    DenseMap<CachedHashStringRef, const InputFile *> &ComdatGroups) {
   std::vector<bool> KeptComdats;
   for (StringRef S : Obj->getComdatTable())
-    KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second);
+    KeptComdats.push_back(
+        ComdatGroups.try_emplace(CachedHashStringRef(S), this).second);
 
   for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
     Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, *this));
@@ -1342,10 +1348,14 @@
 template void ArchiveFile::parse<ELF64LE>();
 template void ArchiveFile::parse<ELF64BE>();
 
-template void BitcodeFile::parse<ELF32LE>(DenseSet<CachedHashStringRef> &);
-template void BitcodeFile::parse<ELF32BE>(DenseSet<CachedHashStringRef> &);
-template void BitcodeFile::parse<ELF64LE>(DenseSet<CachedHashStringRef> &);
-template void BitcodeFile::parse<ELF64BE>(DenseSet<CachedHashStringRef> &);
+template void
+BitcodeFile::parse<ELF32LE>(DenseMap<CachedHashStringRef, const InputFile *> &);
+template void
+BitcodeFile::parse<ELF32BE>(DenseMap<CachedHashStringRef, const InputFile *> &);
+template void
+BitcodeFile::parse<ELF64LE>(DenseMap<CachedHashStringRef, const InputFile *> &);
+template void
+BitcodeFile::parse<ELF64BE>(DenseMap<CachedHashStringRef, const InputFile *> &);
 
 template void LazyObjFile::parse<ELF32LE>();
 template void LazyObjFile::parse<ELF32BE>();
Index: ELF/LTO.cpp
===================================================================
--- ELF/LTO.cpp
+++ ELF/LTO.cpp
@@ -154,7 +154,7 @@
 
 static void undefine(Symbol *S) {
   replaceSymbol<Undefined>(S, nullptr, S->getName(), STB_GLOBAL, STV_DEFAULT,
-                           S->Type);
+                           S->Type, 0);
 }
 
 void BitcodeCompiler::add(BitcodeFile &F) {
Index: ELF/Relocations.cpp
===================================================================
--- ELF/Relocations.cpp
+++ ELF/Relocations.cpp
@@ -663,10 +663,39 @@
   return Addend;
 }
 
+// Custom error message if Sym is defined in a discarded section.
+template <class ELFT, class RelTy>
+static std::string maybeReportDiscarded(Undefined &Sym, InputSectionBase &Sec,
+                                        const RelTy &Rel) {
+  auto *File = dyn_cast_or_null<ObjFile<ELFT>>(Sym.File);
+  if (!File || !Sym.DiscardedSecIdx ||
+      File->getSections()[Sym.DiscardedSecIdx] != &InputSection::Discarded)
+    return "";
+  ArrayRef<Elf_Shdr_Impl<ELFT>> ObjSections =
+      CHECK(File->getObj().sections(), File);
+  std::string Msg =
+      "relocation refers to a symbol in a discarded section: " + toString(Sym) +
+      "\n>>> defined in " + toString(File);
+
+  // If the discarded section is a COMDAT.
+  Elf_Shdr_Impl<ELFT> ELFSec = ObjSections[Sym.DiscardedSecIdx - 1];
+  if (ELFSec.sh_type == SHT_GROUP) {
+    StringRef Signature = File->getShtGroupSignature(ObjSections, ELFSec);
+    auto It = Symtab->ComdatGroups.find(CachedHashStringRef(Signature));
+    if (It != Symtab->ComdatGroups.end())
+      Msg += ("\n>>> section group signature: " + Signature +
+              "\n>>> prevailing definition is in " + toString(It->second))
+                 .str();
+  }
+
+  return Msg;
+}
+
 // Report an undefined symbol if necessary.
 // Returns true if this function printed out an error message.
+template <class ELFT, class RelTy>
 static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
-                                 uint64_t Offset) {
+                                 const RelTy &Rel) {
   if (Sym.isLocal() || !Sym.isUndefined() || Sym.isWeak())
     return false;
 
@@ -675,19 +704,29 @@
   if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
     return false;
 
-  std::string Msg = "undefined ";
-  if (Sym.Visibility == STV_INTERNAL)
-    Msg += "internal ";
-  else if (Sym.Visibility == STV_HIDDEN)
-    Msg += "hidden ";
-  else if (Sym.Visibility == STV_PROTECTED)
-    Msg += "protected ";
-  Msg += "symbol: " + toString(Sym) + "\n>>> referenced by ";
+  auto Visibility = [&]() -> StringRef {
+    switch (Sym.Visibility) {
+    case STV_INTERNAL:
+      return "internal ";
+    case STV_HIDDEN:
+      return "hidden ";
+    case STV_PROTECTED:
+      return "protected ";
+    default:
+      return "";
+    }
+  };
 
-  std::string Src = Sec.getSrcMsg(Sym, Offset);
+  std::string Msg =
+      maybeReportDiscarded<ELFT, RelTy>(cast<Undefined>(Sym), Sec, Rel);
+  if (Msg.empty())
+    Msg = ("undefined " + Visibility() + "symbol: " + toString(Sym)).str();
+
+  Msg += "\n>>> referenced by ";
+  std::string Src = Sec.getSrcMsg(Sym, Rel.r_offset);
   if (!Src.empty())
     Msg += Src + "\n>>>               ";
-  Msg += Sec.getObjMsg(Offset);
+  Msg += Sec.getObjMsg(Rel.r_offset);
 
   if (Sym.getName().startswith("_ZTV"))
     Msg += "\nthe vtable symbol may be undefined because the class is missing "
@@ -1019,7 +1058,7 @@
     return;
 
   // Skip if the target symbol is an erroneous undefined symbol.
-  if (maybeReportUndefined(Sym, Sec, Rel.r_offset))
+  if (maybeReportUndefined<ELFT, RelTy>(Sym, Sec, Rel))
     return;
 
   const uint8_t *RelocatedAddr = Sec.data().begin() + Rel.r_offset;
Index: ELF/SymbolTable.h
===================================================================
--- ELF/SymbolTable.h
+++ ELF/SymbolTable.h
@@ -42,7 +42,8 @@
 
   template <class ELFT>
   Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther,
-                       uint8_t Type, bool CanOmitFromDynSym, InputFile *File);
+                       uint8_t Type, bool CanOmitFromDynSym, InputFile *File,
+                       uint32_t DiscardedSecIdx);
 
   Defined *addDefined(StringRef Name, uint8_t StOther, uint8_t Type,
                       uint64_t Value, uint64_t Size, uint8_t Binding,
@@ -82,6 +83,11 @@
   // Set of .so files to not link the same shared object file more than once.
   llvm::DenseMap<StringRef, InputFile *> SoNames;
 
+  // Comdat groups define "link once" sections. If two comdat groups have the
+  // same name, only one of them is linked, and the other is ignored. This map
+  // is used to uniquify them.
+  llvm::DenseMap<llvm::CachedHashStringRef, const InputFile *> ComdatGroups;
+
 private:
   std::pair<Symbol *, bool> insertName(StringRef Name);
 
@@ -104,11 +110,6 @@
   llvm::DenseMap<llvm::CachedHashStringRef, int> SymMap;
   std::vector<Symbol *> SymVector;
 
-  // Comdat groups define "link once" sections. If two comdat groups have the
-  // same name, only one of them is linked, and the other is ignored. This set
-  // is used to uniquify them.
-  llvm::DenseSet<llvm::CachedHashStringRef> ComdatGroups;
-
   // A map from demangled symbol names to their symbol objects.
   // This mapping is 1:N because two symbols with different versions
   // can have the same name. We use this map to handle "extern C++ {}"
Index: ELF/SymbolTable.cpp
===================================================================
--- ELF/SymbolTable.cpp
+++ ELF/SymbolTable.cpp
@@ -141,7 +141,7 @@
     LTO->add(*F);
 
   for (InputFile *File : LTO->compile()) {
-    DenseSet<CachedHashStringRef> DummyGroups;
+    DenseMap<CachedHashStringRef, const InputFile *> DummyGroups;
     auto *Obj = cast<ObjFile<ELFT>>(File);
     Obj->parse(DummyGroups);
     for (Symbol *Sym : Obj->getGlobalSymbols())
@@ -246,7 +246,8 @@
 template <class ELFT>
 Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
                                   uint8_t StOther, uint8_t Type,
-                                  bool CanOmitFromDynSym, InputFile *File) {
+                                  bool CanOmitFromDynSym, InputFile *File,
+                                  uint32_t DiscardedSecIdx) {
   Symbol *S;
   bool WasInserted;
   uint8_t Visibility = getVisibility(StOther);
@@ -254,8 +255,13 @@
 
   // An undefined symbol with non default visibility must be satisfied
   // in the same DSO.
-  if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) {
-    replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type);
+  //
+  // If Name is in a discarded section, override the existing undefined symbol
+  // for better error message later.
+  if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT) ||
+      (S->isUndefined() && Binding != STB_WEAK && DiscardedSecIdx)) {
+    replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type,
+                             DiscardedSecIdx);
     return S;
   }
 
@@ -766,13 +772,17 @@
 template void SymbolTable::addFile<ELF64BE>(InputFile *);
 
 template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef, uint8_t, uint8_t,
-                                                    uint8_t, bool, InputFile *);
+                                                    uint8_t, bool, InputFile *,
+                                                    uint32_t);
 template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef, uint8_t, uint8_t,
-                                                    uint8_t, bool, InputFile *);
+                                                    uint8_t, bool, InputFile *,
+                                                    uint32_t);
 template Symbol *SymbolTable::addUndefined<ELF64LE>(StringRef, uint8_t, uint8_t,
-                                                    uint8_t, bool, InputFile *);
+                                                    uint8_t, bool, InputFile *,
+                                                    uint32_t);
 template Symbol *SymbolTable::addUndefined<ELF64BE>(StringRef, uint8_t, uint8_t,
-                                                    uint8_t, bool, InputFile *);
+                                                    uint8_t, bool, InputFile *,
+                                                    uint32_t);
 
 template void SymbolTable::addCombinedLTOObject<ELF32LE>();
 template void SymbolTable::addCombinedLTOObject<ELF32BE>();
Index: ELF/Symbols.h
===================================================================
--- ELF/Symbols.h
+++ ELF/Symbols.h
@@ -227,13 +227,18 @@
   SectionBase *Section;
 };
 
+// Represents an undefined symbol or a defined symbol in a discarded section.
 class Undefined : public Symbol {
 public:
   Undefined(InputFile *File, StringRefZ Name, uint8_t Binding, uint8_t StOther,
-            uint8_t Type)
-      : Symbol(UndefinedKind, File, Name, Binding, StOther, Type) {}
+            uint8_t Type, uint32_t DiscardedSecIdx)
+      : Symbol(UndefinedKind, File, Name, Binding, StOther, Type),
+        DiscardedSecIdx(DiscardedSecIdx) {}
 
   static bool classof(const Symbol *S) { return S->kind() == UndefinedKind; }
+
+  // The section index if in a discarded section, 0 otherwise.
+  uint32_t DiscardedSecIdx;
 };
 
 class SharedSymbol : public Symbol {
Index: test/ELF/comdat-discarded-error.s
===================================================================
--- /dev/null
+++ test/ELF/comdat-discarded-error.s
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: echo '.section .text.foo,"axG",@progbits,foo,comdat; .globl foo; foo:' | \
+# RUN:   llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o
+# RUN: echo '.section .text.foo,"axG",@progbits,foo,comdat; .globl bar; bar:' | \
+# RUN:   llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t3.o
+
+# RUN: not ld.lld %t1.o %t2.o %t3.o -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK:      error: relocation refers to a symbol in a discarded section: bar
+# CHECK-NEXT: >>> defined in {{.*}}3.o
+# CHECK-NEXT: >>> section group signature: foo
+# CHECK-NEXT: >>> prevailing definition is in {{.*}}2.o
+# CHECK-NEXT: >>> referenced by {{.*}}1.o:(.text+0x1)
+
+.globl _start
+_start:
+  jmp bar
Index: test/ELF/exclude-discarded-error.s
===================================================================
--- /dev/null
+++ test/ELF/exclude-discarded-error.s
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK:      error: relocation refers to a symbol in a discarded section: foo
+# CHECK-NEXT: >>> defined in {{.*}}.o
+# CHECK-NEXT: >>> referenced by {{.*}}.o:(.text+0x1)
+
+.globl _start
+_start:
+  jmp foo
+
+.section .foo,"ae"
+.globl foo
+foo:
Index: test/ELF/exclude-discarded-error2.s
===================================================================
--- /dev/null
+++ test/ELF/exclude-discarded-error2.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo '.section .foo,"ae"; .weak foo; foo:' | \
+# RUN:   llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t1.o
+# RUN: not ld.lld %t.o %t1.o -o /dev/null 2>&1 | FileCheck %s
+
+# Because foo defined in %t1.o is weak, it does not override global undefined
+# in %t.o
+# CHECK-NOT: discarded section
+
+.globl _start, foo
+_start:
+  jmp foo