gollvm: handle unresolved placeholder in type_field_offset

Check for the presence of unresolved placeholder types as
part of Llvm_backend::type_field_offset, since this method
can be invoked on a struct type whose fields may incorporate
unresolved placeholder types.

Change-Id: I13e4ac860cc62cad0046df4fc70d5981f77e095c
Reviewed-on: https://go-review.googlesource.com/46730
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/llvm-gofrontend/go-llvm-typemanager.cpp b/llvm-gofrontend/go-llvm-typemanager.cpp
index 3d70607..f7f23c0 100644
--- a/llvm-gofrontend/go-llvm-typemanager.cpp
+++ b/llvm-gofrontend/go-llvm-typemanager.cpp
@@ -1285,6 +1285,21 @@
   return nullptr;
 }
 
+// Helper for use with typeSize() and typeFieldOffset methods.
+// Handles situations where we're asking about size/offset for
+// types that still incorporate placeholders.
+llvm::Type *TypeManager::getPlaceholderProxyIfNeeded(Btype *btype)
+{
+  llvm::Type *toget = btype->type();
+  llvm::SmallPtrSet<llvm::Type *, 32> vis;
+  if (!btype->type()->isSized(&vis)) {
+    pproxymap pmap;
+    toget = placeholderProxyType(btype, &pmap);
+    assert(toget);
+  }
+  return toget;
+}
+
 // Return the size of a type.
 
 // Note: frontend sometimes asks for the size of a placeholder
@@ -1296,15 +1311,7 @@
 int64_t TypeManager::typeSize(Btype *btype) {
   if (btype == errorType_)
     return 1;
-
-  llvm::Type *toget = btype->type();
-  llvm::SmallPtrSet<llvm::Type *, 32> vis;
-  if (!btype->type()->isSized(&vis)) {
-    pproxymap pmap;
-    toget = placeholderProxyType(btype, &pmap);
-    assert(toget);
-  }
-
+  llvm::Type *toget = getPlaceholderProxyIfNeeded(btype);
   uint64_t uvalbytes = datalayout_->getTypeAllocSize(toget);
   return static_cast<int64_t>(uvalbytes);
 }
@@ -1365,8 +1372,10 @@
 int64_t TypeManager::typeFieldOffset(Btype *btype, size_t index) {
   if (btype == errorType_)
     return 0;
-  assert(btype->type()->isStructTy());
-  llvm::StructType *llvm_st = llvm::cast<llvm::StructType>(btype->type());
+
+  llvm::Type *toget = getPlaceholderProxyIfNeeded(btype);
+  assert(toget->isStructTy());
+  llvm::StructType *llvm_st = llvm::cast<llvm::StructType>(toget);
   return llvmTypeFieldOffset(llvm_st, index);
 }
 
diff --git a/llvm-gofrontend/go-llvm-typemanager.h b/llvm-gofrontend/go-llvm-typemanager.h
index 8a2c3be..824849a 100644
--- a/llvm-gofrontend/go-llvm-typemanager.h
+++ b/llvm-gofrontend/go-llvm-typemanager.h
@@ -265,6 +265,10 @@
   typedef std::unordered_map<Btype *, llvm::Type *> pproxymap;
   llvm::Type *placeholderProxyType(Btype *typ, pproxymap *pmap);
 
+  // Checks for placeholder and invokes routine above if needed,
+  // otherwise returns the LLVM type for the specified Btype.
+  llvm::Type *getPlaceholderProxyIfNeeded(Btype *btype);
+
   // Context information needed for the LLVM backend.
   llvm::LLVMContext &context_;
   const llvm::DataLayout *datalayout_;
diff --git a/unittests/BackendCore/BackendCoreTests.cpp b/unittests/BackendCore/BackendCoreTests.cpp
index dd27cac..039d7d5 100644
--- a/unittests/BackendCore/BackendCoreTests.cpp
+++ b/unittests/BackendCore/BackendCoreTests.cpp
@@ -305,6 +305,7 @@
   be->set_placeholder_struct_type(phst, fields);
   Btype *rst = mkTwoFieldStruct(be.get(), pvt, pvt);
   EXPECT_EQ(be->type_size(rst), be->type_size(phst));
+  EXPECT_EQ(be->type_field_offset(rst,1), be->type_field_offset(phst,1));
 
   // type field alignment
   Btype *u32 = be->integer_type(true, 32);