From 4c846a263a7e94c0966ef66a0e0fc4adda58c737 Mon Sep 17 00:00:00 2001 From: k-hara Date: Mon, 6 Jan 2014 23:54:54 +0900 Subject: [PATCH] fix Issue 11863 - std.conv.to!string(int/uint, radix) returns incorrect string --- src/glue.c | 40 +++++------ test/runnable/imports/std11863bitmanip.d | 11 +++ test/runnable/imports/std11863conv.d | 90 ++++++++++++++++++++++++ test/runnable/imports/std11863format.d | 13 ++++ test/runnable/test11863.d | 10 +++ 5 files changed, 140 insertions(+), 24 deletions(-) create mode 100644 test/runnable/imports/std11863bitmanip.d create mode 100644 test/runnable/imports/std11863conv.d create mode 100644 test/runnable/imports/std11863format.d create mode 100644 test/runnable/test11863.d diff --git a/src/glue.c b/src/glue.c index a6e783388402..f4aa87441d3a 100644 --- a/src/glue.c +++ b/src/glue.c @@ -647,6 +647,20 @@ void FuncDeclaration::toObjFile(int multiobj) } } + if (isNested()) + { + /* The enclosing function must have its code generated first, + * so defer this code generation until ancestors are completed. + */ + FuncDeclaration *fd = toAliasFunc(); + FuncDeclaration *fdp = fd->toParent2()->isFuncDeclaration(); + if (fdp && fdp->semanticRun < PASSobj) + { + fdp->deferred.push(fd); + return; + } + } + // start code generation semanticRun = PASSobj; @@ -696,31 +710,9 @@ void FuncDeclaration::toObjFile(int multiobj) if (isNested()) { - -// if (!(config.flags3 & CFG3pic)) -// s->Sclass = SCstatic; + //if (!(config.flags3 & CFG3pic)) + // s->Sclass = SCstatic; f->Fflags3 |= Fnested; - - /* The enclosing function must have its code generated first, - * so we know things like where its local symbols are stored. - */ - FuncDeclaration *fdp = toAliasFunc()->toParent2()->isFuncDeclaration(); - // Bug 8016 - only include the function if it is a template instance - Dsymbol * owner = NULL; - if (fdp) - { - //printf("fdp = %s %s\n", fdp->kind(), fdp->toChars()); - owner = fdp->toParent2(); - if (owner && fdp->semanticRun == PASSsemantic3done && - !fdp->isUnitTestDeclaration()) - { - /* Can't do unittest's out of order, they are order dependent in that their - * execution is done in lexical order, and some modules (std.datetime *cough* - * *cough*) rely on this. - */ - fdp->toObjFile(multiobj); - } - } } else { diff --git a/test/runnable/imports/std11863bitmanip.d b/test/runnable/imports/std11863bitmanip.d new file mode 100644 index 000000000000..4f8e33e500c9 --- /dev/null +++ b/test/runnable/imports/std11863bitmanip.d @@ -0,0 +1,11 @@ +module imports.std11863bitmanip; + +import imports.std11863format : FormatSpec; + +struct BitArray +{ + void toString(scope void delegate(const(char)[]) sink, + FormatSpec!char fmt) const + { + } +} diff --git a/test/runnable/imports/std11863conv.d b/test/runnable/imports/std11863conv.d new file mode 100644 index 000000000000..d28a96320c8c --- /dev/null +++ b/test/runnable/imports/std11863conv.d @@ -0,0 +1,90 @@ +module imports.std11863conv; + +import imports.std11863format; + +template to(T) +{ + T to(A...)(A args) + { + return toImpl!T(args); + } +} + +T toImpl(T, S)(S value) +{ + static if (is(S == int) && is(T == string)) + { + // other integral-to-string conversions with default radix + return toImpl!(T, S)(value, 10); + } + else + static assert(0); +} + +@trusted pure T toImpl(T, S)(S value, uint radix/*, LetterCase letterCase = LetterCase.upper*/) +{ + static assert(is(S == int) && is(T == string)); + + alias EEType = char/*Unqual!(typeof(T.init[0]))*/; + + T toStringRadixConvert(size_t bufLen, uint radix = 0, bool neg = false)(uint runtimeRadix = 0) + { + static if (neg) + ulong div = void, mValue = cast(uint)(-value); + else + uint/*Unsigned!(Unqual!S)*/ div = void, mValue = cast(uint)(value); + + size_t index = bufLen; + EEType[bufLen] buffer = void; + char baseChar = /*letterCase == LetterCase.lower ? 'a' : */'A'; + char mod = void; + + do + { + static if (radix == 0) + { + div = cast(S)(mValue / runtimeRadix ); + mod = cast(ubyte)(mValue % runtimeRadix); + mod += mod < 10 ? '0' : baseChar - 10; + } + else static if (radix > 10) + { + div = cast(S)(mValue / radix ); + mod = cast(ubyte)(mValue % radix); + mod += mod < 10 ? '0' : baseChar - 10; + } + else + { + div = cast(S)(mValue / radix); + mod = mValue % radix + '0'; + } + buffer[--index] = cast(char)mod; + mValue = div; + } while (mValue); + + static if (neg) + { + buffer[--index] = '-'; + } + return cast(T)buffer[index .. $].dup; + } + + //enforce(radix >= 2 && radix <= 36, new ConvException("Radix error")); + + switch(radix) + { + case 10: + if (value < 0) + return toStringRadixConvert!(S.sizeof * 3 + 1, 10, true)(); + else + return toStringRadixConvert!(S.sizeof * 3, 10)(); + //case 16: + // return toStringRadixConvert!(S.sizeof * 2, 16)(); + //case 2: + // return toStringRadixConvert!(S.sizeof * 8, 2)(); + //case 8: + // return toStringRadixConvert!(S.sizeof * 3, 8)(); + default: + assert(0);//return toStringRadixConvert!(S.sizeof * 6)(radix); + } +} diff --git a/test/runnable/imports/std11863format.d b/test/runnable/imports/std11863format.d new file mode 100644 index 000000000000..9ae720928d54 --- /dev/null +++ b/test/runnable/imports/std11863format.d @@ -0,0 +1,13 @@ +module imports.std11863format; + +import imports.std11863bitmanip; +import imports.std11863conv; + +struct FormatSpec(Char) +{ + string toString() + { + // text(width) + return to!string(1); // instantiate toImpl!(string, int) + } +} diff --git a/test/runnable/test11863.d b/test/runnable/test11863.d new file mode 100644 index 000000000000..ab9f06dbafde --- /dev/null +++ b/test/runnable/test11863.d @@ -0,0 +1,10 @@ +// COMPILE_SEPARATELY +// EXTRA_SOURCES: imports/std11863conv.d + +import imports.std11863conv; + +void main() +{ + auto s = to!string(15, 10); + assert(s == "15"); // failure +}