https://gcc.gnu.org/g:1ad1bcc991b32d72d4de4758c0dcac611f20cda8
commit r15-8275-g1ad1bcc991b32d72d4de4758c0dcac611f20cda8 Author: Iain Buclaw <ibuc...@gdcproject.org> Date: Tue Mar 18 19:15:40 2025 +0100 libphobos: Fix std.getopt doesn't accept const(string)[] anymore Instead of passing receiver into the conversion function, just return the value and assign it to the receiver. Renamed the conversion function and also cleaned up all the `typeof' calls, which were very verbose. libphobos/ChangeLog: * src/MERGE: Merge upstream phobos 79cbde1ab. Reviewed-on: https://github.com/dlang/phobos/pull/10684 Diff: --- libphobos/src/MERGE | 2 +- libphobos/src/std/getopt.d | 73 +++++++++++++++++++++++++--------------------- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 93b7a4d1ac2c..a4888fc96180 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -cafe8645336bfc60be03b5a558164b3bc7df79ef +79cbde1ab69bae9372f310d663edfc43166095e3 The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/std/getopt.d b/libphobos/src/std/getopt.d index 1a9072207f5d..fc5cdac73cec 100644 --- a/libphobos/src/std/getopt.d +++ b/libphobos/src/std/getopt.d @@ -610,14 +610,14 @@ private template optionValidator(A...) alias optionValidator = message; } -private void handleConversion(R)(string option, string value, R* receiver, +private auto getoptTo(R)(string option, string value, size_t idx, string file = __FILE__, size_t line = __LINE__) { import std.conv : to, ConvException; import std.format : format; try { - *receiver = to!(typeof(*receiver))(value); + return to!R(value); } catch (ConvException e) { @@ -876,12 +876,18 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, // (and potentially args[i + 1] too, but that comes later) args = args[0 .. i] ~ args[i + 1 .. $]; - static if (is(typeof(*receiver) == bool)) + static if (is(typeof(*receiver))) + alias Target = typeof(*receiver); + else + // delegate + alias Target = void; + + static if (is(Target == bool)) { if (val.length) { // parse '--b=true/false' - handleConversion(option, val, receiver, i); + *receiver = getoptTo!(Target)(option, val, i); } else { @@ -894,23 +900,23 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, import std.exception : enforce; // non-boolean option, which might include an argument enum isCallbackWithLessThanTwoParameters = - (is(typeof(receiver) == delegate) || is(typeof(*receiver) == function)) && + (is(R == delegate) || is(Target == function)) && !is(typeof(receiver("", ""))); if (!isCallbackWithLessThanTwoParameters && !(val.length) && !incremental) { // Eat the next argument too. Check to make sure there's one // to be eaten first, though. enforce!GetOptException(i < args.length, - "Missing value for argument " ~ a ~ "."); + "Missing value for argument " ~ a ~ "."); val = args[i]; args = args[0 .. i] ~ args[i + 1 .. $]; } - static if (is(typeof(*receiver) == enum) || - is(typeof(*receiver) == string)) + static if (is(Target == enum) || + is(Target == string)) { - handleConversion(option, val, receiver, i); + *receiver = getoptTo!Target(option, val, i); } - else static if (is(typeof(*receiver) : real)) + else static if (is(Target : real)) { // numeric receiver if (incremental) @@ -919,16 +925,16 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, } else { - handleConversion(option, val, receiver, i); + *receiver = getoptTo!Target(option, val, i); } } - else static if (is(typeof(*receiver) == string)) + else static if (is(Target == string)) { // string receiver - *receiver = to!(typeof(*receiver))(val); + *receiver = getoptTo!(Target)(option, val, i); } - else static if (is(typeof(receiver) == delegate) || - is(typeof(*receiver) == function)) + else static if (is(R == delegate) || + is(Target == function)) { static if (is(typeof(receiver("", "")) : void)) { @@ -952,29 +958,25 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, receiver(); } } - else static if (isArray!(typeof(*receiver))) + else static if (isArray!(Target)) { // array receiver import std.range : ElementEncodingType; - alias E = ElementEncodingType!(typeof(*receiver)); + alias E = ElementEncodingType!(Target); if (arraySep == "") { - E tmp; - handleConversion(option, val, &tmp, i); - *receiver ~= tmp; + *receiver ~= getoptTo!E(option, val, i); } else { foreach (elem; val.splitter(arraySep)) { - E tmp; - handleConversion(option, elem, &tmp, i); - *receiver ~= tmp; + *receiver ~= getoptTo!E(option, elem, i); } } } - else static if (isAssociativeArray!(typeof(*receiver))) + else static if (isAssociativeArray!(Target)) { // hash receiver alias K = typeof(receiver.keys[0]); @@ -991,14 +993,7 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, ~ to!string(assignChar) ~ "' in argument '" ~ input ~ "'."); auto key = input[0 .. j]; auto value = input[j + 1 .. $]; - - K k; - handleConversion("", key, &k, 0); - - V v; - handleConversion("", value, &v, 0); - - return tuple(k,v); + return tuple(getoptTo!K("", key, 0), getoptTo!V("", value, 0)); } static void setHash(Range)(R receiver, Range range) @@ -1013,7 +1008,7 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, setHash(receiver, val.splitter(arraySep)); } else - static assert(false, "getopt does not know how to handle the type " ~ typeof(receiver).stringof); + static assert(false, "getopt does not know how to handle the type " ~ R.stringof); } } @@ -1099,6 +1094,18 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, assert(values == ["foo":0, "bar":1, "baz":2], to!string(values)); } +// https://github.com/dlang/phobos/issues/10680 +@safe unittest +{ + arraySep = ","; + scope(exit) arraySep = ""; + const(string)[] s; + string[] args = ["program.name", "-s", "a", "-s", "b", "-s", "c,d,e"]; + getopt(args, "values|s", &s); + assert(s == ["a", "b", "c", "d", "e"]); +} + + /** The option character (default '-').