From 98aa8bd0dfe3cbc2988e0c3c70ea4728c331e983 Mon Sep 17 00:00:00 2001 From: Sebastian Wilzbach Date: Thu, 20 Jul 2017 21:54:43 +0200 Subject: [PATCH 1/6] Fix bookmark table for std.functional --- std/functional.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/functional.d b/std/functional.d index 128c89c58..e478cecb9 100644 --- a/std/functional.d +++ b/std/functional.d @@ -23,7 +23,7 @@ $(TR $(TH Function Name) $(TH Description) $(TR $(TD $(LREF forward)) $(TD Forwards function arguments while saving ref-ness. )) - $(TR $(TD $(LREF lessThan)), $(LREF greaterThan)), $(D $(LREF equalTo) + $(TR $(TD $(LREF lessThan), $(LREF greaterThan), $(LREF equalTo)) $(TD Ready-made predicate functions to compare two values. )) $(TR $(TD $(LREF memoize)) From afcf16e1d87c55df207207d4727661ba7e5c9c59 Mon Sep 17 00:00:00 2001 From: Sebastian Wilzbach Date: Fri, 21 Jul 2017 03:42:02 +0200 Subject: [PATCH 2/6] std.functional: Fix more DDoc links --- std/functional.d | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/functional.d b/std/functional.d index e478cecb9..dd7a0740d 100644 --- a/std/functional.d +++ b/std/functional.d @@ -15,7 +15,7 @@ $(TR $(TH Function Name) $(TH Description) $(TD Joins a couple of functions into one that executes the original functions independently and returns a tuple with all the results. )) - $(TR $(TD $(LREF compose)), $(LREF pipe) + $(TR $(TD $(LREF compose), $(LREF pipe)) $(TD Join a couple of functions into one that executes the original functions one after the other, using one function's result for the next function's argument. @@ -36,13 +36,13 @@ $(TR $(TH Function Name) $(TH Description) $(TD Creates a function that binds the first argument of a given function to a given value. )) - $(TR $(TD $(LREF reverseArgs)), $(LREF binaryReverseArgs) + $(TR $(TD $(LREF reverseArgs), $(LREF binaryReverseArgs)) $(TD Predicate that reverses the order of its arguments. )) $(TR $(TD $(LREF toDelegate)) $(TD Converts a callable to a delegate. )) - $(TR $(TD $(LREF unaryFun)), $(LREF binaryFun) + $(TR $(TD $(LREF unaryFun), $(LREF binaryFun)) $(TD Create a unary or binary function from a string. Most often used when defining algorithms on ranges. )) From 42c0d79e5a405e12bae3b6ae642c9b2a1e2bf06e Mon Sep 17 00:00:00 2001 From: Dmitry Olshansky Date: Wed, 26 Jul 2017 14:35:32 +0300 Subject: [PATCH 3/6] Fix issue 17667 - regex([r".", r"[\(\{[\]\}\)]"]); --- std/regex/internal/parser.d | 28 ++++++++++++++++++++++++---- std/regex/internal/tests.d | 16 ++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/std/regex/internal/parser.d b/std/regex/internal/parser.d index 6498bddb7..0a1ecdec0 100644 --- a/std/regex/internal/parser.d +++ b/std/regex/internal/parser.d @@ -1182,6 +1182,8 @@ if (isForwardRange!R && is(ElementType!R : dchar)) state = State.Start; break; default: + if (current >= privateUseStart && current <= privateUseEnd) + enforce(false, "no matching ']' found while parsing character class"); enforce(false, "invalid escape sequence"); } break; @@ -1256,8 +1258,17 @@ if (isForwardRange!R && is(ElementType!R : dchar)) end = parseUniHex(pat, 8); break; default: + if (current >= privateUseStart && current <= privateUseEnd) + enforce(false, "no matching ']' found while parsing character class"); error("invalid escape sequence"); } + // Lookahead to check if it's a \T + // where T is sub-pattern terminator in multi-pattern scheme + if (end == '\\' && !pat.empty) + { + if (pat.front >= privateUseStart && pat.front <= privateUseEnd) + enforce(false, "invalid escape sequence"); + } enforce(last <= end,"inverted range"); set.add(last, end + 1); state = State.Start; @@ -1364,8 +1375,7 @@ if (isForwardRange!R && is(ElementType!R : dchar)) "character class syntax error"); enforce(!opstack.empty, "unmatched ']'"); opstack.pop(); - next(); - if (opstack.empty) + if (!next() || opstack.empty) break L_CharsetLoop; auto pair = parseCharTerm(); if (!pair[0].empty)//not only operator e.g. -- or ~~ @@ -1390,10 +1400,13 @@ if (isForwardRange!R && is(ElementType!R : dchar)) } vstack.push(pair[0]); } - }while (!empty || !opstack.empty); while (!opstack.empty) - apply(opstack.pop(),vstack); + { + enforce(opstack.top != Operator.Open, + "no matching ']' found while parsing character class"); + apply(opstack.pop(), vstack); + } assert(vstack.length == 1); g.charsetToIr(vstack.top); } @@ -1483,6 +1496,13 @@ if (isForwardRange!R && is(ElementType!R : dchar)) g.markBackref(nref); break; default: + // Lookahead to check if it's a \T + // where T is sub-pattern terminator in multi-pattern scheme + if (current == '\\' && !pat.empty) + { + if (pat.front >= privateUseStart && current <= privateUseEnd) + enforce(false, "invalid escape sequence"); + } if (current >= privateUseStart && current <= privateUseEnd) { g.endPattern(current - privateUseStart + 1); diff --git a/std/regex/internal/tests.d b/std/regex/internal/tests.d index 80e278bf6..5415f45b4 100644 --- a/std/regex/internal/tests.d +++ b/std/regex/internal/tests.d @@ -1082,3 +1082,19 @@ alias Sequence(int B, int E) = staticIota!(B, E); assert(equal!equal(s.matchAll(ctr), outcomes)); assert(equal!equal(s.bmatch(r), outcomes)); } + +// bugzilla 17667 +@safe unittest +{ + import std.algorithm.searching : canFind; + void willThrow(T)(T arg, string msg) + { + auto e = collectException(regex(arg)); + assert(e.msg.canFind(msg), e.msg); + } + willThrow([r".", r"[\(\{[\]\}\)]"], "no matching ']' found while parsing character class"); + willThrow([r"[\", r"123"], "no matching ']' found while parsing character class"); + willThrow([r"[a-", r"123"], "no matching ']' found while parsing character class"); + willThrow([r"[a-\", r"123"], "invalid escape sequence"); + willThrow([r"\", r"123"], "invalid escape sequence"); +} From 2e063e92469bcbda9171ba6dea45a3c158810ae6 Mon Sep 17 00:00:00 2001 From: anonymous Date: Wed, 2 Aug 2017 22:18:08 +0200 Subject: [PATCH 4/6] fix issue 17192 - ParameterDefaults fails when parameter is called "i" --- std/traits.d | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/std/traits.d b/std/traits.d index e53fc8f76..616ad711a 100644 --- a/std/traits.d +++ b/std/traits.d @@ -1226,20 +1226,32 @@ If a parameter doesn't have the default value, $(D void) is returned instead. template ParameterDefaults(func...) if (func.length == 1 && isCallable!func) { + alias param_names = ParameterIdentifierTuple!func; static if (is(FunctionTypeOf!(func[0]) PT == __parameters)) { template Get(size_t i) { - // workaround scope escape check, see - // https://issues.dlang.org/show_bug.cgi?id=16582 - // should use return scope once available - enum get = (PT[i .. i+1] __args) @trusted - { - // If __args[0] is lazy, we force it to be evaluated like this. - PT[i] __pd_value = __args[0]; - PT[i]* __pd_val = &__pd_value; // workaround Bugzilla 16582 - return *__pd_val; - }; + // `PT[i .. i+1]` declares a parameter with an arbitrary name. + // To avoid a name clash, generate local names that are distinct + // from the parameter name, and mix them in. + enum name = param_names[i]; + enum args = "args" ~ (name == "args" ? "_" : ""); + enum val = "val" ~ (name == "val" ? "_" : ""); + enum ptr = "ptr" ~ (name == "ptr" ? "_" : ""); + mixin(" + // workaround scope escape check, see + // https://issues.dlang.org/show_bug.cgi?id=16582 + // should use return scope once available + enum get = (PT[i .. i+1] " ~ args ~ ") @trusted + { + // If the parameter is lazy, we force it to be evaluated + // like this. + auto " ~ val ~ " = " ~ args ~ "[0]; + auto " ~ ptr ~ " = &" ~ val ~ "; + // workaround Bugzilla 16582 + return *" ~ ptr ~ "; + }; + "); static if (is(typeof(get()))) enum Get = get(); else @@ -1277,6 +1289,17 @@ template ParameterDefaults(func...) static assert( ParameterDefaults!foo[3] == 0); } +unittest // issue 17192 +{ + static void func(int i, int PT, int __pd_value, int __pd_val, int __args, + int name, int args, int val, int ptr, int args_, int val_, int ptr_) + { + } + alias Voids = ParameterDefaults!func; + static assert(Voids.length == 12); + foreach (V; Voids) static assert(is(V == void)); +} + /** * Alternate name for $(LREF ParameterDefaults), kept for legacy compatibility. */ From ba15802664b806ffc2a56e2ef1cec4f6ce523dac Mon Sep 17 00:00:00 2001 From: Dmitry Olshansky Date: Wed, 26 Jul 2017 14:36:04 +0300 Subject: [PATCH 5/6] Fix issue 17668 - assert failure regex(q"<[^]>") --- std/regex/internal/parser.d | 1 + std/regex/internal/tests.d | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/std/regex/internal/parser.d b/std/regex/internal/parser.d index 0a1ecdec0..e235292c6 100644 --- a/std/regex/internal/parser.d +++ b/std/regex/internal/parser.d @@ -1304,6 +1304,7 @@ if (isForwardRange!R && is(ElementType!R : dchar)) switch (op) { case Operator.Negate: + enforce(!stack.empty, "no operand for '^'"); stack.top = stack.top.inverted; break; case Operator.Union: diff --git a/std/regex/internal/tests.d b/std/regex/internal/tests.d index 5415f45b4..1d4f9a26a 100644 --- a/std/regex/internal/tests.d +++ b/std/regex/internal/tests.d @@ -1098,3 +1098,11 @@ alias Sequence(int B, int E) = staticIota!(B, E); willThrow([r"[a-\", r"123"], "invalid escape sequence"); willThrow([r"\", r"123"], "invalid escape sequence"); } + +// bugzilla 17668 +@safe unittest +{ + import std.algorithm.searching; + auto e = collectException!RegexException(regex(q"<[^]>")); + assert(e.msg.canFind("no operand for '^'")); +} From 477c4ea6d88925af6f2b2617ca7e121e16d3383d Mon Sep 17 00:00:00 2001 From: Martin Nowak Date: Wed, 16 Aug 2017 12:12:30 +0200 Subject: [PATCH 6/6] safe unittest --- std/traits.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/traits.d b/std/traits.d index 616ad711a..6c37b3ad6 100644 --- a/std/traits.d +++ b/std/traits.d @@ -1289,7 +1289,7 @@ template ParameterDefaults(func...) static assert( ParameterDefaults!foo[3] == 0); } -unittest // issue 17192 +@safe unittest // issue 17192 { static void func(int i, int PT, int __pd_value, int __pd_val, int __args, int name, int args, int val, int ptr, int args_, int val_, int ptr_)