summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/compiler/src/beam_kernel_to_ssa.erl13
-rw-r--r--lib/compiler/src/beam_ssa_pre_codegen.erl128
-rw-r--r--lib/compiler/src/beam_validator.erl13
-rw-r--r--lib/compiler/src/v3_core.erl2
-rw-r--r--lib/compiler/src/v3_kernel.erl49
-rw-r--r--lib/compiler/test/beam_except_SUITE.erl8
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl7
-rw-r--r--lib/compiler/test/guard_SUITE.erl3
-rw-r--r--lib/compiler/test/inline_SUITE.erl2
-rw-r--r--lib/crypto/src/crypto.erl6
-rw-r--r--lib/crypto/test/crypto_SUITE.erl5
-rw-r--r--lib/eldap/src/eldap.erl4
-rw-r--r--lib/eldap/test/eldap_basic_SUITE.erl85
-rw-r--r--lib/stdlib/doc/src/peer.xml24
-rwxr-xr-xlib/stdlib/scripts/update_deprecations6
-rw-r--r--lib/stdlib/src/otp_internal.erl12
16 files changed, 285 insertions, 82 deletions
diff --git a/lib/compiler/src/beam_kernel_to_ssa.erl b/lib/compiler/src/beam_kernel_to_ssa.erl
index c2e22f4b6d..7722078206 100644
--- a/lib/compiler/src/beam_kernel_to_ssa.erl
+++ b/lib/compiler/src/beam_kernel_to_ssa.erl
@@ -25,7 +25,7 @@
-export([module/2]).
-import(lists, [all/2,append/1,flatmap/2,foldl/3,
- keysort/2,mapfoldl/3,member/2,
+ keyfind/3,keysort/2,mapfoldl/3,member/2,
reverse/1,sort/1]).
-include("v3_kernel.hrl").
@@ -672,7 +672,7 @@ call_cg(Func, As, [#k_var{name=R}|MoreRs]=Rs, Le, St0) ->
%% Ordinary function call in a function body.
Args = ssa_args([Func|As], St0),
{Ret,St1} = new_ssa_var(R, St0),
- Call = #b_set{anno=line_anno(Le),op=call,dst=Ret,args=Args},
+ Call = #b_set{anno=call_anno(Le),op=call,dst=Ret,args=Args},
%% If this is a call to erlang:error(), MoreRs could be a
%% nonempty list of variables that each need a value.
@@ -685,9 +685,16 @@ call_cg(Func, As, [#k_var{name=R}|MoreRs]=Rs, Le, St0) ->
enter_cg(Func, As0, Le, St0) ->
As = ssa_args([Func|As0], St0),
{Ret,St} = new_ssa_var('@ssa_ret', St0),
- Call = #b_set{anno=line_anno(Le),op=call,dst=Ret,args=As},
+ Call = #b_set{anno=call_anno(Le),op=call,dst=Ret,args=As},
{[Call,#b_ret{arg=Ret}],St}.
+call_anno(Le) ->
+ Anno = line_anno(Le),
+ case keyfind(inlined, 1, Le) of
+ false -> Anno;
+ {inlined,NameArity} -> Anno#{inlined => NameArity}
+ end.
+
%% bif_cg(#k_bif{}, Le,State) -> {[Ainstr],State}.
%% Generate code for a guard BIF or primop.
diff --git a/lib/compiler/src/beam_ssa_pre_codegen.erl b/lib/compiler/src/beam_ssa_pre_codegen.erl
index 3567fb4210..f5ad81f760 100644
--- a/lib/compiler/src/beam_ssa_pre_codegen.erl
+++ b/lib/compiler/src/beam_ssa_pre_codegen.erl
@@ -73,14 +73,16 @@
-import(lists, [all/2,any/2,append/1,duplicate/2,
foldl/3,last/1,member/2,partition/2,
- reverse/1,reverse/2,sort/1,splitwith/2,zip/2]).
+ reverse/1,reverse/2,seq/2,sort/1,
+ splitwith/2,usort/1,zip/2]).
-spec module(beam_ssa:b_module(), [compile:option()]) ->
{'ok',beam_ssa:b_module()}.
module(#b_module{body=Fs0}=Module, Opts) ->
Ps = passes(Opts),
- Fs = functions(Fs0, Ps),
+ Fs1 = functions(Fs0, Ps),
+ Fs = fc_stubs(Fs1, Module),
{ok,Module#b_module{body=Fs}}.
functions([F|Fs], Ps) ->
@@ -835,19 +837,21 @@ match_fail_instrs_1([{L,#b_blk{is=Is0}=Blk}|Bs], Arity, Blocks0) ->
match_fail_instrs_1([], _Arity, Blocks) -> Blocks.
match_fail_instrs_blk([#b_set{op=put_tuple,dst=Dst,
- args=[#b_literal{val=Tag},Val]},
+ args=[#b_literal{val=Tag}|Values]},
#b_set{op=call,
args=[#b_remote{mod=#b_literal{val=erlang},
name=#b_literal{val=error}},
Dst]}=Call|Is],
_Arity, Acc) ->
- match_fail_instr(Call, Tag, Val, Is, Acc);
+ match_fail_instr(Call, Tag, Values, Is, Acc);
match_fail_instrs_blk([#b_set{op=call,
args=[#b_remote{mod=#b_literal{val=erlang},
name=#b_literal{val=error}},
- #b_literal{val={Tag,Val}}]}=Call|Is],
- _Arity, Acc) ->
- match_fail_instr(Call, Tag, #b_literal{val=Val}, Is, Acc);
+ #b_literal{val=Tuple}]}=Call|Is],
+ _Arity, Acc) when tuple_size(Tuple) >= 1 ->
+ [Tag|Values0] = tuple_to_list(Tuple),
+ Values = [#b_literal{val=V} || V <- Values0],
+ match_fail_instr(Call, Tag, Values, Is, Acc);
match_fail_instrs_blk([#b_set{op=call,
args=[#b_remote{mod=#b_literal{val=erlang},
name=#b_literal{val=error}},
@@ -860,34 +864,29 @@ match_fail_instrs_blk([#b_set{op=call,anno=Anno,
name=#b_literal{val=error}},
#b_literal{val=function_clause},
Stk]}=Call],
- {Arity,Location}, Acc) ->
- case match_fail_stk(Stk, Acc, [], []) of
- {[_|_]=Vars,Is} when length(Vars) =:= Arity ->
- case maps:get(location, Anno, none) of
- Location ->
- I = Call#b_set{op=match_fail,
- args=[#b_literal{val=function_clause}|Vars]},
- Is ++ [I];
- _ ->
- %% erlang:error/2 has a different location than the
- %% func_info instruction at the beginning of the function
- %% (probably because of inlining). Keep the original call.
- reverse(Acc, [Call])
- end;
- _ ->
- %% Either the stacktrace could not be picked apart (for example,
- %% if the call to erlang:error/2 was handwritten) or the number
- %% of arguments in the stacktrace was different from the arity
- %% of the host function (because it is the implementation of a
- %% fun). Keep the original call.
- reverse(Acc, [Call])
- end;
+ Arity, Acc) ->
+ match_fail_fc(Anno, Call, Stk, Arity, Acc);
match_fail_instrs_blk([I|Is], Arity, Acc) ->
match_fail_instrs_blk(Is, Arity, [I|Acc]);
match_fail_instrs_blk(_, _, _) ->
none.
-match_fail_instr(Call, Tag, Val, Is, Acc) ->
+match_fail_instr(Call, function_clause, Values, Is, Acc) ->
+ case beam_ssa:get_anno(inlined, Call, none) of
+ none ->
+ %% If there is no `inlined` annotation, it implies that
+ %% the call to erlang:error/1 was handwritten.
+ none;
+ {Name,Arity} ->
+ %% A `function_clause` in inlined code. Convert it to
+ %% a call to a stub function that will raise a proper
+ %% `function_clause` exception. (The stub function will
+ %% be created later by fc_stubs/2.)
+ Target = #b_local{name=#b_literal{val=Name},arity=Arity},
+ I = Call#b_set{args=[Target|Values]},
+ reverse(Acc, [I|Is])
+ end;
+match_fail_instr(Call, Tag, [Val], Is, Acc) ->
Op = case Tag of
badmatch -> Tag;
case_clause -> case_end;
@@ -900,19 +899,84 @@ match_fail_instr(Call, Tag, Val, Is, Acc) ->
_ ->
I = Call#b_set{op=match_fail,args=[#b_literal{val=Op},Val]},
reverse(Acc, [I|Is])
+ end;
+match_fail_instr(_, _, _, _, _) -> none.
+
+match_fail_fc(Anno, Call, Stk, {Arity,Location}, Acc) ->
+ case match_fail_stk(Stk, Acc, [], []) of
+ {[_|_]=Vars,Is} when length(Vars) =:= Arity ->
+ case maps:get(location, Anno, none) of
+ Location ->
+ I = Call#b_set{op=match_fail,
+ args=[#b_literal{val=function_clause}|Vars]},
+ Is ++ [I];
+ _ ->
+ %% erlang:error/2 has a different location than
+ %% the func_info instruction at the beginning of
+ %% the function (probably because of
+ %% inlining). Keep the original call.
+ reverse(Acc, [Call])
+ end;
+ _ ->
+ %% Either the stacktrace could not be picked apart (for
+ %% example, if the call to erlang:error/2 was handwritten)
+ %% or the number of arguments in the stacktrace was
+ %% different from the arity of the host function (because
+ %% it is the implementation of a fun). Keep the original
+ %% call.
+ reverse(Acc, [Call])
end.
match_fail_stk(#b_var{}=V, [#b_set{op=put_list,dst=V,args=[H,T]}|Is], IAcc, VAcc) ->
match_fail_stk(T, Is, IAcc, [H|VAcc]);
match_fail_stk(#b_literal{val=[H|T]}, Is, IAcc, VAcc) ->
match_fail_stk(#b_literal{val=T}, Is, IAcc, [#b_literal{val=H}|VAcc]);
-match_fail_stk(#b_literal{val=[]}, [], IAcc, VAcc) ->
- {reverse(VAcc),IAcc};
+match_fail_stk(#b_literal{val=[]}, Is, IAcc, VAcc) ->
+ {reverse(VAcc),reverse(Is, IAcc)};
match_fail_stk(T, [#b_set{op=Op}=I|Is], IAcc, VAcc)
when Op =:= bs_get_tail; Op =:= bs_set_position ->
match_fail_stk(T, Is, [I|IAcc], VAcc);
match_fail_stk(_, _, _, _) -> none.
+%% Create stubs for `function_clause` exceptions generated by
+%% inlined code.
+fc_stubs(Fs, #b_module{name=Mod}) ->
+ Stubs0 = usort(find_fc_calls(Fs, [])),
+ Stubs = [begin
+ Seq = seq(0, Arity-1),
+ Args = [#b_var{name=V} || V <- Seq],
+ XRegs = [{x,V} || V <- Seq],
+ Ret = #b_var{name='@ssa_ret'},
+ Regs = maps:from_list([{Ret,{x,0}}|zip(Args, XRegs)]),
+ Anno = #{func_info => {Mod,Name,Arity},
+ location => Location,
+ parameter_info => #{},
+ registers => Regs},
+ Fc = #b_set{op=match_fail,dst=Ret,
+ args=[#b_literal{val=function_clause}|Args]},
+ Blk = #b_blk{is=[Fc],last=#b_ret{arg=Ret}},
+ #b_function{anno=Anno,args=Args,
+ bs=#{0 => Blk},
+ cnt=1}
+ end || {{Name,Arity},Location} <- Stubs0],
+ Fs ++ Stubs.
+
+find_fc_calls([#b_function{bs=Blocks}|Fs], Acc0) ->
+ F = fun(#b_set{anno=Anno,op=call}, A) ->
+ case Anno of
+ #{inlined := FA} ->
+ [{FA,maps:get(location, Anno, [])}|A];
+ #{} ->
+ A
+ end;
+ (_, A) ->
+ A
+ end,
+ Acc = beam_ssa:fold_instrs(F, maps:keys(Blocks), Acc0, Blocks),
+ find_fc_calls(Fs, Acc);
+find_fc_calls([], Acc) -> Acc.
+
+
%%%
%%% Introduce the set_tuple_element instructions to make
%%% multiple-field record updates faster.
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 125c01c6a6..adbddc7059 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -245,7 +245,8 @@ build_function_table([{function,Name,Arity,Entry,Code0}|Fs], Acc) ->
[{label,Entry} | Is] ->
Info = #{ name => Name,
arity => Arity,
- parameter_info => find_parameter_info(Is, #{}) },
+ parameter_info => find_parameter_info(Is, #{}),
+ always_fails => always_fails(Is) },
build_function_table(Fs, Acc#{ Entry => Info });
_ ->
%% Something is seriously wrong. Ignore it for now.
@@ -262,6 +263,9 @@ find_parameter_info([{'%', _} | Is], Acc) ->
find_parameter_info(_, Acc) ->
Acc.
+always_fails([{jump,_}|_]) -> true;
+always_fails(_) -> false.
+
validate_1(Is, MFA0, Entry, Level, Ft) ->
{Offset, MFA, Header, Body} = extract_header(Is, MFA0, Entry, 1, []),
@@ -3078,6 +3082,13 @@ will_call_succeed(bs_init_writable, _Vst) ->
yes;
will_call_succeed(raw_raise, _Vst) ->
no;
+will_call_succeed({f,Lbl}, #vst{ft=Ft}) ->
+ case Ft of
+ #{Lbl := #{always_fails := true}} ->
+ no;
+ #{} ->
+ maybe
+ end;
will_call_succeed(_Call, _Vst) ->
maybe.
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 6bf87e131c..8e89c88318 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -264,7 +264,7 @@ body(Cs0, Name, Arity, St0) ->
Args = reverse(Args0), %Nicer order
{Cs1,St2} = clauses(Cs0, St1),
{Ps,St3} = new_vars(Arity, St2), %Need new variables here
- Fc = function_clause(Ps, Anno),
+ Fc = function_clause(Ps, FunAnno),
{#ifun{anno=#a{anno=FunAnno},id=[],vars=Args,clauses=Cs1,fc=Fc},St3}.
%% clause(Clause, State) -> {Cclause,State}.
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index aa3fc033eb..aa8a906ca7 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -405,36 +405,51 @@ letrec_goto([{#c_var{name={Label,0}},Cfail}], Cb, Sub0,
%% erlang:error/2.
translate_match_fail(Arg, Sub, Anno, St0) ->
- Cargs = case {cerl:data_type(Arg),cerl:data_es(Arg)} of
- {tuple,[#c_literal{val=function_clause}|As]} ->
- translate_fc_args(As, Sub, St0);
- {_,_} ->
- [Arg]
- end,
- {Kargs,Ap,St} = atomic_list(Cargs, Sub, St0),
+ {Cargs,ExtraAnno,St1} =
+ case {cerl:data_type(Arg),cerl:data_es(Arg)} of
+ {tuple,[#c_literal{val=function_clause}|As]} ->
+ translate_fc_args(As, Sub, Anno, St0);
+ {_,_} ->
+ {[Arg],[],St0}
+ end,
+ {Kargs,Ap,St} = atomic_list(Cargs, Sub, St1),
Ar = length(Cargs),
- Call = #k_call{anno=Anno,
+ Call = #k_call{anno=ExtraAnno++Anno,
op=#k_remote{mod=#k_literal{val=erlang},
name=#k_literal{val=error},
arity=Ar},args=Kargs},
{Call,Ap,St}.
-translate_fc_args(As, Sub, #kern{fargs=Fargs}) ->
+translate_fc_args(As, Sub, Anno, #kern{fargs=Fargs}=St0) ->
case same_args(As, Fargs, Sub) of
true ->
%% The arguments for the `function_clause` exception are
%% the arguments for the current function in the correct
%% order.
- [#c_literal{val=function_clause},cerl:make_list(As)];
+ {[#c_literal{val=function_clause},cerl:make_list(As)],
+ [],
+ St0};
false ->
%% The arguments in the `function_clause` exception don't
- %% match the arguments for the current function because
- %% of inlining. Keeping the `function_clause`
- %% exception reason would be confusing. Rewrite it to
- %% a `case_clause` exception with the arguments in a
- %% tuple.
- [cerl:c_tuple([#c_literal{val=case_clause},
- cerl:c_tuple(As)])]
+ %% match the arguments for the current function because of
+ %% inlining.
+ Args = [cerl:c_tuple([#c_literal{val=function_clause}|As])],
+ case keyfind(function, 1, Anno) of
+ false ->
+ %% This is probably a fun that has been inlined
+ %% by sys_core_fold.
+ {Name,St1} = new_fun_name("inlined", St0),
+ {Args,
+ [{inlined,{Name,length(As)}}],
+ St1};
+ {_,{Name0,Arity}} ->
+ %% This is function that has been inlined.
+ Name1 = ["-inlined-",Name0,"/",Arity,"-"],
+ Name = list_to_atom(lists:concat(Name1)),
+ {Args,
+ [{inlined,{Name,Arity}}],
+ St0}
+ end
end.
same_args([#c_var{name=Cv}|Vs], [#k_var{name=Kv}|As], Sub) ->
diff --git a/lib/compiler/test/beam_except_SUITE.erl b/lib/compiler/test/beam_except_SUITE.erl
index 95e5989081..2bc805be71 100644
--- a/lib/compiler/test/beam_except_SUITE.erl
+++ b/lib/compiler/test/beam_except_SUITE.erl
@@ -135,14 +135,18 @@ coverage(_) ->
{'EXIT',{function_clause,[{?MODULE,foobar,[[fail],1,2],
[{file,"fake.erl"},{line,16}]}|_]}} =
(catch foobar([fail], 1, 2)),
+
{'EXIT',{function_clause,[{?MODULE,fake_function_clause1,[{a,b},42.0],_}|_]}} =
(catch fake_function_clause1({a,b})),
{'EXIT',{function_clause,[{?MODULE,fake_function_clause2,[42|bad_tl],_}|_]}} =
(catch fake_function_clause2(42, bad_tl)),
+
{'EXIT',{function_clause,[{?MODULE,fake_function_clause3,[x,y],_}|_]}} =
(catch fake_function_clause3(42, id([x,y]))),
+ {'EXIT',{{function_clause,a,b,c}, _}} = catch fake_function_clause4(),
+
{'EXIT',{{badmatch,0.0},_}} = (catch coverage_1(id(42))),
{'EXIT',{badarith,_}} = (catch coverage_1(id(a))),
@@ -153,9 +157,13 @@ coverage_1(X) ->
true = 0 / X.
fake_function_clause1(A) -> error(function_clause, [A,42.0]).
+
fake_function_clause2(A, Tl) -> error(function_clause, [A|Tl]).
+
fake_function_clause3(_, Stk) -> error(function_clause, Stk).
+fake_function_clause4() -> error({function_clause,a,b,c}).
+
binary_construction_allocation(_Config) ->
ok = do_binary_construction_allocation("PUT"),
ok.
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index f7542be568..96ae549b28 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -1468,10 +1468,11 @@ haystack_2(Haystack) ->
fc({'EXIT',{function_clause,_}}) -> ok;
fc({'EXIT',{{case_clause,_},_}}) when ?MODULE =:= bs_match_inline_SUITE -> ok.
-fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Args,_}|_]}}) -> ok;
-fc(_, Args, {'EXIT',{{case_clause,ActualArgs},_}})
+fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Args,_}|_]}}) ->
+ ok;
+fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,_,Args,_}|_]}})
when ?MODULE =:= bs_match_inline_SUITE ->
- Args = tuple_to_list(ActualArgs).
+ ok.
%% Cover the clause handling bs_context to binary in
%% beam_block:initialized_regs/2.
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index 6699d82262..6a42453654 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -3070,5 +3070,4 @@ check(F, Result) ->
ct:fail(check_failed)
end.
-fc({'EXIT',{function_clause,_}}) -> ok;
-fc({'EXIT',{{case_clause,_},_}}) when ?MODULE =:= guard_inline_SUITE -> ok.
+fc({'EXIT',{function_clause,_}}) -> ok.
diff --git a/lib/compiler/test/inline_SUITE.erl b/lib/compiler/test/inline_SUITE.erl
index 7482f53ed4..b2778bebcd 100644
--- a/lib/compiler/test/inline_SUITE.erl
+++ b/lib/compiler/test/inline_SUITE.erl
@@ -332,7 +332,7 @@ badarg(Reply, _A) ->
Reply.
otp_7223(Config) when is_list(Config) ->
- {'EXIT', {{case_clause,{1}},_}} = (catch otp_7223_1(1)),
+ {'EXIT', {function_clause, [{?MODULE,_,[1],_}|_]}} = (catch otp_7223_1(1)),
ok.
-compile({inline,[{otp_7223_1,1}]}).
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 248442532a..70edc257f6 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -46,6 +46,12 @@
-export([pbkdf2_hmac/5]).
%%%----------------------------------------------------------------
+%% Deprecated functions
+-deprecated([crypto_dyn_iv_init/3,
+ crypto_dyn_iv_update/3
+ ]).
+
+%%%----------------------------------------------------------------
%% Removed functions.
%%
%% Old interface. Now implemented with the New interface.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 58614d9b0a..37bcecf4eb 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -170,6 +170,11 @@
rsa_oaep_label/0
]).
+
+-compile({nowarn_deprecated_function, [{crypto, crypto_dyn_iv_init, 3},
+ {crypto, crypto_dyn_iv_update, 3}
+ ]}).
+
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl
index 24562eb790..dfdcfccf55 100644
--- a/lib/eldap/src/eldap.erl
+++ b/lib/eldap/src/eldap.erl
@@ -418,9 +418,9 @@ mra([{matchingRule,Val}|T], Ack) when is_list(Val) ->
mra([{type,Val}|T], Ack) when is_list(Val) ->
mra(T, Ack#'MatchingRuleAssertion'{type=Val});
mra([{dnAttributes,true}|T], Ack) ->
- mra(T, Ack#'MatchingRuleAssertion'{dnAttributes="TRUE"});
+ mra(T, Ack#'MatchingRuleAssertion'{dnAttributes=true});
mra([{dnAttributes,false}|T], Ack) ->
- mra(T, Ack#'MatchingRuleAssertion'{dnAttributes="FALSE"});
+ mra(T, Ack#'MatchingRuleAssertion'{dnAttributes=false});
mra([H|_], _) ->
throw({error,{extensibleMatch_arg,H}});
mra([], Ack) ->
diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl
index 15cf6a9039..6d90158050 100644
--- a/lib/eldap/test/eldap_basic_SUITE.erl
+++ b/lib/eldap/test/eldap_basic_SUITE.erl
@@ -59,6 +59,8 @@
search_non_existant/1,
search_referral/1,
search_two_hits/1,
+ search_extensible_match_with_dn/1,
+ search_extensible_match_without_dn/1,
ssl_connection/1,
start_tls_on_ssl_should_fail/1,
start_tls_twice_should_fail/1,
@@ -129,6 +131,8 @@ groups() ->
search_filter_or,
search_filter_and_not,
search_two_hits,
+ search_extensible_match_with_dn,
+ search_extensible_match_without_dn,
search_referral,
search_filter_or_sizelimit_ok,
search_filter_or_sizelimit_exceeded,
@@ -722,6 +726,87 @@ search_two_hits(Config) ->
[ok=eldap:delete(H,DN) || DN <- ExpectedDNs].
%%%----------------------------------------------------------------
+search_extensible_match_with_dn(Config) ->
+ H = proplists:get_value(handle, Config),
+ BasePath = proplists:get_value(eldap_path, Config),
+
+ %% Create intermediate tree
+ OU1 = "o=Designers," ++ BasePath,
+ ok = eldap:add(H, OU1, [{"objectclass", ["top", "organization"]}, {"o", ["Designers"]}]),
+ OU2 = "o=Graphics," ++ BasePath,
+ ok = eldap:add(H, OU2, [{"objectclass", ["top", "organization"]}, {"o", ["Graphics"]}]),
+
+ %% Add objects, they belongs to different trees
+ DN1 = "cn=Bob Noorda,o=Designers," ++ BasePath,
+ DN2 = "cn=Bob Noorda,o=Graphics," ++ BasePath,
+ ok = eldap:add(H, DN1,
+ [{"objectclass", ["person"]},
+ {"cn", ["Bob Noorda"]},
+ {"sn", ["Noorda"]},
+ {"description", ["Amsterdam"]}]),
+ ok = eldap:add(H, DN2,
+ [{"objectclass", ["person"]},
+ {"cn", ["Bob Noorda"]},
+ {"sn", ["Noorda"]},
+ {"description", ["Milan"]}]),
+
+ %% Search using extensible filter only in Designers tree
+ Filter = eldap:'and'([
+ eldap:extensibleMatch("Designers", [{type, "o"}, {dnAttributes, true}]),
+ eldap:equalityMatch("sn", "Noorda")
+ ]),
+ {ok, #eldap_search_result{entries=Es}} =
+ eldap:search(H, #eldap_search{base = BasePath,
+ filter = Filter,
+ scope=eldap:wholeSubtree()}),
+
+ %% Check
+ [DN1] = [D || #eldap_entry{object_name=D} <- Es],
+
+ %% Restore the database
+ [ok=eldap:delete(H,DN) || DN <- [DN1, DN2, OU1, OU2]].
+
+%%%----------------------------------------------------------------
+search_extensible_match_without_dn(Config) ->
+ H = proplists:get_value(handle, Config),
+ BasePath = proplists:get_value(eldap_path, Config),
+
+ %% Create intermediate tree
+ OU1 = "o=Teachers," ++ BasePath,
+ ok = eldap:add(H, OU1, [{"objectclass", ["top", "organization"]}, {"o", ["Teachers"]}]),
+ OU2 = "o=Designers," ++ BasePath,
+ ok = eldap:add(H, OU2, [{"objectclass", ["top", "organization"]}, {"o", ["Designers"]}]),
+
+ %% Add objects, they belongs to different trees
+ DN1 = "cn=Max Huber,o=Teachers," ++ BasePath,
+ DN2 = "cn=Max Huber,o=Designers," ++ BasePath,
+ ok = eldap:add(H, DN1,
+ [{"objectclass", ["person"]},
+ {"cn", ["Max Huber"]},
+ {"sn", ["Huber"]},
+ {"description", ["Baar"]}]),
+ ok = eldap:add(H, DN2,
+ [{"objectclass", ["person"]},
+ {"cn", ["Max Huber"]},
+ {"sn", ["Huber"]},
+ {"description", ["Milan"]}]),
+
+ %% Search using extensible filter without dn attribute
+ Filter = eldap:extensibleMatch("Huber", [{type, "sn"}]),
+ {ok, #eldap_search_result{entries=Es}} =
+ eldap:search(H, #eldap_search{base = BasePath,
+ filter = Filter,
+ scope = eldap:wholeSubtree()
+ }),
+
+ %% And check that they are the expected ones:
+ ExpectedDNs = lists:sort([DN1, DN2]),
+ ExpectedDNs = lists:sort([D || #eldap_entry{object_name=D} <- Es]),
+
+ %% Restore the database:
+ [ok=eldap:delete(H,DN) || DN <- [DN1, DN2, OU1, OU2]].
+
+%%%----------------------------------------------------------------
search_referral(Config) ->
H = proplists:get_value(handle, Config),
BasePath = proplists:get_value(eldap_path, Config),
diff --git a/lib/stdlib/doc/src/peer.xml b/lib/stdlib/doc/src/peer.xml
index d67385157f..a5b513d810 100644
--- a/lib/stdlib/doc/src/peer.xml
+++ b/lib/stdlib/doc/src/peer.xml
@@ -31,7 +31,7 @@
<rev></rev>
<file>peer.xml</file>
</header>
- <module since="OTP 25.0">peer</module>
+ <module since="OTP @OTP-17720@">peer</module>
<modulesummary>Start and control linked Erlang nodes.
</modulesummary>
<description>
@@ -384,8 +384,8 @@
<funcs>
<func>
- <name name="call" arity="4" since="OTP 25.0"/>
- <name name="call" arity="5" since="OTP 25.0"/>
+ <name name="call" arity="4" since="OTP @OTP-17720@"/>
+ <name name="call" arity="5" since="OTP @OTP-17720@"/>
<fsummary>Evaluates a function call on a peer node.</fsummary>
<desc>
<p>
@@ -407,7 +407,7 @@
</func>
<func>
- <name name="cast" arity="4" since="OTP 25.0"/>
+ <name name="cast" arity="4" since="OTP @OTP-17720@"/>
<fsummary>Evaluates a function call on a peer node ignoring the result.</fsummary>
<desc>
<p>
@@ -425,7 +425,7 @@
</func>
<func>
- <name name="send" arity="3" since="OTP 25.0"/>
+ <name name="send" arity="3" since="OTP @OTP-17720@"/>
<fsummary>Sends a message to a process on the peer node.</fsummary>
<desc>
<p>
@@ -437,7 +437,7 @@
</func>
<func>
- <name name="get_state" arity="1" since="OTP 25.0"/>
+ <name name="get_state" arity="1" since="OTP @OTP-17720@"/>
<fsummary>Returns peer node state.</fsummary>
<desc>
<p>Returns the peer node state. Th initial state is <c>booting</c>; the node stays in that
@@ -448,7 +448,7 @@
</func>
<func>
- <name name="random_name" arity="0" since="OTP 25.0"/>
+ <name name="random_name" arity="0" since="OTP @OTP-17720@"/>
<fsummary>Creates a sufficiently unique node name.</fsummary>
<desc>
<p>
@@ -458,7 +458,7 @@
</func>
<func>
- <name name="random_name" arity="1" since="OTP 25.0"/>
+ <name name="random_name" arity="1" since="OTP @OTP-17720@"/>
<fsummary>Creates a sufficiently unique node name given a prefix.</fsummary>
<desc>
<p>
@@ -478,7 +478,7 @@
</func>
<func>
- <name name="start" arity="1" since="OTP 25.0"/>
+ <name name="start" arity="1" since="OTP @OTP-17720@"/>
<fsummary>Starts a peer node.</fsummary>
<desc>
<p>
@@ -491,7 +491,7 @@
</func>
<func>
- <name name="start_link" arity="0" since="OTP 25.0"/>
+ <name name="start_link" arity="0" since="OTP @OTP-17720@"/>
<fsummary>Starts a peer node, and links controlling process to caller process.</fsummary>
<desc>
<p>
@@ -502,7 +502,7 @@
</func>
<func>
- <name name="start_link" arity="1" since="OTP 25.0"/>
+ <name name="start_link" arity="1" since="OTP @OTP-17720@"/>
<fsummary>Starts a peer node, and links controlling process to caller process.</fsummary>
<desc>
<p>Starts a peer node in the same way as <seemfa marker="#start/1"><c>start/1</c></seemfa>,
@@ -523,7 +523,7 @@
</func>
<func>
- <name name="stop" arity="1" since="OTP 25.0"/>
+ <name name="stop" arity="1" since="OTP @OTP-17720@"/>
<fsummary>Stop controlling process and terminate peer node.</fsummary>
<desc>
<p>Depending on the <c>shutdown</c> option used to start the peer,
diff --git a/lib/stdlib/scripts/update_deprecations b/lib/stdlib/scripts/update_deprecations
index ef6be3b5af..8d359da050 100755
--- a/lib/stdlib/scripts/update_deprecations
+++ b/lib/stdlib/scripts/update_deprecations
@@ -238,12 +238,10 @@ make_xml(Top, Type, OutFile, InfoText0) ->
Collected = make_xml_collect(Depr, RelKey, InfoTextMap, []),
All = make_xml_gen(lists:reverse(Collected), Type, OutDir),
- file:write_file(OutFile, All),
-
- ok.
+ ok = file:write_file(OutFile, All).
make_xml_info([{Tag,M,F,A,Text} | Attributes], Tag) ->
- [{{M,F,A}, Text} | make_xml_info(Attributes, Tag)];
+ [{{M,F,A}, info_string(Text)} | make_xml_info(Attributes, Tag)];
make_xml_info([_ | Attributes], Tag) ->
make_xml_info(Attributes, Tag);
make_xml_info([], _Tag) ->
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index fed37f3953..2332df5315 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -35,6 +35,10 @@ obsolete(code, is_module_native, 1) ->
{deprecated, "HiPE has been removed", "OTP 26"};
obsolete(code, rehash, 0) ->
{deprecated, "the code path cache feature has been removed", "OTP 26"};
+obsolete(crypto, crypto_dyn_iv_init, 3) ->
+ {deprecated, "see the documentation for details", "OTP 27"};
+obsolete(crypto, crypto_dyn_iv_update, 3) ->
+ {deprecated, "see the documentation for details", "OTP 27"};
obsolete(crypto, rand_uniform, 2) ->
{deprecated, "use rand:uniform/1 instead"};
obsolete(disk_log, accessible_logs, 0) ->
@@ -180,9 +184,9 @@ obsolete(erlang, hash, 2) ->
obsolete(httpd_conf, check_enum, 2) ->
{removed, "use lists:member/2 instead"};
obsolete(httpd_conf, clean, 1) ->
- {removed, "use sting:strip/1 instead or possibly the re module"};
+ {removed, "use string:strip/1 instead or possibly the re module"};
obsolete(httpd_conf, custom_clean, 3) ->
- {removed, "use sting:strip/1 instead or possibly the re module"};
+ {removed, "use string:strip/1 instead or possibly the re module"};
obsolete(httpd_conf, is_directory, 1) ->
{removed, "use filelib:is_dir/1 instead"};
obsolete(httpd_conf, is_file, 1) ->
@@ -221,14 +225,14 @@ obsolete(filename, find_src, _) ->
{removed, "use filelib:find_source/1,3 instead"};
obsolete(ssl, ssl_accept, _) ->
{removed, "use ssl_handshake/1,2,3 instead"};
+obsolete(ct_slave, _, _) ->
+ {deprecated, "use ?CT_PEER(), or the 'peer' module instead", "OTP 27"};
obsolete(gen_fsm, _, _) ->
{deprecated, "use the 'gen_statem' module instead"};
obsolete(random, _, _) ->
{deprecated, "use the 'rand' module instead"};
obsolete(slave, _, _) ->
{deprecated, "use the 'peer' module instead", "OTP 27"};
-obsolete(ct_slave, _, _) ->
- {deprecated, "use ?CT_PEER(), or the 'peer' module instead", "OTP 27"};
obsolete(os_mon_mib, _, _) ->
{removed, "this module was removed in OTP 22.0"};
obsolete(pg2, _, _) ->