From 5cc7fc5fb22089a8e8821e7a72adc763c570bee0 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 2 Feb 2019 22:31:16 +0100 Subject: [PATCH] std.regex: Fix reassignment of ctRegex wrapper structs Previously, reassigning such a wrapper resulted in the static immutable Regex!Char global for that pattern (`staticRe`) to be overwritten by the global for the new pattern (!). Made possible via alias this and the logical-const hack. Proposed fix: keep on allowing reassignments (people are already using them), but just point to another pattern's global. So use a common Wrapper struct type wrapping a pointer instead of an empty struct type per pattern. Bug reported in https://github.com/ldc-developers/ldc/issues/2961. --- std/regex/package.d | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/std/regex/package.d b/std/regex/package.d index 2f8ea0cbf..15dee8c18 100644 --- a/std/regex/package.d +++ b/std/regex/package.d @@ -423,6 +423,16 @@ if (isSomeString!(S)) } +private struct CTRegexWrapper(Char) +{ + private immutable(Regex!Char)* re; + + // allow code that expects mutable Regex to still work + // we stay "logically const" + @property @trusted ref getRe() const { return *cast(Regex!Char*) re; } + alias getRe this; +} + template ctRegexImpl(alias pattern, string flags=[]) { import std.regex.internal.backtracking, std.regex.internal.parser; @@ -437,14 +447,7 @@ template ctRegexImpl(alias pattern, string flags=[]) } static immutable staticRe = cast(immutable) r.withFactory(new CtfeFactory!(BacktrackingMatcher, Char, func)); - struct Wrapper - { - // allow code that expects mutable Regex to still work - // we stay "logically const" - @property @trusted ref getRe() const { return *cast(Regex!Char*)&staticRe; } - alias getRe this; - } - enum wrapper = Wrapper(); + enum wrapper = CTRegexWrapper!Char(&staticRe); } @safe unittest @@ -457,6 +460,17 @@ template ctRegexImpl(alias pattern, string flags=[]) test(re); } +@safe unittest +{ + auto re = ctRegex!`foo`; + assert(matchFirst("foo", re)); + + // test reassignment + re = ctRegex!`bar`; + assert(matchFirst("bar", re)); + assert(!matchFirst("bar", ctRegex!`foo`)); +} + /++ Compile regular expression using CTFE and generate optimized native machine code for matching it.