d: Fix ICE in expand_intrinsic_vaarg
authorIain Buclaw <ibuclaw@gdcproject.org>
Thu, 16 Jul 2020 16:34:18 +0000 (18:34 +0200)
committerIain Buclaw <ibuclaw@gdcproject.org>
Thu, 30 Jul 2020 21:44:31 +0000 (23:44 +0200)
Both intrinsics did not handle the case where the va_list object comes
from a ref parameter.

gcc/d/ChangeLog:

PR d/96140
* intrinsics.cc (expand_intrinsic_vaarg): Handle ref parameters as
arguments to va_arg().
(expand_intrinsic_vastart): Handle ref parameters as arguments to
va_start().

gcc/testsuite/ChangeLog:

PR d/96140
* gdc.dg/pr96140.d: New test.

gcc/d/intrinsics.cc
gcc/testsuite/gdc.dg/pr96140.d [new file with mode: 0644]

index 28667c63e17442dc6f3ac4446e9fb97bd269df42..8eec0af60eeb047ae8bc856d9ff204617727889f 100644 (file)
@@ -549,8 +549,17 @@ expand_intrinsic_vaarg (tree callexp)
     {
       parmn = CALL_EXPR_ARG (callexp, 1);
       STRIP_NOPS (parmn);
-      gcc_assert (TREE_CODE (parmn) == ADDR_EXPR);
-      parmn = TREE_OPERAND (parmn, 0);
+
+      /* The `ref' argument to va_arg is either an address or reference,
+        get the value of it.  */
+      if (TREE_CODE (parmn) == PARM_DECL && POINTER_TYPE_P (TREE_TYPE (parmn)))
+       parmn = build_deref (parmn);
+      else
+       {
+         gcc_assert (TREE_CODE (parmn) == ADDR_EXPR);
+         parmn = TREE_OPERAND (parmn, 0);
+       }
+
       type = TREE_TYPE (parmn);
     }
 
@@ -584,10 +593,16 @@ expand_intrinsic_vastart (tree callexp)
   /* The va_list argument should already have its address taken.  The second
      argument, however, is inout and that needs to be fixed to prevent a
      warning.  Could be casting, so need to check type too?  */
-  gcc_assert (TREE_CODE (ap) == ADDR_EXPR && TREE_CODE (parmn) == ADDR_EXPR);
+  gcc_assert (TREE_CODE (ap) == ADDR_EXPR
+             || (TREE_CODE (ap) == PARM_DECL
+                 && POINTER_TYPE_P (TREE_TYPE (ap))));
 
   /* Assuming nobody tries to change the return type.  */
-  parmn = TREE_OPERAND (parmn, 0);
+  if (TREE_CODE (parmn) != PARM_DECL)
+    {
+      gcc_assert (TREE_CODE (parmn) == ADDR_EXPR);
+      parmn = TREE_OPERAND (parmn, 0);
+    }
 
   return call_builtin_fn (callexp, BUILT_IN_VA_START, 2, ap, parmn);
 }
diff --git a/gcc/testsuite/gdc.dg/pr96140.d b/gcc/testsuite/gdc.dg/pr96140.d
new file mode 100644 (file)
index 0000000..d25bb5d
--- /dev/null
@@ -0,0 +1,15 @@
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96140
+// { dg-do compile }
+module pr94140;
+
+import core.stdc.stdarg;
+
+void test_va_arg(ref int a, ...)
+{
+    return va_arg!int(_argptr, a);
+}
+
+void test_va_start(ref va_list a, ...)
+{
+    return va_start(a, a);
+}