From d9830b739ed35e5154ee669bd2413d7558d10bac Mon Sep 17 00:00:00 2001 From: Sebastian Wilzbach Date: Fri, 9 Feb 2018 18:29:38 +0100 Subject: [PATCH 1/2] Fix DScanner warnings --- std/algorithm/comparison.d | 4 ++ std/algorithm/iteration.d | 88 ++++++++++++++-------------- std/algorithm/searching.d | 18 ++++-- std/bigint.d | 1 + std/datetime/systime.d | 2 - std/digest/sha.d | 9 ++- std/exception.d | 2 +- std/experimental/allocator/package.d | 8 +-- std/experimental/scripting.d | 2 +- std/format.d | 2 +- std/math.d | 2 +- std/net/curl.d | 25 ++++---- std/range/package.d | 13 ++-- std/regex/package.d | 3 +- std/string.d | 2 +- std/traits.d | 3 +- std/typecons.d | 2 +- 17 files changed, 104 insertions(+), 82 deletions(-) diff --git a/std/algorithm/comparison.d b/std/algorithm/comparison.d index 8a5486afdee..9a2a3b166a4 100644 --- a/std/algorithm/comparison.d +++ b/std/algorithm/comparison.d @@ -851,6 +851,8 @@ pure @safe unittest ++ctr; return 0; } + bool opEquals(T)(T o) const { return false; } + size_t toHash() const { return 0; } } immutable S[4] a; immutable S[4] b; @@ -869,6 +871,8 @@ nothrow pure @safe unittest { return value - rhs.value; } + bool opEquals(T)(T o) const { return false; } + size_t toHash() const { return 0; } } auto result = cmp([F(1), F(2), F(3)], [F(1), F(2), F(3)]); assert(result == 0); diff --git a/std/algorithm/iteration.d b/std/algorithm/iteration.d index 5e67665046d..c47fdbb7deb 100644 --- a/std/algorithm/iteration.d +++ b/std/algorithm/iteration.d @@ -4689,6 +4689,47 @@ if (isSomeChar!C) } } +// In same combinations substitute needs to calculate the auto-decoded length +// of its needles +private template hasDifferentAutodecoding(Range, Needles...) +{ + import std.meta : anySatisfy; + /* iff + - the needles needs auto-decoding, but the incoming range doesn't (or vice versa) + - both (range, needle) need auto-decoding and don't share the same common type + */ + enum needlesAreNarrow = anySatisfy!(isNarrowString, Needles); + enum sourceIsNarrow = isNarrowString!Range; + enum hasDifferentAutodecoding = sourceIsNarrow != needlesAreNarrow || + (sourceIsNarrow && needlesAreNarrow && + is(CommonType!(Range, Needles) == void)); +} + +@safe nothrow @nogc pure unittest +{ + import std.meta : AliasSeq; // used for better clarity + + static assert(!hasDifferentAutodecoding!(string, AliasSeq!(string, string))); + static assert(!hasDifferentAutodecoding!(wstring, AliasSeq!(wstring, wstring))); + static assert(!hasDifferentAutodecoding!(dstring, AliasSeq!(dstring, dstring))); + + // the needles needs auto-decoding, but the incoming range doesn't (or vice versa) + static assert(hasDifferentAutodecoding!(string, AliasSeq!(wstring, wstring))); + static assert(hasDifferentAutodecoding!(string, AliasSeq!(dstring, dstring))); + static assert(hasDifferentAutodecoding!(wstring, AliasSeq!(string, string))); + static assert(hasDifferentAutodecoding!(wstring, AliasSeq!(dstring, dstring))); + static assert(hasDifferentAutodecoding!(dstring, AliasSeq!(string, string))); + static assert(hasDifferentAutodecoding!(dstring, AliasSeq!(wstring, wstring))); + + // both (range, needle) need auto-decoding and don't share the same common type + static foreach (T; AliasSeq!(string, wstring, dstring)) + { + static assert(hasDifferentAutodecoding!(T, AliasSeq!(wstring, string))); + static assert(hasDifferentAutodecoding!(T, AliasSeq!(dstring, string))); + static assert(hasDifferentAutodecoding!(T, AliasSeq!(wstring, dstring))); + } +} + // substitute /** Returns a range with all occurrences of `substs` in `r`. @@ -4731,14 +4772,16 @@ if (substs.length >= 2 && isExpressions!substs) // Substitute single range elements with compile-time substitution mappings return value.map!(a => substitute(a)); } - else static if (isInputRange!Value && !is(CommonType!(ElementType!Value, ElementType!(typeof(substs[0]))) == void)) + else static if (isInputRange!Value && + !is(CommonType!(ElementType!Value, ElementType!(typeof(substs[0]))) == void)) { // not implemented yet, fallback to runtime variant for now return .substitute(value, substs); } else { - static assert(0, "Compile-time substitutions must be elements or ranges of the same type of ` ~ Value.stringof ~ `."); + static assert(0, `Compile-time substitutions must be elements or ranges of the same type of ` ~ + Value.stringof ~ `.`); } } // Substitute single values with compile-time substitution mappings. @@ -4756,47 +4799,6 @@ if (substs.length >= 2 && isExpressions!substs) } } -// In same combinations substitute needs to calculate the auto-decoded length -// of its needles -private template hasDifferentAutodecoding(Range, Needles...) -{ - import std.meta : anySatisfy; - /* iff - - the needles needs auto-decoding, but the incoming range doesn't (or vice versa) - - both (range, needle) need auto-decoding and don't share the same common type - */ - enum needlesAreNarrow = anySatisfy!(isNarrowString, Needles); - enum sourceIsNarrow = isNarrowString!Range; - enum hasDifferentAutodecoding = sourceIsNarrow != needlesAreNarrow || - (sourceIsNarrow && needlesAreNarrow && - is(CommonType!(Range, Needles) == void)); -} - -@safe nothrow @nogc pure unittest -{ - import std.meta : AliasSeq; // used for better clarity - - static assert(!hasDifferentAutodecoding!(string, AliasSeq!(string, string))); - static assert(!hasDifferentAutodecoding!(wstring, AliasSeq!(wstring, wstring))); - static assert(!hasDifferentAutodecoding!(dstring, AliasSeq!(dstring, dstring))); - - // the needles needs auto-decoding, but the incoming range doesn't (or vice versa) - static assert(hasDifferentAutodecoding!(string, AliasSeq!(wstring, wstring))); - static assert(hasDifferentAutodecoding!(string, AliasSeq!(dstring, dstring))); - static assert(hasDifferentAutodecoding!(wstring, AliasSeq!(string, string))); - static assert(hasDifferentAutodecoding!(wstring, AliasSeq!(dstring, dstring))); - static assert(hasDifferentAutodecoding!(dstring, AliasSeq!(string, string))); - static assert(hasDifferentAutodecoding!(dstring, AliasSeq!(wstring, wstring))); - - // both (range, needle) need auto-decoding and don't share the same common type - static foreach (T; AliasSeq!(string, wstring, dstring)) - { - static assert(hasDifferentAutodecoding!(T, AliasSeq!(wstring, string))); - static assert(hasDifferentAutodecoding!(T, AliasSeq!(dstring, string))); - static assert(hasDifferentAutodecoding!(T, AliasSeq!(wstring, dstring))); - } -} - /// ditto auto substitute(alias pred = (a, b) => a == b, R, Substs...)(R r, Substs substs) if (isInputRange!R && Substs.length >= 2 && !is(CommonType!(Substs) == void)) diff --git a/std/algorithm/searching.d b/std/algorithm/searching.d index 4d13df70156..6eefb102e69 100644 --- a/std/algorithm/searching.d +++ b/std/algorithm/searching.d @@ -1138,10 +1138,13 @@ if (isBidirectionalRange!R && static if (isDefaultPred && isSomeChar!E && E.sizeof <= ElementEncodingType!R.sizeof) return doesThisEnd[$ - 1] == withThis; // specialize for ASCII as to not change previous behavior - else if (withThis <= 0x7F) - return predFunc(doesThisEnd[$ - 1], withThis); else - return predFunc(doesThisEnd.back, withThis); + { + if (withThis <= 0x7F) + return predFunc(doesThisEnd[$ - 1], withThis); + else + return predFunc(doesThisEnd.back, withThis); + } } else { @@ -4263,10 +4266,13 @@ if (isInputRange!R && static if (isDefaultPred && isSomeChar!E && E.sizeof <= ElementEncodingType!R.sizeof) return doesThisStart[0] == withThis; // specialize for ASCII as to not change previous behavior - else if (withThis <= 0x7F) - return predFunc(doesThisStart[0], withThis); else - return predFunc(doesThisStart.front, withThis); + { + if (withThis <= 0x7F) + return predFunc(doesThisStart[0], withThis); + else + return predFunc(doesThisStart.front, withThis); + } } else { diff --git a/std/bigint.d b/std/bigint.d index a983766b191..4213676cab8 100644 --- a/std/bigint.d +++ b/std/bigint.d @@ -1835,6 +1835,7 @@ unittest enum BigInt test1 = BigInt(123); enum BigInt test2 = plusTwo(test1); + assert(test2 == 125); } /** diff --git a/std/datetime/systime.d b/std/datetime/systime.d index a399a2f487c..1af9b276e17 100644 --- a/std/datetime/systime.d +++ b/std/datetime/systime.d @@ -10322,7 +10322,6 @@ if (isSomeString!S) import std.ascii : isDigit; import std.conv : to; import std.string : representation; - import core.time; if (isoString.empty) return Duration.zero; @@ -10963,7 +10962,6 @@ version(StdUnittest) void initializeTests() @safe { - import core.time; import std.algorithm.sorting : sort; import std.typecons : Rebindable; immutable lt = LocalTime().utcToTZ(0); diff --git a/std/digest/sha.d b/std/digest/sha.d index 354aa3d7cff..3cc589c2e65 100644 --- a/std/digest/sha.d +++ b/std/digest/sha.d @@ -909,7 +909,8 @@ alias SHA512_256 = SHA!(1024, 256); /// SHA alias for SHA-512/256, hash is ubyte sha256.put(cast(ubyte[])"abcdef"); sha256.start(); sha256.put(cast(ubyte[])""); - assert(sha256.finish() == cast(ubyte[]) hexString!"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + assert(sha256.finish() == cast(ubyte[]) + hexString!"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); SHA384 sha384; sha384.put(cast(ubyte[])"abcdef"); @@ -922,7 +923,8 @@ alias SHA512_256 = SHA!(1024, 256); /// SHA alias for SHA-512/256, hash is ubyte sha512.put(cast(ubyte[])"abcdef"); sha512.start(); sha512.put(cast(ubyte[])""); - assert(sha512.finish() == cast(ubyte[]) hexString!("cf83e1357eefb8bdf1542850d66d8007d620e4050b571" + assert(sha512.finish() == cast(ubyte[]) + hexString!("cf83e1357eefb8bdf1542850d66d8007d620e4050b571" ~"5dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e")); SHA512_224 sha512_224; @@ -935,7 +937,8 @@ alias SHA512_256 = SHA!(1024, 256); /// SHA alias for SHA-512/256, hash is ubyte sha512_256.put(cast(ubyte[])"abcdef"); sha512_256.start(); sha512_256.put(cast(ubyte[])""); - assert(sha512_256.finish() == cast(ubyte[]) hexString!"c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"); + assert(sha512_256.finish() == cast(ubyte[]) + hexString!"c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a"); digest = sha1Of (""); digest224 = sha224Of (""); diff --git a/std/exception.d b/std/exception.d index ccbb01d09d2..d37ad5fd6a3 100644 --- a/std/exception.d +++ b/std/exception.d @@ -416,7 +416,7 @@ T enforce(T)(T value, lazy Throwable ex) } /// -unittest +@system unittest { import core.stdc.stdlib : malloc, free; import std.conv : ConvException, to; diff --git a/std/experimental/allocator/package.d b/std/experimental/allocator/package.d index 2c80a637384..e38035ee4b4 100644 --- a/std/experimental/allocator/package.d +++ b/std/experimental/allocator/package.d @@ -531,7 +531,7 @@ nothrow: } } -unittest +@system unittest { import std.experimental.allocator.building_blocks.region : Region; import std.conv : emplace; @@ -553,7 +553,7 @@ unittest assert((cast(CAllocatorImpl!(Region!(), Yes.indirect))(rcalloc._alloc)).rc == 1); } -unittest +@system unittest { import std.conv; import std.experimental.allocator.mallocator; @@ -576,7 +576,7 @@ unittest ~ to!string(bytesUsed) ~ " bytes"); } -unittest +@safe unittest { import std.conv; import std.experimental.allocator.mallocator; @@ -2554,7 +2554,7 @@ RCIAllocator allocatorObject(A)(A* pa) assert(a.deallocate(b)); } -unittest +@system unittest { import std.conv; import std.experimental.allocator.mallocator; diff --git a/std/experimental/scripting.d b/std/experimental/scripting.d index c27147212ac..8b666bae182 100644 --- a/std/experimental/scripting.d +++ b/std/experimental/scripting.d @@ -9,7 +9,7 @@ module std.experimental.scripting; import std.experimental.scripting; int len; - auto r = 6.iota + const r = 6.iota .filter!(a => a % 2) // 0 2 4 .map!(a => a * 2) // 0 4 8 .tee!(_ => len++) diff --git a/std/format.d b/std/format.d index 2cfba740fc9..958855aa344 100644 --- a/std/format.d +++ b/std/format.d @@ -4047,7 +4047,7 @@ if ((is(T == struct) || is(T == union)) && (hasToString!(T, Char) || !is(Builtin assert(w.data == "S()"); } -unittest +@safe unittest { //struct Foo { @disable string toString(); } //Foo foo; diff --git a/std/math.d b/std/math.d index 7203cda186e..1c7b5157074 100644 --- a/std/math.d +++ b/std/math.d @@ -524,7 +524,7 @@ template isDeprecatedComplex(T) } } -deprecated unittest +@safe deprecated unittest { static assert(isDeprecatedComplex!cfloat); static assert(isDeprecatedComplex!cdouble); diff --git a/std/net/curl.d b/std/net/curl.d index 2cca4197499..ab9e4028808 100644 --- a/std/net/curl.d +++ b/std/net/curl.d @@ -313,7 +313,7 @@ version(StdUnittest) version(StdDdoc) import std.stdio; // Default data timeout for Protocols -enum _defaultDataTimeout = dur!"minutes"(2); +private enum _defaultDataTimeout = dur!"minutes"(2); /** Macros: @@ -1643,7 +1643,7 @@ if (isCurlConn!Conn && isSomeChar!Char && isSomeChar!Terminator) } else { - import std.concurrency; + import std.concurrency : OnCrowding, send, setMaxMailboxSize, spawn, thisTid, Tid; // 50 is just an arbitrary number for now setMaxMailboxSize(thisTid, 50, OnCrowding.block); auto tid = spawn(&_async!().spawn!(Conn, Char, Terminator)); @@ -1767,7 +1767,7 @@ if (isCurlConn!(Conn)) } else { - import std.concurrency; + import std.concurrency : OnCrowding, send, setMaxMailboxSize, spawn, thisTid, Tid; // 50 is just an arbitrary number for now setMaxMailboxSize(thisTid, 50, OnCrowding.block); auto tid = spawn(&_async!().spawn!(Conn, ubyte)); @@ -1826,7 +1826,7 @@ if (isCurlConn!(Conn)) */ private mixin template Protocol() { - import etc.c.curl : CurlReadFunc; + import etc.c.curl : CurlReadFunc, RawCurlProxy = CurlProxy; import core.time : Duration; import std.socket : InternetAddress; @@ -1911,7 +1911,7 @@ private mixin template Protocol() } /// Type of proxy - alias CurlProxy = etc.c.curl.CurlProxy; + alias CurlProxy = RawCurlProxy; /** Proxy type * See: $(HTTP curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROXY, _proxy_type) @@ -2323,7 +2323,7 @@ struct HTTP import std.datetime.systime : SysTime; import std.typecons : RefCounted; - import etc.c.curl; + import etc.c.curl : CurlAuth, CurlInfo, curl_slist, CURLVERSION_NOW, curl_off_t; /// Authentication method equal to $(REF CurlAuth, etc,c,curl) alias AuthMethod = CurlAuth; @@ -3244,7 +3244,7 @@ struct FTP mixin Protocol; import std.typecons : RefCounted; - import etc.c.curl; + import etc.c.curl : CurlError, CurlInfo, curl_off_t, curl_slist; private struct Impl { @@ -3646,7 +3646,7 @@ struct SMTP { mixin Protocol; import std.typecons : RefCounted; - import etc.c.curl; + import etc.c.curl : CurlUseSSL, curl_slist; private struct Impl { @@ -4056,9 +4056,11 @@ alias ThrowOnError = Flag!"throwOnError"; private struct CurlAPI { - import etc.c.curl; + import etc.c.curl : CurlGlobal; static struct API { + import etc.c.curl : curl_version_info, curl_version_info_data, + CURL, CURLcode, CURLINFO, CURLoption, CURLversion, curl_slist; extern(C): import core.stdc.config : c_long; CURLcode function(c_long flags) global_init; @@ -4189,7 +4191,10 @@ private struct CurlAPI */ struct Curl { - import etc.c.curl; + import etc.c.curl : CURL, CurlError, CurlPause, CurlSeek, CurlSeekPos, + curl_socket_t, CurlSockType, + CurlReadFunc, CurlInfo, curlsocktype, curl_off_t, + LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH; alias OutData = void[]; alias InData = ubyte[]; diff --git a/std/range/package.d b/std/range/package.d index 1c683a76685..00e2f47d115 100644 --- a/std/range/package.d +++ b/std/range/package.d @@ -2545,7 +2545,7 @@ pure @safe nothrow unittest // https://issues.dlang.org/show_bug.cgi?id=18092 // can't combine take and takeExactly -unittest +@safe unittest { import std.algorithm.comparison : equal; import std.internal.test.dummyrange : AllDummyRanges; @@ -8475,7 +8475,7 @@ public: assert(3.iota.slide!(Partial)(4, 3).walkLength == expectedLength); }} - enum list = [ + static immutable list = [ // iota slide expected [4, 2, 1, 3, 3], [5, 3, 1, 3, 3], @@ -8637,7 +8637,7 @@ public: import std.typecons : tuple; alias t = tuple; - enum list = [ + static immutable list = [ // iota slide expected t(6, t(4, 2), [[1, 2, 3, 4], [3, 4, 5, 6]]), t(6, t(4, 6), [[1, 2, 3, 4]]), @@ -8655,7 +8655,7 @@ public: foreach (e; list) assert(Range().take(e[0]).slide!Partial(e[1].expand).equal!equal(e[2])); - enum listSpecial = [ + static immutable listSpecial = [ // iota slide expected t(6, t(4, 3), [[1, 2, 3, 4], [4, 5, 6]]), t(7, t(4, 5), [[1, 2, 3, 4], [6, 7]]), @@ -8686,11 +8686,12 @@ public: import std.typecons : tuple; alias t = tuple; - enum list = [ + static immutable list = [ // slide expected t(1, 1, [[10], [9], [8], [7], [6], [5], [4], [3], [2], [1]]), t(2, 1, [[9, 10], [8, 9], [7, 8], [6, 7], [5, 6], [4, 5], [3, 4], [2, 3], [1, 2]]), - t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8], [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]), + t(5, 1, [[6, 7, 8, 9, 10], [5, 6, 7, 8, 9], [4, 5, 6, 7, 8], + [3, 4, 5, 6, 7], [2, 3, 4, 5, 6], [1, 2, 3, 4, 5]]), t(2, 2, [[9, 10], [7, 8], [5, 6], [3, 4], [1, 2]]), t(2, 4, [[9, 10], [5, 6], [1, 2]]), ]; diff --git a/std/regex/package.d b/std/regex/package.d index addbc2203a3..a8cb48da0d7 100644 --- a/std/regex/package.d +++ b/std/regex/package.d @@ -827,11 +827,12 @@ private auto matchMany(RegEx, R)(R input, RegEx re) @safe } // https://issues.dlang.org/show_bug.cgi?id=18135 -unittest +@system unittest { static struct MapResult { RegexMatch!string m; } MapResult m; m = MapResult(); + assert(m == m); } private enum isReplaceFunctor(alias fun, R) = diff --git a/std/string.d b/std/string.d index b41b97214ef..e67d3297068 100644 --- a/std/string.d +++ b/std/string.d @@ -6402,7 +6402,7 @@ if (isSomeString!S || version(TestComplex) deprecated -unittest +@safe unittest { import std.conv : to; assert(isNumeric(to!string(123e+2+1234.78Li)) == true); diff --git a/std/traits.d b/std/traits.d index c98d5eabf8f..e4855b264b4 100644 --- a/std/traits.d +++ b/std/traits.d @@ -5238,7 +5238,8 @@ template IntegralTypeOf(T) static assert( is(Q!T == IntegralTypeOf!( SubTypeOf!(Q!T) ))); } - static foreach (T; AliasSeq!(void, bool, FloatingPointTypeList, /*ImaginaryTypeList, ComplexTypeList,*/ CharTypeList)) + static foreach (T; AliasSeq!(void, bool, FloatingPointTypeList, + /*ImaginaryTypeList, ComplexTypeList,*/ CharTypeList)) static foreach (Q; TypeQualifierList) { static assert(!is(IntegralTypeOf!( Q!T ))); diff --git a/std/typecons.d b/std/typecons.d index 3e5d5dbb083..32d06356f9d 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -1299,7 +1299,7 @@ if (distinctFieldNames!(Specs)) } /// Use tuples as ranges -unittest +@safe unittest { import std.algorithm.iteration : sum; import std.range : only; From a2985edaad4873819ac079141a1a23e1784a9b36 Mon Sep 17 00:00:00 2001 From: Sebastian Wilzbach Date: Sat, 10 Feb 2018 02:52:02 +0100 Subject: [PATCH 2/2] Use -return-exit-code to fail the testsuite on DScanner failures --- posix.mak | 2 +- std/experimental/allocator/package.d | 2 +- std/net/curl.d | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/posix.mak b/posix.mak index bd309627136..2af963825a7 100644 --- a/posix.mak +++ b/posix.mak @@ -535,7 +535,7 @@ style: publictests style_lint # runs static code analysis with Dscanner dscanner: | $(DSCANNER_DIR)/dsc @echo "Running DScanner" - $(DEBUGGER) -q -ex run -ex bt -batch --args $(DSCANNER_DIR)/dsc --config .dscanner.ini --styleCheck etc std -I. + $(DEBUGGER) -return-child-result -q -ex run -ex bt -batch --args $(DSCANNER_DIR)/dsc --config .dscanner.ini --styleCheck etc std -I. style_lint: dscanner $(LIB) @echo "Check for trailing whitespace" diff --git a/std/experimental/allocator/package.d b/std/experimental/allocator/package.d index e38035ee4b4..648ff960c95 100644 --- a/std/experimental/allocator/package.d +++ b/std/experimental/allocator/package.d @@ -576,7 +576,7 @@ nothrow: ~ to!string(bytesUsed) ~ " bytes"); } -@safe unittest +@system unittest { import std.conv; import std.experimental.allocator.mallocator; diff --git a/std/net/curl.d b/std/net/curl.d index ab9e4028808..222fadc15a4 100644 --- a/std/net/curl.d +++ b/std/net/curl.d @@ -2561,6 +2561,8 @@ struct HTTP // docs mixed in. version (StdDdoc) { + static import etc.c.curl; + /// Value to return from $(D onSend)/$(D onReceive) delegates in order to /// pause a request alias requestPause = CurlReadFunc.pause; @@ -3338,6 +3340,8 @@ struct FTP // docs mixed in. version (StdDdoc) { + static import etc.c.curl; + /// Value to return from $(D onSend)/$(D onReceive) delegates in order to /// pause a request alias requestPause = CurlReadFunc.pause; @@ -3762,6 +3766,8 @@ struct SMTP // docs mixed in. version (StdDdoc) { + static import etc.c.curl; + /// Value to return from $(D onSend)/$(D onReceive) delegates in order to /// pause a request alias requestPause = CurlReadFunc.pause;