cpp: allow casting C++ struct reference types to C types

This is safe because the C++ layout is static_assert'ed to be the
same as the C layout. It removes bad-looking reinterpret_cast
from application code.

Mutable reference casts are not allowed. This is because:
 - Some C++ structs have RAII objects in them. Casting to C and
   then changing the members could cause unexpected lifetime
   changes
 - Structs with "free members" functions only get const conversion
   operators. This is because output structs like this have RAII data
   which should not be mutated. The C structs do not have
   const-qualified members, so conversion to a mutable C struct would
   be unsafe.

Bug: chromium:40195122
Change-Id: I18cd06b04da2ea34803f517e2b640ceaaba408af
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/185966
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
diff --git a/generator/templates/api_cpp.h b/generator/templates/api_cpp.h
index d2ed0de..9790a50 100644
--- a/generator/templates/api_cpp.h
+++ b/generator/templates/api_cpp.h
@@ -336,6 +336,8 @@
             inline {{as_cppType(type.name)}}({{as_cppType(type.name)}}&&);
             inline {{as_cppType(type.name)}}& operator=({{as_cppType(type.name)}}&&);
         {% endif %}
+        inline operator const {{as_cType(type.name)}}&() const noexcept;
+
         {% if type.extensible %}
             ChainedStruct{{Out}} {{const}} * nextInChain = nullptr;
         {% endif %}
@@ -411,6 +413,10 @@
         }
     {% endif %}
 
+    {{CppType}}::operator const {{as_cType(type.name)}}&() const noexcept {
+        return *reinterpret_cast<const {{as_cType(type.name)}}*>(this);
+    }
+
     static_assert(sizeof({{CppType}}) == sizeof({{CType}}), "sizeof mismatch for {{CppType}}");
     static_assert(alignof({{CppType}}) == alignof({{CType}}), "alignof mismatch for {{CppType}}");
     {% if type.extensible %}