Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion lib/elixir/lib/regex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,9 @@ defmodule Regex do

pattern_ast =
cond do
is_nil(regex.re_pattern) ->
nil

# TODO: Remove this when we require Erlang/OTP 28+
# Before OTP 28.0, patterns did not contain any refs and could be safely be escaped
:erlang.system_info(:otp_release) < [?2, ?8] ->
Expand All @@ -1018,8 +1021,10 @@ defmodule Regex do
{:ok, exported} = :re.compile(regex.source, [:export] ++ regex.opts)

quote do
:re.import(unquote(Macro.escape(exported)))
Regex.__import_pattern__(unquote(Macro.escape(exported)))
end
# we now that the Regex module is defined at this stage, so this macro can be safely called
|> Macro.update_meta(&([required: true] ++ &1))

# TODO: Remove this when we require Erlang/OTP 28.1+
# OTP 28.0 works in degraded mode performance-wise, we need to recompile from the source
Expand All @@ -1041,4 +1046,15 @@ defmodule Regex do
}
end
end

@doc false
defmacro __import_pattern__(pattern) do
if __CALLER__.context in [:match, :guard] do
raise ArgumentError, "escaped Regex structs are not allowed in match or guards"
end

quote do
:re.import(unquote(pattern))
end
end
end
3 changes: 2 additions & 1 deletion lib/elixir/test/elixir/macro_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ defmodule MacroTest do
[
__struct__: Regex,
re_pattern:
{{:., [], [:re, :import]}, [], [{:{}, [], [:re_exported_pattern | _]}]},
{{:., [], [{:__aliases__, _, [:Regex]}, :__import_pattern__]},
[required: true], [{:{}, [], [:re_exported_pattern | _]}]},
source: "foo",
opts: []
]
Expand Down
19 changes: 19 additions & 0 deletions lib/elixir/test/elixir/regex_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ defmodule RegexTest do
end
end

@tag :re_import
test "module attribute in match context" do
assert_raise(
ArgumentError,
~r/escaped Regex structs are not allowed in match or guards/,
fn ->
Code.eval_quoted(
quote do
defmodule ModAttrGuard do
@regex ~r/example/
def example?(@regex), do: true
def example?(_), do: false
end
end
)
end
)
end

test "multiline" do
refute Regex.match?(~r/^b$/, "a\nb\nc")
assert Regex.match?(~r/^b$/m, "a\nb\nc")
Expand Down