dtoh: Emit public imports in aggregates whenever possible

Previously only top-level imports were included by the header generator.
This isn't sufficient because patterns like `ASTCodegen` require the
imported symbols to be available as members of the aggregate.

Also added the checks for `static` and non-public imports that were
lost in the first PR.
This commit is contained in:
MoonlightSentinel 2021-06-21 01:27:09 +02:00
parent 1b6d90cc74
commit 45810b608f
No known key found for this signature in database
GPG key ID: 1A1A60AECDC956AB
6 changed files with 2463 additions and 1660 deletions

View file

@ -9,7 +9,7 @@ experimental C++ header generator:
- `extern(D)` structs and classes are emitted if referenced by an exported symbol
- Forward declarations consistently include `template<...>`
- `extern(C++, class)`, `extern(C++, struct)` affects forward declarations
- Renamed imports are emitted as `using ...`
- Renamed or local imports are emitted as `using ...` when possible
- Complex types are emitted as `_Complex`.
- Declarations are emitted before the first member access
- Global variables with invalid names in C++ are omitted

View file

@ -556,22 +556,57 @@ public:
buf.writestring("using ");
writeIdentifier(alias_, i.loc, "renamed import");
buf.writestring(" = ");
// Start at module scope to avoid collisions with local symbols
if (this.context.adparent)
buf.writestring("::");
buf.writestring(sym.ident.toString());
writeDeclEnd();
return null;
}
// Omit local imports
assert(i.parent);
if (!i.parent.isModule())
// Only missing without semantic analysis
// FIXME: Templates need work due to missing parent & imported module
if (!i.parent)
{
ignored("local %s", i.toChars());
assert(tdparent);
ignored("`%s` because it's inside of a template declaration", i.toChars());
return;
}
// Non-public imports don't create new symbols, include as needed
if (i.visibility.kind < AST.Visibility.Kind.public_)
return;
// Symbols from static imports should be emitted inline
if (i.isstatic)
return;
const isLocal = !i.parent.isModule();
// Need module for symbol lookup
assert(i.mod);
// Emit an alias for each public module member
if (isLocal && i.names.length == 0)
{
assert(i.mod.symtab);
foreach (entry; i.mod.symtab.tab.asRange)
{
auto ident = entry.key;
auto sym = entry.value;
// Skip invisible members
import dmd.access : symbolIsVisible;
if (!symbolIsVisible(i, sym))
continue;
includeSymbol(sym);
if (auto err = writeImport(sym, ident))
ignored("public import for `%s` because `using` %s", ident.toChars(), err);
}
return;
}
// Include all public imports and emit using declarations for each alias
foreach (const idx, name; i.names)
{
@ -1592,6 +1627,16 @@ public:
override void visit(AST.EnumMember em)
{
assert(em.ed);
// Members of anonymous members are reachable without referencing the
// EnumDeclaration, e.g. public import foo : someEnumMember;
if (em.ed.isAnonymous())
{
visit(em.ed);
return;
}
assert(false, "This node type should be handled in the EnumDeclaration");
}

File diff suppressed because it is too large Load diff

View file

@ -51,6 +51,11 @@ class ImportsC
typedef int32_t MyStdcInt;
enum
{
IgnoreErrors = 0,
};
typedef int32_t T;
extern "C" int32_t x;
@ -90,6 +95,30 @@ typedef TSD<int32_t, int16_t > TSI;
using aliasName = ImportsC;
using MyStdc = MyStdcInt;
struct FullImport final
{
using MyStdcInt = ::MyStdcInt;
using ImportsC = ::ImportsC;
FullImport()
{
}
};
struct SelectiveImports final
{
using aliasName = ::ImportsC;
SelectiveImports()
{
}
};
struct PrivateImport final
{
PrivateImport()
{
}
};
---
*/
@ -141,3 +170,24 @@ public import dtoh_imports :
importFunc,
aliasName = ImportsC,
MyStdc = MyStdcInt;
struct FullImport
{
public import dtoh_imports;
}
struct SelectiveImports
{
public import dtoh_imports :
importFunc,
aliasName = ImportsC;
public static import dtoh_imports;
}
struct PrivateImport
{
import dtoh_imports;
}

View file

@ -56,7 +56,7 @@ extern void importFunc();
// Ignored renamed import `myFunc = importFunc` because `using` only supports types
struct A final
{
// Ignored local __anonymous
// Ignored renamed import `myFunc = importFunc` because `using` only supports types
A()
{
}
@ -82,6 +82,23 @@ public:
extern void unused();
// Ignored variable dtoh_verbose.and because its name is a special operator in C++
template <typename T>
struct FullImportTmpl final
{
// Ignored `dtoh_imports` because it's inside of a template declaration
FullImportTmpl()
{
}
};
template <typename T>
struct SelectiveImportsTmpl final
{
// Ignored `__anonymous` because it's inside of a template declaration
SelectiveImportsTmpl()
{
}
};
---
*/
@ -112,7 +129,7 @@ public import dtoh_imports : myFunc = importFunc;
extern(C++) struct A
{
import core.stdc.errno : cErrorC = errno;
public import dtoh_imports : myFunc = importFunc;
}
extern(C++) struct Hidden
@ -140,3 +157,16 @@ extern(C++) class Visitor
extern(C++) void unused() {}
extern(C++) __gshared bool and;
extern(C++) struct FullImportTmpl(T)
{
public import dtoh_imports;
}
extern(C++) struct SelectiveImportsTmpl(T)
{
public import dtoh_imports :
importFunc,
aliasName = ImportsC;
}

View file

@ -5,3 +5,9 @@ public import dtoh_imports2 : MyStdcInt = customInt;
class ImportsC {}
void importFunc() {}
private struct HiddenData {}
enum : int {
IgnoreErrors
}