From d8fa79149a1339b2359ecc981f992bd53e5a9d18 Mon Sep 17 00:00:00 2001
From: Anthony Ramine <n.oxyde@gmail.com>
Date: Wed, 25 Mar 2015 13:59:26 +0100
Subject: Properly report unknown parse transforms

We don't want undef errors coming from the parse transform itself to be confused
with undef errors caused by the absence of the parse transform.

Reported-by: Klas Johansson
---
 lib/compiler/src/compile.erl      | 51 ++++++++++++++++++++++-----------------
 lib/compiler/test/error_SUITE.erl | 12 +++++++--
 2 files changed, 39 insertions(+), 24 deletions(-)

(limited to 'lib')

diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index c7d91070f6..60311ef002 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -906,28 +906,35 @@ transform_module(#compile{options=Opt,code=Code0}=St0) ->
 
 foldl_transform(St, [T|Ts]) ->
     Name = "transform " ++ atom_to_list(T),
-    Fun = fun(S) -> T:parse_transform(S#compile.code, S#compile.options) end,
-    Run = case member(time, St#compile.options) of
-	      true  -> fun run_tc/2;
-	      false -> fun({_Name,F}, S) -> catch F(S) end
-	  end,
-    case Run({Name, Fun}, St) of
-	{error,Es,Ws} ->
-	    {error,St#compile{warnings=St#compile.warnings ++ Ws,
-			      errors=St#compile.errors ++ Es}};
-	{'EXIT',{undef,_}} ->
-	    Es = [{St#compile.ifile,[{none,compile,
-				      {undef_parse_transform,T}}]}],
-	    {error,St#compile{errors=St#compile.errors ++ Es}};
-	{'EXIT',R} ->
-	    Es = [{St#compile.ifile,[{none,compile,{parse_transform,T,R}}]}],
-	    {error,St#compile{errors=St#compile.errors ++ Es}};
-	{warning, Forms, Ws} ->
-	    foldl_transform(
-	      St#compile{code=Forms,
-			 warnings=St#compile.warnings ++ Ws}, Ts);
-	Forms ->
-	    foldl_transform(St#compile{code=Forms}, Ts)
+    case code:ensure_loaded(T) =:= {module,T} andalso
+                erlang:function_exported(T, parse_transform, 2) of
+        true ->
+            Fun = fun(S) ->
+                         T:parse_transform(S#compile.code, S#compile.options)
+                  end,
+            Run = case member(time, St#compile.options) of
+                      true  -> fun run_tc/2;
+                      false -> fun({_Name,F}, S) -> catch F(S) end
+                  end,
+            case Run({Name, Fun}, St) of
+                {error,Es,Ws} ->
+                    {error,St#compile{warnings=St#compile.warnings ++ Ws,
+                                      errors=St#compile.errors ++ Es}};
+                {'EXIT',R} ->
+                    Es = [{St#compile.ifile,[{none,compile,
+                                              {parse_transform,T,R}}]}],
+                    {error,St#compile{errors=St#compile.errors ++ Es}};
+                {warning, Forms, Ws} ->
+                    foldl_transform(
+                      St#compile{code=Forms,
+                                 warnings=St#compile.warnings ++ Ws}, Ts);
+                Forms ->
+                    foldl_transform(St#compile{code=Forms}, Ts)
+            end;
+        false ->
+            Es = [{St#compile.ifile,[{none,compile,
+                                      {undef_parse_transform,T}}]}],
+            {error,St#compile{errors=St#compile.errors ++ Es}}
     end;
 foldl_transform(St, []) -> {ok,St}.
 
diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl
index bd877bb528..8e79b88821 100644
--- a/lib/compiler/test/error_SUITE.erl
+++ b/lib/compiler/test/error_SUITE.erl
@@ -235,10 +235,18 @@ transforms(Config) ->
              ">>,
     {error,[{none,compile,{parse_transform,?MODULE,{too_bad,_}}}],[]} =
 	run_test(Ts2, test_filename(Config), [], dont_write_beam),
+    Ts3 = <<"
+              -compile({parse_transform,",?MODULE_STRING,"}).
+             ">>,
+    {error,[{none,compile,{parse_transform,?MODULE,{undef,_}}}],[]} =
+        run_test(Ts3, test_filename(Config), [call_undef], dont_write_beam),
     ok.
 
-parse_transform(_, _) ->
-    error(too_bad).
+parse_transform(_, Opts) ->
+    case lists:member(call_undef, Opts) of
+        false -> error(too_bad);
+        true -> camembert:délicieux()
+    end.
 
 
 forbidden_maps(Config) when is_list(Config) ->
-- 
cgit v1.2.3