diff --git a/dstep/Configuration.d b/dstep/Configuration.d index 3720e54d..54c18d2e 100644 --- a/dstep/Configuration.d +++ b/dstep/Configuration.d @@ -113,6 +113,9 @@ struct Configuration @("public-global-import", "Add as a public global import.") string[] publicGlobalImports; + /// needed for converting absolute includes to relative + string[] includePaths = ["/usr/local/include", "/usr/include"]; + Options toOptions(string inputFile, string outputFile) const { Options options = toOptions(); @@ -150,6 +153,7 @@ struct Configuration options.globalAttributes = globalAttributes; options.globalImports = globalImports; options.publicGlobalImports = publicGlobalImports; + options.includePaths = includePaths; return options; } diff --git a/dstep/driver/CommandLine.d b/dstep/driver/CommandLine.d index 346eca67..1bfb75c3 100644 --- a/dstep/driver/CommandLine.d +++ b/dstep/driver/CommandLine.d @@ -8,6 +8,8 @@ module dstep.driver.CommandLine; import std.typecons : tuple, Tuple; import std.getopt; +import clang.Util : asAbsNormPath; + import dstep.Configuration; import dstep.translator.Options; import dstep.core.Exceptions; @@ -86,7 +88,13 @@ auto parseCommandLine(string[] args) // Post-processing of CLI - import std.algorithm : canFind; + import std.algorithm; + import std.array : array; + + config.includePaths ~= config.clangParams.filter!(p => p.length > 2 && p.startsWith("-I")) + .map!(p => p[2 .. $].asAbsNormPath).array; + + config.includePaths = config.includePaths.sort().uniq.array.sort!((a, b) => a.length > b.length).array; if (forceObjectiveC) config.clangParams ~= "-ObjC"; diff --git a/dstep/translator/Context.d b/dstep/translator/Context.d index 34f04e19..7684c4dc 100644 --- a/dstep/translator/Context.d +++ b/dstep/translator/Context.d @@ -11,6 +11,7 @@ import clang.Cursor; import clang.Index; import clang.SourceRange; import clang.TranslationUnit; +import clang.Util; import dstep.translator.CommentIndex; import dstep.translator.IncludeHandler; @@ -18,6 +19,7 @@ import dstep.translator.MacroDefinition; import dstep.translator.MacroIndex; import dstep.translator.Options; import dstep.translator.Output; +import dstep.translator.Preprocessor; import dstep.translator.Translator; import dstep.translator.TypedefIndex; import dstep.translator.HeaderIndex; @@ -46,6 +48,8 @@ class Context public this(TranslationUnit translUnit, Options options, Translator translator = null) { + import std.algorithm.iteration : filter; + this.translUnit = translUnit; macroIndex = new MacroIndex(translUnit); includeHandler_ = new IncludeHandler(headerIndex, options); @@ -56,6 +60,14 @@ class Context foreach (item; options.publicGlobalImports) includeHandler_.addImport(item, Visibility.public_); + foreach (cursor; translUnit.cursor.children.filter!(c => c.kind == CXCursorKind.inclusionDirective)) + { + if (cursor.path.asAbsNormPath != translUnit.spelling.asAbsNormPath) + continue; + + includeHandler_.addInclude(cursor.spelling, cursor.includedFile.absolutePath); + } + this.options = options; if (options.enableComments) diff --git a/dstep/translator/HeaderIndex.d b/dstep/translator/HeaderIndex.d index ae1b2531..91f9cd62 100644 --- a/dstep/translator/HeaderIndex.d +++ b/dstep/translator/HeaderIndex.d @@ -225,6 +225,7 @@ class HeaderIndex private IncludeGraph includeGraph_; private string[string] stdLibPaths; private string[string] knownModules; + private string[string] includeNames; private string mainFilePath; public this(TranslationUnit translationUnit) @@ -318,6 +319,11 @@ class HeaderIndex private this(T)(T directives, const string[string] moduleMapping) { + foreach (directive; directives) + { + includeNames.require(directive.includedFile.absolutePath, directive.spelling); + } + knownModules = resolveKnownModules( directives, resolveKnownModulePaths( @@ -331,6 +337,11 @@ class HeaderIndex return knownModule !is null ? *knownModule : null; } + string getIncludeName(string absolutePath) + { + return includeNames.get(absolutePath, null); + } + IncludeGraph includeGraph() { return includeGraph_; diff --git a/dstep/translator/IncludeHandler.d b/dstep/translator/IncludeHandler.d index 24aeb49b..2878ba93 100644 --- a/dstep/translator/IncludeHandler.d +++ b/dstep/translator/IncludeHandler.d @@ -25,7 +25,7 @@ class IncludeHandler { private Options options; private string[string] submodules; - private bool[string] includes; + private string[string] includes; private bool[string] imports; private Set!string publicImports; private HeaderIndex headerIndex; @@ -106,6 +106,7 @@ class IncludeHandler "sys/un" : "core.sys.posix.sys.un", "sys/utsname" : "core.sys.posix.sys.utsname", "sys/wait" : "core.sys.posix.sys.wait", + "sys/ioctl" : "core.sys.posix.sys.ioctl", "windows" : "core.sys.windows.windows" ]; @@ -133,21 +134,40 @@ class IncludeHandler } } - void addInclude (string include) + void addInclude (string name, string absolutePath) { - import std.path; - import std.file; - import std.array; + assert(name.length > 0); + assert(absolutePath.length > 0); - auto absolute = include.asAbsNormPath; + includes.require(absolutePath, name); + } + + void addInclude (string absolutePath) + { + import std.path : isAbsolute, baseName; + import std.algorithm.searching : startsWith; - if (absolute != options.inputFile && !include.empty) + auto includeName = headerIndex.getIncludeName(absolutePath); + assert(includeName.length > 0); + + if (isAbsolute(includeName)) { - if (exists(absolute) && isFile(absolute)) - includes[absolute] = true; - else - includes[include] = true; + foreach (includePath; options.includePaths) + { + if (absolutePath.startsWith(includePath)) + { + includeName = absolutePath[includePath.length + 1 .. $]; + break; + } + } + + + if (isAbsolute(includeName)) + // didn't match any known path, fallback to just filename + includeName = absolutePath.baseName; } + + addInclude(includeName, absolutePath); } void addImport (string imp) @@ -167,36 +187,48 @@ class IncludeHandler void addCompatible () { - includes["config.h"] = true; + includes["config.h"] = "config.h"; } void toImports (Output output) { - import std.algorithm : map; - import std.array : array; + import std.algorithm : map, sort, copy; + import std.array : array, replace; import std.format : format; - import std.algorithm.iteration : filter, map; + import std.algorithm.iteration : map, uniq; + import std.path : stripExtension; + import std.uni : toLower; Set!string standard, package_, unhandled; - foreach (entry; includes.byKey) + foreach (absolute, includeName; includes) { - if (auto i = isKnownInclude(entry)) - standard.add(toImport(i)); - else if (auto i = isPackageSubmodule(entry)) + if (auto i = isPackageSubmodule(absolute)) package_.add(toSubmoduleImport(i)); - else - unhandled.add(format(`/+ #include "%s" +/`, entry)); + else if (includeName.length > 0) + { + if (auto i = isKnownInclude(includeName)) + { + standard.add(toImport(i)); + } + else + { + auto name = stripExtension(includeName).toLower(); + unhandled.add(format(`// FIXME: import %s;`, name.replace("/", "."))); + } + } } const publicExtra = publicImports.byKey.map!(e => toImport(e, Visibility.public_)).array; auto extra = imports.byKey.map!(e => toImport(e)).array; + auto imports = standard.keys ~ publicExtra ~ extra.array; + imports.sort(); + imports.length -= imports.uniq().copy(imports).length; - importsBlock(output, standard.keys ~ publicExtra ~ extra.array); + importsBlock(output, imports); importsBlock(output, package_.keys); - if (options.keepUntranslatable) - importsBlock(output, unhandled.keys); + importsBlock(output, unhandled.keys); output.finalize(); } @@ -248,11 +280,11 @@ private: string isKnownInclude (string include) { - import std.path : stripExtension, baseName; + import std.path : stripExtension; - include = stripExtension(baseName(include)); + auto name = stripExtension(include); - if (auto ptr = include in knownIncludes) + if (auto ptr = name in knownIncludes) return *ptr; else return null; diff --git a/dstep/translator/Options.d b/dstep/translator/Options.d index d1ec6d68..09578734 100644 --- a/dstep/translator/Options.d +++ b/dstep/translator/Options.d @@ -35,7 +35,6 @@ struct Options bool enableComments = true; bool publicSubmodules = false; bool normalizeModules = false; - bool keepUntranslatable = false; bool reduceAliases = true; bool translateMacros = true; bool portableWCharT = true; @@ -51,6 +50,7 @@ struct Options const(string)[] globalAttributes; const(string)[] globalImports; const(string)[] publicGlobalImports; + const(string)[] includePaths; bool delegate(ref const(Cursor)) isWantedCursorForTypedefs; string toString() const diff --git a/dstep/translator/Preprocessor.d b/dstep/translator/Preprocessor.d index 52ab02ba..5e32093c 100644 --- a/dstep/translator/Preprocessor.d +++ b/dstep/translator/Preprocessor.d @@ -70,6 +70,12 @@ class PragmaDirective : Directive { } +class IncludeDirective : Directive +{ + bool system; + string path; +} + class DefineDirective : Directive { MacroDefinition macroDefinition; @@ -458,6 +464,30 @@ struct DirectiveRange Directive parseInclude(Token[] tokens) { + import std.algorithm.searching; + import std.algorithm.iteration; + import std.string : strip; + + if (acceptDirective!"include"(tokens)) + { + auto directive = new IncludeDirective(); + directive.kind = DirectiveKind.include; + directive.tokens = tokens; + directive.extent = tokens.extent; + + if (acceptPunctuation!("<")(tokens)) + { + directive.system = true; + directive.path = tokens.until!((token) => token.spelling == ">") + .fold!((str, token) => str ~= token.spelling)(""); + } else if (tokens.length == 1) + { + directive.system = false; + directive.path = tokens[0].spelling.strip("\""); + } + return directive; + } + return null; } @@ -1006,3 +1036,71 @@ unittest assert(case0[0].length == 3); } + +// System include directive. +unittest +{ + auto case0 = directives(q"C +#include +int x; +C"); + + assert(case0.length == 1); + assert(case0[0].kind == DirectiveKind.include); + + auto include = cast(IncludeDirective) case0[0]; + assert(include !is null); + assert(include.system == true); + assert(include.path == "stdio.h"); +} + +// Local include directive. +unittest +{ + auto case0 = directives(q"C +#include "local.h" +int x; +C"); + + assert(case0.length == 1); + assert(case0[0].kind == DirectiveKind.include); + + auto include = cast(IncludeDirective) case0[0]; + assert(include !is null); + assert(include.system == false); + assert(include.path == "local.h"); +} + +// Multiple include directives. +unittest +{ + auto case0 = directives(q"C +#include +#include "local.h" +#include +#include "local2.h" +int x; +C"); + + assert(case0.length == 4); + + auto include0 = cast(IncludeDirective) case0[0]; + assert(include0 !is null); + assert(include0.system == true); + assert(include0.path == "stdio.h"); + + auto include1 = cast(IncludeDirective) case0[1]; + assert(include1 !is null); + assert(include1.system == false); + assert(include1.path == "local.h"); + + auto include2 = cast(IncludeDirective) case0[2]; + assert(include2 !is null); + assert(include2.system == true); + assert(include2.path == "stdlib.h"); + + auto include3 = cast(IncludeDirective) case0[3]; + assert(include3 !is null); + assert(include3.system == false); + assert(include3.path == "local2.h"); +} diff --git a/dstep/translator/Translator.d b/dstep/translator/Translator.d index 2555aa40..b76186d7 100644 --- a/dstep/translator/Translator.d +++ b/dstep/translator/Translator.d @@ -491,12 +491,16 @@ void translateVariable (Output output, Context context, Cursor cursor, string pr void handleInclude (Context context, Type type) { - import std.algorithm.searching; - import std.path; + if (!type.declaration.isValid || type.declaration.path.length == 0) + return; - if (!context.includeHandler.resolveDependency(type.declaration)) { - context.includeHandler.addInclude(type.declaration.path); - } + auto path = type.declaration.path.asAbsNormPath; + + if (path == context.translUnit.spelling.asAbsNormPath) + return; + + if (!context.includeHandler.resolveDependency(type.declaration)) + context.includeHandler.addInclude(path); } bool isDKeyword (string str) diff --git a/tests/functional/Tests.d b/tests/functional/Tests.d index 7eebf707..506ca556 100644 --- a/tests/functional/Tests.d +++ b/tests/functional/Tests.d @@ -227,6 +227,37 @@ unittest ); } +unittest +{ + assertRunsDStepCFile( + "tests/functional/include/file.d", + "tests/functional/include/file.h", + ["-Itests/functional/include"] + ); +} + +unittest +{ + import std.path : absolutePath; + + assertRunsDStepCFile( + "tests/functional/imports.d", + "tests/functional/imports.h", + ["-I" ~ "tests/functional/include".absolutePath(), "-includesubdir/primary.h"] + ); +} + +unittest +{ + import std.path : absolutePath; + + assertRunsDStepCFile( + "tests/functional/imports.d", + "tests/functional/imports.h", + ["-Itests/functional/include", "-include" ~ "tests/functional/include/subdir/primary.h".absolutePath()] + ); +} + // DStep should exit with non-zero status when an input file doesn't exist. unittest { diff --git a/tests/functional/clang-c/BuildSystem.d b/tests/functional/clang-c/BuildSystem.d index 4ce84858..04631888 100644 --- a/tests/functional/clang-c/BuildSystem.d +++ b/tests/functional/clang-c/BuildSystem.d @@ -14,6 +14,8 @@ module clang.c.build_system; public import clang.c.cx_error_code; +public import clang.c.cx_string; +public import clang.c.platform; extern (C): diff --git a/tests/functional/clang-c/CXCompilationDatabase.d b/tests/functional/clang-c/CXCompilationDatabase.d index c255fcb1..1e3df196 100644 --- a/tests/functional/clang-c/CXCompilationDatabase.d +++ b/tests/functional/clang-c/CXCompilationDatabase.d @@ -15,6 +15,7 @@ module clang.c.cx_compilation_database; public import clang.c.cx_string; +public import clang.c.platform; extern (C): diff --git a/tests/functional/clang-c/CXErrorCode.d b/tests/functional/clang-c/CXErrorCode.d index a84418fa..b8e65c2e 100644 --- a/tests/functional/clang-c/CXErrorCode.d +++ b/tests/functional/clang-c/CXErrorCode.d @@ -13,6 +13,8 @@ module clang.c.cx_error_code; +public import clang.c.platform; + extern (C): /** diff --git a/tests/functional/clang-c/CXString.d b/tests/functional/clang-c/CXString.d index d852acfd..2fa0b3ad 100644 --- a/tests/functional/clang-c/CXString.d +++ b/tests/functional/clang-c/CXString.d @@ -13,6 +13,8 @@ module clang.c.cx_string; +public import clang.c.platform; + extern (C): /** diff --git a/tests/functional/clang-c/Index.d b/tests/functional/clang-c/Index.d index 8e77e923..e0f3abc9 100644 --- a/tests/functional/clang-c/Index.d +++ b/tests/functional/clang-c/Index.d @@ -18,8 +18,10 @@ module clang.c.index; import core.stdc.config; import core.stdc.time; +public import clang.c.build_system; public import clang.c.cx_error_code; public import clang.c.cx_string; +public import clang.c.platform; extern (C): diff --git a/tests/functional/imports.d b/tests/functional/imports.d new file mode 100644 index 00000000..1352f1f2 --- /dev/null +++ b/tests/functional/imports.d @@ -0,0 +1,11 @@ +// FIXME: import subdir.nested; +// FIXME: import subdir.primary; +// FIXME: import subfile2; + +extern (C): + +struct SomeStruct +{ + INT a; + SubdirStruct b; +} diff --git a/tests/functional/imports.h b/tests/functional/imports.h new file mode 100644 index 00000000..07b397e8 --- /dev/null +++ b/tests/functional/imports.h @@ -0,0 +1,8 @@ + +#include + +struct SomeStruct { + INT a; + struct SubdirStruct b; +}; + diff --git a/tests/functional/include/file.d b/tests/functional/include/file.d new file mode 100644 index 00000000..2809c6e7 --- /dev/null +++ b/tests/functional/include/file.d @@ -0,0 +1,6 @@ +// FIXME: import subfile1; +// FIXME: import subfile2; +// FIXME: import subfile3; + +extern (C): + diff --git a/tests/functional/include/subdir/nested.h b/tests/functional/include/subdir/nested.h new file mode 100644 index 00000000..24cae6ec --- /dev/null +++ b/tests/functional/include/subdir/nested.h @@ -0,0 +1,5 @@ + +struct SubdirStruct { + PTR a; +}; + diff --git a/tests/functional/include/subdir/primary.h b/tests/functional/include/subdir/primary.h new file mode 100644 index 00000000..2918cc7b --- /dev/null +++ b/tests/functional/include/subdir/primary.h @@ -0,0 +1,7 @@ + +typedef void *PTR; + +#include + +typedef int INT; + diff --git a/tests/functional/module/main0.d b/tests/functional/module/main0.d index 0ba435dc..7cbb1550 100644 --- a/tests/functional/module/main0.d +++ b/tests/functional/module/main0.d @@ -1,6 +1,7 @@ module modules.main0; import modules.include; +import modules.unused; extern (C): diff --git a/tests/functional/module/main0NotNormalized.d b/tests/functional/module/main0NotNormalized.d index 9378d643..7cedcc9e 100644 --- a/tests/functional/module/main0NotNormalized.d +++ b/tests/functional/module/main0NotNormalized.d @@ -1,6 +1,7 @@ module modules.main0NotNormalized; public import modules.include; +public import modules.unused; extern (C): diff --git a/tests/functional/module/main0_public.d b/tests/functional/module/main0_public.d index b61a1cb2..56c90be0 100644 --- a/tests/functional/module/main0_public.d +++ b/tests/functional/module/main0_public.d @@ -1,6 +1,7 @@ module modules.main0_public; public import modules.include; +public import modules.unused; extern (C): diff --git a/tests/unit/Common.d b/tests/unit/Common.d index 9773ead1..7b960cd6 100644 --- a/tests/unit/Common.d +++ b/tests/unit/Common.d @@ -103,6 +103,26 @@ TranslationUnit makeTranslationUnit(string source) return TranslationUnit.parseString(index, source, arguments); } +TranslationUnit makeTranslationUnitFromFile( + string sourceFilename, + const string[] commandLineArgs = ["-Wno-missing-declarations"], + uint options = CXTranslationUnit_Flags.detailedPreprocessingRecord) +{ + import std.algorithm; + import std.array; + + Compiler compiler; + + auto index = Index(false, false); + + return TranslationUnit.parse( + index, + sourceFilename, + commandLineArgs ~ compiler.internalFlags, + compiler.internalHeaders, + options); +} + CommentIndex makeCommentIndex(string c) { TranslationUnit translUnit = makeTranslationUnit(c); diff --git a/tests/unit/IncludeGraphTests.d b/tests/unit/IncludeGraphTests.d index 8fcf78e5..74aa1590 100644 --- a/tests/unit/IncludeGraphTests.d +++ b/tests/unit/IncludeGraphTests.d @@ -14,29 +14,9 @@ import clang.Util; import dstep.translator.HeaderIndex; -static TranslationUnit makeTranslationUnit( - string sourceFilename, - const string[] commandLineArgs = ["-Wno-missing-declarations"], - uint options = CXTranslationUnit_Flags.detailedPreprocessingRecord) -{ - import std.algorithm; - import std.array; - - Compiler compiler; - - auto index = Index(false, false); - - return TranslationUnit.parse( - index, - sourceFilename, - commandLineArgs ~ compiler.internalFlags, - compiler.internalHeaders, - options); -} - static IncludeGraph makeIncludeGraph(string sourceFilename) { - return new IncludeGraph(makeTranslationUnit(sourceFilename)); + return new IncludeGraph(makeTranslationUnitFromFile(sourceFilename)); } unittest @@ -72,7 +52,7 @@ unittest { import std.algorithm; - auto translationUnit = makeTranslationUnit( + auto translationUnit = makeTranslationUnitFromFile( "tests/functional/clang-c/Index.h", ["-Wno-missing-declarations", "-Itests/functional"]); auto headerIndex = new HeaderIndex(translationUnit); @@ -84,7 +64,7 @@ unittest unittest { - auto translationUnit = makeTranslationUnit( + auto translationUnit = makeTranslationUnitFromFile( "tests/functional/graph/self_including_main.h", ["-Wno-missing-declarations", "-Itests/functional"]); diff --git a/tests/unit/IncludeHandlerTests.d b/tests/unit/IncludeHandlerTests.d index 3764523d..f5533eed 100644 --- a/tests/unit/IncludeHandlerTests.d +++ b/tests/unit/IncludeHandlerTests.d @@ -13,6 +13,7 @@ import clang.TranslationUnit; import clang.Util; import dstep.translator.HeaderIndex; +import dstep.translator.Options; // Include standard library module when the dependency is used in macro. unittest @@ -85,3 +86,37 @@ D"); } } + +unittest +{ + assertTranslates( +q"C +#include + +int foo; +C", +q"D +import core.stdc.stdio; + +extern (C): + +extern __gshared int foo; +D"); +} + +unittest +{ + assertTranslates( +q"C +#include + +int foo; +C", +q"D +// FIXME: import memory; + +extern (C): + +extern __gshared int foo; +D"); +} diff --git a/tests/unit/MacroTranslTests.d b/tests/unit/MacroTranslTests.d index 6a7cb3c3..d39e4948 100644 --- a/tests/unit/MacroTranslTests.d +++ b/tests/unit/MacroTranslTests.d @@ -610,6 +610,8 @@ unittest #define ROWBYTES(pixel_bits) (int32_t)(pixel_bits) C", q"D +import core.stdc.stdint; + extern (C): extern (D) auto ROWBYTES(T)(auto ref T pixel_bits) diff --git a/tests/unit/UnitTests.d b/tests/unit/UnitTests.d index 87acea3c..28d9e777 100644 --- a/tests/unit/UnitTests.d +++ b/tests/unit/UnitTests.d @@ -380,6 +380,8 @@ size_t foo; ptrdiff_t bar; C", q"D +import core.stdc.stddef; + extern (C): extern __gshared size_t foo; @@ -414,6 +416,8 @@ q"C uint8_t foo; uint32_t bar; C", q"D +import core.stdc.stdint; + extern (C): extern __gshared ubyte foo; @@ -555,6 +559,8 @@ q"C uint8_t foo; uint32_t bar; C", q"D +import core.stdc.stdint; + extern (C): extern __gshared ubyte foo; @@ -598,6 +604,7 @@ wchar_t x; C", q"D import core.stdc.stddef; +import core.stdc.wchar_; extern (C): @@ -611,13 +618,13 @@ D"); { assertTranslates( "#include \n\nwchar_t x;\n", - "extern (C):\n\nextern __gshared wchar x;\n", options); + "import core.stdc.wchar_;\n\nextern (C):\n\nextern __gshared wchar x;\n", options); } else { assertTranslates( "#include \n\nwchar_t x;\n", - "extern (C):\n\nextern __gshared dchar x;\n", options); + "import core.stdc.wchar_;\n\nextern (C):\n\nextern __gshared dchar x;\n", options); } } @@ -636,6 +643,8 @@ struct bar { ptrdiff_t n; }; C", q"D +import core.stdc.stddef; + extern (C): struct foo @@ -977,6 +986,24 @@ D", options); } +// Test compiler builtin types +unittest +{ + assertTranslates( + q"C +typedef __builtin_va_list VA_LIST; + +#define VA_COPY(Dest, Start) __builtin_va_copy (Dest, Start) +C", q"D +extern (C): + +alias VA_LIST = __va_list_tag[1]; + +alias VA_COPY = __builtin_va_copy; +D"); + +} + // Test global attributes unittest { diff --git a/tests/unit/issues/Issue199.d b/tests/unit/issues/Issue199.d index 6846314f..63992a2c 100644 --- a/tests/unit/issues/Issue199.d +++ b/tests/unit/issues/Issue199.d @@ -16,6 +16,8 @@ unittest #define __le64 uint64_t C", q"D +import core.stdc.stdint; + extern (C): alias __le64 = ulong; diff --git a/tests/unit/issues/Issue8.d b/tests/unit/issues/Issue8.d index c2670891..6b63ab7c 100644 --- a/tests/unit/issues/Issue8.d +++ b/tests/unit/issues/Issue8.d @@ -39,6 +39,8 @@ int rd_kafka_metadata (rd_kafka_t *rk, int all_topics, int timeout_ms); C", q"D +import core.stdc.stdint; + extern (C): struct rd_kafka diff --git a/tests/unit/issues/Issue85.d b/tests/unit/issues/Issue85.d index e4a8baff..bb3e69a0 100644 --- a/tests/unit/issues/Issue85.d +++ b/tests/unit/issues/Issue85.d @@ -16,6 +16,8 @@ unittest int complex_forward (const double data[], const size_t stride, const size_t n, double result[]); C", q"D +import core.stdc.stddef; + extern (C): int complex_forward (const(double)* data, const size_t stride, const size_t n, double* result);