[committed] d: Fix ICE using non-local variable: internal compiler error: Segmentation fault

Iain Buclaw ibuclaw@gdcproject.org
Mon Aug 3 10:00:40 GMT 2020


Hi,

This patch 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.

Bootstrapped and regression tested on x86_64-linux-gnu with multilib
configurations -m32 and -mx32.  Committed to mainline.

Regards
Iain

---
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              | 53 +++++++++++++++++++--------------
 gcc/d/d-tree.h                  |  1 +
 gcc/d/decl.cc                   |  5 ++++
 gcc/testsuite/gdc.dg/pr96254a.d | 28 +++++++++++++++++
 gcc/testsuite/gdc.dg/pr96254b.d | 24 +++++++++++++++
 5 files changed, 89 insertions(+), 22 deletions(-)
 create mode 100644 gcc/testsuite/gdc.dg/pr96254a.d
 create mode 100644 gcc/testsuite/gdc.dg/pr96254b.d

diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 2dce09d7187..296d62a91a4 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -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)
diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h
index df317d557eb..2be80dd1867 100644
--- a/gcc/d/d-tree.h
+++ b/gcc/d/d-tree.h
@@ -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 *);
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 15eb9a43399..72c8a8cff06 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -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
index 00000000000..e5dd1244b94
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr96254a.d
@@ -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
index 00000000000..02e3c484d26
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr96254b.d
@@ -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);
+}
-- 
2.25.1



More information about the Gcc-patches mailing list