[ELF/LinkerScript] Support EXCLUDE_FILE inside KEEP.

Differential Revision:	https://reviews.llvm.org/D22795

llvm-svn: 276825
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 2ca0fde..804d0c9 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -79,15 +79,15 @@
 // input sections start with ".foo." or ".bar." should be added to
 // ".text" section.
 template <class ELFT>
-std::vector<std::pair<StringRef, ArrayRef<StringRef>>>
+std::vector<std::pair<StringRef, const InputSectionDescription *>>
 LinkerScript<ELFT>::getSectionMap() {
-  std::vector<std::pair<StringRef, ArrayRef<StringRef>>> Ret;
+  std::vector<std::pair<StringRef, const InputSectionDescription *>> Ret;
 
   for (const std::unique_ptr<BaseCommand> &Base1 : Opt.Commands)
     if (auto *Cmd1 = dyn_cast<OutputSectionCommand>(Base1.get()))
       for (const std::unique_ptr<BaseCommand> &Base2 : Cmd1->Commands)
         if (auto *Cmd2 = dyn_cast<InputSectionDescription>(Base2.get()))
-          Ret.emplace_back(Cmd1->Name, Cmd2->Patterns);
+          Ret.emplace_back(Cmd1->Name, Cmd2);
 
   return Ret;
 }
@@ -95,13 +95,17 @@
 // Returns input sections filtered by given glob patterns.
 template <class ELFT>
 std::vector<InputSectionBase<ELFT> *>
-LinkerScript<ELFT>::getInputSections(ArrayRef<StringRef> Patterns) {
+LinkerScript<ELFT>::getInputSections(const InputSectionDescription *I) {
+  ArrayRef<StringRef> Patterns = I->Patterns;
+  ArrayRef<StringRef> ExcludedFiles = I->ExcludedFiles;
   std::vector<InputSectionBase<ELFT> *> Ret;
   for (const std::unique_ptr<ObjectFile<ELFT>> &F :
        Symtab<ELFT>::X->getObjectFiles())
     for (InputSectionBase<ELFT> *S : F->getSections())
       if (!isDiscarded(S) && !S->OutSec && match(Patterns, S->getSectionName()))
-        Ret.push_back(S);
+        if (ExcludedFiles.empty() ||
+            !match(ExcludedFiles, sys::path::filename(F->getName())))
+          Ret.push_back(S);
   return Ret;
 }
 
@@ -123,8 +127,8 @@
 
   for (auto &P : getSectionMap()) {
     StringRef OutputName = P.first;
-    ArrayRef<StringRef> InputPatterns = P.second;
-    for (InputSectionBase<ELFT> *S : getInputSections(InputPatterns)) {
+    const InputSectionDescription *I = P.second;
+    for (InputSectionBase<ELFT> *S : getInputSections(I)) {
       if (OutputName == "/DISCARD/") {
         S->Live = false;
         reportDiscarded(S);
@@ -420,6 +424,7 @@
   void readAsNeeded();
   void readEntry();
   void readExtern();
+  std::unique_ptr<InputSectionDescription> readFilePattern();
   void readGroup();
   void readKeep(OutputSectionCommand *Cmd);
   void readInclude();
@@ -662,16 +667,31 @@
       .Default(-1);
 }
 
-void ScriptParser::readKeep(OutputSectionCommand *Cmd) {
-  expect("(");
+std::unique_ptr<InputSectionDescription> ScriptParser::readFilePattern() {
   expect("*");
   expect("(");
-  auto *InCmd = new InputSectionDescription();
-  Cmd->Commands.emplace_back(InCmd);
-  while (!Error && !skip(")")) {
-    Opt.KeptSections.push_back(peek());
+
+  auto InCmd = llvm::make_unique<InputSectionDescription>();
+
+  if (skip("EXCLUDE_FILE")) {
+    expect("(");
+    while (!Error && !skip(")"))
+      InCmd->ExcludedFiles.push_back(next());
     InCmd->Patterns.push_back(next());
+    expect(")");
+  } else {
+    while (!Error && !skip(")"))
+      InCmd->Patterns.push_back(next());
   }
+  return InCmd;
+}
+
+void ScriptParser::readKeep(OutputSectionCommand *Cmd) {
+  expect("(");
+  std::unique_ptr<InputSectionDescription> InCmd = readFilePattern();
+  Opt.KeptSections.insert(Opt.KeptSections.end(), InCmd->Patterns.begin(),
+                          InCmd->Patterns.end());
+  Cmd->Commands.push_back(std::move(InCmd));
   expect(")");
 }