[llvm-commits] [parallel] CVS: llvm/lib/Support/Annotation.cpp LeakDetector.cpp Mangler.cpp PluginLoader.cpp Signals.cpp ToolRunner.cpp

Misha Brukman brukman at cs.uiuc.edu
Mon Mar 1 18:03:30 PST 2004


Changes in directory llvm/lib/Support:

Annotation.cpp updated: 1.13 -> 1.13.2.1
LeakDetector.cpp updated: 1.6 -> 1.6.2.1
Mangler.cpp updated: 1.8 -> 1.8.2.1
PluginLoader.cpp updated: 1.8 -> 1.8.2.1
Signals.cpp updated: 1.11 -> 1.11.2.1
ToolRunner.cpp updated: 1.13 -> 1.13.2.1

---
Log message:

Merge from trunk

---
Diffs of the changes:  (+267 -153)

Index: llvm/lib/Support/Annotation.cpp
diff -u llvm/lib/Support/Annotation.cpp:1.13 llvm/lib/Support/Annotation.cpp:1.13.2.1
--- llvm/lib/Support/Annotation.cpp:1.13	Sun Dec 14 15:35:53 2003
+++ llvm/lib/Support/Annotation.cpp	Mon Mar  1 17:58:13 2004
@@ -15,6 +15,18 @@
 #include "Support/Annotation.h"
 using namespace llvm;
 
+Annotation::~Annotation() {}  // Designed to be subclassed
+
+Annotable::~Annotable() {   // Virtual because it's designed to be subclassed...
+  Annotation *A = AnnotationList;
+  while (A) {
+    Annotation *Next = A->getNext();
+    delete A;
+    A = Next;
+  }
+}
+
+
 typedef std::map<const std::string, unsigned> IDMapType;
 static unsigned IDCounter = 0;  // Unique ID counter
 
@@ -40,7 +52,6 @@
     TheFactMap = 0;
   }
 }
-
 
 AnnotationID AnnotationManager::getID(const std::string &Name) {  // Name -> ID
   IDMapType::iterator I = getIDMap().find(Name);


Index: llvm/lib/Support/LeakDetector.cpp
diff -u llvm/lib/Support/LeakDetector.cpp:1.6 llvm/lib/Support/LeakDetector.cpp:1.6.2.1
--- llvm/lib/Support/LeakDetector.cpp:1.6	Sun Dec 14 15:35:53 2003
+++ llvm/lib/Support/LeakDetector.cpp	Mon Mar  1 17:58:13 2004
@@ -16,75 +16,95 @@
 #include <set>
 using namespace llvm;
 
-// Lazily allocate set so that release build doesn't have to do anything.
-static std::set<const void*> *Objects = 0;
-static std::set<const Value*> *LLVMObjects = 0;
-
-// Because the most common usage pattern, by far, is to add a garbage object,
-// then remove it immediately, we optimize this case.  When an object is added,
-// it is not added to the set immediately, it is added to the CachedValue Value.
-// If it is immediately removed, no set search need be performed.
-//
-static const Value *CachedValue;
+namespace {
+  template <typename T>
+  struct LeakDetectorImpl {
+    LeakDetectorImpl(const char* const name) : Cache(0), Name(name) { }
+
+    // Because the most common usage pattern, by far, is to add a
+    // garbage object, then remove it immediately, we optimize this
+    // case.  When an object is added, it is not added to the set
+    // immediately, it is added to the CachedValue Value.  If it is
+    // immediately removed, no set search need be performed.
+    void addGarbage(const T* o) {
+      if (Cache) {
+        assert(Ts.count(Cache) == 0 && "Object already in set!");
+        Ts.insert(Cache);
+      }
+      Cache = o;
+    }
 
-void LeakDetector::addGarbageObjectImpl(void *Object) {
-  if (Objects == 0)
-    Objects = new std::set<const void*>();
-  assert(Objects->count(Object) == 0 && "Object already in set!");
-  Objects->insert(Object);
+    void removeGarbage(const T* o) {
+      if (o == Cache)
+        Cache = 0; // Cache hit
+      else
+          Ts.erase(o);
+    }
+
+    bool hasGarbage(const std::string& Message) {
+      addGarbage(0); // Flush the Cache
+
+      assert(Cache == 0 && "No value should be cached anymore!");
+
+      if (!Ts.empty()) {
+        std::cerr
+            << "Leaked " << Name << " objects found: " << Message << ":\n\t";
+        std::copy(Ts.begin(), Ts.end(),
+                  std::ostream_iterator<const T*>(std::cerr, " "));
+        std::cerr << '\n';
+
+        // Clear out results so we don't get duplicate warnings on
+        // next call...
+        Ts.clear();
+        return true;
+      }
+      return false;
+    }
+
+  private:
+    std::set<const T*> Ts;
+    const T* Cache;
+    const char* const Name;
+  };
+
+  typedef LeakDetectorImpl<void>  Objects;
+  typedef LeakDetectorImpl<Value> LLVMObjects;
+
+  Objects& getObjects() {
+    static Objects *o = 0;
+    if (o == 0)
+      o = new Objects("GENERIC");
+    return *o;
+  }
+
+  LLVMObjects& getLLVMObjects() {
+    static LLVMObjects *o = 0;
+    if (o == 0)
+      o = new LLVMObjects("LLVM");
+    return *o;
+  }
 }
 
-void LeakDetector::removeGarbageObjectImpl(void *Object) {
-  if (Objects)
-    Objects->erase(Object);
+void LeakDetector::addGarbageObjectImpl(void *Object) {
+  getObjects().addGarbage(Object);
 }
 
 void LeakDetector::addGarbageObjectImpl(const Value *Object) {
-  if (CachedValue) {
-    if (LLVMObjects == 0)
-      LLVMObjects = new std::set<const Value*>();
-    assert(LLVMObjects->count(CachedValue) == 0 && "Object already in set!");
-    LLVMObjects->insert(CachedValue);
-  }
-  CachedValue = Object;
+  getLLVMObjects().addGarbage(Object);
+}
+
+void LeakDetector::removeGarbageObjectImpl(void *Object) {
+  getObjects().removeGarbage(Object);
 }
 
 void LeakDetector::removeGarbageObjectImpl(const Value *Object) {
-  if (Object == CachedValue)
-    CachedValue = 0;             // Cache hit!
-  else if (LLVMObjects)
-    LLVMObjects->erase(Object);
+  getLLVMObjects().removeGarbage(Object);
 }
 
 void LeakDetector::checkForGarbageImpl(const std::string &Message) {
-  if (CachedValue)  // Flush the cache to the set...
-    addGarbageObjectImpl((Value*)0);
-
-  assert(CachedValue == 0 && "No value should be cached anymore!");
-
-  if ((Objects && !Objects->empty()) || (LLVMObjects && !LLVMObjects->empty())){
-    std::cerr << "Leaked objects found: " << Message << "\n";
-
-    if (Objects && !Objects->empty()) {
-      std::cerr << "  Non-Value objects leaked:";
-      for (std::set<const void*>::iterator I = Objects->begin(),
-             E = Objects->end(); I != E; ++I)
-        std::cerr << " " << *I;
-    }
-
-    if (LLVMObjects && !LLVMObjects->empty()) {
-      std::cerr << "  LLVM Value subclasses leaked:";
-      for (std::set<const Value*>::iterator I = LLVMObjects->begin(),
-             E = LLVMObjects->end(); I != E; ++I)
-        std::cerr << **I << "\n";
-    }
-
-    std::cerr << "This is probably because you removed an LLVM value "
-              << "(Instruction, BasicBlock, \netc), but didn't delete it.  "
-              << "Please check your code for memory leaks.\n";
-
-    // Clear out results so we don't get duplicate warnings on next call...
-    delete Objects; delete LLVMObjects;
-    Objects = 0; LLVMObjects = 0;
-  }
+  // use non-short-circuit version so that both checks are performed
+  if (getObjects().hasGarbage(Message) |
+      getLLVMObjects().hasGarbage(Message))
+    std::cerr << "\nThis is probably because you removed an object, but didn't "
+                 "delete it.  Please check your code for memory leaks.\n";
 }


Index: llvm/lib/Support/Mangler.cpp
diff -u llvm/lib/Support/Mangler.cpp:1.8 llvm/lib/Support/Mangler.cpp:1.8.2.1
--- llvm/lib/Support/Mangler.cpp:1.8	Sun Dec 14 15:35:53 2003
+++ llvm/lib/Support/Mangler.cpp	Mon Mar  1 17:58:13 2004
@@ -80,22 +80,37 @@
   return name;
 }
 
+void Mangler::InsertName(GlobalValue *GV,
+                         std::map<std::string, GlobalValue*> &Names) {
+  if (!GV->hasName()) {   // We must mangle unnamed globals.
+    MangledGlobals.insert(GV);
+    return;
+  }
+
+  // Figure out if this is already used.
+  GlobalValue *&ExistingValue = Names[GV->getName()];
+  if (!ExistingValue) {
+    ExistingValue = GV;
+  } else {
+    // If GV is external but the existing one is static, mangle the existing one
+    if (GV->hasExternalLinkage() && !ExistingValue->hasExternalLinkage()) {
+      MangledGlobals.insert(ExistingValue);
+      ExistingValue = GV;
+    } else {
+      // Otherwise, mangle GV
+      MangledGlobals.insert(GV);
+    }
+  }
+}
+
+
 Mangler::Mangler(Module &m, bool addUnderscorePrefix)
-  : M(m), AddUnderscorePrefix(addUnderscorePrefix) {
+  : M(m), AddUnderscorePrefix(addUnderscorePrefix), Count(0) {
   // Calculate which global values have names that will collide when we throw
   // away type information.
-  std::set<std::string> FoundNames;
+  std::map<std::string, GlobalValue*> Names;
   for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
-    if (I->hasName())                      // If the global has a name...
-      if (FoundNames.count(I->getName()))  // And the name is already used
-        MangledGlobals.insert(I);          // Mangle the name
-      else
-        FoundNames.insert(I->getName());   // Otherwise, keep track of name
-
+    InsertName(I, Names);
   for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I)
-    if (I->hasName())                      // If the global has a name...
-      if (FoundNames.count(I->getName()))  // And the name is already used
-        MangledGlobals.insert(I);          // Mangle the name
-      else
-        FoundNames.insert(I->getName());   // Otherwise, keep track of name
+    InsertName(I, Names);
 }


Index: llvm/lib/Support/PluginLoader.cpp
diff -u llvm/lib/Support/PluginLoader.cpp:1.8 llvm/lib/Support/PluginLoader.cpp:1.8.2.1
--- llvm/lib/Support/PluginLoader.cpp:1.8	Sun Dec 14 15:35:53 2003
+++ llvm/lib/Support/PluginLoader.cpp	Mon Mar  1 17:58:13 2004
@@ -37,5 +37,5 @@
 
 // This causes operator= above to be invoked for every -load option.
 static cl::opt<PluginLoader, false, cl::parser<std::string> >
-LoadOpt("load", cl::ZeroOrMore, cl::value_desc("plugin.so"),
+LoadOpt("load", cl::ZeroOrMore, cl::value_desc("plugin" SHLIBEXT),
         cl::desc("Load the specified plugin"));


Index: llvm/lib/Support/Signals.cpp
diff -u llvm/lib/Support/Signals.cpp:1.11 llvm/lib/Support/Signals.cpp:1.11.2.1
--- llvm/lib/Support/Signals.cpp:1.11	Sun Dec 14 15:35:53 2003
+++ llvm/lib/Support/Signals.cpp	Mon Mar  1 17:58:13 2004
@@ -17,8 +17,14 @@
 #include <algorithm>
 #include <cstdlib>
 #include <cstdio>
-#include <signal.h>
 #include "Config/config.h"     // Get the signal handler return type
+#ifdef HAVE_EXECINFO_H
+# include <execinfo.h>         // For backtrace().
+#endif
+#include <signal.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <cerrno>
 using namespace llvm;
 
 static std::vector<std::string> FilesToRemove;
@@ -39,6 +45,65 @@
 };
 static const int *KillSigsEnd = KillSigs + sizeof(KillSigs)/sizeof(KillSigs[0]);
 
+#ifdef HAVE_BACKTRACE
+static void* StackTrace[256];
+#endif
+
+
+// PrintStackTrace - In the case of a program crash or fault, print out a stack
+// trace so that the user has an indication of why and where we died.
+//
+// On glibc systems we have the 'backtrace' function, which works nicely, but
+// doesn't demangle symbols.  In order to backtrace symbols, we fork and exec a
+// 'c++filt' process to do the demangling.  This seems like the simplest and
+// most robust solution when we can't allocate memory (such as in a signal
+// handler).  If we can't find 'c++filt', we fallback to printing mangled names.
+//
+static void PrintStackTrace() {
+#ifdef HAVE_BACKTRACE
+  // Use backtrace() to output a backtrace on Linux systems with glibc.
+  int depth = backtrace(StackTrace, sizeof(StackTrace)/sizeof(StackTrace[0]));
+  
+  // Create a one-way unix pipe.  The backtracing process writes to PipeFDs[1],
+  // the c++filt process reads from PipeFDs[0].
+  int PipeFDs[2];
+  if (pipe(PipeFDs)) {
+    backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
+    return;
+  }
+
+  switch (pid_t ChildPID = fork()) {
+  case -1:        // Error forking, print mangled stack trace
+    close(PipeFDs[0]);
+    close(PipeFDs[1]);
+    backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
+    return;
+  default:        // backtracing process
+    close(PipeFDs[0]);  // Close the reader side.
+
+    // Print the mangled backtrace into the pipe.
+    backtrace_symbols_fd(StackTrace, depth, PipeFDs[1]);
+    close(PipeFDs[1]);   // We are done writing.
+    while (waitpid(ChildPID, 0, 0) == -1)
+      if (errno != EINTR) break;
+    return;
+
+  case 0:         // c++filt process
+    close(PipeFDs[1]);    // Close the writer side.
+    dup2(PipeFDs[0], 0);  // Read from standard input
+    close(PipeFDs[0]);    // Close the old descriptor
+    dup2(2, 1);           // Revector stdout -> stderr
+
+    // Try to run c++filt or gc++filt.  If neither is found, call back on 'cat'
+    // to print the mangled stack trace.  If we can't find cat, just exit.
+    execlp("c++filt", "c++filt", 0);
+    execlp("gc++filt", "gc++filt", 0);
+    execlp("cat", "cat", 0);
+    execlp("/bin/cat", "cat", 0);
+    exit(0);
+  }
+#endif
+}
 
 // SignalHandler - The signal handler that runs...
 static RETSIGTYPE SignalHandler(int Sig) {
@@ -50,7 +115,9 @@
   if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd)
     exit(1);   // If this is an interrupt signal, exit the program
 
-  // Otherwise if it is a fault (like SEGV) reissue the signal to die...
+  // Otherwise if it is a fault (like SEGV) output the stacktrace to
+  // STDERR (if we can) and reissue the signal to die...
+  PrintStackTrace();
   signal(Sig, SIG_DFL);
 }
 
@@ -61,5 +128,11 @@
   FilesToRemove.push_back(Filename);
 
   std::for_each(IntSigs, IntSigsEnd, RegisterHandler);
+  std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
+}
+
+/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
+/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
+void llvm::PrintStackTraceOnErrorSignal() {
   std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
 }


Index: llvm/lib/Support/ToolRunner.cpp
diff -u llvm/lib/Support/ToolRunner.cpp:1.13 llvm/lib/Support/ToolRunner.cpp:1.13.2.1
--- llvm/lib/Support/ToolRunner.cpp:1.13	Sun Dec 14 15:35:53 2003
+++ llvm/lib/Support/ToolRunner.cpp	Mon Mar  1 17:58:13 2004
@@ -18,8 +18,36 @@
 #include "Support/FileUtilities.h"
 #include <iostream>
 #include <fstream>
+#include <sstream>
 using namespace llvm;
 
+ToolExecutionError::~ToolExecutionError() throw() { }
+
+static void ProcessFailure(std::string ProgPath, const char** Args) {
+  std::ostringstream OS;
+  OS << "\nError running tool:\n ";
+  for (const char **Arg = Args; *Arg; ++Arg)
+    OS << " " << *Arg;
+  OS << "\n";
+
+  // Rerun the compiler, capturing any error messages to print them.
+  std::string ErrorFilename = getUniqueFilename("error_messages");
+  RunProgramWithTimeout(ProgPath, Args, "/dev/null", ErrorFilename.c_str(),
+                        ErrorFilename.c_str());
+
+  // Print out the error messages generated by GCC if possible...
+  std::ifstream ErrorFile(ErrorFilename.c_str());
+  if (ErrorFile) {
+    std::copy(std::istreambuf_iterator<char>(ErrorFile),
+              std::istreambuf_iterator<char>(),
+              std::ostreambuf_iterator<char>(OS));
+    ErrorFile.close();
+  }
+
+  removeFile(ErrorFilename);
+  throw ToolExecutionError(OS.str());
+}
+
 //===---------------------------------------------------------------------===//
 // LLI Implementation of AbstractIntepreter interface
 //
@@ -44,11 +72,9 @@
                         const std::string &InputFile,
                         const std::string &OutputFile,
                         const std::vector<std::string> &SharedLibs) {
-  if (!SharedLibs.empty()) {
-    std::cerr << "LLI currently does not support loading shared libraries.\n"
-              << "Exiting.\n";
-    exit(1);
-  }
+  if (!SharedLibs.empty())
+    throw ToolExecutionError("LLI currently does not support "
+                             "loading shared libraries.");
 
   std::vector<const char*> LLIArgs;
   LLIArgs.push_back(LLIPath.c_str());
@@ -86,7 +112,7 @@
 //===----------------------------------------------------------------------===//
 // LLC Implementation of AbstractIntepreter interface
 //
-int LLC::OutputAsm(const std::string &Bytecode, std::string &OutputAsmFile) {
+void LLC::OutputAsm(const std::string &Bytecode, std::string &OutputAsmFile) {
   OutputAsmFile = getUniqueFilename(Bytecode+".llc.s");
   const char *LLCArgs[] = {
     LLCPath.c_str(),
@@ -98,14 +124,14 @@
 
   std::cout << "<llc>" << std::flush;
   if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
-                            "/dev/null")) {                            
-    // If LLC failed on the bytecode, print error...
-    std::cerr << "Error: `llc' failed!\n";
-    removeFile(OutputAsmFile);
-    return 1;
-  }
+                            "/dev/null"))
+    ProcessFailure(LLCPath, LLCArgs);
+}
 
-  return 0;
+void LLC::compileProgram(const std::string &Bytecode) {
+  std::string OutputAsmFile;
+  OutputAsm(Bytecode, OutputAsmFile);
+  removeFile(OutputAsmFile);
 }
 
 int LLC::ExecuteProgram(const std::string &Bytecode,
@@ -115,16 +141,12 @@
                         const std::vector<std::string> &SharedLibs) {
 
   std::string OutputAsmFile;
-  if (OutputAsm(Bytecode, OutputAsmFile)) {
-    std::cerr << "Could not generate asm code with `llc', exiting.\n";
-    exit(1);
-  }
+  OutputAsm(Bytecode, OutputAsmFile);
+  FileRemover OutFileRemover(OutputAsmFile);
 
   // Assuming LLC worked, compile the result with GCC and run it.
-  int Result = gcc->ExecuteProgram(OutputAsmFile, Args, GCC::AsmFile,
-                                   InputFile, OutputFile, SharedLibs);
-  removeFile(OutputAsmFile);
-  return Result;
+  return gcc->ExecuteProgram(OutputAsmFile, Args, GCC::AsmFile,
+                             InputFile, OutputFile, SharedLibs);
 }
 
 /// createLLC - Try to find the LLC executable
@@ -211,27 +233,28 @@
   return 0;
 }
 
-int CBE::OutputC(const std::string &Bytecode,
+void CBE::OutputC(const std::string &Bytecode,
                  std::string &OutputCFile) {
   OutputCFile = getUniqueFilename(Bytecode+".cbe.c");
-  const char *DisArgs[] = {
-    DISPath.c_str(),
+  const char *LLCArgs[] = {
+    LLCPath.c_str(),
     "-o", OutputCFile.c_str(),   // Output to the C file
-    "-c",                        // Output to C
+    "-march=c",                  // Output to C
     "-f",                        // Overwrite as necessary...
     Bytecode.c_str(),            // This is the input bytecode
     0
   };
 
   std::cout << "<cbe>" << std::flush;
-  if (RunProgramWithTimeout(DISPath, DisArgs, "/dev/null", "/dev/null",
-                            "/dev/null")) {                            
-    // If dis failed on the bytecode, print error...
-    std::cerr << "Error: `llvm-dis -c' failed!\n";
-    return 1;
-  }
+  if (RunProgramWithTimeout(LLCPath, LLCArgs, "/dev/null", "/dev/null",
+                            "/dev/null"))
+    ProcessFailure(LLCPath, LLCArgs);
+}
 
-  return 0;
+void CBE::compileProgram(const std::string &Bytecode) {
+  std::string OutputCFile;
+  OutputC(Bytecode, OutputCFile);
+  removeFile(OutputCFile);
 }
 
 int CBE::ExecuteProgram(const std::string &Bytecode,
@@ -240,36 +263,32 @@
                         const std::string &OutputFile,
                         const std::vector<std::string> &SharedLibs) {
   std::string OutputCFile;
-  if (OutputC(Bytecode, OutputCFile)) {
-    std::cerr << "Could not generate C code with `llvm-dis', exiting.\n";
-    exit(1);
-  }
+  OutputC(Bytecode, OutputCFile);
 
-  int Result = gcc->ExecuteProgram(OutputCFile, Args, GCC::CFile, 
-                                   InputFile, OutputFile, SharedLibs);
-  removeFile(OutputCFile);
+  FileRemover CFileRemove(OutputCFile);
 
-  return Result;
+  return gcc->ExecuteProgram(OutputCFile, Args, GCC::CFile, 
+                             InputFile, OutputFile, SharedLibs);
 }
 
-/// createCBE - Try to find the 'llvm-dis' executable
+/// createCBE - Try to find the 'llc' executable
 ///
 CBE *AbstractInterpreter::createCBE(const std::string &ProgramPath,
                                     std::string &Message) {
-  std::string DISPath = FindExecutable("llvm-dis", ProgramPath);
-  if (DISPath.empty()) {
+  std::string LLCPath = FindExecutable("llc", ProgramPath);
+  if (LLCPath.empty()) {
     Message = 
-      "Cannot find `llvm-dis' in executable directory or PATH!\n";
+      "Cannot find `llc' in executable directory or PATH!\n";
     return 0;
   }
 
-  Message = "Found llvm-dis: " + DISPath + "\n";
+  Message = "Found llc: " + LLCPath + "\n";
   GCC *gcc = GCC::create(ProgramPath, Message);
   if (!gcc) {
     std::cerr << Message << "\n";
     exit(1);
   }
-  return new CBE(DISPath, gcc);
+  return new CBE(LLCPath, gcc);
 }
 
 //===---------------------------------------------------------------------===//
@@ -311,7 +330,7 @@
   std::cout << "<gcc>" << std::flush;
   if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], "/dev/null", "/dev/null",
                             "/dev/null")) {
-    ProcessFailure(&GCCArgs[0]);
+    ProcessFailure(GCCPath, &GCCArgs[0]);
     exit(1);
   }
 
@@ -329,15 +348,15 @@
           std::cerr << " " << ProgramArgs[i];
         std::cerr << "\n";
         );
-  int ProgramResult = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
-                                            InputFile, OutputFile, OutputFile);
-  removeFile(OutputBinary);
-  return ProgramResult;
+
+  FileRemover OutputBinaryRemover(OutputBinary);
+  return RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
+                               InputFile, OutputFile, OutputFile);
 }
 
 int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
                           std::string &OutputFile) {
-  OutputFile = getUniqueFilename(InputFile+".so");
+  OutputFile = getUniqueFilename(InputFile+SHLIBEXT);
   // Compile the C/asm file into a shared object
   const char* GCCArgs[] = {
     GCCPath.c_str(),
@@ -357,34 +376,10 @@
   std::cout << "<gcc>" << std::flush;
   if (RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", "/dev/null",
                             "/dev/null")) {
-    ProcessFailure(GCCArgs);
+    ProcessFailure(GCCPath, GCCArgs);
     return 1;
   }
   return 0;
-}
-
-void GCC::ProcessFailure(const char** GCCArgs) {
-  std::cerr << "\n*** Error: invocation of the C compiler failed!\n";
-  for (const char **Arg = GCCArgs; *Arg; ++Arg)
-    std::cerr << " " << *Arg;
-  std::cerr << "\n";
-
-  // Rerun the compiler, capturing any error messages to print them.
-  std::string ErrorFilename = getUniqueFilename("gcc.errors");
-  RunProgramWithTimeout(GCCPath, GCCArgs, "/dev/null", ErrorFilename.c_str(),
-                        ErrorFilename.c_str());
-
-  // Print out the error messages generated by GCC if possible...
-  std::ifstream ErrorFile(ErrorFilename.c_str());
-  if (ErrorFile) {
-    std::copy(std::istreambuf_iterator<char>(ErrorFile),
-              std::istreambuf_iterator<char>(),
-              std::ostreambuf_iterator<char>(std::cerr));
-    ErrorFile.close();
-    std::cerr << "\n";      
-  }
-
-  removeFile(ErrorFilename);
 }
 
 /// create - Try to find the `gcc' executable





More information about the llvm-commits mailing list