d: Fix ICE in finish_thunk (PR97644)

Because this what the upstream reference compiler did, thunks for the D
front-end were associated with the class definition, so were forced
code-gen even if the target function was extern.  This has now been
changed so there are now only generated if there is a function
definition, fixing the ICE that occurred in PR 97644, which was caused
by calling expand_thunk() early.

gcc/d/ChangeLog:

	PR d/97644
	* dmd/MERGE: Merge upstream dmd 95044d8e4.
	* d-target.cc (TargetCPP::thunkMangle): New function.
	* decl.cc (finish_thunk): Don't force expand thunks for external
	functions.
	(make_thunk): Emit thunks only if the function has a definition.
	Generate correct mangling for thunks to C++ classes.

gcc/testsuite/ChangeLog:

	* gdc.dg/pr92216.d: Update scan-assember.
This commit is contained in:
Iain Buclaw 2020-11-12 15:37:46 +01:00
parent 5fa821bba7
commit 5d4b824faf
7 changed files with 58 additions and 36 deletions

View file

@ -329,6 +329,15 @@ TargetCPP::typeInfoMangle (ClassDeclaration *cd)
return cppTypeInfoMangleItanium (cd);
}
/* Get mangle name of a this-adjusting thunk to the function declaration FD
at call offset OFFSET for C++ linkage. */
const char *
TargetCPP::thunkMangle (FuncDeclaration *fd, int offset)
{
return cppThunkMangleItanium (fd, offset);
}
/* For a vendor-specific type, return a string containing the C++ mangling.
In all other cases, return NULL. */

View file

@ -1693,26 +1693,6 @@ finish_thunk (tree thunk, tree function)
if (DECL_ONE_ONLY (function))
thunk_node->add_to_same_comdat_group (funcn);
/* Target assemble_mi_thunk doesn't work across section boundaries
on many targets, instead force thunk to be expanded in gimple. */
if (DECL_EXTERNAL (function))
{
/* cgraph::expand_thunk writes over current_function_decl, so if this
could ever be in use by the codegen pass, we want to know about it. */
gcc_assert (current_function_decl == NULL_TREE);
if (!stdarg_p (TREE_TYPE (thunk)))
{
thunk_node->create_edge (funcn, NULL, thunk_node->count);
expand_thunk (thunk_node, false, true);
}
/* Tell the back-end to not bother inlining the function, this is
assumed not to work as it could be referencing symbols outside
of the current compilation unit. */
DECL_UNINLINABLE (function) = 1;
}
}
/* Return a thunk to DECL. Thunks adjust the incoming `this' pointer by OFFSET.
@ -1789,12 +1769,11 @@ make_thunk (FuncDeclaration *decl, int offset)
DECL_CONTEXT (thunk) = d_decl_context (decl);
/* Thunks inherit the public access of the function they are targetting.
When the function is outside the current compilation unit however, then the
thunk must be kept private to not conflict. */
TREE_PUBLIC (thunk) = TREE_PUBLIC (function) && !DECL_EXTERNAL (function);
DECL_EXTERNAL (thunk) = 0;
/* Thunks inherit the public access of the function they are targeting.
Thunks are connected to the definitions of the functions, so thunks are
not produced for external functions. */
TREE_PUBLIC (thunk) = TREE_PUBLIC (function);
DECL_EXTERNAL (thunk) = DECL_EXTERNAL (function);
/* Thunks are always addressable. */
TREE_ADDRESSABLE (thunk) = 1;
@ -1806,18 +1785,31 @@ make_thunk (FuncDeclaration *decl, int offset)
DECL_COMDAT (thunk) = DECL_COMDAT (function);
DECL_WEAK (thunk) = DECL_WEAK (function);
tree target_name = DECL_ASSEMBLER_NAME (function);
unsigned identlen = IDENTIFIER_LENGTH (target_name) + 14;
const char *ident = XNEWVEC (const char, identlen);
snprintf (CONST_CAST (char *, ident), identlen,
"_DT%u%s", offset, IDENTIFIER_POINTER (target_name));
/* When the thunk is for an extern C++ function, let C++ do the thunk
generation and just reference the symbol as extern, instead of
forcing a D local thunk to be emitted. */
const char *ident;
if (decl->linkage == LINKcpp)
ident = target.cpp.thunkMangle (decl, offset);
else
{
tree target_name = DECL_ASSEMBLER_NAME (function);
unsigned identlen = IDENTIFIER_LENGTH (target_name) + 14;
ident = XNEWVEC (const char, identlen);
snprintf (CONST_CAST (char *, ident), identlen,
"_DTi%u%s", offset, IDENTIFIER_POINTER (target_name));
}
DECL_NAME (thunk) = get_identifier (ident);
SET_DECL_ASSEMBLER_NAME (thunk, DECL_NAME (thunk));
d_keep (thunk);
free (CONST_CAST (char *, ident));
finish_thunk (thunk, function);
if (!DECL_EXTERNAL (function))
finish_thunk (thunk, function);
/* Add it to the list of thunks associated with the function. */
DECL_LANG_THUNKS (thunk) = NULL_TREE;

View file

@ -1,4 +1,4 @@
bec5973b0203c95adbda2a049ccdf3cd3a4378f6
95044d8e45a4320f07d9c75b4eb30e55688a8195
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.

View file

@ -582,13 +582,21 @@ class CppMangleVisitor : public Visitor
//printf("mangle_function(%s)\n", d->toChars());
/*
* <mangled-name> ::= _Z <encoding>
*/
buf->writestring("_Z");
this->mangle_function_encoding(d);
}
void mangle_function_encoding(FuncDeclaration *d)
{
//printf("mangle_function_encoding(%s)\n", d->toChars());
/*
* <encoding> ::= <function name> <bare-function-type>
* ::= <data name>
* ::= <special-name>
*/
TypeFunction *tf = (TypeFunction *)d->type;
buf->writestring("_Z");
if (getFuncTemplateDecl(d))
{
/* It's an instance of a function template
@ -1132,3 +1140,13 @@ const char *cppTypeInfoMangleItanium(Dsymbol *s)
v.cpp_mangle_name(s, false);
return buf.extractChars();
}
const char *cppThunkMangleItanium(FuncDeclaration *fd, int offset)
{
//printf("cppThunkMangleItanium(%s)\n", fd.toChars());
OutBuffer buf;
buf.printf("_ZThn%u_", offset); // "Th" means thunk, "n%u" is the call offset
CppMangleVisitor v(&buf, fd->loc);
v.mangle_function_encoding(fd);
return buf.extractChars();
}

View file

@ -20,6 +20,7 @@ struct OutBuffer;
// In cppmangle.c
const char *toCppMangleItanium(Dsymbol *s);
const char *cppTypeInfoMangleItanium(Dsymbol *s);
const char *cppThunkMangleItanium(FuncDeclaration *fd, int offset);
// In cppmanglewin.c
const char *toCppMangleMSVC(Dsymbol *s);

View file

@ -19,6 +19,7 @@
class ClassDeclaration;
class Dsymbol;
class Expression;
class FuncDeclaration;
class Parameter;
class Type;
class TypeTuple;
@ -38,6 +39,7 @@ struct TargetCPP
const char *toMangle(Dsymbol *s);
const char *typeInfoMangle(ClassDeclaration *cd);
const char *thunkMangle(FuncDeclaration *fd, int offset);
const char *typeMangle(Type *t);
Type *parameterType(Parameter *p);
bool fundamentalType(const Type *t, bool& isFundamental);

View file

@ -1,8 +1,8 @@
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92216
// { dg-options "-I $srcdir/gdc.dg" }
// { dg-do compile }
// { dg-final { scan-assembler "_DT(4|8|16)_D7imports7pr922161B8__mixin24getSMFZPv\[: \t\n\]" } }
// { dg-final { scan-assembler-not "(.globl|.global)\[ \]+_DT(4|8|16)_D7imports7pr922161B8__mixin24getSMFZPv" } }
// { dg-final { scan-assembler "_DTi(4|8|16)_D7imports7pr922161B8__mixin24getSMFZPv\[: \t\n\]" } }
// { dg-final { scan-assembler-not "(.globl|.global)\[ \]+_DTi(4|8|16)_D7imports7pr922161B8__mixin24getSMFZPv" } }
module pr92216;
private import imports.pr92216;