gollvm: fix compiler assert on duplicate parameter

When the front end encounters a syntax error of some sort with a
parameter in a function definition (ex: func f(x int, x bool)) it will
continue the compilation, but won't go on to create the Bvariable for
the parameter. This can confuse things later on, in case that expects
to see entries for all of the params.  Check for this case in
Llvm_backend::function_set_parameters and set a flag on the Bfunction
in question, so that later on we can work around the missing param
(and avoid any asserts/crashes).

Change-Id: I51cd9aee9f5ec10270d6a932f471bc0889612ccc
Reviewed-on: https://go-review.googlesource.com/63671
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/llvm-gofrontend/go-llvm-bfunction.cpp b/llvm-gofrontend/go-llvm-bfunction.cpp
index b7cbb2a..fef36b7 100644
--- a/llvm-gofrontend/go-llvm-bfunction.cpp
+++ b/llvm-gofrontend/go-llvm-bfunction.cpp
@@ -39,7 +39,8 @@
       rtnValueMem_(nullptr), chainVal_(nullptr),
       paramsRegistered_(0), name_(name), asmName_(asmName),
       location_(location), splitStack_(YesSplit),
-      prologGenerated_(false), abiSetupComplete_(false)
+      prologGenerated_(false), abiSetupComplete_(false),
+      errorSeen_(false)
 {
   if (! fcnType->followsCabi())
     abiSetupComplete_ = true;
@@ -305,8 +306,7 @@
 Bvariable *Bfunction::getBvarForValue(llvm::Value *val)
 {
   auto it = valueVarMap_.find(val);
-  assert(it != valueVarMap_.end());
-  return it->second;
+  return (it != valueVarMap_.end() ? it->second : nullptr);
 }
 
 Bvariable *Bfunction::getNthParamVar(unsigned argIdx)
@@ -402,6 +402,10 @@
     if (paramInfo.disp() != ParmDirect)
       continue;
     Bvariable *v = getNthParamVar(pidx);
+    if (!v) {
+      assert(errorSeen());
+      continue;
+    }
     llvm::Value *sploc = llvm::cast<llvm::Instruction>(paramValues_[pidx]);
     argIdx += genArgSpill(v, paramInfo, &spills, sploc);
   }
@@ -425,6 +429,10 @@
   if (! entry->empty()) {
     for (unsigned pidx = 0; pidx < nParms; ++pidx) {
       Bvariable *v = getNthParamVar(pidx);
+      if (!v) {
+        assert(errorSeen());
+        continue;
+      }
       if (v->initializer() == nullptr)
         v->setInitializer(&entry->front());
     }
diff --git a/llvm-gofrontend/go-llvm-bfunction.h b/llvm-gofrontend/go-llvm-bfunction.h
index 25a3325..ecc2d43 100644
--- a/llvm-gofrontend/go-llvm-bfunction.h
+++ b/llvm-gofrontend/go-llvm-bfunction.h
@@ -136,6 +136,12 @@
   // the ABI type).  Exposed for unit testing.
   Bvariable *getNthParamVar(unsigned idx);
 
+  // Get/set whether we've seen errors in this function. At the
+  // moment this is used mainly to flag situations where there were
+  // errors in the parameter declaration.
+  bool errorSeen() const { return errorSeen_; }
+  void setErrorSeen(bool val) { errorSeen_ = val; }
+
  private:
 
   // Perform ABI-related setup for this function.
@@ -219,12 +225,27 @@
   std::string name_;
   std::string asmName_;
 
-  // Other bits of info about this function: location, split stack flag,
-  // flag to indicate that we finished generating prolog.
+  // Location for this function.
   Location location_;
+
+  // Whether this is a split-stack function.
   SplitStackDisposition splitStack_;
+
+  // Whether prolog generation was completed successfully or not for
+  // this function. May have been skipped due to errors or if we're
+  // running unit tests.
   bool prologGenerated_;
+
+  // Used to implement lazy ABI setup -- this avoids doing ABI setup on
+  // external function we don't call, or in cases where there are errors.
   bool abiSetupComplete_;
+
+  // Initially false; set to true in cases where we infer that an
+  // error has taken place.  If a function is declared with N
+  // parameters, but we only see N-2 parameter vars created, this is
+  // typically an indication that a syntax error was encountered by
+  // the FE somewhere along the line.
+  bool errorSeen_;
 };
 
 #endif // LLVMGOFRONTEND_GO_LLVM_BFUNCTION_H
diff --git a/llvm-gofrontend/go-llvm.cpp b/llvm-gofrontend/go-llvm.cpp
index 3509e93..cb7245e 100644
--- a/llvm-gofrontend/go-llvm.cpp
+++ b/llvm-gofrontend/go-llvm.cpp
@@ -14,6 +14,7 @@
 
 #include "go-llvm.h"
 #include "go-llvm-builtins.h"
+#include "go-llvm-diagnostics.h"
 #include "backend.h"
 #include "go-c.h"
 #include "go-system.h"
@@ -2452,7 +2453,17 @@
 bool Llvm_backend::function_set_parameters(
     Bfunction *function, const std::vector<Bvariable *> &param_vars)
 {
-  // At the moment this is a no-op.
+  if (function == errorFunction_.get())
+    return true;
+
+  // If the number of param vars doesn't match up with the number expected,
+  // we interpret that to mean that the FE encountered a syntax error
+  // while processing a parameter. Flag the function in this case so that
+  // we can avoid avoid asserting when doing prolog processing for
+  // the function.
+  if (function->fcnType()->paramTypes().size() != param_vars.size())
+    function->setErrorSeen(true);
+
   return true;
 }
 
@@ -3408,7 +3419,7 @@
 
   // Avoid debug meta-generation if errors seen
   DIBuildHelper *dibh = nullptr;
-  if (createDebugMetaData_ && errorCount_ == 0)
+  if (createDebugMetaData_ && errorCount_ == 0 && !go_be_saw_errors())
     dibh = dibuildhelper();
 
   // Walk the code statements