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

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.
This commit is contained in:
Iain Buclaw 2020-07-21 19:59:00 +02:00
parent 58cfec3a6e
commit 2b1c2a4bd9
5 changed files with 89 additions and 22 deletions

View 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)

View 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 *);

View 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;

View File

@ -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; })());
}

View File

@ -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);
}