diff --git a/lib/elixir/lib/system.ex b/lib/elixir/lib/system.ex index d6931db41f..a7478a21d9 100644 --- a/lib/elixir/lib/system.ex +++ b/lib/elixir/lib/system.ex @@ -450,7 +450,7 @@ defmodule System do # TODO: Fully deprecate it on Elixir v1.9. # It is currently partially deprecated in elixir_dispatch.erl def stacktrace do - :erlang.get_stacktrace() + apply(:erlang, :get_stacktrace, []) end @doc """ diff --git a/lib/elixir/src/elixir.erl b/lib/elixir/src/elixir.erl index 2b77a5ba22..92c6395366 100644 --- a/lib/elixir/src/elixir.erl +++ b/lib/elixir/src/elixir.erl @@ -255,7 +255,7 @@ eval_forms(Tree, Binding, Env, Scope) -> % Below must be all one line for locations to be the same % when the stacktrace is extended to the full stacktrace. {value, Value, NewBinding} = - try erl_eval:expr(Erl, ParsedBinding, none, none, none) catch Class:Exception -> erlang:raise(Class, Exception, get_stacktrace(erlang:get_stacktrace())) end, + try erl_eval:expr(Erl, ParsedBinding, none, none, none) catch ?WITH_STACKTRACE(Class, Exception, Stacktrace) erlang:raise(Class, Exception, get_stacktrace(Stacktrace)) end, {Value, elixir_erl_var:dump_binding(NewBinding, NewScope), NewEnv, NewScope} end. @@ -266,10 +266,9 @@ get_stacktrace(Stacktrace) -> try throw(stack) catch - throw:stack -> + ?WITH_STACKTRACE(throw, stack, CurrentStack) % Ignore stack item for current function. - [_ | CurrentStack] = erlang:get_stacktrace(), - merge_stacktrace(Stacktrace, CurrentStack) + merge_stacktrace(Stacktrace, tl(CurrentStack)) end. % The stacktrace did not include the current stack, re-add it. diff --git a/lib/elixir/src/elixir.hrl b/lib/elixir/src/elixir.hrl index 146ecc43f5..337ac14e36 100644 --- a/lib/elixir/src/elixir.hrl +++ b/lib/elixir/src/elixir.hrl @@ -39,3 +39,10 @@ mismatch_hints=[], warn_on_unnecessary_quotes=true }). + +%% TODO: Remove this once we support Erlang/OTP 21+ exclusively. +-ifdef(OTP_RELEASE). %% defined on OTP 21+ +-define(WITH_STACKTRACE(K, R, S), K:R:S ->). +-else. +-define(WITH_STACKTRACE(K, R, S), K:R -> S = erlang:get_stacktrace(),). +-endif. diff --git a/lib/elixir/src/elixir_compiler.erl b/lib/elixir/src/elixir_compiler.erl index bd6d17d778..7a71103449 100644 --- a/lib/elixir/src/elixir_compiler.erl +++ b/lib/elixir/src/elixir_compiler.erl @@ -123,8 +123,8 @@ bootstrap_file(File) -> _ = [binary_to_path(X, "lib/elixir/ebin") || X <- Lists], io:format("Compiled ~ts~n", [File]) catch - Kind:Reason -> - io:format("~p: ~p~nstacktrace: ~p~n", [Kind, Reason, erlang:get_stacktrace()]), + ?WITH_STACKTRACE(Kind, Reason, Stacktrace) + io:format("~p: ~p~nstacktrace: ~p~n", [Kind, Reason, Stacktrace]), erlang:halt(1) end. diff --git a/lib/elixir/src/elixir_dispatch.erl b/lib/elixir/src/elixir_dispatch.erl index 5006441143..c2550d7aa8 100644 --- a/lib/elixir/src/elixir_dispatch.erl +++ b/lib/elixir/src/elixir_dispatch.erl @@ -185,8 +185,7 @@ expand_macro_fun(Meta, Fun, Receiver, Name, Args, E) -> try apply(Fun, [EArg | Args]) catch - Kind:Reason -> - Stacktrace = erlang:get_stacktrace(), + ?WITH_STACKTRACE(Kind, Reason, Stacktrace) Arity = length(Args), MFA = {Receiver, elixir_utils:macro_name(Name), Arity+1}, Info = [{Receiver, Name, Arity, [{file, "expanding macro"}]}, caller(Line, E)], @@ -208,8 +207,7 @@ expand_quoted(Meta, Receiver, Name, Arity, Quoted, E) -> elixir_quote:linify_with_context_counter(Line, {Receiver, Next}, Quoted), E) catch - Kind:Reason -> - Stacktrace = erlang:get_stacktrace(), + ?WITH_STACKTRACE(Kind, Reason, Stacktrace) MFA = {Receiver, elixir_utils:macro_name(Name), Arity+1}, Info = [{Receiver, Name, Arity, [{file, "expanding macro"}]}, caller(Line, E)], erlang:raise(Kind, Reason, prune_stacktrace(Stacktrace, MFA, Info, error)) diff --git a/lib/elixir/src/elixir_errors.erl b/lib/elixir/src/elixir_errors.erl index 814b0a56d0..24805cdb1f 100644 --- a/lib/elixir/src/elixir_errors.erl +++ b/lib/elixir/src/elixir_errors.erl @@ -145,6 +145,6 @@ raise(none, File, Kind, Message) -> raise({Line, _, _}, File, Kind, Message) when is_integer(Line) -> raise(Line, File, Kind, Message); raise(Line, File, Kind, Message) when is_integer(Line), is_binary(File), is_binary(Message) -> - Stacktrace = try throw(ok) catch ok -> erlang:get_stacktrace() end, + Stacktrace = try throw(ok) catch ?WITH_STACKTRACE(_, _, Stack) Stack end, Exception = Kind:exception([{description, Message}, {file, File}, {line, Line}]), erlang:raise(error, Exception, tl(Stacktrace)). diff --git a/lib/elixir/src/elixir_map.erl b/lib/elixir/src/elixir_map.erl index c6cc6e4982..27b64c3c88 100644 --- a/lib/elixir/src/elixir_map.erl +++ b/lib/elixir/src/elixir_map.erl @@ -155,13 +155,6 @@ load_struct(Meta, Name, Args, InContext, E) -> erlang:raise(Kind, Reason, Info) end. -prune_stacktrace([{Module, '__struct__', Arity, _} | _], Module, Arity) -> - []; -prune_stacktrace([H | T], Module, Arity) -> - [H | prune_stacktrace(T, Module, Arity)]; -prune_stacktrace([], _Module, _Arity) -> - []. - ensure_loaded(Module) -> code:ensure_loaded(Module) == {module, Module}. diff --git a/lib/elixir/src/elixir_module.erl b/lib/elixir/src/elixir_module.erl index 375403fd5c..5fc7ecc2ea 100644 --- a/lib/elixir/src/elixir_module.erl +++ b/lib/elixir/src/elixir_module.erl @@ -123,8 +123,8 @@ compile(Line, Module, Block, Vars, E) -> make_module_available(Module, Binary), {module, Module, Binary, Result} catch - error:undef -> - case erlang:get_stacktrace() of + ?WITH_STACKTRACE(error, undef, Stacktrace) + case Stacktrace of [{Module, Fun, Args, _Info} | _] = Stack when is_list(Args) -> compile_undef(Module, Fun, length(Args), Stack); [{Module, Fun, Arity, _Info} | _] = Stack -> @@ -332,8 +332,7 @@ expand_callback(Line, M, F, Args, E, Fun) -> {_Value, _Binding, EF, _S} = elixir:eval_forms(EE, [], ET), EF catch - Kind:Reason -> - Stacktrace = erlang:get_stacktrace(), + ?WITH_STACKTRACE(Kind, Reason, Stacktrace) Info = {M, F, length(Args), location(Line, E)}, erlang:raise(Kind, Reason, prune_stacktrace(Info, Stacktrace)) end