d: Fix ICE using non-local variable: internal compiler error: Segmentation fault
authorIain Buclaw <ibuclaw@gdcproject.org>
Tue, 21 Jul 2020 17:59:00 +0000 (19:59 +0200)
committerIain Buclaw <ibuclaw@gdcproject.org>
Mon, 3 Aug 2020 09:18:46 +0000 (11:18 +0200)
Moves no frame access error to own function, adding use of it for both
when get_framedecl() cannot find a path to the outer function frame, and
guarding get_decl_tree() from recursively calling itself.

gcc/d/ChangeLog:

PR d/96254
* d-codegen.cc (error_no_frame_access): New.
(get_frame_for_symbol): Use fdparent name in error message.
(get_framedecl): Replace call to assert with error.
* d-tree.h (error_no_frame_access): Declare.
* decl.cc (get_decl_tree): Detect recursion and error.

gcc/testsuite/ChangeLog:

PR d/96254
* gdc.dg/pr96254a.d: New test.
* gdc.dg/pr96254b.d: New test.

gcc/d/d-codegen.cc
gcc/d/d-tree.h
gcc/d/decl.cc
gcc/testsuite/gdc.dg/pr96254a.d [new file with mode: 0644]
gcc/testsuite/gdc.dg/pr96254b.d [new file with mode: 0644]

index 2dce09d..73a6a34 100644 (file)
@@ -2127,6 +2127,17 @@ build_vthis_function (tree basetype, tree type)
   return fntype;
 }
 
+/* Raise an error at that the context pointer of the function or object SYM is
+   not accessible from the current scope.  */
+
+tree
+error_no_frame_access (Dsymbol *sym)
+{
+  error_at (input_location, "cannot get frame pointer to %qs",
+           sym->toPrettyChars ());
+  return null_pointer_node;
+}
+
 /* If SYM is a nested function, return the static chain to be
    used when calling that function from the current function.
 
@@ -2191,7 +2202,7 @@ get_frame_for_symbol (Dsymbol *sym)
        {
          error_at (make_location_t (sym->loc),
                    "%qs is a nested function and cannot be accessed from %qs",
-                   fd->toPrettyChars (), thisfd->toPrettyChars ());
+                   fdparent->toPrettyChars (), thisfd->toPrettyChars ());
          return null_pointer_node;
        }
 
@@ -2202,39 +2213,35 @@ get_frame_for_symbol (Dsymbol *sym)
       while (fd != dsym)
        {
          /* Check if enclosing function is a function.  */
-         FuncDeclaration *fd = dsym->isFuncDeclaration ();
+         FuncDeclaration *fdp = dsym->isFuncDeclaration ();
+         Dsymbol *parent = dsym->toParent2 ();
 
-         if (fd != NULL)
+         if (fdp != NULL)
            {
-             if (fdparent == fd->toParent2 ())
+             if (fdparent == parent)
                break;
 
-             gcc_assert (fd->isNested () || fd->vthis);
-             dsym = dsym->toParent2 ();
+             gcc_assert (fdp->isNested () || fdp->vthis);
+             dsym = parent;
              continue;
            }
 
          /* Check if enclosed by an aggregate.  That means the current
             function must be a member function of that aggregate.  */
-         AggregateDeclaration *ad = dsym->isAggregateDeclaration ();
+         AggregateDeclaration *adp = dsym->isAggregateDeclaration ();
 
-         if (ad == NULL)
-           goto Lnoframe;
-         if (ad->isClassDeclaration () && fdparent == ad->toParent2 ())
-           break;
-         if (ad->isStructDeclaration () && fdparent == ad->toParent2 ())
-           break;
-
-         if (!ad->isNested () || !ad->vthis)
+         if (adp != NULL)
            {
-           Lnoframe:
-             error_at (make_location_t (thisfd->loc),
-                       "cannot get frame pointer to %qs",
-                       sym->toPrettyChars ());
-             return null_pointer_node;
+             if ((adp->isClassDeclaration () || adp->isStructDeclaration ())
+                 && fdparent == parent)
+               break;
            }
 
-         dsym = dsym->toParent2 ();
+         /* No frame to outer function found.  */
+         if (!adp || !adp->isNested () || !adp->vthis)
+           return error_no_frame_access (sym);
+
+         dsym = parent;
        }
     }
 
@@ -2724,8 +2731,10 @@ get_framedecl (FuncDeclaration *inner, FuncDeclaration *outer)
        break;
     }
 
+  if (fd != outer)
+    return error_no_frame_access (outer);
+
   /* Go get our frame record.  */
-  gcc_assert (fd == outer);
   tree frame_type = FRAMEINFO_TYPE (get_frameinfo (outer));
 
   if (frame_type != NULL_TREE)
index df317d5..2be80dd 100644 (file)
@@ -575,6 +575,7 @@ extern tree d_build_call (TypeFunction *, tree, tree, Expressions *);
 extern tree d_assert_call (const Loc &, libcall_fn, tree = NULL_TREE);
 extern tree build_float_modulus (tree, tree, tree);
 extern tree build_vthis_function (tree, tree);
+extern tree error_no_frame_access (Dsymbol *);
 extern tree get_frame_for_symbol (Dsymbol *);
 extern tree build_vthis (AggregateDeclaration *);
 extern void build_closure (FuncDeclaration *);
index 15eb9a4..72c8a8c 100644 (file)
@@ -1480,6 +1480,11 @@ get_decl_tree (Declaration *decl)
       AggregateDeclaration *ad = fd->isThis ();
       gcc_assert (ad != NULL);
 
+      /* The parent function is for the same `this' declaration we are
+        building a chain to.  Non-local declaration is inaccessible.  */
+      if (fd->vthis == vd)
+       return error_no_frame_access (fd);
+
       t = get_decl_tree (fd->vthis);
       Dsymbol *outer = fd;
 
diff --git a/gcc/testsuite/gdc.dg/pr96254a.d b/gcc/testsuite/gdc.dg/pr96254a.d
new file mode 100644 (file)
index 0000000..e5dd124
--- /dev/null
@@ -0,0 +1,28 @@
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96254
+// { dg-do compile }
+struct map(alias fun)
+{
+    @property run()
+    {
+    }
+}
+
+struct Task(Args)
+{
+    Args _args;
+}
+
+template reduce(functions...)
+{
+    auto reduce(Args)(Args args)
+    {
+        alias RTask = Task!(typeof(args));
+        auto task = RTask();
+    }
+}
+
+void main() // { dg-error "'D main' is a nested function and cannot be accessed" }
+{
+    immutable delta = 1;
+    reduce!"a + b"(map!({ immutable x = delta; })());
+}
diff --git a/gcc/testsuite/gdc.dg/pr96254b.d b/gcc/testsuite/gdc.dg/pr96254b.d
new file mode 100644 (file)
index 0000000..02e3c48
--- /dev/null
@@ -0,0 +1,24 @@
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96254
+// { dg-do compile }
+mixin template test()
+{
+    int next;
+}
+
+void foo(alias l)()
+{
+    l.next = 0; // { dg-error "cannot get frame pointer to 'D main'" }
+}
+
+void bar(alias l, alias t)()
+{
+    l.next = 0; // { dg-error "cannot get frame pointer to 'D main'" }
+}
+
+void main()
+{
+    mixin test l1;
+    mixin test l2;
+    foo!(l1);
+    bar!(l1,l2);
+}