Restore "Fix an assertion triggered when using anonymous structs in kernel"

This reverts commit d463956aa4e3e1a26eeb32dc9d705b4b59865041.

Legacy kernels can/will use void pointers for some kernels, which can't
be exported, but are still legal.

Change-Id: Iba405356fe09385ddd424805787ce1c596c37dac
diff --git a/slang_rs_export_foreach.cpp b/slang_rs_export_foreach.cpp
index 213154d..2432bf2 100644
--- a/slang_rs_export_foreach.cpp
+++ b/slang_rs_export_foreach.cpp
@@ -525,14 +525,20 @@
     }
   }
 
-  if (FE->hasIns()) {
+  // Construct type information about inputs and outputs. Return null when
+  // there is an error exporting types.
 
+  bool TypeExportError = false;
+
+  if (FE->hasIns()) {
     for (InIter BI = FE->mIns.begin(), EI = FE->mIns.end(); BI != EI; BI++) {
       const clang::Type *T = (*BI)->getType().getCanonicalType().getTypePtr();
       RSExportType *InExportType = RSExportType::Create(Context, T);
 
-      if (FE->mIsKernelStyle) {
-        slangAssert(InExportType != nullptr);
+      // It is not an error if we don't export an input type for legacy
+      // kernels. This can happen in the case of a void pointer.
+      if (FE->mIsKernelStyle && !InExportType) {
+        TypeExportError = true;
       }
 
       FE->mInTypes.push_back(InExportType);
@@ -540,12 +546,21 @@
   }
 
   if (FE->mIsKernelStyle && FE->mHasReturnType) {
-    const clang::Type *T = FE->mResultType.getTypePtr();
-    FE->mOutType = RSExportType::Create(Context, T);
-    slangAssert(FE->mOutType);
+    const clang::Type *ReturnType = FE->mResultType.getTypePtr();
+    FE->mOutType = RSExportType::Create(Context, ReturnType);
+    TypeExportError |= !FE->mOutType;
   } else if (FE->mOut) {
-    const clang::Type *T = FE->mOut->getType().getCanonicalType().getTypePtr();
-    FE->mOutType = RSExportType::Create(Context, T);
+    const clang::Type *OutType =
+        FE->mOut->getType().getCanonicalType().getTypePtr();
+    FE->mOutType = RSExportType::Create(Context, OutType);
+    // It is not an error if we don't export an output type.
+    // This can happen in the case of a void pointer.
+  }
+
+  if (TypeExportError) {
+    slangAssert(Context->getDiagnostics()->hasErrorOccurred() &&
+                "Error exporting type but no diagnostic message issued!");
+    return nullptr;
   }
 
   return FE;
diff --git a/tests/F_anon_struct_kernel_sig/anon_struct_kernel_sig.rs b/tests/F_anon_struct_kernel_sig/anon_struct_kernel_sig.rs
new file mode 100644
index 0000000..028a328
--- /dev/null
+++ b/tests/F_anon_struct_kernel_sig/anon_struct_kernel_sig.rs
@@ -0,0 +1,21 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+typedef struct {
+  int i;
+} myStruct;
+
+/* Test old-style kernel */
+void root(const myStruct *in, int *out) {
+  *out = in->i;
+}
+
+/* Test new-style kernel */
+myStruct RS_KERNEL kernel_returning_myStruct(int in) {
+  myStruct out = { in };
+  return out;
+}
+
+int RS_KERNEL kernel_with_myStruct_param(myStruct in) {
+  return in.i;
+}
diff --git a/tests/F_anon_struct_kernel_sig/stderr.txt.expect b/tests/F_anon_struct_kernel_sig/stderr.txt.expect
new file mode 100644
index 0000000..276aaaf
--- /dev/null
+++ b/tests/F_anon_struct_kernel_sig/stderr.txt.expect
@@ -0,0 +1 @@
+anon_struct_kernel_sig.rs:4:9: error: anonymous structures cannot be exported
diff --git a/tests/F_anon_struct_kernel_sig/stdout.txt.expect b/tests/F_anon_struct_kernel_sig/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/F_anon_struct_kernel_sig/stdout.txt.expect
diff --git a/tests/P_root_void/root_void.rs b/tests/P_root_void/root_void.rs
new file mode 100644
index 0000000..13bed22
--- /dev/null
+++ b/tests/P_root_void/root_void.rs
@@ -0,0 +1,83 @@
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+void root(const void *ain, void *aout, const void *usrData,
+          uint32_t x, uint32_t y) {
+}
+
+void in_only(const void *ain) {
+}
+
+void in_x_only(const void *ain, uint32_t x) {
+}
+
+void in_y_only(const void *ain, uint32_t y) {
+}
+
+void in_x_y_only(const void *ain, uint32_t x, uint32_t y) {
+}
+
+void in_usrdata_only(const void *ain, const void *usrData) {
+}
+
+void in_usrdata_x_only(const void *ain, const void *usrData, uint32_t x) {
+}
+
+void in_usrdata_y_only(const void *ain, const void *usrData, uint32_t y) {
+}
+
+void in_usrdata_x_y_only(const void *ain, const void *usrData, uint32_t x,
+                         uint32_t y) {
+}
+
+void out_only(void *aout) {
+}
+
+void out_x_only(void *aout, uint32_t x) {
+}
+
+void out_y_only(void *aout, uint32_t y) {
+}
+
+void out_x_y_only(void *aout, uint32_t x, uint32_t y) {
+}
+
+void out_usrdata_only(void *aout, const void *usrData) {
+}
+
+void out_usrdata_x_only(void *aout, const void *usrData, uint32_t x) {
+}
+
+void out_usrdata_y_only(void *aout, const void *usrData, uint32_t y) {
+}
+
+void out_usrdata_x_y_only(void *aout, const void *usrData, uint32_t x,
+                         uint32_t y) {
+}
+
+void in_out_only(const void *ain, void *aout) {
+}
+
+void in_out_x_only(const void *ain, void *aout, uint32_t x) {
+}
+
+void in_out_y_only(const void *ain, void *aout, uint32_t y) {
+}
+
+void in_out_x_y_only(const void *ain, void *aout, uint32_t x, uint32_t y) {
+}
+
+void in_out_usrdata_only(const void *ain, void *aout, const void *usrData) {
+}
+
+void in_out_usrdata_x_only(const void *ain, void *aout, const void *usrData,
+                           uint32_t x) {
+}
+
+void in_out_usrdata_y_only(const void *ain, void *aout, const void *usrData,
+                           uint32_t y) {
+}
+
+void in_out_usrdata_x_y_only(const void *ain, void *aout, const void *usrData,
+                             uint32_t x, uint32_t y) {
+}
diff --git a/tests/P_root_void/stderr.txt.expect b/tests/P_root_void/stderr.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_root_void/stderr.txt.expect
diff --git a/tests/P_root_void/stdout.txt.expect b/tests/P_root_void/stdout.txt.expect
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/P_root_void/stdout.txt.expect