catch broken vector member access
authorWolfgang Bumiller <wry.git@bumiller.com>
Sun, 14 Jan 2018 09:58:29 +0000 (10:58 +0100)
committerWolfgang Bumiller <wry.git@bumiller.com>
Sun, 14 Jan 2018 09:58:29 +0000 (10:58 +0100)
These kinds of expressions currently cannot be handled
without pionter support in the qcvm without scanning the
ast from within ast_member::codegen for an assignments as
seen in the added test case.

This change makes code like that return a pointer type which
will cause an error that we did not get a vector or field
back. With pointer support this pointer could actually be
used instead.

So at least it shouldn't silently produce broken code
anymore.

Signed-off-by: Wolfgang Bumiller <wry.git@bumiller.com>
ast.cpp
tests/vecfields-broken.tmpl [new file with mode: 0644]
tests/vecfields.qc

diff --git a/ast.cpp b/ast.cpp
index cbc5db9..1ac0a44 100644 (file)
--- a/ast.cpp
+++ b/ast.cpp
@@ -1932,6 +1932,7 @@ bool ast_binstore::codegen(ast_function *func, bool lvalue, ir_value **out)
         if (!idx->codegen(func, false, &iridx))
             return false;
     }
+
     if (!m_dest->codegen(func, false, &leftr))
         return false;
 
@@ -2153,19 +2154,28 @@ bool ast_member::codegen(ast_function *func, bool lvalue, ir_value **out)
         else
             m_outr = *out;
         return (*out != nullptr);
-    } else {
-        if (!m_owner->codegen(func, false, &vec))
-            return false;
     }
 
+    // Vector member access
+    if (!m_owner->codegen(func, lvalue, &vec))
+        return false;
+
     if (vec->m_vtype != TYPE_VECTOR &&
         !(vec->m_vtype == TYPE_FIELD && m_owner->m_next->m_vtype == TYPE_VECTOR))
     {
+        compile_error(m_context, "vector member produced neither vector nor field");
         return false;
     }
 
     *out = vec->vectorMember(m_field);
-    m_outl = *out;
+    if (!*out) {
+        compile_error(m_context, "internal error: failed to create vector member access");
+        return false;
+    }
+    if (lvalue)
+        m_outl = *out;
+    else
+        m_outr = *out;
 
     return (*out != nullptr);
 }
diff --git a/tests/vecfields-broken.tmpl b/tests/vecfields-broken.tmpl
new file mode 100644 (file)
index 0000000..59f968b
--- /dev/null
@@ -0,0 +1,4 @@
+I: vecfields.qc
+D: vector field member accesses
+T: -fail
+C: -std=gmqcc -fftepp -DBROKEN_ACCESS
index 6cc053a..815de98 100644 (file)
@@ -10,4 +10,8 @@ void main() {
        e.v1 = '1 2 3';
        print(ftos(set(e, 42)), " => ");
        print(vtos(e.v1), "\n");
+
+#ifdef BROKEN_ACCESS
+       (e.v1 = '0 0 0').x += 1;
+#endif
 }