@@ -451,6 +451,13 @@ format_error_1({unbound_var,V,GuessV}) ->
451451format_error_1 ({unsafe_var ,V ,{What ,Where }}) ->
452452 {~ " variable ~w unsafe in ~w ~s " ,
453453 [V ,What ,format_where (Where )]};
454+ format_error_1 ({exported_subexpr_var ,V ,{What ,Where }}) ->
455+ {~ """
456+ variable ~w exported from ~w ~s .
457+ Exporting bindings from subexpressions is deprecated and
458+ may be removed in a future version of Erlang/OTP.
459+ You should move the binding of ~w before the ~w .
460+ """ , [V ,What ,format_where (Where ),V ,What ]};
454461format_error_1 ({exported_var ,V ,{What ,Where }}) ->
455462 {~ " variable ~w exported from ~w ~s " ,
456463 [V ,What ,format_where (Where )]};
@@ -2699,21 +2706,27 @@ expr({atom,Anno,A}, _Vt, St) ->
26992706 {[],keyword_warning (Anno , A , St )};
27002707expr ({string ,_Anno ,_S }, _Vt , St ) -> {[],St };
27012708expr ({nil ,_Anno }, _Vt , St ) -> {[],St };
2702- expr ({cons ,_Anno ,H ,T }, Vt , St ) ->
2703- expr_list ( [H ,T ], Vt , St );
2709+ expr ({cons ,Anno ,H ,T }, Vt , St ) ->
2710+ vtupd_export_expr_list ({ list , Anno }, [H , T ], Vt , St );
27042711expr ({lc ,_Anno ,E ,Qs }, Vt , St ) ->
27052712 handle_comprehension (E , Qs , Vt , St );
27062713expr ({bc ,_Anno ,E ,Qs }, Vt , St ) ->
27072714 handle_comprehension (E , Qs , Vt , St );
27082715expr ({mc ,_Anno ,E ,Qs }, Vt , St ) ->
27092716 handle_comprehension (E , Qs , Vt , St );
2710- expr ({tuple ,_Anno ,Es }, Vt , St ) ->
2711- expr_list (Es , Vt , St );
2712- expr ({map ,_Anno ,Es }, Vt , St ) ->
2713- map_fields (Es , Vt , check_assoc_fields (Es , St ), fun expr_list /3 );
2717+ expr ({tuple ,Anno ,Es }, Vt , St ) ->
2718+ vtupd_export_expr_list ({tuple , Anno }, Es , Vt , St );
2719+ expr ({map ,Anno ,Es }, Vt , St ) ->
2720+ map_fields (Es , Vt , check_assoc_fields (Es , St ),
2721+ fun (Es0 , Vt0 , St0 ) ->
2722+ vtupd_export_expr_list ({map , Anno }, Es0 , Vt0 , St0 )
2723+ end );
27142724expr ({map ,Anno ,Src ,Es }, Vt , St ) ->
2715- {Svt ,St1 } = expr (Src , Vt , St ),
2716- {Fvt ,St2 } = map_fields (Es , Vt , St1 , fun expr_list /3 ),
2725+ {Svt ,St1 } = vtupd_export_expr_list ({map , Anno }, [Src ], Vt , St ),
2726+ {Fvt ,St2 } = map_fields (Es , Vt , St1 ,
2727+ fun (Es0 , Vt0 , St0 ) ->
2728+ vtupd_export_expr_list ({map , Anno }, Es0 , Vt0 , St0 )
2729+ end ),
27172730 {vtupdate (Svt , Fvt ), warn_if_literal_update (Anno , Src , St2 )};
27182731expr ({record_index ,Anno ,Name ,Field }, _Vt , St ) ->
27192732 check_record (Anno , Name , St ,
@@ -2740,11 +2753,13 @@ expr({record,Anno,Rec,Name,Upds}, Vt, St0) ->
27402753 no -> {vtmerge (Rvt , Usvt ), warn_if_literal_update (Anno , Rec , St2 )};
27412754 WildAnno -> {[],add_error (WildAnno , {wildcard_in_update ,Name }, St2 )}
27422755 end ;
2743- expr ({bin ,_Anno ,Fs }, Vt , St ) ->
2744- expr_bin (Fs , Vt , St , fun expr /3 );
2745- expr ({block ,_Anno ,Es }, Vt , St ) ->
2756+ expr ({bin ,Anno ,Fs }, Vt , St ) ->
2757+ {Vt1 , St1 } = expr_bin (Fs , Vt , St , fun expr /3 ),
2758+ {vtupd_export ({binary , Anno }, Vt1 , Vt ), St1 };
2759+ expr ({block ,Anno ,Es }, Vt , St ) ->
27462760 % % Unfold block into a sequence.
2747- exprs (Es , Vt , St );
2761+ {Vt1 , St1 } = exprs (Es , Vt , St ),
2762+ {vtupd_export ({'begin' , Anno }, Vt1 , Vt ), St1 };
27482763expr ({'if' ,Anno ,Cs }, Vt , St ) ->
27492764 icrt_clauses (Cs , {'if' ,Anno }, Vt , St );
27502765expr ({'case' ,Anno ,E ,Cs }, Vt , St0 ) ->
@@ -2816,7 +2831,7 @@ expr({call,Anno,{remote,_Ar,{atom,_Am,M},{atom,Af,F}},As}, Vt, St0) ->
28162831 St2 = check_remote_function (Anno , M , F , As , St1 ),
28172832 St3 = check_module_name (M , Anno , St2 ),
28182833 St4 = check_remote_self_call (Anno , M , F , length (As ), St3 ),
2819- expr_list ( As , Vt , St4 );
2834+ vtupd_export_expr_list ({ call , Anno }, As , Vt , St4 );
28202835expr ({call ,Anno ,{remote ,_Ar ,M ,F },As }, Vt , St0 ) ->
28212836 St1 = keyword_warning (Anno , M , St0 ),
28222837 St2 = keyword_warning (Anno , F , St1 ),
@@ -2826,14 +2841,14 @@ expr({call,Anno,{remote,_Ar,M,F},As}, Vt, St0) ->
28262841 _ ->
28272842 St2
28282843 end ,
2829- expr_list ( [M ,F | As ], Vt , St3 );
2844+ vtupd_export_expr_list ({ call , Anno }, [M , F | As ], Vt , St3 );
28302845expr ({call ,Anno ,{atom ,Aa ,F },As }, Vt , St0 ) ->
28312846 St1 = keyword_warning (Aa , F , St0 ),
2832- {Asvt ,St2 } = expr_list ( As , Vt , St1 ),
2847+ {Asvt ,St2 } = vtupd_export_expr_list ({ call , Anno }, As , Vt , St1 ),
28332848 {Asvt , check_call (Anno , F , As , Aa , St2 )};
28342849expr ({call ,Anno ,F ,As }, Vt , St0 ) ->
28352850 St = warn_invalid_call (Anno ,F ,St0 ),
2836- expr_list ([ F | As ], Vt , St ); % They see the same variables
2851+ vtupd_export_expr_list ({ call , Anno }, [ F | As ], Vt , St ); % They see the same variables
28372852expr ({'try' ,Anno ,Es ,Scs ,Ccs ,As }, Vt , St0 ) ->
28382853 % % The only exports we allow are from the try expressions to the
28392854 % % success clauses.
@@ -2880,19 +2895,19 @@ expr({'maybe',MaybeAnno,Es,{'else',ElseAnno,Cs}}, Vt, St) ->
28802895 Cvt2 = vtmerge (Cvt0 , Cvt1 ),
28812896 {vtmerge (Evt2 , Cvt2 ),St2 };
28822897% % No comparison or boolean operators yet.
2883- expr ({op ,_Anno , _Op ,A }, Vt , St ) ->
2884- expr ( A , Vt , St );
2898+ expr ({op ,Anno , Op ,A }, Vt , St ) ->
2899+ vtupd_export_expr_list ({ Op , Anno }, [ A ] , Vt , St );
28852900expr ({op ,Anno ,Op ,L ,R }, Vt , St0 ) when Op =:= 'orelse' ; Op =:= 'andalso' ->
2886- {Evt1 ,St1 } = expr ( L , Vt , St0 ),
2901+ {Evt1 , St1 } = vtupd_export_expr_list ({ Op , Anno }, [ L ] , Vt , St0 ),
28872902 Vt1 = vtupdate (Evt1 , Vt ),
28882903 {Evt2 ,St2 } = expr (R , Vt1 , St1 ),
28892904 Evt3 = vtupd_unsafe ({Op , Anno }, Evt2 , Vt1 ),
28902905 {vtmerge (Evt1 , Evt3 ),St2 };
2891- expr ({op ,_Anno ,EqOp ,L ,R }, Vt , St0 ) when EqOp =:= '=:=' ; EqOp =:= '=/=' ->
2906+ expr ({op ,Anno ,EqOp ,L ,R }, Vt , St0 ) when EqOp =:= '=:=' ; EqOp =:= '=/=' ->
28922907 St = expr_check_match_zero (R , expr_check_match_zero (L , St0 )),
2893- expr_list ( [L ,R ], Vt , St ); % They see the same variables
2894- expr ({op ,_Anno , _Op ,L ,R }, Vt , St ) ->
2895- expr_list ( [L ,R ], Vt , St ); % They see the same variables
2908+ vtupd_export_expr_list ({ EqOp , Anno }, [L , R ], Vt , St ); % They see the same variables
2909+ expr ({op ,Anno , Op ,L ,R }, Vt , St ) ->
2910+ vtupd_export_expr_list ({ Op , Anno }, [L , R ], Vt , St ); % They see the same variables
28962911% % The following are not allowed to occur anywhere!
28972912expr ({remote ,_Anno ,M ,_F }, _Vt , St ) ->
28982913 {[],add_error (erl_parse :first_anno (M ), illegal_expr , St )};
@@ -2973,6 +2988,12 @@ expr_list(Es, Vt, St0) ->
29732988 vtmerge_pat (Evt , Esvt , St2 )
29742989 end , {[], St0 }, Es ).
29752990
2991+ % % as expr_list but mark new vars as exported
2992+
2993+ vtupd_export_expr_list (Where , Es , Vt , St ) ->
2994+ {Evt , St1 } = expr_list (Es , Vt , St ),
2995+ {vtupd_export (Where , Evt , Vt ), St1 }.
2996+
29762997record_expr (Anno , Rec , Vt , St0 ) ->
29772998 St1 = warn_invalid_record (Anno , Rec , St0 ),
29782999 expr (Rec , Vt , St1 ).
@@ -4380,12 +4401,18 @@ do_expr_var(V, Anno, Vt, St) ->
43804401 {[{V ,{bound ,used ,As }}],
43814402 add_error (Anno , {unsafe_var ,V ,In }, St )};
43824403 {ok ,{{export ,From },_Usage ,As }} ->
4383- case is_warn_enabled ( export_vars , St ) of
4404+ case exported_subexpr_var ( From ) of
43844405 true ->
43854406 {[{V ,{bound ,used ,As }}],
4386- add_warning (Anno , {exported_var ,V ,From }, St )};
4407+ add_warning (Anno , {exported_subexpr_var ,V ,From }, St )};
43874408 false ->
4388- {[{V ,{{export ,From },used ,As }}],St }
4409+ case is_warn_enabled (export_vars , St ) of
4410+ true ->
4411+ {[{V ,{bound ,used ,As }}],
4412+ add_warning (Anno , {exported_var ,V ,From }, St )};
4413+ false ->
4414+ {[{V ,{{export ,From },used ,As }}],St }
4415+ end
43894416 end ;
43904417 {ok ,{stacktrace ,_Usage ,As }} ->
43914418 {[{V ,{bound ,used ,As }}],
@@ -4408,6 +4435,14 @@ exported_var(Anno, V, From, St) ->
44084435 false -> St
44094436 end .
44104437
4438+ % % warn about exporting from non-block subexpressions
4439+ exported_subexpr_var ({'if' ,_ }) -> false ;
4440+ exported_subexpr_var ({'case' ,_ }) -> false ;
4441+ exported_subexpr_var ({'receive' ,_ }) -> false ;
4442+ exported_subexpr_var ({'try' ,_ }) -> false ;
4443+ exported_subexpr_var ({'begin' ,_ }) -> false ;
4444+ exported_subexpr_var (_ ) -> true .
4445+
44114446shadow_vars (Vt , Vt0 , In , St0 ) ->
44124447 case is_warn_enabled (shadow_vars , St0 ) of
44134448 true ->
@@ -4473,6 +4508,16 @@ vtunsafe({Tag,Anno}, Uvt, Vt) ->
44734508vtupd_unsafe (Where , NewVt , OldVt ) ->
44744509 vtupdate (vtunsafe (Where , NewVt , OldVt ), NewVt ).
44754510
4511+ % % vtexport(From, UpdVarTable, VarTable) -> ExpVarTable.
4512+ % % Return all new variables in UpdVarTable as exported.
4513+
4514+ vtexport ({Tag , FileLine }, Uvt , Vt ) ->
4515+ Line = erl_anno :location (FileLine ),
4516+ [{V , {{export , {Tag , Line }}, U , Ls }} || {V , {_ , U , Ls }} <- vtnew (Uvt , Vt )].
4517+
4518+ vtupd_export (Where , NewVt , OldVt ) ->
4519+ vtupdate (vtexport (Where , NewVt , OldVt ), NewVt ).
4520+
44764521% % vtmerge(VarTable, VarTable) -> VarTable.
44774522% % Merge two variables tables generating a new vartable. Give priority to
44784523% % errors then warnings.
0 commit comments