Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue #17503 - Associative Arrays improperly register a GC-allocated TypeInfo for element cleanup #20863

Merged
merged 7 commits into from
Feb 19, 2025

Conversation

rainers
Copy link
Member

@rainers rainers commented Feb 13, 2025

let the compiler generate type info for the AA entry defined by TypeInfo_AssociativeArray.Entry(K, V) and add it to TypeInfo_AssociativeArray.

@schveiguy Here's my attempt for getting rid of the fake TypeInfo. I guess more logic regarding the dtor can be removed as it should all be there in the Entry TypeInfo.

@rainers rainers requested a review from ibuclaw as a code owner February 13, 2025 22:13
@dlang-bot
Copy link
Contributor

Thanks for your pull request, @rainers!

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

⚠️⚠️⚠️ Warnings ⚠️⚠️⚠️

  • In preparation for migrating from Bugzilla to GitHub Issues, the issue reference syntax has changed. Please add the word "Bugzilla" to issue references. For example, Fix Bugzilla Issue 12345 or Fix Bugzilla 12345.(Reminder: the edit needs to be done in the Git commit message, not the GitHub pull request.)

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + dmd#20863"

@schveiguy
Copy link
Member

Nice @rainers! I have been steeped in this for the last week, so I'll download and see if I can get the library side to work. It's just the compiler side I was unsure of.

@schveiguy
Copy link
Member

schveiguy commented Feb 14, 2025

The type in core.internal.newaa needs to have the same type/layout as the true aa impl struct. So you need to change the entryTI type to const(TypeInfo).

After that, I got a compiler assert when building druntime unittests, and I'm not sure what to do there.

---
ERROR: This is a compiler bug.
Please report it via https://github.com/dlang/dmd/issues
with, preferably, a reduced, reproducible example and the information below.
DustMite (https://github.com/CyberShadow/DustMite/wiki) can help with the reduction.
---
DMD v2.110.0-rc.1-683-g8b1bbe9e36
predefs   Shared CoreUnittest DigitalMars LittleEndian D_Version2 all D_SIMD Posix ELFv1 linux CRuntime_Glibc CppRuntime_GNU CppRuntime_Gcc D_InlineAsm_X86_64 X86_64 D_LP64 D_PIC unittest assert D_PreConditions D_PostConditions D_Invariants D_ModuleInfo D_Exceptions D_TypeInfo D_HardFloat
binary    ../generated/linux/release/64/dmd
version   v2.110.0-rc.1-683-g8b1bbe9e36
config    
DFLAGS    (none)
---
core.exception.AssertError@src/dmd/typesem.d(3315): Assertion failure
----------------
??:? _d_assertp [0x560a937eb420]
src/dmd/typesem.d:3314 dmd.mtype.Type dmd.typesem.merge2(dmd.mtype.Type) [0x560a93632089]
src/dmd/typinf.d:69 bool dmd.typinf.genTypeInfo(dmd.expression.Expression, ref const(dmd.location.Loc), dmd.mtype.Type, dmd.dscope.Scope*) [0x560a9363f80f]
src/dmd/toobj.d:287 void dmd.toobj.TypeInfo_toObjFile(dmd.expression.Expression, ref const(dmd.location.Loc), dmd.mtype.Type) [0x560a9369f03e]
src/dmd/todt.d:1365 _ZN17TypeInfoDtVisitor5visitEP35TypeInfoAssociativeArrayDeclaration [0x560a9369a7db]
src/dmd/declaration.d:1564 _ZN35TypeInfoAssociativeArrayDeclaration6acceptEP7Visitor [0x560a934c8a6d]
src/dmd/todt.d:1633 void dmd.todt.TypeInfo_toDt(ref dmd.backend.dt.DtBuilder, dmd.declaration.TypeInfoDeclaration) [0x560a9369b601]
src/dmd/toobj.d:756 _ZN9toObjFile9ToObjFile5visitEP19TypeInfoDeclaration [0x560a936a0198]
src/dmd/visitor/package.d:52 _ZN7Visitor5visitEP35TypeInfoAssociativeArrayDeclaration [0x560a9364e17d]
src/dmd/declaration.d:1564 _ZN35TypeInfoAssociativeArrayDeclaration6acceptEP7Visitor [0x560a934c8a6d]
src/dmd/toobj.d:1043 void dmd.toobj.toObjFile(dmd.dsymbol.Dsymbol, bool) [0x560a9369f0d0]
src/dmd/toobj.d:290 void dmd.toobj.TypeInfo_toObjFile(dmd.expression.Expression, ref const(dmd.location.Loc), dmd.mtype.Type) [0x560a9369f05e]
src/dmd/e2ir.d:6200 dmd.backend.el.elem* dmd.e2ir.getTypeInfo(dmd.expression.Expression, dmd.mtype.Type, ref dmd.toir.IRState) [0x560a93674b72]
src/dmd/e2ir.d:4129 dmd.backend.el.elem* dmd.e2ir.toElem(dmd.expression.Expression, ref dmd.toir.IRState).visitAssocArrayLiteral(dmd.expression.AssocArrayLiteralExp) [0x560a9366f708]
src/dmd/e2ir.d:4226 dmd.backend.el.elem* dmd.e2ir.toElem(dmd.expression.Expression, ref dmd.toir.IRState) [0x560a93664115]
src/dmd/e2ir.d:5492 dmd.backend.el.elem* dmd.e2ir.callfunc(ref const(dmd.location.Loc), ref dmd.toir.IRState, int, dmd.mtype.Type, dmd.backend.el.elem*, dmd.mtype.Type, dmd.func.FuncDeclaration, dmd.mtype.Type, dmd.backend.el.elem*, dmd.root.array.Array!(dmd.expression.Expression).Array*, dmd.backend.el.elem*, dmd.backend.el.elem*) [0x560a9367310a]
src/dmd/e2ir.d:3471 dmd.backend.el.elem* dmd.e2ir.toElem(dmd.expression.Expression, ref dmd.toir.IRState).visitCall(dmd.expression.CallExp) [0x560a9366d4cd]
src/dmd/e2ir.d:4242 dmd.backend.el.elem* dmd.e2ir.toElem(dmd.expression.Expression, ref dmd.toir.IRState) [0x560a936642b5]
src/dmd/e2ir.d:411 dmd.backend.el.elem* dmd.e2ir.toElemDtor(dmd.expression.Expression, ref dmd.toir.IRState) [0x560a936635c5]
src/dmd/e2ir.d:1562 dmd.backend.el.elem* dmd.e2ir.toElem(dmd.expression.Expression, ref dmd.toir.IRState).visitAssert(dmd.expression.AssertExp) [0x560a93667509]
src/dmd/e2ir.d:4237 dmd.backend.el.elem* dmd.e2ir.toElem(dmd.expression.Expression, ref dmd.toir.IRState) [0x560a93664233]
src/dmd/e2ir.d:411 dmd.backend.el.elem* dmd.e2ir.toElemDtor(dmd.expression.Expression, ref dmd.toir.IRState) [0x560a936635c5]
src/dmd/s2ir.d:692 void dmd.s2ir.Statement_toIR(dmd.statement.Statement, ref dmd.toir.IRState, dmd.stmtstate.StmtState!(dmd.backend.cc.block).StmtState*).visitExp(dmd.statement.ExpStatement) [0x560a9368e116]
src/dmd/statement.d:1886 void dmd.s2ir.Statement_toIR(dmd.statement.Statement, ref dmd.toir.IRState, dmd.stmtstate.StmtState!(dmd.backend.cc.block).StmtState*).visit.VisitStatement(dmd.statement.Statement) [0x560a936906b3]
src/dmd/s2ir.d:1466 void dmd.s2ir.Statement_toIR(dmd.statement.Statement, ref dmd.toir.IRState, dmd.stmtstate.StmtState!(dmd.backend.cc.block).StmtState*) [0x560a9368c70f]
src/dmd/s2ir.d:718 void dmd.s2ir.Statement_toIR(dmd.statement.Statement, ref dmd.toir.IRState, dmd.stmtstate.StmtState!(dmd.backend.cc.block).StmtState*).visitCompound(dmd.statement.CompoundStatement) [0x560a9368e1f9]
src/dmd/statement.d:1886 void dmd.s2ir.Statement_toIR(dmd.statement.Statement, ref dmd.toir.IRState, dmd.stmtstate.StmtState!(dmd.backend.cc.block).StmtState*).visit.VisitStatement(dmd.statement.Statement) [0x560a936906d8]
src/dmd/s2ir.d:1466 void dmd.s2ir.Statement_toIR(dmd.statement.Statement, ref dmd.toir.IRState, dmd.stmtstate.StmtState!(dmd.backend.cc.block).StmtState*) [0x560a9368c70f]
src/dmd/s2ir.d:718 void dmd.s2ir.Statement_toIR(dmd.statement.Statement, ref dmd.toir.IRState, dmd.stmtstate.StmtState!(dmd.backend.cc.block).StmtState*).visitCompound(dmd.statement.CompoundStatement) [0x560a9368e1f9]
src/dmd/statement.d:1886 void dmd.s2ir.Statement_toIR(dmd.statement.Statement, ref dmd.toir.IRState, dmd.stmtstate.StmtState!(dmd.backend.cc.block).StmtState*).visit.VisitStatement(dmd.statement.Statement) [0x560a936906d8]
src/dmd/s2ir.d:1466 void dmd.s2ir.Statement_toIR(dmd.statement.Statement, ref dmd.toir.IRState, dmd.stmtstate.StmtState!(dmd.backend.cc.block).StmtState*) [0x560a9368c70f]
src/dmd/s2ir.d:93 void dmd.s2ir.Statement_toIR(dmd.statement.Statement, ref dmd.toir.IRState) [0x560a9368c6ed]
src/dmd/glue.d:882 void dmd.glue.FuncDeclaration_toObjFile(dmd.func.FuncDeclaration, bool) [0x560a93683fd4]
src/dmd/toobj.d:330 _ZN9toObjFile9ToObjFile5visitEP15FuncDeclaration [0x560a9369f169]
src/dmd/visitor/parsetime.d:62 _ZN16ParseTimeVisitorI10ASTCodegenE5visitEP19UnitTestDeclaration [0x560a93652b01]
src/dmd/func.d:1809 _ZN19UnitTestDeclaration6acceptEP7Visitor [0x560a93585405]
src/dmd/toobj.d:1043 void dmd.toobj.toObjFile(dmd.dsymbol.Dsymbol, bool) [0x560a9369f0d0]
src/dmd/glue.d:1418 void dmd.glue.genObjFile(dmd.dmodule.Module, bool) [0x560a93686064]
src/dmd/glue.d:338 void dmd.glue.generateCodeAndWrite(dmd.dmodule.Module[], const(char)*[], const(char)[], const(char)[], bool, bool, bool, bool, bool) [0x560a936825f9]
src/dmd/main.d:760 int dmd.main.tryMain(ulong, const(char)**, ref dmd.globals.Param) [0x560a93484e7d]
src/dmd/main.d:143 _Dmain [0x560a93483330]
make[1]: *** [Makefile:471: ../generated/linux/debug/64/unittest/libdruntime-ut.so] Error 1
make[1]: Leaving directory '/home/steves/git/dmd/druntime'

@thewilsonator
Copy link
Contributor

@rainers
Copy link
Member Author

rainers commented Feb 14, 2025

I tested this on druntime, but still fails on phobos. The new entry doesn't seem to be generated for some reason. Digging deeper...

@rainers rainers force-pushed the rainer_aa_fak_entry_ti branch 2 times, most recently from 87b980f to 4c45158 Compare February 14, 2025 13:56
@schveiguy
Copy link
Member

The new entry doesn't seem to be generated for some reason.

The code failing is this:

@safe unittest
{
    struct S;

    static assert( isAssociativeArray!(int[string]));
    static assert( isAssociativeArray!(S[S]));
    static assert(!isAssociativeArray!(string[]));
    static assert(!isAssociativeArray!S);
    static assert(!isAssociativeArray!(int[4]));
}

Failing, because S is an opaque struct.

I think you may have to ask if the struct has a definition, and if not, just generate a null typeinfo. What does it generate for the key and value typeinfos?

UPDATE: it's just putting garbage in there...

Honestly, I think this unittest is bogus.

@rainers
Copy link
Member Author

rainers commented Feb 15, 2025

Thanks for the hint. I guess it needs to better check for errors on the input types.

I'm currently struggling with the druntime unittests which are missing a single symbol when linking. The trouble is that type infos are referenced from the backend, when no more semantic analysis must run, so they have to be generated up-front predicting what happens to the type later. That's similar to issues with RTInfo generation, reminding me of #2480, still open after almost 12 years ;)

@schveiguy
Copy link
Member

reminding me of #2480, still open after almost 12 years ;)

Wow, reading that makes me sad. We should have merged that by now... If I get a chance, I'll bring it up in the next DLF meeting.

@schveiguy
Copy link
Member

schveiguy commented Feb 15, 2025

I don't know the way the compiler would do this, but is it possible to instantiate the struct on AA declaration, instead of when the typeinfo is needed?

EDIT: or maybe that's already what you are doing? I can't tell.

@rainers
Copy link
Member Author

rainers commented Feb 15, 2025

Wow, reading that makes me sad. We should have merged that by now... If I get a chance, I'll bring it up in the next DLF meeting.

I haven't checked whether it's still valid since the last rebase 4 years ago, though. Obviously, it needs another rebase.

@rainers
Copy link
Member Author

rainers commented Feb 15, 2025

don't know the way the compiler would do this, but is it possible to instantiate the struct on AA declaration, instead of when the typeinfo is needed?

EDIT: or maybe that's already what you are doing? I can't tell.

In the pushed state, it is generated with the assoc array most of the time, but in my local version I have moved it to the type info generation (which usually happens immediately, too). My latest investigations show that the compiler is a bit confused what happens when adding const to the type and removing it later in the back end:

K[V] : add const -> const(K[v]): remove const -> const(K)[const(V)]

Unfortunately removing const is ambiguous, but that's what's happening in the backend and then requesting typeinfo for the latter. A workaround could be to genrerate that typeinfo early, too. I'll try that...

@thewilsonator thewilsonator added Druntime:AA Specific to Associative Arrays Feature:type info typeid labels Feb 16, 2025
@rainers rainers force-pushed the rainer_aa_fak_entry_ti branch from 1c9916b to 69c774b Compare February 16, 2025 20:02
@rainers
Copy link
Member Author

rainers commented Feb 16, 2025

I have opted to remove all modifiers from the key and value types, so we don't have to care how the glue layer modifies them.
For me, there is a single test left failing to link (test9461() in testconst.d), which is tangled in speculative compilation, template generation and missed instantiation.

@rainers rainers force-pushed the rainer_aa_fak_entry_ti branch 3 times, most recently from 7d1682a to 87a2b72 Compare February 17, 2025 20:35
…llocated TypeInfo for element cleanup

- let the compiler generate type info for the AA Entry and add it to TypeInfo_AssociativeArray
- strip modifiers for index and next in TypeInfo_AssociativeArray to make it agnostic to changes by the glue layer
@rainers rainers force-pushed the rainer_aa_fak_entry_ti branch from 87a2b72 to 7d6fff7 Compare February 17, 2025 21:03
@schveiguy
Copy link
Member

circleci says frontend.h out of date. Looks auto generated, not sure how it needs to be generated?

@rainers
Copy link
Member Author

rainers commented Feb 17, 2025

circleci says frontend.h out of date. Looks auto generated, not sure how it needs to be generated?

I fixed that manually, but the failures on buildkite seem a bit more complicated. Let's hope they can be reproduced locally.

@schveiguy
Copy link
Member

For dstep, this is the line that is asserting:

https://github.com/dlang/dmd/pull/20863/files#diff-dd2a2e73a504f2d8256bec9731b01fdd79133bb20ded63470174039c3174e63cR174

It's in the new code, so maybe there is an issue with where it is called (hinted by the comment "must not be called in the code generation phase")? There is an exception trace.

@rainers
Copy link
Member Author

rainers commented Feb 18, 2025

Hurray, it passed all tests now!

This might still be a bit brittle, as this is a bit similar to TypeInfo emission for structs which has a number of workarounds (e.g. semanticTypeInfoMembers() being called from the glue layer). It would be nice if someone with more knowledge of the current code emission/suppression strategies could have a look.

BTW: I noticed that the Dlang-community/D-Scanner test on buildkite is cancelled after 20 minutes, but that happens with other PRs, too:

2025-02-11 01:50:02 CEST ./utf.d(4707:12)[warn]: Local imports should specify the symbols being imported to avoid hiding local symbols.
2025-02-11 02:02:35 CEST ./.travis.sh: line 24: 33322 Killed                  ../../bin/dscanner -S

Copy link
Member

@schveiguy schveiguy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hurray, it passed all tests now!

Yay!

This might still be a bit brittle

Honestly, if we have a pass, I think we should merge rather than look for the perfect solution. I would anticipate that any future issues will provide more bugs to fix, but this should be par for the course!

One thing remains -- please add the test as identified in the bug report. You can copy from here: https://github.com/dlang/dmd/pull/20853/files#diff-598818d2bef54acd1fba7714831fb453393c558a57c1257f2cd7ea34655fb614

Approved so this can be merged once done.

@rainers
Copy link
Member Author

rainers commented Feb 18, 2025

One thing remains -- please add the test as identified in the bug report.

Added, but the test will get interesting only if someone adds back a runtime allocated type info.

@schveiguy
Copy link
Member

I'll just poke a bit at @ibuclaw and @kinke if you see anything horrendous in this that jumps out as needing to be fixed, please let us know. Otherwise, I'm apt to merge this by tomorrow.

@ibuclaw
Copy link
Member

ibuclaw commented Feb 18, 2025

I'll just poke a bit at @ibuclaw and @kinke if you see anything horrendous in this that jumps out as needing to be fixed, please let us know. Otherwise, I'm apt to merge this by tomorrow.

declaration.h needs updating in order to expose this to us C++ back-ends.

@rainers
Copy link
Member Author

rainers commented Feb 18, 2025

declaration.h needs updating in order to expose this to us C++ back-ends.

Oops, missed that. Now updated.

@kinke
Copy link
Contributor

kinke commented Feb 18, 2025

It would be nice if someone with more knowledge of the current code emission/suppression strategies could have a look.

I guess it works fine with LDC's emission strategy (for non-classes: lazily whenever accessed from codegen, into every referencing object file), where genTypeInfo() always returns false: https://github.com/ldc-developers/ldc/blob/d3f065816ec7d420f370e4c95c6000eb78187e25/dmd/typinf.d#L85-L96

@schveiguy
Copy link
Member

OK, I'm going to pull the trigger. I'd rather have this in than bitrot, and it's a huge improvement. Things can't be hackier than they are now...

The true path forward is the template-based hooks.

@dlang-bot dlang-bot merged commit 016c38e into dlang:master Feb 19, 2025
42 checks passed
@rainers
Copy link
Member Author

rainers commented Feb 19, 2025

OK, I'm going to pull the trigger.

👍

The true path forward is the template-based hooks.

Maybe this is a small step in that direction with the entry struct now templated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Druntime:AA Specific to Associative Arrays Feature:type info typeid Merge:auto-merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants