aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile2
-rw-r--r--lib/common_test/doc/src/notes.xml117
-rw-r--r--lib/common_test/src/ct_release_test.erl2
-rw-r--r--lib/common_test/vsn.mk2
-rw-r--r--lib/compiler/doc/src/notes.xml16
-rw-r--r--lib/compiler/src/beam_type.erl3
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl22
-rw-r--r--lib/compiler/test/guard_SUITE.erl4
-rw-r--r--lib/compiler/vsn.mk2
-rw-r--r--lib/crypto/c_src/crypto.c167
-rw-r--r--lib/crypto/doc/src/crypto.xml36
-rw-r--r--lib/crypto/doc/src/notes.xml18
-rw-r--r--lib/crypto/src/crypto.app.src2
-rw-r--r--lib/crypto/src/crypto.erl14
-rw-r--r--lib/crypto/test/crypto_SUITE.erl26
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/debugger/src/dbg_wx_win.erl4
-rw-r--r--lib/debugger/test/int_SUITE.erl5
-rw-r--r--lib/dialyzer/doc/src/notes.xml42
-rw-r--r--lib/dialyzer/test/abstract_SUITE.erl3
-rw-r--r--lib/dialyzer/test/plt_SUITE.erl6
-rw-r--r--lib/dialyzer/vsn.mk2
-rw-r--r--lib/diameter/doc/src/notes.xml49
-rw-r--r--lib/diameter/src/base/diameter.erl3
-rw-r--r--lib/diameter/src/base/diameter_config.erl5
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl71
-rw-r--r--lib/diameter/src/base/diameter_service.erl18
-rw-r--r--lib/diameter/src/base/diameter_sup.erl4
-rw-r--r--lib/diameter/src/base/diameter_traffic.erl263
-rw-r--r--lib/diameter/src/base/diameter_watchdog.erl28
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl4
-rw-r--r--lib/diameter/src/diameter.appup.src14
-rw-r--r--lib/diameter/vsn.mk4
-rw-r--r--lib/edoc/src/edoc_layout.erl12
-rw-r--r--lib/edoc/test/edoc_SUITE.erl2
-rw-r--r--lib/erl_interface/doc/src/notes.xml15
-rw-r--r--lib/erl_interface/vsn.mk2
-rw-r--r--lib/eunit/doc/overview.edoc4
-rw-r--r--lib/eunit/src/eunit.erl2
-rw-r--r--lib/hipe/amd64/Makefile1
-rw-r--r--lib/hipe/amd64/hipe_amd64_encode.erl2
-rw-r--r--lib/hipe/amd64/hipe_amd64_registers.erl27
-rw-r--r--lib/hipe/doc/src/notes.xml28
-rw-r--r--lib/hipe/flow/ebb.inc14
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl31
-rw-r--r--lib/hipe/icode/hipe_icode_type.erl21
-rw-r--r--lib/hipe/llvm/hipe_rtl_to_llvm.erl2
-rw-r--r--lib/hipe/regalloc/hipe_amd64_specific_sse2.erl4
-rw-r--r--lib/hipe/rtl/hipe_icode2rtl.erl12
-rw-r--r--lib/hipe/rtl/hipe_rtl_binary_construct.erl170
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl106
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_tuples.erl14
-rw-r--r--lib/hipe/util/hipe_vectors.erl3
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/hipe/x86/hipe_rtl_to_x86.erl1
-rw-r--r--lib/hipe/x86/hipe_x86_assemble.erl29
-rw-r--r--lib/hipe/x86/hipe_x86_postpass.erl8
-rw-r--r--lib/inets/doc/src/notes.xml40
-rw-r--r--lib/inets/vsn.mk2
-rw-r--r--lib/kernel/doc/src/notes.xml39
-rw-r--r--lib/kernel/src/application_controller.erl4
-rw-r--r--lib/kernel/src/kernel.appup.src4
-rw-r--r--lib/kernel/test/code_SUITE.erl3
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/observer/doc/src/notes.xml41
-rw-r--r--lib/observer/doc/src/observer_ug.xml5
-rw-r--r--lib/observer/src/observer_alloc_wx.erl35
-rw-r--r--lib/observer/src/observer_perf_wx.erl98
-rw-r--r--lib/observer/vsn.mk2
-rw-r--r--lib/os_mon/doc/src/notes.xml15
-rw-r--r--lib/os_mon/vsn.mk2
-rw-r--r--lib/parsetools/doc/src/yecc.xml2
-rw-r--r--lib/parsetools/src/yecc.erl130
-rw-r--r--lib/parsetools/src/yeccgramm.yrl45
-rw-r--r--lib/parsetools/src/yeccparser.erl192
-rw-r--r--lib/parsetools/test/yecc_SUITE.erl4
-rw-r--r--lib/public_key/doc/src/notes.xml28
-rw-r--r--lib/public_key/doc/src/public_key.xml9
-rw-r--r--lib/public_key/src/public_key.app.src2
-rw-r--r--lib/public_key/src/public_key.erl63
-rw-r--r--lib/public_key/test/erl_make_certs.erl16
-rw-r--r--lib/public_key/vsn.mk2
-rw-r--r--lib/reltool/doc/src/notes.xml21
-rw-r--r--lib/reltool/src/reltool.hrl6
-rw-r--r--lib/reltool/vsn.mk2
-rw-r--r--lib/runtime_tools/doc/src/notes.xml18
-rw-r--r--lib/runtime_tools/vsn.mk2
-rw-r--r--lib/sasl/doc/src/notes.xml22
-rw-r--r--lib/sasl/vsn.mk2
-rw-r--r--lib/snmp/doc/src/notes.xml22
-rw-r--r--lib/ssh/doc/src/notes.xml80
-rw-r--r--lib/ssh/doc/src/ssh.xml3
-rw-r--r--lib/ssh/src/ssh.app.src6
-rw-r--r--lib/ssh/src/ssh.erl10
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/doc/src/notes.xml64
-rw-r--r--lib/stdlib/doc/src/notes.xml104
-rw-r--r--lib/stdlib/src/c.erl4
-rw-r--r--lib/stdlib/src/epp.erl2
-rw-r--r--lib/stdlib/src/erl_anno.erl8
-rw-r--r--lib/stdlib/src/erl_compile.erl4
-rw-r--r--lib/stdlib/src/erl_lint.erl9
-rw-r--r--lib/stdlib/src/erl_parse.yrl39
-rw-r--r--lib/stdlib/src/erl_pp.erl17
-rw-r--r--lib/stdlib/src/erl_tar.erl6
-rw-r--r--lib/stdlib/src/escript.erl8
-rw-r--r--lib/stdlib/src/otp_internal.erl2
-rw-r--r--lib/stdlib/src/qlc_pt.erl4
-rw-r--r--lib/stdlib/src/stdlib.appup.src4
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl10
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl11
-rw-r--r--lib/stdlib/test/erl_scan_SUITE.erl6
-rw-r--r--lib/stdlib/test/tar_SUITE.erl59
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/tools/doc/src/notes.xml15
-rw-r--r--lib/tools/emacs/erldoc.el4
-rw-r--r--lib/tools/test/Makefile4
-rw-r--r--lib/tools/vsn.mk2
-rw-r--r--lib/typer/Makefile44
-rw-r--r--lib/typer/RELEASE_NOTES22
-rw-r--r--lib/typer/doc/Makefile40
-rw-r--r--lib/typer/doc/html/.gitignore0
-rw-r--r--lib/typer/doc/pdf/.gitignore0
-rw-r--r--lib/typer/doc/src/Makefile118
-rw-r--r--lib/typer/doc/src/book.xml42
-rw-r--r--lib/typer/doc/src/fascicules.xml12
-rw-r--r--lib/typer/doc/src/notes.xml111
-rw-r--r--lib/typer/doc/src/part_notes.xml36
-rw-r--r--lib/typer/doc/src/ref_man.xml36
-rw-r--r--lib/typer/doc/src/typer_app.xml44
-rw-r--r--lib/typer/ebin/.gitignore0
-rw-r--r--lib/typer/info2
-rw-r--r--lib/typer/src/Makefile111
-rw-r--r--lib/typer/src/typer.app.src11
-rw-r--r--lib/typer/src/typer.appup.src22
-rw-r--r--lib/typer/src/typer.erl1110
-rw-r--r--lib/typer/test/Makefile65
-rw-r--r--lib/typer/test/typer.spec1
-rw-r--r--lib/typer/test/typer_SUITE.erl57
-rw-r--r--lib/typer/vsn.mk1
-rw-r--r--lib/xmerl/doc/src/notes.xml55
-rw-r--r--lib/xmerl/vsn.mk2
142 files changed, 2018 insertions, 2765 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 4740e6eb59..ae466ed518 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -35,7 +35,7 @@ ALL_ERLANG_APPLICATIONS = xmerl edoc erl_docgen snmp otp_mibs erl_interface \
public_key ssl observer odbc diameter \
cosTransactions cosEvent cosTime cosNotification \
cosProperty cosFileTransfer cosEventDomain et megaco \
- eunit ssh typer eldap dialyzer hipe
+ eunit ssh eldap dialyzer hipe
ifdef BUILD_ALL
ERLANG_APPLICATIONS += $(ALL_ERLANG_APPLICATIONS)
diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml
index 83e6511c04..efeacd4a72 100644
--- a/lib/common_test/doc/src/notes.xml
+++ b/lib/common_test/doc/src/notes.xml
@@ -33,6 +33,123 @@
<file>notes.xml</file>
</header>
+<section><title>Common_Test 1.14</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The following corrections and improvements are done in
+ the common_test hook handling:</p> <list> <item> <p>An
+ extra argument, <c>Suite</c>, is added as the first
+ argument to each of the following hook callback
+ functions:</p> <list>
+ <item><c>pre_init_per_group</c></item>
+ <item><c>post_init_per_group</c></item>
+ <item><c>pre_end_per_group</c></item>
+ <item><c>post_end_per_group</c></item>
+ <item><c>pre_init_per_testcase</c></item>
+ <item><c>post_init_per_testcase</c></item>
+ <item><c>pre_end_per_testcase</c></item>
+ <item><c>post_end_per_testcase</c></item>
+ <item><c>on_tc_fail</c></item>
+ <item><c>on_tc_skip</c></item> </list> <p>For backwards
+ compatibility, if the new function is not exported from a
+ hook callback module, <c>common_test</c> will fall back
+ to the old interface and call the function without the
+ <c>Suite</c> argument.</p> </item> <item> <p>If either
+ <c>init_per_suite</c> or <c>end_per_suite</c> exists, but
+ not the other, then the non-existing function will be
+ reported as failed with reason <c>undef</c> in the test
+ log. The same goes for <c>init/end_per_group</c>. This
+ has always been a requirement according to the user's
+ guide, but now <c>common_test</c> is more explicit in the
+ report.</p> </item> <item> <p>If <c>init_per_suite</c>
+ was exported from a test suite, but not
+ <c>end_per_suite</c>, then <c>pre/post_end_per_suite</c>
+ was called with <c>Suite=ct_framework</c> instead of the
+ correct suite name. This is now corrected.</p> </item>
+ <item> <p>If <c>end_per_group</c> was exported from a
+ suite, but not <c>init_per_group</c>, then
+ <c>end_per_group</c> was never called. This is now
+ corrected.</p> </item> <item> <p>Tests that were skipped
+ before calling <c>pre_init_per_*</c> got faulty calls to
+ the corresponding <c>post_init_per_*</c>. E.g. if a test
+ was skipped because <c>suite/0</c> failed, then
+ <c>post_init_per_suite</c> would be called even though
+ <c>pre_init_per_suite</c> and <c>init_per_suite</c> were
+ not called. This is now corrected so a <c>post_*</c>
+ callback will never be called unless the corresponding
+ <c>pre_*</c> callback has been called first.</p> </item>
+ <item> <p>Tests that were skipped before or in
+ <c>init_per_testcase</c> got faulty calls to
+ <c>pre_end_per_testcase</c> and
+ <c>post_end_per_testcase</c>. This is now corrected so
+ <c>pre/post_end_per_testcase</c> are not called when
+ <c>end_per_testcase</c> is not called.</p> </item> <item>
+ <p>If an exit signal causes the test case process to die
+ while running <c>init_per_testcase</c>, the case was
+ earlier reported as failed with reason <c>{skip,...}</c>.
+ This is now corrected so the case will be marked as
+ skipped.</p> </item> <item> <p>If an exist signal causes
+ the test case process to die while running
+ <c>end_per_testcase</c>, the case was earlier marked as
+ failed. This is now corrected so the status of the test
+ case is not changed - there is only a warning added to
+ the comment field.</p> </item> <item> <p>If a test case
+ was skipped because of option
+ <c>{force_stop,skip_rest}</c> or because of a failed
+ sequence, then no <c>tc_start</c> event would be sent,
+ only <c>tc_done</c>. This is now corrected so both events
+ are sent.</p> </item> <item> <p>When skipping or failing
+ in a configuration function, the configuration function
+ itself would get <c>{auto_skipped,Reason}</c>,
+ <c>{skipped,Reason}</c> or <c>{failed,Reason}</c> in the
+ hook callbacks <c>on_tc_skip</c> or <c>on_tc_fail</c>.
+ The other test cases that were skipped as a result of
+ this would only get <c>Reason</c> in <c>on_tc_skip</c>.
+ This is now corrected so even the configuration function
+ that caused the skip/fail will only get <c>Reason</c> in
+ the hook callback.</p> </item> </list>
+ <p>
+ Own Id: OTP-10599 Aux Id: kunagi-344 [255] </p>
+ </item>
+ <item>
+ <p>
+ When a test case was skipped by a <c>skip_cases</c>
+ statement in a test spec, then <c>cth_surefire</c> would
+ erroneously mark the previous test case as skipped in the
+ xml report. The actually skipped test case would not be
+ present in the xml report at all. This is now corrected.</p>
+ <p>
+ Own Id: OTP-14129 Aux Id: seq13244 </p>
+ </item>
+ <item>
+ <p>The <c>multiply_timetraps</c> and
+ <c>scale_timetraps</c> options did not work with test
+ specifications, which has been corrected.</p>
+ <p>
+ Own Id: OTP-14210</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ ct_testspec:get_tests/1 is added. This is used by rebar3
+ to get all directories that must be compiled when running
+ tests from testspec - instead of implementing testspec
+ parsing in rebar3.</p>
+ <p>
+ Own Id: OTP-14132</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Common_Test 1.13</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/common_test/src/ct_release_test.erl b/lib/common_test/src/ct_release_test.erl
index d783f8d04e..c53e72ee88 100644
--- a/lib/common_test/src/ct_release_test.erl
+++ b/lib/common_test/src/ct_release_test.erl
@@ -132,7 +132,7 @@
%%-----------------------------------------------------------------
-define(testnode, 'ct_release_test-upgrade').
--define(exclude_apps, [hipe, typer, dialyzer]). % never include these apps
+-define(exclude_apps, [hipe, dialyzer]). % never include these apps
%%-----------------------------------------------------------------
-record(ct_data, {from,to}).
diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk
index 2fab4d3883..e6ae8b2e7a 100644
--- a/lib/common_test/vsn.mk
+++ b/lib/common_test/vsn.mk
@@ -1 +1 @@
-COMMON_TEST_VSN = 1.13
+COMMON_TEST_VSN = 1.14
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index 2e58b68bf0..449453bf88 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -32,6 +32,22 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 7.0.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Minor internal changes. A typo in the documentation was
+ also fixed.</p>
+ <p>
+ Own Id: OTP-14240</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 7.0.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl
index 050c599d6b..2b5d558ee4 100644
--- a/lib/compiler/src/beam_type.erl
+++ b/lib/compiler/src/beam_type.erl
@@ -683,6 +683,9 @@ op_type('bsr') -> integer;
op_type('div') -> integer;
op_type(_) -> unknown.
+flush(Rs, [{set,[_],[_,_,_],{bif,is_record,_}}|_]=Is0, Acc0) ->
+ Acc = flush_all(Rs, Is0, Acc0),
+ {[],Acc};
flush(Rs, [{set,[_],[],{put_tuple,_}}|_]=Is0, Acc0) ->
Acc = flush_all(Rs, Is0, Acc0),
{[],Acc};
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index 492067ef00..7ca544a537 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -22,7 +22,7 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
integers/1,coverage/1,booleans/1,setelement/1,cons/1,
- tuple/1]).
+ tuple/1,record_float/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -37,7 +37,8 @@ groups() ->
booleans,
setelement,
cons,
- tuple
+ tuple,
+ record_float
]}].
init_per_suite(Config) ->
@@ -126,5 +127,22 @@ tuple(_Config) ->
do_tuple() ->
{0, _} = {necessary}.
+-record(x, {a}).
+
+record_float(_Config) ->
+ 17.0 = record_float(#x{a={0}}, 1700),
+ 23.0 = record_float(#x{a={0}}, 2300.0),
+ {'EXIT',{if_clause,_}} = (catch record_float(#x{a={1}}, 88)),
+ {'EXIT',{if_clause,_}} = (catch record_float(#x{a={}}, 88)),
+ {'EXIT',{if_clause,_}} = (catch record_float(#x{}, 88)),
+ ok.
+
+record_float(R, N0) ->
+ N = N0 / 100,
+ if element(1, R#x.a) =:= 0 ->
+ N
+ end.
+
+
id(I) ->
I.
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index a662d85272..ccb9b58225 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1538,7 +1538,7 @@ literal_type_tests_1(Config) ->
Func = {function, Anno, test, 0, [{clause,Anno,[],[],Tests}]},
Form = [{attribute,Anno,module,Mod},
{attribute,Anno,compile,export_all},
- Func, {eof,Anno}],
+ Func, {eof,999}],
%% Print generated code for inspection.
lists:foreach(fun (F) -> io:put_chars([erl_pp:form(F),"\n"]) end, Form),
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index 9c3cf1f34b..5c87304a01 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 7.0.3
+COMPILER_VSN = 7.0.4
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 9b5e1736a8..b2f31870b9 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -279,9 +279,19 @@ static void HMAC_CTX_free(HMAC_CTX *ctx)
#define EVP_MD_CTX_new() EVP_MD_CTX_create()
#define EVP_MD_CTX_free(ctx) EVP_MD_CTX_destroy(ctx)
+static INLINE void *BN_GENCB_get_arg(BN_GENCB *cb);
+
+static INLINE void *BN_GENCB_get_arg(BN_GENCB *cb)
+{
+ return cb->arg;
+}
+
static INLINE int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
+static INLINE void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
static INLINE int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
+static INLINE void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
static INLINE int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
+static INLINE void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp);
static INLINE int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
{
@@ -291,6 +301,13 @@ static INLINE int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
return 1;
}
+static INLINE void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
+{
+ *n = r->n;
+ *e = r->e;
+ *d = r->d;
+}
+
static INLINE int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
{
r->p = p;
@@ -298,6 +315,12 @@ static INLINE int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
return 1;
}
+static INLINE void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
+{
+ *p = r->p;
+ *q = r->q;
+}
+
static INLINE int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
{
r->dmp1 = dmp1;
@@ -306,6 +329,13 @@ static INLINE int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM
return 1;
}
+static INLINE void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp)
+{
+ *dmp1 = r->dmp1;
+ *dmq1 = r->dmq1;
+ *iqmp = r->iqmp;
+}
+
static INLINE int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
static INLINE int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
@@ -368,7 +398,11 @@ DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
*priv_key = dh->priv_key;
}
-#endif /* End of compatibility definitions. */
+#else /* End of compatibility definitions. */
+
+#define HAVE_OPAQUE_BN_GENCB
+
+#endif
/* NIF interface declarations */
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
@@ -406,6 +440,7 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -439,6 +474,7 @@ static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg);
static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
EC_GROUP *group, EC_POINT **pptr);
#endif
+static ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn);
static int library_refc = 0; /* number of users of this dynamic library */
@@ -476,6 +512,7 @@ static ErlNifFunc nif_funcs[] = {
{"dss_sign_nif", 3, dss_sign_nif},
{"rsa_public_crypt", 4, rsa_public_crypt},
{"rsa_private_crypt", 4, rsa_private_crypt},
+ {"rsa_generate_key_nif", 2, rsa_generate_key_nif},
{"dh_generate_parameters_nif", 2, dh_generate_parameters_nif},
{"dh_check", 1, dh_check},
{"dh_generate_key_nif", 4, dh_generate_key_nif},
@@ -925,6 +962,7 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
CRYPTO_set_dynlock_destroy_callback(ccb->dyn_destroy_function);
}
#endif /* OPENSSL_THREADS */
+
return 0;
}
@@ -2279,6 +2317,20 @@ static int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
return 1;
}
+static ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn)
+{
+ int bn_len;
+ unsigned char *bin_ptr;
+ ERL_NIF_TERM term;
+
+ /* Copy the bignum into an erlang binary. */
+ bn_len = BN_num_bytes(bn);
+ bin_ptr = enif_make_new_binary(env, bn_len, &term);
+ BN_bn2bin(bn, bin_ptr);
+
+ return term;
+}
+
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Lo,Hi) */
BIGNUM *bn_from = NULL, *bn_to, *bn_rand;
@@ -2850,6 +2902,119 @@ static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TE
}
}
+/* Creates a term which can be parsed by get_rsa_private_key(). This is a list of plain integer binaries (not mpints). */
+static ERL_NIF_TERM put_rsa_private_key(ErlNifEnv* env, const RSA *rsa)
+{
+ ERL_NIF_TERM result[8];
+ const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
+
+ /* Return at least [E,N,D] */
+ n = NULL; e = NULL; d = NULL;
+ RSA_get0_key(rsa, &n, &e, &d);
+
+ result[0] = bin_from_bn(env, e); // Exponent E
+ result[1] = bin_from_bn(env, n); // Modulus N = p*q
+ result[2] = bin_from_bn(env, d); // Exponent D
+
+ /* Check whether the optional additional parameters are available */
+ p = NULL; q = NULL;
+ RSA_get0_factors(rsa, &p, &q);
+ dmp1 = NULL; dmq1 = NULL; iqmp = NULL;
+ RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
+
+ if (p && q && dmp1 && dmq1 && iqmp) {
+ result[3] = bin_from_bn(env, p); // Factor p
+ result[4] = bin_from_bn(env, q); // Factor q
+ result[5] = bin_from_bn(env, dmp1); // D mod (p-1)
+ result[6] = bin_from_bn(env, dmq1); // D mod (q-1)
+ result[7] = bin_from_bn(env, iqmp); // (1/q) mod p
+
+ return enif_make_list_from_array(env, result, 8);
+ } else {
+ return enif_make_list_from_array(env, result, 3);
+ }
+}
+
+static int check_erlang_interrupt(int maj, int min, BN_GENCB *ctxt)
+{
+ ErlNifEnv *env = BN_GENCB_get_arg(ctxt);
+
+ if (!enif_is_current_process_alive(env)) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (ModulusSize, PublicExponent) */
+ int modulus_bits;
+ BIGNUM *pub_exp, *three;
+ RSA *rsa;
+ int success;
+ ERL_NIF_TERM result;
+ BN_GENCB *intr_cb;
+#ifndef HAVE_OPAQUE_BN_GENCB
+ BN_GENCB intr_cb_buf;
+#endif
+
+ if (!enif_get_int(env, argv[0], &modulus_bits) || modulus_bits < 256) {
+ return enif_make_badarg(env);
+ }
+
+ if (!get_bn_from_bin(env, argv[1], &pub_exp)) {
+ return enif_make_badarg(env);
+ }
+
+ /* Make sure the public exponent is large enough (at least 3).
+ * Without this, RSA_generate_key_ex() can run forever. */
+ three = BN_new();
+ BN_set_word(three, 3);
+ success = BN_cmp(pub_exp, three);
+ BN_free(three);
+ if (success < 0) {
+ BN_free(pub_exp);
+ return enif_make_badarg(env);
+ }
+
+ /* For large keys, prime generation can take many seconds. Set up
+ * the callback which we use to test whether the process has been
+ * interrupted. */
+#ifdef HAVE_OPAQUE_BN_GENCB
+ intr_cb = BN_GENCB_new();
+#else
+ intr_cb = &intr_cb_buf;
+#endif
+ BN_GENCB_set(intr_cb, check_erlang_interrupt, env);
+
+ rsa = RSA_new();
+ success = RSA_generate_key_ex(rsa, modulus_bits, pub_exp, intr_cb);
+ BN_free(pub_exp);
+
+#ifdef HAVE_OPAQUE_BN_GENCB
+ BN_GENCB_free(intr_cb);
+#endif
+
+ if (!success) {
+ RSA_free(rsa);
+ return atom_error;
+ }
+
+ result = put_rsa_private_key(env, rsa);
+ RSA_free(rsa);
+
+ return result;
+}
+
+static ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ /* RSA key generation can take a long time (>1 sec for a large
+ * modulus), so schedule it as a CPU-bound operation. */
+ return enif_schedule_nif(env, "rsa_generate_key",
+ ERL_NIF_DIRTY_JOB_CPU_BOUND,
+ rsa_generate_key, argc, argv);
+}
+
static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (PrimeLen, Generator) */
int prime_len, generator;
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index a4b34657ba..d0deaceaaf 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -77,7 +77,7 @@
<code>rsa_private() = [key_value()] = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] </code>
<p>Where E is the public exponent, N is public modulus and D is
- the private exponent.The longer key format contains redundant
+ the private exponent. The longer key format contains redundant
information that will make the calculation faster. P1,P2 are first
and second prime factors. E1,E2 are first and second exponents. C
is the CRT coefficient. Terminology is taken from <url href="http://www.ietf.org/rfc/rfc3477.txt"> RFC 3447</url>.</p>
@@ -298,22 +298,32 @@
<func>
<name>generate_key(Type, Params) -> {PublicKey, PrivKeyOut} </name>
<name>generate_key(Type, Params, PrivKeyIn) -> {PublicKey, PrivKeyOut} </name>
- <fsummary>Generates a public keys of type <c>Type</c></fsummary>
+ <fsummary>Generates a public key of type <c>Type</c></fsummary>
<type>
- <v> Type = dh | ecdh | srp </v>
- <v>Params = dh_params() | ecdh_params() | SrpUserParams | SrpHostParams </v>
+ <v> Type = dh | ecdh | rsa | srp </v>
+ <v>Params = dh_params() | ecdh_params() | RsaParams | SrpUserParams | SrpHostParams </v>
+ <v>RsaParams = {ModulusSizeInBits::integer(), PublicExponent::key_value()}</v>
<v>SrpUserParams = {user, [Generator::binary(), Prime::binary(), Version::atom()]}</v>
<v>SrpHostParams = {host, [Verifier::binary(), Generator::binary(), Prime::binary(), Version::atom()]}</v>
- <v>PublicKey = dh_public() | ecdh_public() | srp_public() </v>
+ <v>PublicKey = dh_public() | ecdh_public() | rsa_public() | srp_public() </v>
<v>PrivKeyIn = undefined | dh_private() | ecdh_private() | srp_private() </v>
- <v>PrivKeyOut = dh_private() | ecdh_private() | srp_private() </v>
- </type>
- <desc>
- <p>Generates public keys of type <c>Type</c>.
- See also <seealso marker="public_key:public_key#generate_key-1">public_key:generate_key/1</seealso>
- May throw exception <c>low_entropy</c> in case the random generator
- failed due to lack of secure "randomness".
- </p>
+ <v>PrivKeyOut = dh_private() | ecdh_private() | rsa_private() | srp_private() </v>
+ </type>
+ <desc>
+ <p>Generates a public key of type <c>Type</c>.
+ See also <seealso marker="public_key:public_key#generate_key-1">public_key:generate_key/1</seealso>.
+ May throw exception an exception of class <c>error</c>:
+ </p>
+ <list type="bulleted">
+ <item><c>badarg</c>: an argument is of wrong type or has an illegal value,</item>
+ <item><c>low_entropy</c>: the random generator failed due to lack of secure "randomness",</item>
+ <item><c>computation_failed</c>: the computation fails of another reason than <c>low_entropy</c>.</item>
+ </list>
+ <note>
+ <p>RSA key generation is only available if the runtime was
+ built with dirty scheduler support. Otherwise, attempting to
+ generate an RSA key will throw exception <c>error:notsup</c>.</p>
+ </note>
</desc>
</func>
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index 53ea6bb58b..37997b649b 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -31,6 +31,24 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 3.7.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The implementation of the key exchange algorithms
+ diffie-hellman-group-exchange-sha* are optimized, up to a
+ factor of 11 for the slowest ( = biggest and safest)
+ group size.</p>
+ <p>
+ Own Id: OTP-14169 Aux Id: seq-13261 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 3.7.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/crypto/src/crypto.app.src b/lib/crypto/src/crypto.app.src
index 460894c012..3bf4279ae1 100644
--- a/lib/crypto/src/crypto.app.src
+++ b/lib/crypto/src/crypto.app.src
@@ -25,6 +25,6 @@
{registered, []},
{applications, [kernel, stdlib]},
{env, [{fips_mode, false}]},
- {runtime_dependencies, ["erts-6.0","stdlib-2.0","kernel-3.0"]}]}.
+ {runtime_dependencies, ["erts-9.0","stdlib-3.4","kernel-5.3"]}]}.
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 5a915d4233..631af62615 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -452,6 +452,15 @@ generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg)
end,
user_srp_gen_key(Private, Generator, Prime);
+generate_key(rsa, {ModulusSize, PublicExponent}, undefined) ->
+ case rsa_generate_key_nif(ModulusSize, ensure_int_as_bin(PublicExponent)) of
+ error ->
+ erlang:error(computation_failed,
+ [rsa,{ModulusSize,PublicExponent}]);
+ Private ->
+ {lists:sublist(Private, 2), Private}
+ end;
+
generate_key(ecdh, Curve, PrivKey) ->
ec_key_generate(nif_curve_params(Curve), ensure_int_as_bin(PrivKey)).
@@ -787,6 +796,11 @@ rsa_verify_nif(_Type, _Digest, _Signature, _Key) -> ?nif_stub.
ecdsa_verify_nif(_Type, _Digest, _Signature, _Curve, _Key) -> ?nif_stub.
%% Public Keys --------------------------------------------------------------------
+%% RSA Rivest-Shamir-Adleman functions
+%%
+
+rsa_generate_key_nif(_Bits, _Exp) -> ?nif_stub.
+
%% DH Diffie-Hellman functions
%%
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 31f4e89ffe..1d7037d003 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -119,7 +119,8 @@ groups() ->
{sha384, [], [hash, hmac]},
{sha512, [], [hash, hmac]},
{rsa, [], [sign_verify,
- public_encrypt
+ public_encrypt,
+ generate
]},
{dss, [], [sign_verify]},
{ecdsa, [], [sign_verify]},
@@ -247,6 +248,21 @@ init_per_testcase(cmac, Config) ->
% The CMAC functionality was introduced in OpenSSL 1.0.1
{skip, "OpenSSL is too old"}
end;
+init_per_testcase(generate, Config) ->
+ case proplists:get_value(type, Config) of
+ rsa ->
+ % RSA key generation is a lengthy process, and is only available
+ % if dirty CPU scheduler support was enabled for this runtime.
+ case try erlang:system_info(dirty_cpu_schedulers) of
+ N -> N > 0
+ catch
+ error:badarg -> false
+ end of
+ true -> Config;
+ false -> {skip, "RSA key generation requires dirty scheduler support."}
+ end;
+ _ -> Config
+ end;
init_per_testcase(_Name,Config) ->
Config.
@@ -756,7 +772,10 @@ do_generate({ecdh = Type, Curve, Priv, Pub}) ->
ok;
{Other, _} ->
ct:fail({{crypto, generate_key, [Type, Priv, Curve]}, {expected, Pub}, {got, Other}})
- end.
+ end;
+do_generate({rsa = Type, Mod, Exp}) ->
+ {Pub,Priv} = crypto:generate_key(Type, {Mod,Exp}),
+ do_sign_verify({rsa, sha256, Pub, Priv, rsa_plain()}).
notsup(Fun, Args) ->
Result =
@@ -1008,7 +1027,8 @@ group_config(rsa = Type, Config) ->
rsa_oaep(),
no_padding()
],
- [{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc} | Config];
+ Generate = [{rsa, 2048, 3}, {rsa, 3072, 65537}],
+ [{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc}, {generate, Generate} | Config];
group_config(dss = Type, Config) ->
Msg = dss_plain(),
Public = dss_params() ++ [dss_public()],
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index 38e2db9033..81cb2f8130 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 3.7.2
+CRYPTO_VSN = 3.7.3
diff --git a/lib/debugger/src/dbg_wx_win.erl b/lib/debugger/src/dbg_wx_win.erl
index d302423077..2c9d83ea74 100644
--- a/lib/debugger/src/dbg_wx_win.erl
+++ b/lib/debugger/src/dbg_wx_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -276,7 +276,7 @@ verify(Type, Str) ->
case erl_scan:string(Str) of
{ok, Tokens, _EndLine} when Type==term ->
- case erl_parse:parse_term(Tokens++[{dot, 1}]) of
+ case erl_parse:parse_term(Tokens++[{dot, erl_anno:new(1)}]) of
{ok, Value} -> {edit, Value};
_Error ->
ignore
diff --git a/lib/debugger/test/int_SUITE.erl b/lib/debugger/test/int_SUITE.erl
index f697ace4e5..cb1fcb83f3 100644
--- a/lib/debugger/test/int_SUITE.erl
+++ b/lib/debugger/test/int_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -241,7 +241,8 @@ interpretable(Config) when is_list(Config) ->
true = code:del_path(PrivDir),
%% {error, no_src}
- {ok, lists2, Binary} = compile:forms([{attribute,1,module,lists2}], []),
+ A1 = erl_anno:new(1),
+ {ok, lists2, Binary} = compile:forms([{attribute,A1,module,lists2}], []),
code:load_binary(lists2, "unknown", Binary),
{error, no_src} = int:interpretable(lists2),
diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml
index 54abd09504..cd4ec4c068 100644
--- a/lib/dialyzer/doc/src/notes.xml
+++ b/lib/dialyzer/doc/src/notes.xml
@@ -32,6 +32,48 @@
<p>This document describes the changes made to the Dialyzer
application.</p>
+<section><title>Dialyzer 3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug concerning parameterized opaque types. </p>
+ <p>
+ Own Id: OTP-14130</p>
+ </item>
+ <item>
+ <p> Improve a few warnings. One of them could cause a
+ crash. </p>
+ <p>
+ Own Id: OTP-14177</p>
+ </item>
+ <item>
+ <p>The dialyzer and observer applications will now use a
+ portable way to find the home directory. That means that
+ there is no longer any need to manually set the HOME
+ environment variable on Windows.</p>
+ <p>
+ Own Id: OTP-14249 Aux Id: ERL-161 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The peak memory consumption is reduced. </p><p> The
+ evaluation of huge SCCs in <c>dialyzer_typesig</c> is
+ optimized. </p><p> Analyzing modules with binary
+ construction with huge strings is now much faster. </p>
+ <p>
+ Own Id: OTP-14126 Aux Id: ERL-308 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Dialyzer 3.0.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/dialyzer/test/abstract_SUITE.erl b/lib/dialyzer/test/abstract_SUITE.erl
index 0e84dfab24..37fb39cf27 100644
--- a/lib/dialyzer/test/abstract_SUITE.erl
+++ b/lib/dialyzer/test/abstract_SUITE.erl
@@ -83,7 +83,8 @@ generated_case(Config) when is_list(Config) ->
Config, [], []),
ok.
-test(Prog, Config, COpts, DOpts) ->
+test(Prog0, Config, COpts, DOpts) ->
+ Prog = erl_parse:anno_from_term(Prog0),
{ok, BeamFile} = compile(Config, Prog, COpts),
run_dialyzer(Config, succ_typings, [BeamFile], DOpts).
diff --git a/lib/dialyzer/test/plt_SUITE.erl b/lib/dialyzer/test/plt_SUITE.erl
index fbfa979e1b..ba153c1c27 100644
--- a/lib/dialyzer/test/plt_SUITE.erl
+++ b/lib/dialyzer/test/plt_SUITE.erl
@@ -260,6 +260,8 @@ remove_plt(Config) ->
ok.
bad_dialyzer_attr(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ Plt = filename:join(PrivDir, "plt_bad_dialyzer_attr.plt"),
Prog1 = <<"-module(dial).
-dialyzer({no_return, [undef/0]}).">>,
{ok, Beam1} = compile(Config, Prog1, dial, []),
@@ -267,7 +269,7 @@ bad_dialyzer_attr(Config) ->
"Analysis failed with error:\n"
"Could not scan the following file(s):\n"
" Unknown function undef/0 in line " ++ _} =
- (catch run_dialyzer(plt_build, [Beam1], [])),
+ (catch run_dialyzer(plt_build, [Beam1], [{output_plt, Plt}])),
Prog2 = <<"-module(dial).
-dialyzer({no_return, [{undef,1,2}]}).">>,
@@ -276,7 +278,7 @@ bad_dialyzer_attr(Config) ->
"Analysis failed with error:\n"
"Could not scan the following file(s):\n"
" Bad function {undef,1,2} in line " ++ _} =
- (catch run_dialyzer(plt_build, [Beam2], [])),
+ (catch run_dialyzer(plt_build, [Beam2], [{output_plt, Plt}])),
ok.
diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk
index 9830a36e60..0919fba834 100644
--- a/lib/dialyzer/vsn.mk
+++ b/lib/dialyzer/vsn.mk
@@ -1 +1 @@
-DIALYZER_VSN = 3.0.3
+DIALYZER_VSN = 3.1
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index c2bbed2e5a..70e1880be5 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -43,6 +43,30 @@ first.</p>
<!-- ===================================================================== -->
+<section><title>diameter 1.12.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ An improvement in the handling of peer failover in
+ diameter 1.12.1 adversely affected performance when
+ sending requests. Further, the inefficient use of a
+ public table to route incoming answers has been removed.</p>
+ <p>
+ Own Id: OTP-14206</p>
+ </item>
+ <item>
+ <p>
+ Fixed xml issues in old release notes</p>
+ <p>
+ Own Id: OTP-14269</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>diameter 1.12.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -255,8 +279,8 @@ first.</p>
Fix decode of Grouped AVPs containing errors.</p>
<p>
RFC 6733 says this of Failed-AVP in 7.5:</p>
- <p>
- <taglist><item><p><c> In the case where the offending AVP
+
+ <taglist><tag></tag><item><p><c> In the case where the offending AVP
is embedded within a Grouped AVP, the Failed-AVP MAY
contain the grouped AVP, which in turn contains the
single offending AVP. The same method MAY be employed if
@@ -265,11 +289,11 @@ first.</p>
the grouped AVP hierarchy up to the single offending AVP.
This enables the recipient to detect the location of the
offending AVP when embedded in a
- group.</c></p></item></taglist></p>
+ group.</c></p></item></taglist>
<p>
It says this of DIAMETER_INVALID_AVP_LENGTH in 7.1.5:</p>
- <p>
- <taglist><item><p><c> The request contained an AVP with
+
+ <taglist><tag></tag><item><p><c> The request contained an AVP with
an invalid length. A Diameter message indicating this
error MUST include the offending AVPs within a Failed-AVP
AVP. In cases where the erroneous AVP length value
@@ -284,7 +308,8 @@ first.</p>
the minimum AVP header length, it is sufficient to
include an offending AVP header that is formulated by
padding the incomplete AVP header with zero up to the
- minimum AVP header length.</c></p></item></taglist></p>
+ minimum AVP header length.</c></p></item></taglist>
+
<p>
The AVPs placed in the errors field of a diameter_packet
record are intended to be appropriate for inclusion in a
@@ -949,8 +974,8 @@ first.</p>
Be lenient with the M-bit in Grouped AVPs.</p>
<p>
RFC 6733 says this, in 4.4:</p>
- <p>
- <taglist><item><p><c>Receivers of a Grouped AVP that does
+
+ <taglist><tag></tag><item><p><c>Receivers of a Grouped AVP that does
not have the 'M' (mandatory) bit set and one or more of
the encapsulated AVPs within the group has the 'M'
(mandatory) bit set MAY simply be ignored if the Grouped
@@ -958,14 +983,14 @@ first.</p>
encapsulated AVP with its 'M' (mandatory) bit set is
further encapsulated within other sub-groups, i.e., other
Grouped AVPs embedded within the Grouped
- AVP.</c></p></item></taglist></p>
+ AVP.</c></p></item></taglist>
<p>
The first sentence is mangled but take it to mean this:</p>
- <p>
- <taglist><item><p><c>An unrecognized AVP of type Grouped
+
+ <taglist><tag></tag><item><p><c>An unrecognized AVP of type Grouped
that does not set the 'M' bit MAY be ignored even if one
of its encapsulated AVPs sets the 'M'
- bit.</c></p></item></taglist></p>
+ bit.</c></p></item></taglist>
<p>
This is a bit of a non-statement since if the AVP is
unrecognized then its type is unknown. We therefore don't
diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl
index e8f2f63f86..253f64133c 100644
--- a/lib/diameter/src/base/diameter.erl
+++ b/lib/diameter/src/base/diameter.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -377,6 +377,7 @@ call(SvcName, App, Message) ->
| {capabilities, [capability()]}
| {capabilities_cb, evaluable()}
| {capx_timeout, 'Unsigned32'()}
+ | {capx_strictness, boolean()}
| {disconnect_cb, evaluable()}
| {dpr_timeout, 'Unsigned32'()}
| {dpa_timeout, 'Unsigned32'()}
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index 1b48c0431f..e10804c931 100644
--- a/lib/diameter/src/base/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -580,6 +580,9 @@ opt({K, Tmo})
K == dpa_timeout ->
?IS_UINT32(Tmo);
+opt({capx_strictness, B}) ->
+ is_boolean(B);
+
opt({length_errors, T}) ->
lists:member(T, [exit, handle, discard]);
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index 4b394a2dbe..46d231da74 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -128,6 +128,7 @@
%% outgoing DPR; boolean says whether or not
%% the request was sent explicitly with
%% diameter:call/4.
+ strict :: boolean(),
length_errors :: exit | handle | discard,
incoming_maxlen :: integer() | infinity}).
@@ -233,6 +234,7 @@ i({Ack, WPid, {M, Ref} = T, Opts, {SvcOpts, Nodes, Dict0, Svc}}) ->
proplists:get_value(dpa_timeout, Opts, ?DPA_TIMEOUT)}),
Tmo = proplists:get_value(capx_timeout, Opts, ?CAPX_TIMEOUT),
+ Strictness = proplists:get_value(capx_strictness, Opts, true),
OnLengthErr = proplists:get_value(length_errors, Opts, exit),
{TPid, Addrs} = start_transport(T, Rest, Svc),
@@ -246,6 +248,7 @@ i({Ack, WPid, {M, Ref} = T, Opts, {SvcOpts, Nodes, Dict0, Svc}}) ->
mode = M,
service = svc(Svc, Addrs),
length_errors = OnLengthErr,
+ strict = Strictness,
incoming_maxlen = Maxlen}.
%% The transport returns its local ip addresses so that different
%% transports on the same service can use different local addresses.
@@ -454,6 +457,9 @@ transition({timeout, _}, _) ->
%% Outgoing message.
transition({send, Msg}, S) ->
outgoing(Msg, S);
+transition({send, Msg, Route}, S) ->
+ put_route(Route),
+ outgoing(Msg, S);
%% Request for graceful shutdown at remove_transport, stop_service of
%% application shutdown.
@@ -483,8 +489,10 @@ transition({'DOWN', _, process, TPid, _},
= S) ->
start_next(S);
-%% Transport has died after connection timeout.
-transition({'DOWN', _, process, _, _}, _) ->
+%% Transport has died after connection timeout, or handler process has
+%% died.
+transition({'DOWN', _, process, Pid, _}, _) ->
+ erase_route(Pid),
ok;
%% State query.
@@ -494,6 +502,40 @@ transition({state, Pid}, #state{state = S, transport = TPid}) ->
%% Crash on anything unexpected.
+%% put_route/1
+%%
+%% Map identifiers in an outgoing request to be able to lookup the
+%% handler process when the answer is received.
+
+put_route({Pid, Ref, Seqs}) ->
+ MRef = monitor(process, Pid),
+ put(Pid, Seqs),
+ put(Seqs, {Pid, Ref, MRef}).
+
+%% get_route/1
+
+get_route(#diameter_packet{header = #diameter_header{is_request = false}}
+ = Pkt) ->
+ Seqs = diameter_codec:sequence_numbers(Pkt),
+ case erase(Seqs) of
+ {Pid, Ref, MRef} ->
+ demonitor(MRef),
+ erase(Pid),
+ {Pid, Ref, self()};
+ undefined ->
+ false
+ end;
+
+get_route(_) ->
+ false.
+
+%% erase_route/1
+
+erase_route(Pid) ->
+ erase(erase(Pid)).
+
+%% capx/1
+
capx(recv_CER) ->
'CER';
capx({'Wait-CEA', _, _}) ->
@@ -576,8 +618,7 @@ incoming({Msg, NPid}, S) ->
T
catch
{?MODULE, Name, Pkt} ->
- S#state.parent ! {recv, self(), Name, {Pkt, NPid}},
- rcv(Name, Pkt, S)
+ incoming(Name, Pkt, NPid, S)
end;
incoming(Msg, S) ->
@@ -585,10 +626,15 @@ incoming(Msg, S) ->
recv(Msg, S)
catch
{?MODULE, Name, Pkt} ->
- S#state.parent ! {recv, self(), Name, Pkt},
- rcv(Name, Pkt, S)
+ incoming(Name, Pkt, false, S)
end.
+%% incoming/4
+
+incoming(Name, Pkt, NPid, #state{parent = Pid} = S) ->
+ Pid ! {recv, self(), get_route(Pkt), Name, Pkt, NPid},
+ rcv(Name, Pkt, S).
+
%% recv/2
recv(#diameter_packet{header = #diameter_header{} = Hdr}
@@ -614,6 +660,17 @@ recv1(_,
when M < size(Bin) ->
invalid(false, incoming_maxlen_exceeded, {size(Bin), H});
+%% Ignore anything but an expected CER/CEA if so configured. This is
+%% non-standard behaviour.
+recv1(Name, _, #state{state = {'Wait-CEA', _, _},
+ strict = false})
+ when Name /= 'CEA' ->
+ ok;
+recv1(Name, _, #state{state = recv_CER,
+ strict = false})
+ when Name /= 'CER' ->
+ ok;
+
%% Incoming request after outgoing DPR: discard. Don't discard DPR, so
%% both ends don't do so when sending simultaneously.
recv1(Name,
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index ccf68f4d93..e4f77e3a24 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1858,13 +1858,6 @@ eq(Any, Id, PeerId) ->
%% OctetString() can be specified as an iolist() so test for string
%% rather then term equality.
-%% transports/1
-
-transports(#state{watchdogT = WatchdogT}) ->
- ets:select(WatchdogT, [{#watchdog{peer = '$1', _ = '_'},
- [{'is_pid', '$1'}],
- ['$1']}]).
-
%% ---------------------------------------------------------------------------
%% # service_info/2
%% ---------------------------------------------------------------------------
@@ -1887,7 +1880,6 @@ transports(#state{watchdogT = WatchdogT}) ->
-define(ALL_INFO, [capabilities,
applications,
transport,
- pending,
options]).
%% The rest.
@@ -1981,7 +1973,6 @@ complete_info(Item, #state{service = Svc} = S) ->
applications -> info_apps(S);
transport -> info_transport(S);
options -> info_options(S);
- pending -> info_pending(S);
keys -> ?ALL_INFO ++ ?CAP_INFO ++ ?OTHER_INFO;
all -> service_info(?ALL_INFO, S);
statistics -> info_stats(S);
@@ -2189,13 +2180,6 @@ info_apps(#state{service = #diameter_service{applications = Apps}}) ->
mk_app(#diameter_app{} = A) ->
lists:zip(record_info(fields, diameter_app), tl(tuple_to_list(A))).
-%% info_pending/1
-%%
-%% One entry for each outgoing request whose answer is outstanding.
-
-info_pending(#state{} = S) ->
- diameter_traffic:pending(transports(S)).
-
%% info_info/1
%%
%% Extract process_info from connections info.
diff --git a/lib/diameter/src/base/diameter_sup.erl b/lib/diameter/src/base/diameter_sup.erl
index 482289cb9a..01c51f0856 100644
--- a/lib/diameter/src/base/diameter_sup.erl
+++ b/lib/diameter/src/base/diameter_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@
-define(TABLES, [{diameter_sequence, [set]},
{diameter_service, [set, {keypos, 3}]},
- {diameter_request, [bag]},
+ {diameter_request, [set]},
{diameter_config, [bag, {keypos, 2}]}]).
%% start_link/0
diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl
index d93a3e71e3..bc1ccf4feb 100644
--- a/lib/diameter/src/base/diameter_traffic.erl
+++ b/lib/diameter/src/base/diameter_traffic.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
-export([send_request/4]).
%% towards diameter_watchdog
--export([receive_message/4]).
+-export([receive_message/6]).
%% towards diameter_peer_fsm and diameter_watchdog
-export([incr/4,
@@ -40,11 +40,11 @@
%% towards diameter_service
-export([make_recvdata/1,
peer_up/1,
- peer_down/1,
- pending/1]).
+ peer_down/1]).
-%% towards ?MODULE
--export([send/1]). %% send from remote node
+%% internal
+-export([send/1, %% send from remote node
+ init/1]). %% monitor process start
-include_lib("diameter/include/diameter.hrl").
-include("diameter_internal.hrl").
@@ -57,14 +57,12 @@
-define(DEFAULT_TIMEOUT, 5000). %% for outgoing requests
-define(DEFAULT_SPAWN_OPTS, []).
-%% Table containing outgoing requests for which a reply has yet to be
-%% received.
+%% Table containing outgoing entries that live and die with
+%% peer_up/down. The name is historic, since the table used to contain
+%% information about outgoing requests for which an answer has yet to
+%% be received.
-define(REQUEST_TABLE, diameter_request).
-%% Workaround for dialyzer's lack of understanding of match specs.
--type match(T)
- :: T | '_' | '$1' | '$2' | '$3' | '$4'.
-
%% Record diameter:call/4 options are parsed into.
-record(options,
{filter = none :: diameter:peer_filter(),
@@ -72,7 +70,7 @@
timeout = ?DEFAULT_TIMEOUT :: 0..16#FFFFFFFF,
detach = false :: boolean()}).
-%% Term passed back to receive_message/4 with every incoming message.
+%% Term passed back to receive_message/6 with every incoming message.
-record(recvdata,
{peerT :: ets:tid(),
service_name :: diameter:service_name(),
@@ -87,12 +85,12 @@
%% Record stored in diameter_request for each outgoing request.
-record(request,
- {ref :: match(reference()), %% used to receive answer
- caller :: match(pid()), %% calling process
- handler :: match(pid()), %% request process
- transport :: match(pid()), %% peer process
- caps :: match(#diameter_caps{}), %% of connection
- packet :: match(#diameter_packet{})}). %% of request
+ {ref :: reference(), %% used to receive answer
+ caller :: pid() | undefined, %% calling process
+ handler :: pid(), %% request process
+ transport :: pid() | undefined, %% peer process
+ caps :: #diameter_caps{} | undefined, %% of connection
+ packet :: #diameter_packet{} | undefined}). %% of request
%% ---------------------------------------------------------------------------
%% # make_recvdata/1
@@ -113,26 +111,27 @@ make_recvdata([SvcName, PeerT, Apps, SvcOpts | _]) ->
%% peer_up/1
%% ---------------------------------------------------------------------------
-%% Insert an element that is used to detect whether or not there has
-%% been a failover when inserting an outgoing request.
+%% Start a process that dies with peer_down/1, on which request
+%% processes can monitor. There is no other process that dies with
+%% peer_down since failover doesn't imply the loss of transport in the
+%% case of a watchdog transition into state SUSPECT.
peer_up(TPid) ->
- ets:insert(?REQUEST_TABLE, {TPid}).
+ proc_lib:start(?MODULE, init, [TPid]).
+
+init(TPid) ->
+ ets:insert(?REQUEST_TABLE, {TPid, self()}),
+ proc_lib:init_ack(self()),
+ proc_lib:hibernate(erlang, exit, [{shutdown, TPid}]).
%% ---------------------------------------------------------------------------
%% peer_down/1
%% ---------------------------------------------------------------------------
peer_down(TPid) ->
- ets:delete_object(?REQUEST_TABLE, {TPid}),
- lists:foreach(fun failover/1, ets:lookup(?REQUEST_TABLE, TPid)).
-%% Note that a request process can store its request after failover
-%% notifications are sent here: insert_request/2 sends the notification
-%% in that case.
-
-%% failover/1
-
-failover({_TPid, {Pid, TRef}}) ->
- Pid ! {failover, TRef}.
+ [{_, Pid}] = ets:lookup(?REQUEST_TABLE, TPid),
+ ets:delete(?REQUEST_TABLE, TPid),
+ Pid ! ok, %% make it die
+ Pid.
%% ---------------------------------------------------------------------------
%% incr/4
@@ -207,54 +206,25 @@ incr_rc(Dir, Pkt, TPid, Dict0) ->
incr_rc(Dir, Pkt, TPid, {Dict0, Dict0, Dict0}).
%% ---------------------------------------------------------------------------
-%% pending/1
-%% ---------------------------------------------------------------------------
-
-pending(TPids) ->
- MatchSpec = [{{'$1',
- #request{caller = '$2',
- handler = '$3',
- transport = '$4',
- _ = '_'},
- '_'},
- [?ORCOND([{'==', T, '$4'} || T <- TPids])],
- [{{'$1', [{{caller, '$2'}},
- {{handler, '$3'}},
- {{transport, '$4'}}]}}]}],
-
- try
- ets:select(?REQUEST_TABLE, MatchSpec)
- catch
- error: badarg -> [] %% service has gone down
- end.
-
-%% ---------------------------------------------------------------------------
-%% # receive_message/4
+%% # receive_message/6
%%
%% Handle an incoming Diameter message.
%% ---------------------------------------------------------------------------
-%% Handle an incoming Diameter message in the watchdog process. This
-%% used to come through the service process but this avoids that
-%% becoming a bottleneck.
+%% Handle an incoming Diameter message in the watchdog process.
-receive_message(TPid, {Pkt, NPid}, Dict0, RecvData) ->
- NPid ! {diameter, incoming(TPid, Pkt, Dict0, RecvData)};
+receive_message(TPid, Route, Pkt, false, Dict0, RecvData) ->
+ incoming(TPid, Route, Pkt, Dict0, RecvData);
-receive_message(TPid, Pkt, Dict0, RecvData) ->
- incoming(TPid, Pkt, Dict0, RecvData).
+receive_message(TPid, Route, Pkt, NPid, Dict0, RecvData) ->
+ NPid ! {diameter, incoming(TPid, Route, Pkt, Dict0, RecvData)}.
%% incoming/4
-incoming(TPid, Pkt, Dict0, RecvData)
+incoming(TPid, Route, Pkt, Dict0, RecvData)
when is_pid(TPid) ->
#diameter_packet{header = #diameter_header{is_request = R}} = Pkt,
- recv(R,
- (not R) andalso lookup_request(Pkt, TPid),
- TPid,
- Pkt,
- Dict0,
- RecvData).
+ recv(R, Route, TPid, Pkt, Dict0, RecvData).
%% recv/6
@@ -269,8 +239,8 @@ recv(true, false, TPid, Pkt, Dict0, T) ->
end;
%% ... answer to known request ...
-recv(false, #request{ref = Ref, handler = Pid} = Req, _, Pkt, Dict0, _) ->
- Pid ! {answer, Ref, Req, Dict0, Pkt},
+recv(false, {Pid, Ref, TPid}, _, Pkt, Dict0, _) ->
+ Pid ! {answer, Ref, TPid, Dict0, Pkt},
{answer, Pid};
%% Note that failover could have happened prior to this message being
@@ -1503,32 +1473,39 @@ send_R(Pkt0,
packet = Pkt0},
incr(send, Pkt, TPid, AppDict),
- TRef = send_request(TPid, Pkt, Req, SvcName, Timeout),
+ {TRef, MRef} = zend_requezt(TPid, Pkt, Req, SvcName, Timeout),
Pid ! Ref, %% tell caller a send has been attempted
handle_answer(SvcName,
App,
- recv_A(Timeout, SvcName, App, Opts, {TRef, Req})).
+ recv_A(Timeout, SvcName, App, Opts, {TRef, MRef, Req})).
%% recv_A/5
-recv_A(Timeout, SvcName, App, Opts, {TRef, #request{ref = Ref} = Req}) ->
+recv_A(Timeout, SvcName, App, Opts, {TRef, MRef, #request{ref = Ref} = Req}) ->
%% Matching on TRef below ensures we ignore messages that pertain
%% to a previous transport prior to failover. The answer message
- %% includes the #request{} since it's not necessarily Req; that
- %% is, from the last peer to which we've transmitted.
+ %% includes the pid of the transport on which it was received,
+ %% which may not be the last peer to which we've transmitted.
receive
- {answer = A, Ref, Rq, Dict0, Pkt} -> %% Answer from peer
- {A, Rq, Dict0, Pkt};
+ {answer = A, Ref, TPid, Dict0, Pkt} -> %% Answer from peer
+ {A, #request{} = erase(TPid), Dict0, Pkt};
{timeout = Reason, TRef, _} -> %% No timely reply
{error, Req, Reason};
- {failover, TRef} -> %% Service says peer has gone down
- retransmit(pick_peer(SvcName, App, Req, Opts),
- Req,
- Opts,
- SvcName,
- Timeout)
+ {'DOWN', MRef, process, _, _} when false /= MRef -> %% local peer_down
+ failover(SvcName, App, Req, Opts, Timeout);
+ {failover, TRef} -> %% local or remote peer_down
+ failover(SvcName, App, Req, Opts, Timeout)
end.
+%% failover/5
+
+failover(SvcName, App, Req, Opts, Timeout) ->
+ retransmit(pick_peer(SvcName, App, Req, Opts),
+ Req,
+ Opts,
+ SvcName,
+ Timeout).
+
%% handle_answer/3
handle_answer(SvcName, App, {error, Req, Reason}) ->
@@ -1705,44 +1682,63 @@ encode(DictT, TPid, #diameter_packet{bin = undefined} = Pkt) ->
encode(_, _, #diameter_packet{} = Pkt) ->
Pkt.
+%% zend_requezt/5
+%%
+%% Strip potentially large record fields that aren't used by the
+%% processes the records can be send to, possibly on a remote node.
+
+zend_requezt(TPid, Pkt, Req, SvcName, Timeout) ->
+ put(TPid, Req),
+ send_request(TPid, z(Pkt), Req, SvcName, Timeout).
+
%% send_request/5
send_request(TPid, #diameter_packet{bin = Bin} = Pkt, Req, _SvcName, Timeout)
when node() == node(TPid) ->
Seqs = diameter_codec:sequence_numbers(Bin),
TRef = erlang:start_timer(Timeout, self(), TPid),
- Entry = {Seqs, #request{handler = Pid} = Req, TRef},
-
- %% Ensure that request table is cleaned even if the process is
- %% killed.
- spawn(fun() -> diameter_lib:wait([Pid]), delete_request(Entry) end),
-
- insert_request(Entry),
- send(TPid, Pkt),
- TRef;
+ send(TPid, Pkt, _Route = {self(), Req#request.ref, Seqs}),
+ {TRef, _MRef = peer_monitor(TPid, TRef)};
%% Send using a remote transport: spawn a process on the remote node
%% to relay the answer.
send_request(TPid, #diameter_packet{} = Pkt, Req, SvcName, Timeout) ->
TRef = erlang:start_timer(Timeout, self(), TPid),
- T = {TPid, Pkt, Req, SvcName, Timeout, TRef},
+ T = {TPid, Pkt, z(Req), SvcName, Timeout, TRef},
spawn(node(TPid), ?MODULE, send, [T]),
- TRef.
+ {TRef, false}.
+
+%% z/1
+%%
+%% Avoid sending potentially large terms unnecessarily. The records
+%% themselves are retained since they're sent between nodes in send/1
+%% and changing what's sent causes upgrade issues.
+
+z(#request{ref = Ref, handler = Pid}) ->
+ #request{ref = Ref,
+ handler = Pid};
+
+z(#diameter_packet{header = H, bin = Bin, transport_data = T}) ->
+ #diameter_packet{header = H,
+ bin = Bin,
+ transport_data = T}.
%% send/1
send({TPid, Pkt, #request{handler = Pid} = Req0, SvcName, Timeout, TRef}) ->
Req = Req0#request{handler = self()},
- recv(TPid, Pid, TRef, send_request(TPid, Pkt, Req, SvcName, Timeout)).
+ recv(TPid, Pid, TRef, zend_requezt(TPid, Pkt, Req, SvcName, Timeout)).
%% recv/4
%%
%% Relay an answer from a remote node.
-recv(TPid, Pid, TRef, LocalTRef) ->
+recv(TPid, Pid, TRef, {LocalTRef, MRef}) ->
receive
{answer, _, _, _, _} = A ->
Pid ! A;
+ {'DOWN', MRef, process, _, _} ->
+ Pid ! {failover, TRef};
{failover = T, LocalTRef} ->
Pid ! {T, TRef};
T ->
@@ -1751,14 +1747,13 @@ recv(TPid, Pid, TRef, LocalTRef) ->
%% send/2
-send(Pid, Pkt) -> %% Strip potentially large message terms.
- #diameter_packet{header = H,
- bin = Bin,
- transport_data = T}
- = Pkt,
- Pid ! {send, #diameter_packet{header = H,
- bin = Bin,
- transport_data = T}}.
+send(Pid, Pkt) ->
+ Pid ! {send, Pkt}.
+
+%% send/3
+
+send(Pid, Pkt, Route) ->
+ Pid ! {send, Pkt, Route}.
%% retransmit/4
@@ -1768,8 +1763,8 @@ retransmit({TPid, Caps, App}
= Req,
SvcName,
Timeout) ->
- have_request(Pkt0, TPid) %% Don't failover to a peer we've
- andalso ?THROW(timeout), %% already sent to.
+ undefined == get(TPid) %% Don't failover to a peer we've
+ orelse ?THROW(timeout), %% already sent to.
Pkt = make_retransmit_packet(Pkt0),
@@ -1822,56 +1817,20 @@ resend_request(Pkt0,
?LOG(retransmission, Pkt#diameter_packet.header),
incr(TPid, {msg_id(Pkt, AppDict), send, retransmission}),
- TRef = send_request(TPid, Pkt, Req, SvcName, Tmo),
- {TRef, Req}.
-
-%% insert_request/1
-
-insert_request({_Seqs, #request{transport = TPid}, TRef} = T) ->
- ets:insert(?REQUEST_TABLE, [T, {TPid, {self(), TRef}}]),
- is_peer_up(TPid)
- orelse (self() ! {failover, TRef}). %% failover/1 may have missed
-
-%% is_peer_up/1
-%%
-%% Is the entry written by peer_up/1 and deleted by peer_down/1 still
-%% in the request table?
+ {TRef, MRef} = zend_requezt(TPid, Pkt, Req, SvcName, Tmo),
+ {TRef, MRef, Req}.
-is_peer_up(TPid) ->
- Spec = [{{TPid}, [], ['$_']}],
- '$end_of_table' /= ets:select(?REQUEST_TABLE, Spec, 1).
+%% peer_monitor/2
-%% lookup_request/2
-%%
-%% Note the match on both the key and transport pid. The latter is
-%% necessary since the same Hop-by-Hop and End-to-End identifiers are
-%% reused in the case of retransmission.
-
-lookup_request(Msg, TPid) ->
- Seqs = diameter_codec:sequence_numbers(Msg),
- Spec = [{{Seqs, #request{transport = TPid, _ = '_'}, '_'},
- [],
- ['$_']}],
- case ets:select(?REQUEST_TABLE, Spec) of
- [{_, Req, _}] ->
- Req;
- [] ->
+peer_monitor(TPid, TRef) ->
+ case ets:lookup(?REQUEST_TABLE, TPid) of %% at peer_up/1
+ [{_, MPid}] ->
+ monitor(process, MPid);
+ [] -> %% transport has gone down
+ self() ! {failover, TRef},
false
end.
-%% delete_request/1
-
-delete_request({_Seqs, #request{handler = Pid, transport = TPid}, TRef} = T) ->
- Spec = [{R, [], [true]} || R <- [T, {TPid, {Pid, TRef}}]],
- ets:select_delete(?REQUEST_TABLE, Spec).
-
-%% have_request/2
-
-have_request(Pkt, TPid) ->
- Seqs = diameter_codec:sequence_numbers(Pkt),
- Pat = {Seqs, #request{transport = TPid, _ = '_'}, '_'},
- '$end_of_table' /= ets:select(?REQUEST_TABLE, [{Pat, [], ['$_']}], 1).
-
%% get_destination/2
get_destination(Dict, Msg) ->
diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl
index 2ba60a65fb..f28b8f2910 100644
--- a/lib/diameter/src/base/diameter_watchdog.erl
+++ b/lib/diameter/src/base/diameter_watchdog.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -283,7 +283,7 @@ event(Msg,
?LOG(transition, {From, To}).
data(Msg, TPid, reopen, okay) ->
- {recv, TPid, 'DWA', _Pkt} = Msg, %% assert
+ {recv, TPid, false, 'DWA', _Pkt, _NPid} = Msg, %% assert
{TPid, T} = eraser(open),
[T];
@@ -447,12 +447,14 @@ transition({'DOWN', _, process, TPid, _Reason} = D,
end;
%% Incoming message.
-transition({recv, TPid, Name, PktT}, #watchdog{transport = TPid} = S) ->
+transition({recv, TPid, Route, Name, Pkt, NPid},
+ #watchdog{transport = TPid}
+ = S) ->
try
- incoming(Name, PktT, S)
+ incoming(Name, Pkt, NPid, S)
catch
#watchdog{dictionary = Dict0, receive_data = T} = NS ->
- diameter_traffic:receive_message(TPid, PktT, Dict0, T),
+ diameter_traffic:receive_message(TPid, Route, Pkt, NPid, Dict0, T),
NS
end;
@@ -582,15 +584,17 @@ send_watchdog(#watchdog{pending = false,
%% Don't count encode errors since we don't expect any on DWR/DWA.
-%% incoming/3
+%% incoming/4
-incoming(Name, {Pkt, NPid}, S) ->
- NS = recv(Name, Pkt, S),
- NPid ! {diameter, discard},
- NS;
+incoming(Name, Pkt, false, S) ->
+ recv(Name, Pkt, S);
-incoming(Name, Pkt, S) ->
- recv(Name, Pkt, S).
+incoming(Name, Pkt, NPid, S) ->
+ try
+ recv(Name, Pkt, S)
+ after
+ NPid ! {diameter, discard}
+ end.
%% recv/3
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index 864d5f0691..928ae37e7f 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -184,7 +184,7 @@ erl_forms(Mod, ParseD) ->
f_enumerated_avp(ParseD),
f_empty_value(ParseD),
f_dict(ParseD),
- {eof, erl_anno:new(?LINE)}]],
+ {eof, ?LINE}]],
lists:append(Forms).
diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src
index b1b8e38d39..eb5a5a44f3 100644
--- a/lib/diameter/src/diameter.appup.src
+++ b/lib/diameter/src/diameter.appup.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -50,10 +50,8 @@
{"1.11", [{restart_application, diameter}]}, %% 18.1
{"1.11.1", [{restart_application, diameter}]}, %% 18.2
{"1.11.2", [{restart_application, diameter}]}, %% 18.3
- {"1.12", [{load_module, diameter_lib}, %% 19.0
- {load_module, diameter_traffic},
- {load_module, diameter_tcp},
- {load_module, diameter_sctp}]}
+ {"1.12", [{restart_application, diameter}]}, %% 19.0
+ {"1.12.1", [{restart_application, diameter}]} %% 19.1
],
[
{"0.9", [{restart_application, diameter}]},
@@ -85,9 +83,7 @@
{"1.11", [{restart_application, diameter}]},
{"1.11.1", [{restart_application, diameter}]},
{"1.11.2", [{restart_application, diameter}]},
- {"1.12", [{load_module, diameter_sctp},
- {load_module, diameter_tcp},
- {load_module, diameter_traffic},
- {load_module, diameter_lib}]}
+ {"1.12", [{restart_application, diameter}]},
+ {"1.12.1", [{restart_application, diameter}]}
]
}.
diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk
index 23219950bb..94d9d72a48 100644
--- a/lib/diameter/vsn.mk
+++ b/lib/diameter/vsn.mk
@@ -1,6 +1,6 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2016. All Rights Reserved.
+# Copyright Ericsson AB 2010-2017. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,5 +17,5 @@
# %CopyrightEnd%
APPLICATION = diameter
-DIAMETER_VSN = 1.12.1
+DIAMETER_VSN = 1.12.2
APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)
diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl
index 9407ae1321..5ef210980c 100644
--- a/lib/edoc/src/edoc_layout.erl
+++ b/lib/edoc/src/edoc_layout.erl
@@ -214,7 +214,7 @@ layout_module(#xmlElement{name = module, content = Es}=E, Opts) ->
++ functions(SortedFs, Opts)
++ [hr, ?NL]
++ navigation("bottom")
- ++ timestamp()),
+ ++ footer()),
Encoding = get_attrval(encoding, E),
xhtml(Title, stylesheet(Opts), Body, Encoding).
@@ -228,12 +228,8 @@ module_params(Es) ->
[element(1, First) | [ {[", ",A]} || {A, _D} <- Rest]]
end.
-timestamp() ->
- [?NL, {p, [{i, [io_lib:fwrite("Generated by EDoc, ~s, ~s.",
- [edoc_lib:datestr(date()),
- edoc_lib:timestr(time())])
- ]}]},
- ?NL].
+footer() ->
+ [?NL, {p, [{i, ["Generated by EDoc"]}]}, ?NL].
stylesheet(Opts) ->
case Opts#opts.stylesheet of
@@ -1039,7 +1035,7 @@ overview(E=#xmlElement{name = overview, content = Es}, Options) ->
++ FullDesc
++ [?NL, hr]
++ navigation("bottom")
- ++ timestamp()),
+ ++ footer()),
Encoding = get_attrval(encoding, E),
XML = xhtml(Title, stylesheet(Opts), Body, Encoding),
xmerl:export_simple(XML, ?HTML_EXPORT, []).
diff --git a/lib/edoc/test/edoc_SUITE.erl b/lib/edoc/test/edoc_SUITE.erl
index 00d7550bed..4d846ad63d 100644
--- a/lib/edoc/test/edoc_SUITE.erl
+++ b/lib/edoc/test/edoc_SUITE.erl
@@ -69,7 +69,7 @@ build_std(Config) when is_list(Config) ->
{def, {vsn,"TEST"}},
{dir, PrivDir}]),
- ok = edoc:application(xmerl, [{dir, PrivDir}]),
+ ok = edoc:application(xmerl, [{preprocess,true},{dir, PrivDir}]),
ok.
build_map_module(Config) when is_list(Config) ->
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
index 69ba3cddb8..b5d8def655 100644
--- a/lib/erl_interface/doc/src/notes.xml
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the Erl_interface application.</p>
+<section><title>Erl_Interface 3.9.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Minor documentation update</p>
+ <p>
+ Own Id: OTP-14233 Aux Id: PR-1343 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erl_Interface 3.9.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index c7981ed3a5..563694a0c1 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1,2 +1,2 @@
-EI_VSN = 3.9.2
+EI_VSN = 3.9.3
ERL_INTERFACE_VSN = $(EI_VSN)
diff --git a/lib/eunit/doc/overview.edoc b/lib/eunit/doc/overview.edoc
index 3a46e991cb..dc9f858812 100644
--- a/lib/eunit/doc/overview.edoc
+++ b/lib/eunit/doc/overview.edoc
@@ -578,7 +578,7 @@ results for equality, if testing is enabled. If the values are not
equal, an informative exception will be generated; see the `assert'
macro for further details.
-`assertEqual' is more suitable than than `assertMatch' when the
+`assertEqual' is more suitable than `assertMatch' when the
left-hand side is a computed value rather than a simple pattern, and
gives more details than `?assert(Expect =:= Expr)'.
@@ -994,7 +994,7 @@ specified node. `local' means that the current process will handle both
setup/teardown and running the tests - the drawback is that if a test
times out so that the process is killed, the <em>cleanup will not be
performed</em>; hence, avoid this for persistent fixtures such as file
-operations. In general, 'local' should only be used when:
+operations. In general, `local' should only be used when:
<ul>
<li>the setup/teardown needs to be executed by the process that will
run the tests;</li>
diff --git a/lib/eunit/src/eunit.erl b/lib/eunit/src/eunit.erl
index 2c832a7f7a..1ace85ffde 100644
--- a/lib/eunit/src/eunit.erl
+++ b/lib/eunit/src/eunit.erl
@@ -256,7 +256,7 @@ all_options(Opts) ->
false -> Opts;
S ->
{ok, Ts, _} = erl_scan:string(S),
- {ok, V} = erl_parse:parse_term(Ts ++ [{dot,1}]),
+ {ok, V} = erl_parse:parse_term(Ts ++ [{dot,erl_anno:new(1)}]),
if is_list(V) -> Opts ++ V;
true -> Opts ++ [V]
end
diff --git a/lib/hipe/amd64/Makefile b/lib/hipe/amd64/Makefile
index 617f6749ac..d0da8cdff6 100644
--- a/lib/hipe/amd64/Makefile
+++ b/lib/hipe/amd64/Makefile
@@ -128,6 +128,7 @@ $(EBIN)/hipe_amd64_ra_postconditions.beam: ../main/hipe.hrl ../x86/hipe_x86.hrl
$(EBIN)/hipe_amd64_ra_sse2_postconditions.beam: ../main/hipe.hrl
$(EBIN)/hipe_amd64_registers.beam: ../rtl/hipe_literals.hrl
$(EBIN)/hipe_amd64_spill_restore.beam: ../main/hipe.hrl ../x86/hipe_x86.hrl ../flow/cfg.hrl ../x86/hipe_x86_spill_restore.erl
+$(EBIN)/hipe_amd64_subst.beam: ../x86/hipe_x86_subst.erl
$(EBIN)/hipe_amd64_x87.beam: ../x86/hipe_x86_x87.erl
$(EBIN)/hipe_amd64_sse2.beam: ../main/hipe.hrl ../x86/hipe_x86.hrl
$(EBIN)/hipe_rtl_to_amd64.beam: ../x86/hipe_rtl_to_x86.erl ../rtl/hipe_rtl.hrl
diff --git a/lib/hipe/amd64/hipe_amd64_encode.erl b/lib/hipe/amd64/hipe_amd64_encode.erl
index f8cc0c7d83..bda2824ffc 100644
--- a/lib/hipe/amd64/hipe_amd64_encode.erl
+++ b/lib/hipe/amd64/hipe_amd64_encode.erl
@@ -1316,6 +1316,7 @@ dotest1(OS) ->
RM64 = {rm64,rm_reg(?EDX)},
RM32 = {rm32,rm_reg(?EDX)},
RM16 = {rm16,rm_reg(?EDX)},
+ RM16REX = {rm16,rm_reg(?R13)},
RM8 = {rm8,rm_reg(?EDX)},
RM8REX = {rm8,rm_reg(?SIL)},
Rel32 = {rel32,Word32},
@@ -1479,6 +1480,7 @@ dotest1(OS) ->
t(OS,'test',{RM8,Imm8}),
t(OS,'test',{RM8REX,Imm8}),
t(OS,'test',{RM16,Imm16}),
+ t(OS,'test',{RM16REX,Imm16}),
t(OS,'test',{RM32,Imm32}),
t(OS,'test',{RM64,Imm32}),
t(OS,'test',{RM32,Reg32}),
diff --git a/lib/hipe/amd64/hipe_amd64_registers.erl b/lib/hipe/amd64/hipe_amd64_registers.erl
index a4cb71a106..a5cecef5a1 100644
--- a/lib/hipe/amd64/hipe_amd64_registers.erl
+++ b/lib/hipe/amd64/hipe_amd64_registers.erl
@@ -207,19 +207,14 @@ allocatable_x87() ->
nr_args() -> ?AMD64_NR_ARG_REGS.
-arg(N) ->
- if N < ?AMD64_NR_ARG_REGS ->
- case N of
- 0 -> ?ARG0;
- 1 -> ?ARG1;
- 2 -> ?ARG2;
- 3 -> ?ARG3;
- 4 -> ?ARG4;
- 5 -> ?ARG5;
- _ -> exit({?MODULE, arg, N})
- end;
- true ->
- exit({?MODULE, arg, N})
+arg(N) when N < ?AMD64_NR_ARG_REGS ->
+ case N of
+ 0 -> ?ARG0;
+ 1 -> ?ARG1;
+ 2 -> ?ARG2;
+ 3 -> ?ARG3;
+ 4 -> ?ARG4;
+ 5 -> ?ARG5
end.
is_arg(R) ->
@@ -240,11 +235,7 @@ args(Arity) when is_integer(Arity), Arity >= 0 ->
args(I, Rest) when I < 0 -> Rest;
args(I, Rest) -> args(I-1, [arg(I) | Rest]).
-ret(N) ->
- case N of
- 0 -> ?RAX;
- _ -> exit({?MODULE, ret, N})
- end.
+ret(0) -> ?RAX.
%% Note: the fact that (allocatable() UNION allocatable_x87() UNION
%% allocatable_sse2()) is a subset of call_clobbered() is hard-coded in
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index 314fd55ba3..58ca0b2138 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -31,6 +31,26 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.15.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug concerning parameterized opaque types. </p>
+ <p>
+ Own Id: OTP-14130</p>
+ </item>
+ <item>
+ <p>
+ Fixed xml issues in old release notes</p>
+ <p>
+ Own Id: OTP-14269</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.15.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -130,12 +150,12 @@
</item>
<item>
<p>
- Various fixes and improvements to the HiPE LLVM backend.
+ Various fixes and improvements to the HiPE LLVM backend.</p>
<list> <item>Add support for LLVM 3.7 and 3.8 in the
HiPE/LLVM x86_64 backend</item> <item>Reinstate support
for the LLVM backend on x86 (works OK for LLVM 3.5 to 3.7
-- LLVM 3.8 has a bug that prevents it from generating
- correct native code on x86)</item> </list></p>
+ correct native code on x86)</item> </list>
<p>
Own Id: OTP-13626</p>
</item>
@@ -191,7 +211,7 @@
<item>
<p>
Fix various binary construction inconsistencies for hipe
- compiled code. <list> <item>Passing bad field sizes to
+ compiled code.</p> <list> <item>Passing bad field sizes to
binary constructions would throw <c>badarith</c> rather
than <c>badarg</c>. Worse, in guards, when the unit size
of the field was 1, the exception would leak rather than
@@ -211,7 +231,7 @@
missing check for unit size match when inserting a
binary. For example, a faulty expression like
<c>&lt;&lt;&lt;&lt;1:7&gt;&gt;/binary&gt;&gt;</c> would
- succeed.</item> </list></p>
+ succeed.</item> </list>
<p>
Own Id: OTP-13272</p>
</item>
diff --git a/lib/hipe/flow/ebb.inc b/lib/hipe/flow/ebb.inc
index 58213e44d5..e4b7fd0efb 100644
--- a/lib/hipe/flow/ebb.inc
+++ b/lib/hipe/flow/ebb.inc
@@ -40,12 +40,14 @@
%% | {ebb_leaf, SuccesorLabel}
%%--------------------------------------------------------------------
-%% XXX: Cheating big time! no recursive types
--type ebb() :: {ebb_node, icode_lbl(), _}
- | {ebb_leaf, icode_lbl()}.
+-type ebb() :: ebb_node()
+ | ebb_leaf().
-record(ebb_node, {label :: icode_lbl(), successors :: [ebb()]}).
+-type ebb_node() :: #ebb_node{}.
+
-record(ebb_leaf, {successor :: icode_lbl()}).
+-type ebb_leaf() :: #ebb_leaf{}.
%%--------------------------------------------------------------------
%% Returns a list of extended basic blocks.
@@ -193,7 +195,7 @@ add_succ([Lbl|Lbls], Visited, Node, MkFun, EBBs, CFG) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec mk_node(icode_lbl(), [ebb()]) -> #ebb_node{}.
+-spec mk_node(icode_lbl(), [ebb()]) -> ebb_node().
mk_node(Label, Successors) -> #ebb_node{label=Label, successors=Successors}.
-spec node_label(#ebb_node{}) -> icode_lbl().
@@ -202,11 +204,11 @@ node_label(#ebb_node{label=Label}) -> Label.
-spec node_successors(#ebb_node{}) -> [ebb()].
node_successors(#ebb_node{successors=Successors}) -> Successors.
--spec mk_leaf(icode_lbl()) -> #ebb_leaf{}.
+-spec mk_leaf(icode_lbl()) -> ebb_leaf().
mk_leaf(NextEbb) -> #ebb_leaf{successor=NextEbb}.
%% leaf_next(Leaf) -> Leaf#ebb_leaf.successor.
--spec type(#ebb_node{}) -> 'node' ; (#ebb_leaf{}) -> 'leaf'.
+-spec type(ebb_node()) -> 'node' ; (ebb_leaf()) -> 'leaf'.
type(#ebb_node{}) -> node;
type(#ebb_leaf{}) -> leaf.
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index 100bc0b0e2..610578dfbc 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -148,7 +148,8 @@ trans_mfa_code(M,F,A, FunBeamCode, ClosureInfo) ->
{Code3,_Env3} = mk_debug_calltrace(MFA, Env1, Code2),
{Code3,_Env3} = {Code2,Env1}),
%% For stack optimization
- Leafness = leafness(Code3),
+ IsClosure = get_closure_info(MFA, ClosureInfo) =/= not_a_closure,
+ Leafness = leafness(Code3, IsClosure),
IsLeaf = is_leaf_code(Leafness),
Code4 =
[FunLbl |
@@ -156,7 +157,6 @@ trans_mfa_code(M,F,A, FunBeamCode, ClosureInfo) ->
false -> Code3;
true -> [mk_redtest()|Code3]
end],
- IsClosure = get_closure_info(MFA, ClosureInfo) =/= not_a_closure,
Code5 = hipe_icode:mk_icode(MFA, FunArgs, IsClosure, IsLeaf,
remove_dead_code(Code4),
hipe_gensym:var_range(icode),
@@ -173,12 +173,12 @@ trans_mfa_code(M,F,A, FunBeamCode, ClosureInfo) ->
mk_redtest() -> hipe_icode:mk_primop([], redtest, []).
-leafness(Is) -> % -> true, selfrec, or false
- leafness(Is, true).
+leafness(Is, IsClosure) -> % -> true, selfrec, closure, or false
+ leafness(Is, IsClosure, true).
-leafness([], Leafness) ->
+leafness([], _IsClosure, Leafness) ->
Leafness;
-leafness([I|Is], Leafness) ->
+leafness([I|Is], IsClosure, Leafness) ->
case I of
#icode_comment{} ->
%% BEAM self-tailcalls become gotos, but they leave
@@ -191,7 +191,7 @@ leafness([I|Is], Leafness) ->
'self_tail_recursive' -> selfrec; % call_only to selfrec
_ -> Leafness
end,
- leafness(Is, NewLeafness);
+ leafness(Is, IsClosure, NewLeafness);
#icode_call{} ->
case hipe_icode:call_type(I) of
'primop' ->
@@ -199,12 +199,12 @@ leafness([I|Is], Leafness) ->
call_fun -> false; % Calls closure
enter_fun -> false; % Calls closure
#apply_N{} -> false;
- _ -> leafness(Is, Leafness) % Other primop calls are ok
+ _ -> leafness(Is, IsClosure, Leafness) % Other primop calls are ok
end;
T when T =:= 'local' orelse T =:= 'remote' ->
{M,F,A} = hipe_icode:call_fun(I),
case erlang:is_builtin(M, F, A) of
- true -> leafness(Is, Leafness);
+ true -> leafness(Is, IsClosure, Leafness);
false -> false
end
end;
@@ -223,11 +223,12 @@ leafness([I|Is], Leafness) ->
T when T =:= 'local' orelse T =:= 'remote' ->
{M,F,A} = hipe_icode:enter_fun(I),
case erlang:is_builtin(M, F, A) of
- true -> leafness(Is, Leafness);
+ true -> leafness(Is, IsClosure, Leafness);
+ _ when IsClosure -> leafness(Is, IsClosure, closure);
_ -> false
end
end;
- _ -> leafness(Is, Leafness)
+ _ -> leafness(Is, IsClosure, Leafness)
end.
%% XXX: this old stuff is passed around but essentially unused
@@ -235,12 +236,20 @@ is_leaf_code(Leafness) ->
case Leafness of
true -> true;
selfrec -> true;
+ closure -> false;
false -> false
end.
needs_redtest(Leafness) ->
case Leafness of
true -> false;
+ %% A "leaf" closure may contain tailcalls to non-closures in addition to
+ %% what other leaves may contain. Omitting the redtest is useful to generate
+ %% shorter code for closures generated by (fun F/A), and is safe since
+ %% control flow cannot return to a "leaf" closure again without a reduction
+ %% being consumed. This is true since no function that can call a closure
+ %% will ever have its redtest omitted.
+ closure -> false;
selfrec -> true;
false -> true
end.
diff --git a/lib/hipe/icode/hipe_icode_type.erl b/lib/hipe/icode/hipe_icode_type.erl
index 815d1e57a8..aafaeb5a0a 100644
--- a/lib/hipe/icode/hipe_icode_type.erl
+++ b/lib/hipe/icode/hipe_icode_type.erl
@@ -1410,9 +1410,10 @@ transform_element2(I) ->
NewIndex =
case test_type(integer, IndexType) of
true ->
- case t_number_vals(IndexType) of
- unknown -> unknown;
- [_|_] = Vals -> {number, Vals}
+ case {number_min(IndexType), number_max(IndexType)} of
+ {Lb0, Ub0} when is_integer(Lb0), is_integer(Ub0) ->
+ {number, Lb0, Ub0};
+ {_, _} -> unknown
end;
_ -> unknown
end,
@@ -1427,19 +1428,19 @@ transform_element2(I) ->
_ -> unknown
end,
case {NewIndex, MinSize} of
- {{number, [_|_] = Ns}, {tuple, A}} when is_integer(A) ->
- case lists:all(fun(X) -> 0 < X andalso X =< A end, Ns) of
+ {{number, Lb, Ub}, {tuple, A}} when is_integer(A) ->
+ case 0 < Lb andalso Ub =< A of
true ->
- case Ns of
- [Idx] ->
+ case {Lb, Ub} of
+ {Idx, Idx} ->
[_, Tuple] = hipe_icode:args(I),
update_call_or_enter(I, #unsafe_element{index = Idx}, [Tuple]);
- [_|_] ->
+ {_, _} ->
NewFun = {element, [MinSize, valid]},
update_call_or_enter(I, NewFun)
end;
false ->
- case lists:all(fun(X) -> hipe_tagscheme:is_fixnum(X) end, Ns) of
+ case lists:all(fun(X) -> hipe_tagscheme:is_fixnum(X) end, [Lb, Ub]) of
true ->
NewFun = {element, [MinSize, fixnums]},
update_call_or_enter(I, NewFun);
@@ -1454,7 +1455,7 @@ transform_element2(I) ->
NewFun = {element, [MinSize, fixnums]},
update_call_or_enter(I, NewFun);
false ->
- NewFun = {element, [MinSize, NewIndex]},
+ NewFun = {element, [MinSize, NewIndex]},
update_call_or_enter(I, NewFun)
end
end.
diff --git a/lib/hipe/llvm/hipe_rtl_to_llvm.erl b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
index 208d86841f..79e1bfd381 100644
--- a/lib/hipe/llvm/hipe_rtl_to_llvm.erl
+++ b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
@@ -1364,7 +1364,7 @@ create_function_definition(Fun, Params, Code, LocalVars) ->
EntryBlock =
lists:flatten([EntryLabel, ExceptionSync, I2, LocalVars, StoredParams, I3]),
Final_Code = EntryBlock ++ Code,
- FunctionOptions = [nounwind, noredzone, list_to_atom("gc \"erlang\"")],
+ FunctionOptions = [nounwind, noredzone, 'gc "erlang"'],
WordTy = hipe_llvm:mk_int(?BITS_IN_WORD),
FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
hipe_llvm:mk_fun_def([], [], "cc 11", [], FunRetTy, FunctionName, Args,
diff --git a/lib/hipe/regalloc/hipe_amd64_specific_sse2.erl b/lib/hipe/regalloc/hipe_amd64_specific_sse2.erl
index 9c94539bc6..9682d37520 100644
--- a/lib/hipe/regalloc/hipe_amd64_specific_sse2.erl
+++ b/lib/hipe/regalloc/hipe_amd64_specific_sse2.erl
@@ -126,8 +126,8 @@ temp0(_) ->
all_precoloured(Ctx) ->
allocatable(Ctx).
-is_precoloured(Reg, Ctx) ->
- lists:member(Reg,all_precoloured(Ctx)).
+is_precoloured(Reg, _) ->
+ hipe_amd64_registers:is_precoloured_sse2(Reg).
physical_name(Reg, _) ->
Reg.
diff --git a/lib/hipe/rtl/hipe_icode2rtl.erl b/lib/hipe/rtl/hipe_icode2rtl.erl
index 82970f04ab..6da8a76d34 100644
--- a/lib/hipe/rtl/hipe_icode2rtl.erl
+++ b/lib/hipe/rtl/hipe_icode2rtl.erl
@@ -532,8 +532,12 @@ gen_cond(CondOp, Args, TrueLbl, FalseLbl, Pred) ->
FalseLbl, Pred)];
'=:=' ->
[Arg1, Arg2] = Args,
+ TypeTestLbl = hipe_rtl:mk_new_label(),
[hipe_rtl:mk_branch(Arg1, eq, Arg2, TrueLbl,
- hipe_rtl:label_name(GenLbl), Pred),
+ hipe_rtl:label_name(TypeTestLbl), Pred),
+ TypeTestLbl,
+ hipe_tagscheme:test_either_immed(Arg1, Arg2, FalseLbl,
+ hipe_rtl:label_name(GenLbl)),
GenLbl,
hipe_rtl:mk_call([Tmp], op_exact_eqeq_2, Args,
TestRetName, [], not_remote),
@@ -546,8 +550,12 @@ gen_cond(CondOp, Args, TrueLbl, FalseLbl, Pred) ->
TrueLbl, 1-Pred)];
'=/=' ->
[Arg1, Arg2] = Args,
+ TypeTestLbl = hipe_rtl:mk_new_label(),
[hipe_rtl:mk_branch(Arg1, eq, Arg2, FalseLbl,
- hipe_rtl:label_name(GenLbl), 1-Pred),
+ hipe_rtl:label_name(TypeTestLbl), 1-Pred),
+ TypeTestLbl,
+ hipe_tagscheme:test_either_immed(Arg1, Arg2, TrueLbl,
+ hipe_rtl:label_name(GenLbl)),
GenLbl,
hipe_rtl:mk_call([Tmp], op_exact_eqeq_2, Args,
TestRetName, [], not_remote),
diff --git a/lib/hipe/rtl/hipe_rtl_binary_construct.erl b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
index fd0d1f1223..52ea5db382 100644
--- a/lib/hipe/rtl/hipe_rtl_binary_construct.erl
+++ b/lib/hipe/rtl/hipe_rtl_binary_construct.erl
@@ -137,43 +137,6 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
end
end;
- {bs_put_integer, Size, Flags, ConstInfo} ->
- Aligned = aligned(Flags),
- LittleEndian = littleendian(Flags),
- [NewOffset] = get_real(Dst),
- case is_illegal_const(Size) of
- true ->
- [hipe_rtl:mk_goto(FalseLblName)];
- false ->
- case ConstInfo of
- fail ->
- [hipe_rtl:mk_goto(FalseLblName)];
- _ ->
- case Args of
- [Src, Base, Offset] ->
- CCode = static_int_c_code(NewOffset, Src,
- Base, Offset, Size,
- Flags, TrueLblName,
- FalseLblName),
- put_static_int(NewOffset, Src, Base, Offset, Size,
- CCode, Aligned, LittleEndian, TrueLblName);
- [Src, Bits, Base, Offset] ->
- {SizeCode, SizeReg} =
- hipe_rtl_binary:make_size(Size, Bits,
- SystemLimitLblName,
- FalseLblName),
- CCode = int_c_code(NewOffset, Src, Base,
- Offset, SizeReg, Flags,
- TrueLblName, FalseLblName),
- InCode =
- put_dynamic_int(NewOffset, Src, Base, Offset,
- SizeReg, CCode, Aligned,
- LittleEndian, TrueLblName),
- SizeCode ++ InCode
- end
- end
- end;
-
{unsafe_bs_put_integer, 0, _Flags, _ConstInfo} ->
[NewOffset] = get_real(Dst),
case Args of
@@ -186,44 +149,12 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
end;
{unsafe_bs_put_integer, Size, Flags, ConstInfo} ->
- case is_illegal_const(Size) of
- true ->
- [hipe_rtl:mk_goto(FalseLblName)];
- false ->
- Aligned = aligned(Flags),
- LittleEndian = littleendian(Flags),
- [NewOffset] = get_real(Dst),
- case ConstInfo of
- fail ->
- [hipe_rtl:mk_goto(FalseLblName)];
- _ ->
- case Args of
- [Src, Base, Offset] ->
- CCode = static_int_c_code(NewOffset, Src,
- Base, Offset, Size,
- Flags, TrueLblName,
- FalseLblName),
- put_unsafe_static_int(NewOffset, Src, Base,
- Offset, Size,
- CCode, Aligned, LittleEndian,
- TrueLblName);
- [Src, Bits, Base, Offset] ->
- {SizeCode, SizeReg} =
- hipe_rtl_binary:make_size(Size, Bits,
- SystemLimitLblName,
- FalseLblName),
- CCode = int_c_code(NewOffset, Src, Base,
- Offset, SizeReg, Flags,
- TrueLblName, FalseLblName),
- InCode =
- put_unsafe_dynamic_int(NewOffset, Src, Base,
- Offset, SizeReg, CCode,
- Aligned, LittleEndian,
- TrueLblName),
- SizeCode ++ InCode
- end
- end
- end;
+ do_bs_put_integer(Dst, Args, Size, Flags, ConstInfo, true,
+ TrueLblName, FalseLblName, SystemLimitLblName);
+
+ {bs_put_integer, Size, Flags, ConstInfo} ->
+ do_bs_put_integer(Dst, Args, Size, Flags, ConstInfo, false,
+ TrueLblName, FalseLblName, SystemLimitLblName);
bs_utf8_size ->
case Dst of
@@ -360,6 +291,40 @@ gen_rtl(BsOP, Dst, Args, TrueLblName, FalseLblName, SystemLimitLblName, ConstTab
{Code, ConstTab}
end.
+%% Common implementation of bs_put_integer and unsafe_bs_put_integer
+do_bs_put_integer(Dst, Args, Size, Flags, ConstInfo, SrcUnsafe,
+ TrueLblName, FalseLblName, SystemLimitLblName) ->
+ case is_illegal_const(Size) of
+ true ->
+ [hipe_rtl:mk_goto(FalseLblName)];
+ false ->
+ Aligned = aligned(Flags),
+ LittleEndian = littleendian(Flags),
+ [NewOffset] = get_real(Dst),
+ case ConstInfo of
+ fail ->
+ [hipe_rtl:mk_goto(FalseLblName)];
+ _ ->
+ case Args of
+ [Src, Base, Offset] ->
+ CCode = static_int_c_code(NewOffset, Src, Base, Offset, Size,
+ Flags, TrueLblName, FalseLblName),
+ put_static_int(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
+ LittleEndian, SrcUnsafe, TrueLblName);
+ [Src, Bits, Base, Offset] ->
+ {SizeCode, SizeReg} =
+ hipe_rtl_binary:make_size(Size, Bits, SystemLimitLblName,
+ FalseLblName),
+ CCode = int_c_code(NewOffset, Src, Base, Offset, SizeReg, Flags,
+ TrueLblName, FalseLblName),
+ InCode = put_dynamic_int(NewOffset, Src, Base, Offset, SizeReg,
+ CCode, Aligned, LittleEndian, SrcUnsafe,
+ TrueLblName),
+ SizeCode ++ InCode
+ end
+ end
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Code that is used in the append and init writeable functions
@@ -807,28 +772,8 @@ put_float(_NewOffset, _Src, _Base, _Offset, _Size, CCode, _Aligned,
CCode.
put_static_int(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
- LittleEndian, TrueLblName) ->
- {Init, End, UntaggedSrc} = make_init_end(Src, CCode, TrueLblName),
- case {Aligned, LittleEndian} of
- {true, true} ->
- Init ++
- copy_int_little(Base, Offset, NewOffset, Size, UntaggedSrc) ++
- End;
- {true, false} ->
- Init ++
- copy_int_big(Base, Offset, NewOffset, Size, UntaggedSrc) ++
- End;
- {false, true} ->
- CCode;
- {false, false} ->
- Init ++
- copy_offset_int_big(Base, Offset, NewOffset, Size, UntaggedSrc) ++
- End
- end.
-
-put_unsafe_static_int(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
- LittleEndian, TrueLblName) ->
- {Init, End, UntaggedSrc} = make_init_end(Src, TrueLblName),
+ LittleEndian, SrcUnsafe, TrueLblName) ->
+ {Init, End, UntaggedSrc} = make_init_end(Src, CCode, SrcUnsafe, TrueLblName),
case {Aligned, LittleEndian} of
{true, true} ->
Init ++
@@ -847,27 +792,8 @@ put_unsafe_static_int(NewOffset, Src, Base, Offset, Size, CCode, Aligned,
end.
put_dynamic_int(NewOffset, Src, Base, Offset, SizeReg, CCode, Aligned,
- LittleEndian, TrueLblName) ->
- {Init, End, UntaggedSrc} = make_init_end(Src, CCode, TrueLblName),
- case Aligned of
- true ->
- case LittleEndian of
- true ->
- Init ++
- copy_int_little(Base, Offset, NewOffset, SizeReg, UntaggedSrc) ++
- End;
- false ->
- Init ++
- copy_int_big(Base, Offset, NewOffset, SizeReg, UntaggedSrc) ++
- End
- end;
- false ->
- CCode
- end.
-
-put_unsafe_dynamic_int(NewOffset, Src, Base, Offset, SizeReg, CCode, Aligned,
- LittleEndian, TrueLblName) ->
- {Init, End, UntaggedSrc} = make_init_end(Src, TrueLblName),
+ LittleEndian, SrcUnsafe, TrueLblName) ->
+ {Init, End, UntaggedSrc} = make_init_end(Src, CCode, SrcUnsafe, TrueLblName),
case Aligned of
true ->
case LittleEndian of
@@ -884,14 +810,13 @@ put_unsafe_dynamic_int(NewOffset, Src, Base, Offset, SizeReg, CCode, Aligned,
CCode
end.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Help functions used by the above
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-make_init_end(Src, CCode, TrueLblName) ->
+make_init_end(Src, CCode, false, TrueLblName) ->
[CLbl, SuccessLbl] = create_lbls(2),
[UntaggedSrc] = create_regs(1),
Init = [hipe_tagscheme:test_fixnum(Src, hipe_rtl:label_name(SuccessLbl),
@@ -899,9 +824,8 @@ make_init_end(Src, CCode, TrueLblName) ->
SuccessLbl,
hipe_tagscheme:untag_fixnum(UntaggedSrc,Src)],
End = [hipe_rtl:mk_goto(TrueLblName), CLbl| CCode],
- {Init, End, UntaggedSrc}.
-
-make_init_end(Src, TrueLblName) ->
+ {Init, End, UntaggedSrc};
+make_init_end(Src, _CCode, true, TrueLblName) ->
[UntaggedSrc] = create_regs(1),
Init = [hipe_tagscheme:untag_fixnum(UntaggedSrc,Src)],
End = [hipe_rtl:mk_goto(TrueLblName)],
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index 35d1e7c8a4..68cbe75e85 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -40,6 +40,7 @@
fixnum_gt/5, fixnum_lt/5, fixnum_ge/5, fixnum_le/5, fixnum_val/1,
fixnum_mul/4, fixnum_addsub/5, fixnum_andorxor/4, fixnum_not/2,
fixnum_bsr/3, fixnum_bsl/3]).
+-export([test_either_immed/4]).
-export([unsafe_car/2, unsafe_cdr/2,
unsafe_constant_element/3, unsafe_update_element/3, element/6]).
-export([unsafe_closure_element/3]).
@@ -363,14 +364,17 @@ test_matchstate(X, TrueLab, FalseLab, Pred) ->
mask_and_compare(Tmp, ?TAG_HEADER_MASK, ?TAG_HEADER_BIN_MATCHSTATE,
TrueLab, FalseLab, Pred)].
+test_bitstr_header(HdrTmp, TrueLab, FalseLab, Pred) ->
+ Mask = ?TAG_HEADER_MASK - ?BINARY_XXX_MASK,
+ mask_and_compare(HdrTmp, Mask, ?TAG_HEADER_REFC_BIN, TrueLab, FalseLab, Pred).
+
test_bitstr(X, TrueLab, FalseLab, Pred) ->
Tmp = hipe_rtl:mk_new_reg_gcsafe(),
HalfTrueLab = hipe_rtl:mk_new_label(),
- Mask = ?TAG_HEADER_MASK - ?BINARY_XXX_MASK,
[test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
HalfTrueLab,
get_header(Tmp, X),
- mask_and_compare(Tmp, Mask, ?TAG_HEADER_REFC_BIN, TrueLab, FalseLab, Pred)].
+ test_bitstr_header(Tmp, TrueLab, FalseLab, Pred)].
test_binary(X, TrueLab, FalseLab, Pred) ->
Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
@@ -378,12 +382,10 @@ test_binary(X, TrueLab, FalseLab, Pred) ->
IsBoxedLab = hipe_rtl:mk_new_label(),
IsBitStrLab = hipe_rtl:mk_new_label(),
IsSubBinLab = hipe_rtl:mk_new_label(),
- Mask = ?TAG_HEADER_MASK - ?BINARY_XXX_MASK,
[test_is_boxed(X, hipe_rtl:label_name(IsBoxedLab), FalseLab, Pred),
IsBoxedLab,
get_header(Tmp1, X),
- mask_and_compare(Tmp1, Mask, ?TAG_HEADER_REFC_BIN,
- hipe_rtl:label_name(IsBitStrLab), FalseLab, Pred),
+ test_bitstr_header(Tmp1, hipe_rtl:label_name(IsBitStrLab), FalseLab, Pred),
IsBitStrLab,
mask_and_compare(Tmp1, ?TAG_HEADER_MASK, ?TAG_HEADER_SUB_BIN,
hipe_rtl:label_name(IsSubBinLab), TrueLab, 0.5),
@@ -453,6 +455,10 @@ test_fixnums_1([Arg1, Arg2|Args], Acc) ->
Tmp = hipe_rtl:mk_new_reg_gcsafe(),
test_fixnums_1([Tmp|Args], [hipe_rtl:mk_alu(Tmp, Arg1, 'and', Arg2)|Acc]).
+test_two_fixnums(Arg, Arg, FalseLab) ->
+ TrueLab = hipe_rtl:mk_new_label(),
+ [test_fixnum(Arg, hipe_rtl:label_name(TrueLab), FalseLab, 0.99),
+ TrueLab];
test_two_fixnums(Arg1, Arg2, FalseLab) ->
TrueLab = hipe_rtl:mk_new_label(),
case hipe_rtl:is_imm(Arg1) orelse hipe_rtl:is_imm(Arg2) of
@@ -567,8 +573,8 @@ fixnum_andorxor(AluOp, Arg1, Arg2, Res) ->
case AluOp of
'xor' ->
Tmp = hipe_rtl:mk_new_reg_gcsafe(),
- [hipe_rtl:mk_alu(Tmp, Arg1, 'xor', Arg2), % clears tag :-(
- hipe_rtl:mk_alu(Res, Tmp, 'or', hipe_rtl:mk_imm(?TAG_IMMED1_SMALL))];
+ [hipe_rtl:mk_alu(Tmp, Arg1, 'sub', hipe_rtl:mk_imm(?TAG_IMMED1_SMALL)),
+ hipe_rtl:mk_alu(Res, Tmp, 'xor', Arg2)];
_ -> hipe_rtl:mk_alu(Res, Arg1, AluOp, Arg2)
end.
@@ -595,6 +601,21 @@ fixnum_bsl(Arg1, Arg2, Res) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test if either of two values are immediate (primary tag IMMED1, 0x3)
+test_either_immed(Arg1, Arg2, TrueLab, FalseLab) ->
+ %% This test assumes primary tag 0x0 is reserved and immed has tag 0x3
+ 16#0 = ?TAG_PRIMARY_HEADER,
+ 16#3 = ?TAG_PRIMARY_IMMED1,
+ Tmp1 = hipe_rtl:mk_new_reg_gcsafe(),
+ Tmp2 = hipe_rtl:mk_new_reg_gcsafe(),
+ [hipe_rtl:mk_alu(Tmp1, Arg1, 'sub', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Tmp2, Arg2, 'sub', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_alu(Tmp2, Tmp2, 'or', Tmp1),
+ hipe_rtl:mk_branch(Tmp2, 'and', hipe_rtl:mk_imm(2), eq,
+ FalseLab, TrueLab, 0.01)].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
unsafe_car(Dst, Arg) ->
hipe_rtl:mk_load(Dst, Arg, hipe_rtl:mk_imm(-(?TAG_PRIMARY_LIST))).
@@ -631,14 +652,13 @@ unsafe_update_element(Tuple, Index, Value) -> % Index is an immediate
element(Dst, Index, Tuple, FailLabName, {tuple, A}, IndexInfo) ->
FixnumOkLab = hipe_rtl:mk_new_label(),
IndexOkLab = hipe_rtl:mk_new_label(),
- Ptr = hipe_rtl:mk_new_reg(), % offset from Tuple
UIndex = hipe_rtl:mk_new_reg_gcsafe(),
Arity = hipe_rtl:mk_imm(A),
- InvIndex = hipe_rtl:mk_new_reg_gcsafe(),
- Offset = hipe_rtl:mk_new_reg_gcsafe(),
case IndexInfo of
valid ->
%% This is no branch, 1 load and 3 alus = 4 instr
+ Offset = hipe_rtl:mk_new_reg_gcsafe(),
+ Ptr = hipe_rtl:mk_new_reg(), % offset from Tuple
[untag_fixnum(UIndex, Index),
hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)),
hipe_rtl:mk_alu(Offset, UIndex, 'sll',
@@ -647,72 +667,56 @@ element(Dst, Index, Tuple, FailLabName, {tuple, A}, IndexInfo) ->
fixnums ->
%% This is 1 branch, 1 load and 4 alus = 6 instr
[untag_fixnum(UIndex, Index),
- hipe_rtl:mk_alu(Ptr, Tuple, 'sub',hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED))|
- gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset, UIndex,
- FailLabName, IndexOkLab)];
+ gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab)];
_ ->
%% This is 3 branches, 1 load and 5 alus = 9 instr
[test_fixnum(Index, hipe_rtl:label_name(FixnumOkLab),
FailLabName, 0.99),
FixnumOkLab,
untag_fixnum(UIndex, Index),
- hipe_rtl:mk_alu(Ptr, Tuple, 'sub',hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED))|
- gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset, UIndex,
- FailLabName, IndexOkLab)]
+ gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab)]
end;
element(Dst, Index, Tuple, FailLabName, tuple, IndexInfo) ->
FixnumOkLab = hipe_rtl:mk_new_label(),
IndexOkLab = hipe_rtl:mk_new_label(),
- Ptr = hipe_rtl:mk_new_reg(), % offset from Tuple
Header = hipe_rtl:mk_new_reg_gcsafe(),
UIndex = hipe_rtl:mk_new_reg_gcsafe(),
Arity = hipe_rtl:mk_new_reg_gcsafe(),
- InvIndex = hipe_rtl:mk_new_reg_gcsafe(),
- Offset = hipe_rtl:mk_new_reg_gcsafe(),
case IndexInfo of
fixnums ->
%% This is 1 branch, 2 loads and 5 alus = 8 instr
- [hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)),
- hipe_rtl:mk_load(Header, Ptr, hipe_rtl:mk_imm(0)),
+ [get_header(Header, Tuple),
untag_fixnum(UIndex, Index),
hipe_rtl:mk_alu(Arity,Header,'srl',hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))|
- gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset, UIndex,
- FailLabName, IndexOkLab)];
+ gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab)];
Num when is_integer(Num) ->
%% This is 1 branch, 1 load and 3 alus = 5 instr
- [hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED))|
- gen_element_tail(Dst, Ptr, InvIndex, hipe_rtl:mk_imm(Num),
- Offset, UIndex, FailLabName, IndexOkLab)];
+ gen_element_tail(Dst, Tuple, hipe_rtl:mk_imm(Num), UIndex, FailLabName,
+ IndexOkLab);
_ ->
%% This is 2 branches, 2 loads and 6 alus = 10 instr
[test_fixnum(Index, hipe_rtl:label_name(FixnumOkLab), FailLabName, 0.99),
FixnumOkLab,
- hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)),
- hipe_rtl:mk_load(Header, Ptr, hipe_rtl:mk_imm(0)),
+ get_header(Header, Tuple),
untag_fixnum(UIndex, Index),
hipe_rtl:mk_alu(Arity,Header,'srl',hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))|
- gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset, UIndex,
- FailLabName, IndexOkLab)]
+ gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab)]
end;
element(Dst, Index, Tuple, FailLabName, unknown, IndexInfo) ->
FixnumOkLab = hipe_rtl:mk_new_label(),
BoxedOkLab = hipe_rtl:mk_new_label(),
TupleOkLab = hipe_rtl:mk_new_label(),
IndexOkLab = hipe_rtl:mk_new_label(),
- Ptr = hipe_rtl:mk_new_reg(), % offset from Tuple
Header = hipe_rtl:mk_new_reg_gcsafe(),
UIndex = hipe_rtl:mk_new_reg_gcsafe(),
Arity = hipe_rtl:mk_new_reg_gcsafe(),
- InvIndex = hipe_rtl:mk_new_reg_gcsafe(),
- Offset = hipe_rtl:mk_new_reg_gcsafe(),
case IndexInfo of
fixnums ->
%% This is 3 branches, 2 loads and 5 alus = 10 instr
[test_is_boxed(Tuple, hipe_rtl:label_name(BoxedOkLab),
FailLabName, 0.99),
BoxedOkLab,
- hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)),
- hipe_rtl:mk_load(Header, Ptr, hipe_rtl:mk_imm(0)),
+ get_header(Header, Tuple),
hipe_rtl:mk_branch(Header, 'and',
hipe_rtl:mk_imm(?TAG_HEADER_MASK), 'eq',
hipe_rtl:label_name(TupleOkLab), FailLabName, 0.99),
@@ -720,23 +724,21 @@ element(Dst, Index, Tuple, FailLabName, unknown, IndexInfo) ->
untag_fixnum(UIndex, Index),
hipe_rtl:mk_alu(Arity, Header, 'srl',
hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))|
- gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset,
- UIndex, FailLabName, IndexOkLab)];
+ gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab)];
Num when is_integer(Num) ->
%% This is 3 branches, 2 loads and 4 alus = 9 instr
[test_is_boxed(Tuple, hipe_rtl:label_name(BoxedOkLab),
FailLabName, 0.99),
BoxedOkLab,
- hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)),
- hipe_rtl:mk_load(Header, Ptr, hipe_rtl:mk_imm(0)),
+ get_header(Header, Tuple),
hipe_rtl:mk_branch(Header, 'and',
hipe_rtl:mk_imm(?TAG_HEADER_MASK), 'eq',
hipe_rtl:label_name(TupleOkLab), FailLabName, 0.99),
TupleOkLab,
hipe_rtl:mk_alu(Arity, Header, 'srl',
hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))|
- gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset,
- hipe_rtl:mk_imm(Num), FailLabName, IndexOkLab)];
+ gen_element_tail(Dst, Tuple, Arity, hipe_rtl:mk_imm(Num), FailLabName,
+ IndexOkLab)];
_ ->
%% This is 4 branches, 2 loads, and 6 alus = 12 instr :(
[test_fixnum(Index, hipe_rtl:label_name(FixnumOkLab),
@@ -745,8 +747,7 @@ element(Dst, Index, Tuple, FailLabName, unknown, IndexInfo) ->
test_is_boxed(Tuple, hipe_rtl:label_name(BoxedOkLab),
FailLabName, 0.99),
BoxedOkLab,
- hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)),
- hipe_rtl:mk_load(Header, Ptr, hipe_rtl:mk_imm(0)),
+ get_header(Header, Tuple),
hipe_rtl:mk_branch(Header, 'and',
hipe_rtl:mk_imm(?TAG_HEADER_MASK), 'eq',
hipe_rtl:label_name(TupleOkLab), FailLabName, 0.99),
@@ -754,20 +755,21 @@ element(Dst, Index, Tuple, FailLabName, unknown, IndexInfo) ->
untag_fixnum(UIndex, Index),
hipe_rtl:mk_alu(Arity, Header, 'srl',
hipe_rtl:mk_imm(?HEADER_ARITY_OFFS))|
- gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset,
- UIndex, FailLabName, IndexOkLab)]
+ gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab)]
end.
-gen_element_tail(Dst, Ptr, InvIndex, Arity, Offset,
- UIndex, FailLabName, IndexOkLab) ->
+gen_element_tail(Dst, Tuple, Arity, UIndex, FailLabName, IndexOkLab) ->
+ ZeroIndex = hipe_rtl:mk_new_reg_gcsafe(),
+ Offset = hipe_rtl:mk_new_reg_gcsafe(),
+ Ptr = hipe_rtl:mk_new_reg(), % offset from Tuple
%% now check that 1 <= UIndex <= Arity
- %% if UIndex < 1, then (Arity - UIndex) >= Arity
- %% if UIndex > Arity, then (Arity - UIndex) < 0, which is >=u Arity
- %% otherwise, 0 <= (Arity - UIndex) < Arity
- [hipe_rtl:mk_alu(InvIndex, Arity, 'sub', UIndex),
- hipe_rtl:mk_branch(InvIndex, 'geu', Arity, FailLabName,
+ %% by checking the equivalent (except for when Arity>=2^(WordSize-1))
+ %% (UIndex - 1) <u Arity
+ [hipe_rtl:mk_alu(ZeroIndex, UIndex, 'sub', hipe_rtl:mk_imm(1)),
+ hipe_rtl:mk_branch(ZeroIndex, 'geu', Arity, FailLabName,
hipe_rtl:label_name(IndexOkLab), 0.01),
IndexOkLab,
+ hipe_rtl:mk_alu(Ptr, Tuple, 'sub', hipe_rtl:mk_imm(?TAG_PRIMARY_BOXED)),
hipe_rtl:mk_alu(Offset, UIndex, 'sll',
hipe_rtl:mk_imm(hipe_rtl_arch:log2_word_size())),
hipe_rtl:mk_load(Dst, Ptr, Offset)].
diff --git a/lib/hipe/test/basic_SUITE_data/basic_tuples.erl b/lib/hipe/test/basic_SUITE_data/basic_tuples.erl
index 94c187e364..96e39d565a 100644
--- a/lib/hipe/test/basic_SUITE_data/basic_tuples.erl
+++ b/lib/hipe/test/basic_SUITE_data/basic_tuples.erl
@@ -55,6 +55,8 @@ test_element(T0, T1, T2, N) ->
List = lists:seq(1, N),
Tuple = list_to_tuple(List),
ok = get_elements(List, Tuple, 1),
+ %% element/2 of larger tuple with omitted bounds test
+ true = lists:all(fun(I) -> I * I =:= square(I) end, lists:seq(1, 20)),
%% some cases that throw exceptions
{'EXIT', _} = (catch my_element(0, T2)),
{'EXIT', _} = (catch my_element(3, T2)),
@@ -73,6 +75,18 @@ get_elements([Element|Rest], Tuple, Pos) ->
get_elements([], _Tuple, _Pos) ->
ok.
+squares() ->
+ {1*1, 2*2, 3*3, 4*4, 5*5, 6*6, 7*7, 8*8, 9*9, 10*10,
+ 11*11, 12*12, 13*13, 14*14, 15*15, 16*16, 17*17, 18*18, 19*19, 20*20}.
+
+square(N) when is_integer(N), N >= 1, N =< 20 ->
+ %% The guard tests lets the range analysis conclude N to be an integer in the
+ %% 1..20 range. 20-1=19 is bigger than ?SET_LIMIT in erl_types.erl, and will
+ %% thus be represented by an ?int_range() rather than an ?int_set().
+ %% Because of the range analysis, the bounds test of this element/2 call
+ %% should be omitted.
+ element(N, squares()).
+
%%--------------------------------------------------------------------
%% Tests set_element/3.
diff --git a/lib/hipe/util/hipe_vectors.erl b/lib/hipe/util/hipe_vectors.erl
index fc4e4edb24..788dacd11b 100644
--- a/lib/hipe/util/hipe_vectors.erl
+++ b/lib/hipe/util/hipe_vectors.erl
@@ -116,8 +116,7 @@ get(Vec, Ix) ->
%% ---------------------------------------------------------------------
-ifdef(USE_ARRAYS).
-%%-opaque vector(E) :: array:array(E).
--type vector(E) :: array:array(E). % Work around dialyzer bug
+-opaque vector(E) :: array:array(E).
new(N, V) -> array:new(N, {default, V}).
size(V) -> array:size(V).
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index cb4174381a..172d976931 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.15.3
+HIPE_VSN = 3.15.4
diff --git a/lib/hipe/x86/hipe_rtl_to_x86.erl b/lib/hipe/x86/hipe_rtl_to_x86.erl
index 29cad6ca51..31e4f6e4ac 100644
--- a/lib/hipe/x86/hipe_rtl_to_x86.erl
+++ b/lib/hipe/x86/hipe_rtl_to_x86.erl
@@ -124,7 +124,6 @@ conv_insn(I, Map, Data) ->
hipe_rtl:call_continuation(I),
hipe_rtl:call_fail(I),
hipe_rtl:call_type(I)),
- %% XXX Fixme: this ++ is probably inefficient.
{FixArgs++I2, Map2, Data};
#comment{} ->
I2 = [hipe_x86:mk_comment(hipe_rtl:comment_text(I))],
diff --git a/lib/hipe/x86/hipe_x86_assemble.erl b/lib/hipe/x86/hipe_x86_assemble.erl
index ef9c32ef41..fb0beba293 100644
--- a/lib/hipe/x86/hipe_x86_assemble.erl
+++ b/lib/hipe/x86/hipe_x86_assemble.erl
@@ -148,6 +148,8 @@ insn_size(I) ->
translate_insn(I, Context, Options) ->
case I of
+ #alu{aluop='xor', src=#x86_temp{reg=Reg}=Src, dst=#x86_temp{reg=Reg}=Dst} ->
+ [{'xor', {temp_to_reg32(Dst), temp_to_rm32(Src)}, I}];
#alu{} ->
Arg = resolve_alu_args(hipe_x86:alu_src(I), hipe_x86:alu_dst(I), Context),
[{hipe_x86:alu_op(I), Arg, I}];
@@ -228,11 +230,11 @@ translate_insn(I, Context, Options) ->
#move64{} ->
translate_move64(I, Context);
#movsx{} ->
- Arg = resolve_movx_args(hipe_x86:movsx_src(I), hipe_x86:movsx_dst(I)),
- [{movsx, Arg, I}];
+ Src = resolve_movx_src(hipe_x86:movsx_src(I)),
+ [{movsx, {temp_to_regArch(hipe_x86:movsx_dst(I)), Src}, I}];
#movzx{} ->
- Arg = resolve_movx_args(hipe_x86:movzx_src(I), hipe_x86:movzx_dst(I)),
- [{movzx, Arg, I}];
+ Src = resolve_movx_src(hipe_x86:movzx_src(I)),
+ [{movzx, {temp_to_reg32(hipe_x86:movzx_dst(I)), Src}, I}];
%% pseudo_call: eliminated before assembly
%% pseudo_jcc: eliminated before assembly
%% pseudo_tailcall: eliminated before assembly
@@ -845,16 +847,15 @@ translate_move64(I, _Context) -> exit({?MODULE, I}).
-endif.
%%% mov{s,z}x
-resolve_movx_args(Src=#x86_mem{type=Type}, Dst=#x86_temp{}) ->
- {temp_to_regArch(Dst),
- case Type of
- byte ->
- mem_to_rm8(Src);
- int16 ->
- mem_to_rm16(Src);
- int32 ->
- mem_to_rm32(Src)
- end}.
+resolve_movx_src(Src=#x86_mem{type=Type}) ->
+ case Type of
+ byte ->
+ mem_to_rm8(Src);
+ int16 ->
+ mem_to_rm16(Src);
+ int32 ->
+ mem_to_rm32(Src)
+ end.
%%% alu/cmp (_not_ test)
resolve_alu_args(Src, Dst, Context) ->
diff --git a/lib/hipe/x86/hipe_x86_postpass.erl b/lib/hipe/x86/hipe_x86_postpass.erl
index b84e9bed91..925054dd68 100644
--- a/lib/hipe/x86/hipe_x86_postpass.erl
+++ b/lib/hipe/x86/hipe_x86_postpass.erl
@@ -57,9 +57,10 @@ postpass(#defun{code=Code0}=Defun, Options) ->
peephole_optimization(Insns) ->
peep(Insns, [], []).
-%% MoveSelf related peep-opts
+
+%% MoveSelf related peep-opts
%% ------------------------------
-peep([#fmove{src=Src, dst=Src} | Insns], Res,Lst) ->
+peep([#fmove{src=Src, dst=Src} | Insns], Res,Lst) ->
peep(Insns, Res, [moveSelf1|Lst]);
peep([I=#fmove{src=Src, dst=Dst},
#fmove{src=Dst, dst=Src} | Insns], Res,Lst) ->
@@ -159,8 +160,7 @@ peep([#jcc{label=Lab}, I=#label{label=Lab}|Insns], Res, Lst) ->
%% ElimSet0
%% --------
-peep([#move{src=#x86_imm{value=0},dst=Dst}|Insns],Res,Lst)
-when (Dst==#x86_temp{}) ->
+peep([#move{src=#x86_imm{value=0},dst=Dst=#x86_temp{}}|Insns],Res,Lst) ->
peep(Insns, [#alu{aluop='xor', src=Dst, dst=Dst}|Res], [elimSet0|Lst]);
%% ElimMDPow2
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 1d8432ee35..2ed02e021e 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -33,7 +33,45 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 6.3.5</title>
+ <section><title>Inets 6.3.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Chunk size decoding could fail. The symptom was that
+ chunk decoding sometimes failed depending on timing of
+ the received stream. If chunk size was split into two
+ different packets decoding would fail.</p>
+ <p>
+ Own Id: OTP-13571 Aux Id: ERL-116 </p>
+ </item>
+ <item>
+ <p>
+ Prevent httpc user process to hang if httpc_handler
+ process terminates unexpectedly</p>
+ <p>
+ Own Id: OTP-14091</p>
+ </item>
+ <item>
+ <p>
+ Correct Host header, to include port number, when
+ redirecting requests.</p>
+ <p>
+ Own Id: OTP-14097</p>
+ </item>
+ <item>
+ <p>
+ Shutdown gracefully on connection or TLS handshake errors</p>
+ <p>
+ Own Id: OTP-14173 Aux Id: seq13262 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.3.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 9591ab22ed..5637170c15 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 6.3.5
+INETS_VSN = 6.3.6
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index d80c4f077c..ad349c5aaf 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -31,6 +31,45 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 5.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix a race during cleanup of os:cmd that would cause
+ os:cmd to hang indefinitely.</p>
+ <p>
+ Own Id: OTP-14232 Aux Id: seq13275 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>The functions in the '<c>file</c>' module that take a
+ list of paths (e.g. <c>file:path_consult/2</c>) will now
+ continue to search in the path if the path contains
+ something that is not a directory.</p>
+ <p>
+ Own Id: OTP-14191</p>
+ </item>
+ <item>
+ <p>Two OTP processes that are known to receive many
+ messages are 'rex' (used by 'rpc') and 'error_logger'.
+ Those processes will now store unprocessed messages
+ outside the process heap, which will potentially decrease
+ the cost of garbage collections.</p>
+ <p>
+ Own Id: OTP-14192</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 5.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl
index 0e61153613..3b642f5873 100644
--- a/lib/kernel/src/application_controller.erl
+++ b/lib/kernel/src/application_controller.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1620,7 +1620,7 @@ conv(_) -> [].
make_term(Str) ->
case erl_scan:string(Str) of
{ok, Tokens, _} ->
- case erl_parse:parse_term(Tokens ++ [{dot, 1}]) of
+ case erl_parse:parse_term(Tokens ++ [{dot, erl_anno:new(1)}]) of
{ok, Term} ->
Term;
{error, {_,M,Reason}} ->
diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src
index b505524471..2dc90e2b3e 100644
--- a/lib/kernel/src/kernel.appup.src
+++ b/lib/kernel/src/kernel.appup.src
@@ -18,7 +18,7 @@
%% %CopyrightEnd%
{"%VSN%",
%% Up from - max one major revision back
- [{<<"5\\.[0-1](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-19.*
+ [{<<"5\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-19.*
%% Down to - max one major revision back
- [{<<"5\\.[0-1](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-19.*
+ [{<<"5\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-19.*
}.
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 1f4591a5a3..19d36a7613 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -1360,9 +1360,8 @@ create_big_boot(Config) ->
%% corresponding beam file (if hipe is not enabled).
filter_app("hipe",_) -> false;
-%% Dialyzer and typer depends on hipe
+%% Dialyzer depends on hipe
filter_app("dialyzer",_) -> false;
-filter_app("typer",_) -> false;
%% Orber requires explicit configuration
filter_app("orber",_) -> false;
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index 8d2517e680..76b020e8ed 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 5.1.1
+KERNEL_VSN = 5.2
diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml
index 8f3ebcb4de..79e2b2b9db 100644
--- a/lib/observer/doc/src/notes.xml
+++ b/lib/observer/doc/src/notes.xml
@@ -32,6 +32,47 @@
<p>This document describes the changes made to the Observer
application.</p>
+<section><title>Observer 2.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ etop erroneously reported the average scheduler
+ utilization since the tool was first started instead of
+ the scheduler utilization since last update. This is now
+ corrected.</p>
+ <p>
+ Own Id: OTP-14090 Aux Id: seq13232 </p>
+ </item>
+ <item>
+ <p>
+ crashdump_viewer crashed when the 'Slogan' had more than
+ one line. This is now corrected.</p>
+ <p>
+ Own Id: OTP-14093 Aux Id: ERL-318 </p>
+ </item>
+ <item>
+ <p>
+ When clicking an HTML-link to a port before the port tab
+ has been opened for the first time, observer would crash
+ since port info is not initiated. This is now corrected.</p>
+ <p>
+ Own Id: OTP-14151 Aux Id: PR-1296 </p>
+ </item>
+ <item>
+ <p>The dialyzer and observer applications will now use a
+ portable way to find the home directory. That means that
+ there is no longer any need to manually set the HOME
+ environment variable on Windows.</p>
+ <p>
+ Own Id: OTP-14249 Aux Id: ERL-161 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Observer 2.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/observer/doc/src/observer_ug.xml b/lib/observer/doc/src/observer_ug.xml
index 6eb72f3e58..ae85ab7a29 100644
--- a/lib/observer/doc/src/observer_ug.xml
+++ b/lib/observer/doc/src/observer_ug.xml
@@ -107,6 +107,11 @@
see module
<seealso marker="erts:erts_alloc"><c>erts_alloc</c></seealso>
in application ERTS.</p>
+ <p>The <c>Max Carrier size</c> column shows the maximum value seen by observer
+ since the last node change or since the start of the application, i.e. switching
+ nodes will reset the max column. Values are sampled so higher values may have
+ existed than what is shown.
+ </p>
</section>
<section>
diff --git a/lib/observer/src/observer_alloc_wx.erl b/lib/observer/src/observer_alloc_wx.erl
index ca54080e15..cad02087be 100644
--- a/lib/observer/src/observer_alloc_wx.erl
+++ b/lib/observer/src/observer_alloc_wx.erl
@@ -36,6 +36,7 @@
wins,
mem,
samples,
+ max,
panel,
paint,
appmon,
@@ -74,7 +75,8 @@ init([Notebook, Parent]) ->
wins = Windows,
mem = MemWin,
paint = PaintInfo,
- time = setup_time()
+ time = setup_time(),
+ max = #{}
}
}
catch _:Err ->
@@ -126,16 +128,17 @@ handle_info({Key, {promise_reply, {badrpc, _}}}, #state{async=Key} = State) ->
{noreply, State#state{active=false, appmon=undefined}};
handle_info({Key, {promise_reply, SysInfo}},
- #state{async=Key, panel=_Panel, samples=Data, active=Active, wins=Wins0,
- time=#ti{tick=Tick, disp=Disp0}=Ti} = S0) ->
+ #state{async=Key, samples=Data, max=Max0,
+ active=Active, wins=Wins0, time=#ti{tick=Tick, disp=Disp0}=Ti} = S0) ->
Disp = trunc(Disp0),
Next = max(Tick - Disp, 0),
erlang:send_after(1000 div ?DISP_FREQ, self(), {refresh, Next}),
Info = alloc_info(SysInfo),
+ Max = lists:foldl(fun calc_max/2, Max0, Info),
{Wins, Samples} = add_data(Info, Data, Wins0, Ti, Active),
- S1 = S0#state{time=Ti#ti{tick=Next}, wins=Wins, samples=Samples, async=undefined},
+ S1 = S0#state{time=Ti#ti{tick=Next}, wins=Wins, samples=Samples, max=Max, async=undefined},
if Active ->
- update_alloc(S0, Info),
+ update_alloc(S0, Info, Max),
State = precalc(S1),
{noreply, State};
true ->
@@ -187,25 +190,35 @@ code_change(_, _, State) ->
restart_fetcher(Node, #state{panel=Panel, wins=Wins0, time=Ti} = State) ->
SysInfo = observer_wx:try_rpc(Node, observer_backend, sys_info, []),
Info = alloc_info(SysInfo),
+ Max = lists:foldl(fun calc_max/2, #{}, Info),
{Wins, Samples} = add_data(Info, {0, queue:new()}, Wins0, Ti, true),
erlang:send_after(1000 div ?DISP_FREQ, self(), {refresh, 0}),
wxWindow:refresh(Panel),
precalc(State#state{active=true, appmon=Node, time=Ti#ti{tick=0},
- wins=Wins, samples=Samples}).
+ wins=Wins, samples=Samples, max=Max}).
precalc(#state{samples=Data0, paint=Paint, time=Ti, wins=Wins0}=State) ->
Wins = [precalc(Ti, Data0, Paint, Win) || Win <- Wins0],
State#state{wins=Wins}.
+calc_max({Name, _, Cs}, Max0) ->
+ case maps:get(Name, Max0, 0) of
+ Value when Value < Cs ->
+ Max0#{Name=>Cs};
+ _V ->
+ Max0
+ end.
-update_alloc(#state{mem=Grid}, Fields) ->
+update_alloc(#state{mem=Grid}, Fields, Max) ->
wxWindow:freeze(Grid),
- Max = wxListCtrl:getItemCount(Grid),
+ Last = wxListCtrl:getItemCount(Grid),
Update = fun({Name, BS, CS}, Row) ->
- (Row >= Max) andalso wxListCtrl:insertItem(Grid, Row, ""),
+ (Row >= Last) andalso wxListCtrl:insertItem(Grid, Row, ""),
+ MaxV = maps:get(Name, Max, CS),
wxListCtrl:setItem(Grid, Row, 0, observer_lib:to_str(Name)),
wxListCtrl:setItem(Grid, Row, 1, observer_lib:to_str(BS div 1024)),
wxListCtrl:setItem(Grid, Row, 2, observer_lib:to_str(CS div 1024)),
+ wxListCtrl:setItem(Grid, Row, 3, observer_lib:to_str(MaxV div 1024)),
Row + 1
end,
wx:foldl(Update, 0, Fields),
@@ -269,7 +282,9 @@ create_mem_info(Parent) ->
end,
ListItems = [{"Allocator Type", ?wxLIST_FORMAT_LEFT, 200},
{"Block size (kB)", ?wxLIST_FORMAT_RIGHT, 150},
- {"Carrier size (kB)",?wxLIST_FORMAT_RIGHT, 150}],
+ {"Carrier size (kB)",?wxLIST_FORMAT_RIGHT, 150},
+ {"Max Carrier size (kB)",?wxLIST_FORMAT_RIGHT, 150}
+ ],
lists:foldl(AddListEntry, 0, ListItems),
wxListItem:destroy(Li),
diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl
index b0ead42e3f..0cbcdbceb4 100644
--- a/lib/observer/src/observer_perf_wx.erl
+++ b/lib/observer/src/observer_perf_wx.erl
@@ -55,7 +55,7 @@
-define(wxGC, wxGraphicsContext).
--record(paint, {font, small, pen, pen2, pens, usegc = false}).
+-record(paint, {font, small, pen, pen2, pens, dot_pens, usegc = false}).
start_link(Notebook, Parent) ->
wx_object:start_link(?MODULE, [Notebook, Parent], []).
@@ -124,13 +124,17 @@ setup_graph_drawing(Panels) ->
{F, SF}
end,
BlackPen = wxPen:new({0,0,0}, [{width, 1}]),
- Pens = [wxPen:new(Col, [{width, 1}]) || Col <- tuple_to_list(colors())],
+ Pens = [wxPen:new(Col, [{width, 1}, {style, ?wxSOLID}])
+ || Col <- tuple_to_list(colors())],
+ DotPens = [wxPen:new(Col, [{width, 1}, {style, ?wxDOT}])
+ || Col <- tuple_to_list(colors())],
#paint{usegc = UseGC,
font = Font,
small = SmallFont,
pen = ?wxGREY_PEN,
pen2 = BlackPen,
- pens = list_to_tuple(Pens)
+ pens = list_to_tuple(Pens),
+ dot_pens = list_to_tuple(DotPens)
}.
@@ -181,17 +185,17 @@ handle_cast(Event, _State) ->
%%%%%%%%%%
handle_info({stats, 1, _, _, _} = Stats,
#state{panel=Panel, samples=Data, active=Active, wins=Wins0,
- time=#ti{tick=Tick, disp=Disp0}=Ti} = State0) ->
+ appmon=Node, time=#ti{tick=Tick, disp=Disp0}=Ti} = State0) ->
if Active ->
Disp = trunc(Disp0),
Next = max(Tick - Disp, 0),
erlang:send_after(1000 div ?DISP_FREQ, self(), {refresh, Next}),
- {Wins, Samples} = add_data(Stats, Data, Wins0, Ti, Active),
+ {Wins, Samples} = add_data(Stats, Data, Wins0, Ti, Active, Node),
State = precalc(State0#state{time=Ti#ti{tick=Next}, wins=Wins, samples=Samples}),
wxWindow:refresh(Panel),
{noreply, State};
true ->
- {Wins1, Samples} = add_data(Stats, Data, Wins0, Ti, Active),
+ {Wins1, Samples} = add_data(Stats, Data, Wins0, Ti, Active, Node),
Wins = [W#win{max=undefined} || W <- Wins1],
{noreply, State0#state{samples=Samples, wins=Wins, time=Ti#ti{tick=0}}}
end;
@@ -247,13 +251,17 @@ restart_fetcher(Node, #state{appmon=Old, panel=Panel, time=#ti{fetch=Freq}=Ti, w
reset_data() ->
{0, queue:new()}.
-add_data(Stats, {N, Q0}, Wins, #ti{fetch=Fetch, secs=Secs}, Active) when N > (Secs*Fetch+1) ->
+add_data(Stats, Q, Wins, Ti, Active) ->
+ add_data(Stats, Q, Wins, Ti, Active, ignore).
+
+add_data(Stats, {N, Q0}, Wins, #ti{fetch=Fetch, secs=Secs}, Active, Node)
+ when N > (Secs*Fetch+1) ->
{{value, Drop}, Q} = queue:out(Q0),
- add_data_1(Wins, Stats, N, {Drop,Q}, Active);
-add_data(Stats, {N, Q}, Wins, _, Active) ->
- add_data_1(Wins, Stats, N+1, {empty, Q}, Active).
+ add_data_1(Wins, Stats, N, {Drop,Q}, Active, Node);
+add_data(Stats, {N, Q}, Wins, _, Active, Node) ->
+ add_data_1(Wins, Stats, N+1, {empty, Q}, Active, Node).
-add_data_1([#win{state={_,St}}|_]=Wins0, Last, N, {Drop, Q}, Active)
+add_data_1([#win{state={_,St}}|_]=Wins0, Last, N, {Drop, Q}, Active, Node)
when St /= undefined ->
try
{Wins, Stat} =
@@ -269,14 +277,12 @@ add_data_1([#win{state={_,St}}|_]=Wins0, Last, N, {Drop, Q}, Active)
end, #{}, Wins0),
{Wins, {N,queue:in(Stat#{}, Q)}}
catch no_scheduler_change ->
- {[Win#win{state=init_data(Id, Last),
- info = info(Id, Last)}
+ {[Win#win{state=init_data(Id, Last), info=info(Id, Last, Node)}
|| #win{name=Id}=Win <- Wins0], {0,queue:new()}}
end;
-add_data_1(Wins, Stats, 1, {_, Q}, _) ->
- {[Win#win{state=init_data(Id, Stats),
- info = info(Id, Stats)}
+add_data_1(Wins, Stats, 1, {_, Q}, _, Node) ->
+ {[Win#win{state=init_data(Id, Stats), info=info(Id, Stats, Node)}
|| #win{name=Id}=Win <- Wins], {0,Q}}.
add_data_2(#win{name=Id, state=S0}=Win, Stats, Map) ->
@@ -382,16 +388,24 @@ lmax(MState, Values, State) ->
init_data(runq, {stats, _, T0, _, _}) -> {mk_max(),lists:sort(T0)};
init_data(io, {stats, _, _, {{_,In0}, {_,Out0}}, _}) -> {mk_max(), {In0,Out0}};
-init_data(memory, _) -> {mk_max(), info(memory, undefined)};
+init_data(memory, _) -> {mk_max(), info(memory, undefined, undefined)};
init_data(alloc, _) -> {mk_max(), unused};
init_data(utilz, _) -> {mk_max(), unused}.
-info(runq, {stats, _, T0, _, _}) -> lists:seq(1, length(T0));
-info(memory, _) -> [total, processes, atom, binary, code, ets];
-info(io, _) -> [input, output];
-info(alloc, First) -> [Type || {Type, _, _} <- First];
-info(utilz, First) -> [Type || {Type, _, _} <- First];
-info(_, []) -> [].
+info(runq, {stats, _, T0, _, _}, Node) ->
+ Dirty = get_dirty_cpu(Node),
+ {lists:seq(1, length(T0)-Dirty), Dirty};
+info(memory, _, _) -> [total, processes, atom, binary, code, ets];
+info(io, _, _) -> [input, output];
+info(alloc, First, _) -> [Type || {Type, _, _} <- First];
+info(utilz, First, _) -> [Type || {Type, _, _} <- First];
+info(_, [], _) -> [].
+
+get_dirty_cpu(Node) ->
+ case rpc:call(node(Node), erlang, system_info, [dirty_cpu_schedulers]) of
+ {badrpc,_R} -> 0;
+ N -> N
+ end.
collect_data(runq, {stats, _, T0, _, _}, {Max,S0}) ->
S1 = lists:sort(T0),
@@ -471,9 +485,10 @@ window_geom({W,H}, {_, Max, _Unit, MaxUnit},
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-draw_win(DC, #win{no_samples=Samples, geom=#{scale:={WS,HS}}, graphs=Graphs, max={_,Max,_,_}}=Win,
+draw_win(DC, #win{name=Name, no_samples=Samples, geom=#{scale:={WS,HS}},
+ graphs=Graphs, max={_,Max,_,_}, info=Info}=Win,
#ti{tick=Tick, fetch=FetchFreq, secs=Secs, disp=DispFreq}=Ti,
- Paint=#paint{pens=Pens}) when Samples >= 2, Graphs =/= [] ->
+ Paint=#paint{pens=Pens, dot_pens=Dots}) when Samples >= 2, Graphs =/= [] ->
%% Draw graphs
{X0,Y0,DrawBs} = draw_borders(DC, Ti, Win, Paint),
Offset = Tick / DispFreq,
@@ -483,14 +498,23 @@ draw_win(DC, #win{no_samples=Samples, geom=#{scale:={WS,HS}}, graphs=Graphs, max
end,
Start = X0 + (max(Secs*FetchFreq+Full-Samples, 0) - Offset)*WS,
Last = Secs*FetchFreq*WS+X0,
+ Dirty = case {Name, Info} of
+ {runq, {_, DCpu}} -> DCpu;
+ _ -> 0
+ end,
+ NoGraphs = length(Graphs),
+ NoCpu = NoGraphs - Dirty,
Draw = fun(Lines0, N) ->
- setPen(DC, element(1+ ((N-1) rem tuple_size(Pens)), Pens)),
+ case Dirty > 0 andalso N > NoCpu of
+ true -> setPen(DC, element(1+ ((N-NoCpu-1) rem tuple_size(Dots)), Dots));
+ false -> setPen(DC, element(1+ ((N-1) rem tuple_size(Pens)), Pens))
+ end,
Order = lists:reverse(Lines0),
[{_,Y}|Lines] = translate(Order, {Start, Y0}, 0, WS, {X0,Max*HS,Last}, []),
strokeLines(DC, [{Last,Y}|Lines]),
N-1
end,
- lists:foldl(Draw, length(Graphs), Graphs),
+ lists:foldl(Draw, NoGraphs, Graphs),
DrawBs(),
ok;
@@ -655,11 +679,17 @@ draw_borders(DC, #ti{secs=Secs, fetch=FetchFreq},
case Type of
runq ->
+ {TextInfo, DirtyCpus} = Info,
drawText(DC, "Scheduler Utilization (%) ", TopTextX, ?BH),
TN0 = Text(TopTextX, BottomTextY, "Scheduler: ", 0),
- lists:foldl(fun(Id, Pos0) ->
- Text(Pos0, BottomTextY, integer_to_list(Id), Id)
- end, TN0, Info);
+ Id = fun(Id, Pos0) ->
+ Text(Pos0, BottomTextY, integer_to_list(Id), Id)
+ end,
+ TN1 = lists:foldl(Id, TN0, TextInfo),
+ TN2 = Text(TN1, BottomTextY, "Dirty cpu: ", 0),
+ TN3 = lists:foldl(Id, TN2, lists:seq(1, DirtyCpus)),
+ _ = Text(TN3, BottomTextY, "(dotted)", 0),
+ ok;
memory ->
drawText(DC, "Memory Usage " ++ Unit, TopTextX,?BH),
lists:foldl(fun(MType, {PenId, Pos0}) ->
@@ -748,10 +778,10 @@ calc_max1(Max) ->
end.
colors() ->
- {{240, 100, 100}, {100, 240, 100}, {100, 100, 240},
- {220, 220, 80}, {100, 240, 240}, {240, 100, 240},
- {100, 25, 25}, {25, 100, 25}, {25, 25, 100},
- {120, 120, 0}, {25, 100, 100}, {100, 50, 100}
+ {{240, 100, 100}, {0, 128, 0}, {25, 45, 170}, {255, 165, 0},
+ {220, 220, 40}, {100, 240, 240},{240, 100, 240}, {160, 40, 40},
+ {100, 100, 240}, {140, 140, 0}, {25, 200, 100}, {120, 25, 240},
+ {255, 140, 163}, {25, 120, 120}, {120, 25, 120}, {110, 90, 60}
}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk
index dd23b08484..ca9ad72473 100644
--- a/lib/observer/vsn.mk
+++ b/lib/observer/vsn.mk
@@ -1 +1 @@
-OBSERVER_VSN = 2.3
+OBSERVER_VSN = 2.3.1
diff --git a/lib/os_mon/doc/src/notes.xml b/lib/os_mon/doc/src/notes.xml
index e6e80b046d..df4151147c 100644
--- a/lib/os_mon/doc/src/notes.xml
+++ b/lib/os_mon/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the OS_Mon application.</p>
+<section><title>Os_Mon 2.4.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Support s390x in os_mon.</p>
+ <p>
+ Own Id: OTP-14161 Aux Id: PR-1309 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Os_Mon 2.4.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/os_mon/vsn.mk b/lib/os_mon/vsn.mk
index 1ac0fb1d27..59a3d9dee4 100644
--- a/lib/os_mon/vsn.mk
+++ b/lib/os_mon/vsn.mk
@@ -1 +1 @@
-OS_MON_VSN = 2.4.1
+OS_MON_VSN = 2.4.2
diff --git a/lib/parsetools/doc/src/yecc.xml b/lib/parsetools/doc/src/yecc.xml
index 9188bd2a22..004fc1668d 100644
--- a/lib/parsetools/doc/src/yecc.xml
+++ b/lib/parsetools/doc/src/yecc.xml
@@ -207,7 +207,7 @@
<code>
Header "%% Copyright (C)"
"%% @private"
-"%% @Author John"</code>
+"%% @Author John".</code>
<p>Next comes a declaration of the <c>nonterminal categories</c>
to be used in the rules. For example:</p>
<code type="none">
diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl
index f6b80eb1b4..05446c1a85 100644
--- a/lib/parsetools/src/yecc.erl
+++ b/lib/parsetools/src/yecc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -81,7 +81,7 @@
-record(rule, {
n, % rule n in the grammar file
- line,
+ anno,
symbols, % the names of symbols
tokens,
is_guard, % the action is a guard (not used)
@@ -105,7 +105,7 @@
-record(user_code, {state, terminal, funname, action}).
--record(symbol, {line = none, name}).
+-record(symbol, {anno = none, name}).
%% ACCEPT is neither an atom nor a non-terminal.
-define(ACCEPT, {}).
@@ -517,7 +517,7 @@ parse_grammar(Grammar, Inport, NextLine, St0) ->
parse_grammar(Inport, NextLine, St).
parse_grammar({error,ErrorLine,Error}, St) ->
- add_error(ErrorLine, Error, St);
+ add_error(erl_anno:new(ErrorLine), Error, St);
parse_grammar({rule, Rule, Tokens}, St0) ->
NmbrOfDaughters = case Rule of
[_, #symbol{name = '$empty'}] -> 0;
@@ -534,15 +534,15 @@ parse_grammar({rule, Rule, Tokens}, St0) ->
St#yecc{rules_list = [RuleDef | St#yecc.rules_list]};
parse_grammar({prec, Prec}, St) ->
St#yecc{prec = Prec ++ St#yecc.prec};
-parse_grammar({#symbol{}, [{string,Line,String}]}, St) ->
- add_error(Line, {bad_symbol, String}, St);
-parse_grammar({#symbol{line = Line, name = Name}, Symbols}, St) ->
+parse_grammar({#symbol{}, [{string,Anno,String}]}, St) ->
+ add_error(Anno, {bad_symbol, String}, St);
+parse_grammar({#symbol{anno = Anno, name = Name}, Symbols}, St) ->
CF = fun(I) ->
case element(I, St) of
[] ->
setelement(I, St, Symbols);
_ ->
- add_error(Line, {duplicate_declaration, Name}, St)
+ add_error(Anno, {duplicate_declaration, Name}, St)
end
end,
OneSymbol = length(Symbols) =:= 1,
@@ -553,7 +553,7 @@ parse_grammar({#symbol{line = Line, name = Name}, Symbols}, St) ->
'Endsymbol' when OneSymbol -> CF(#yecc.endsymbol);
'Expect' when OneSymbol -> CF(#yecc.expect_shift_reduce);
'States' when OneSymbol -> CF(#yecc.expect_n_states); % undocumented
- _ -> add_warning(Line, bad_declaration, St)
+ _ -> add_warning(Anno, bad_declaration, St)
end.
read_grammar(Inport, St, Line) ->
@@ -599,7 +599,7 @@ precedence(_) -> unknown.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
check_grammar(St0) ->
- Empty = #symbol{line = none, name = '$empty'},
+ Empty = #symbol{anno = none, name = '$empty'},
AllSymbols = St0#yecc.nonterminals ++ St0#yecc.terminals ++ [Empty],
St1 = St0#yecc{all_symbols = AllSymbols},
Cs = [fun check_nonterminals/1, fun check_terminals/1,
@@ -640,12 +640,12 @@ check_rootsymbol(St) ->
case St#yecc.rootsymbol of
[] ->
add_error(rootsymbol_missing, St);
- [#symbol{line = Line, name = SymName}] ->
+ [#symbol{anno = Anno, name = SymName}] ->
case kind_of_symbol(St, SymName) of
nonterminal ->
St#yecc{rootsymbol = SymName};
_ ->
- add_error(Line, {bad_rootsymbol, SymName}, St)
+ add_error(Anno, {bad_rootsymbol, SymName}, St)
end
end.
@@ -653,12 +653,12 @@ check_endsymbol(St) ->
case St#yecc.endsymbol of
[] ->
St#yecc{endsymbol = '$end'};
- [#symbol{line = Line, name = SymName}] ->
+ [#symbol{anno = Anno, name = SymName}] ->
case kind_of_symbol(St, SymName) of
nonterminal ->
- add_error(Line, {endsymbol_is_nonterminal, SymName}, St);
+ add_error(Anno, {endsymbol_is_nonterminal, SymName}, St);
terminal ->
- add_error(Line, {endsymbol_is_terminal, SymName}, St);
+ add_error(Anno, {endsymbol_is_terminal, SymName}, St);
_ ->
St#yecc{endsymbol = SymName}
end
@@ -670,8 +670,8 @@ check_expect(St0) ->
St0#yecc{expect_shift_reduce = 0};
[#symbol{name = Expect}] when is_integer(Expect) ->
St0#yecc{expect_shift_reduce = Expect};
- [#symbol{line = Line, name = Name}] ->
- St1 = add_error(Line, {bad_expect, Name}, St0),
+ [#symbol{anno = Anno, name = Name}] ->
+ St1 = add_error(Anno, {bad_expect, Name}, St0),
St1#yecc{expect_shift_reduce = 0}
end.
@@ -681,27 +681,27 @@ check_states(St) ->
St;
[#symbol{name = NStates}] when is_integer(NStates) ->
St#yecc{expect_n_states = NStates};
- [#symbol{line = Line, name = Name}] ->
- add_error(Line, {bad_states, Name}, St)
+ [#symbol{anno = Anno, name = Name}] ->
+ add_error(Anno, {bad_states, Name}, St)
end.
check_precedences(St0) ->
{St1, _} =
- foldr(fun({#symbol{line = Line, name = Op},_I,_A}, {St,Ps}) ->
+ foldr(fun({#symbol{anno = Anno, name = Op},_I,_A}, {St,Ps}) ->
case member(Op, Ps) of
true ->
- {add_error(Line, {duplicate_precedence,Op}, St),
+ {add_error(Anno, {duplicate_precedence,Op}, St),
Ps};
false ->
{St, [Op | Ps]}
end
end, {St0,[]}, St0#yecc.prec),
- foldl(fun({#symbol{line = Line, name = Op},I,A}, St) ->
+ foldl(fun({#symbol{anno = Anno, name = Op},I,A}, St) ->
case kind_of_symbol(St, Op) of
endsymbol ->
- add_error(Line,{precedence_op_is_endsymbol,Op}, St);
+ add_error(Anno,{precedence_op_is_endsymbol,Op}, St);
unknown ->
- add_error(Line, {precedence_op_is_unknown, Op}, St);
+ add_error(Anno, {precedence_op_is_unknown, Op}, St);
_ ->
St#yecc{prec = [{Op,I,A} | St#yecc.prec]}
end
@@ -709,13 +709,13 @@ check_precedences(St0) ->
check_rule(Rule0, {St0,Rules}) ->
Symbols = Rule0#rule.symbols,
- #symbol{line = HeadLine, name = Head} = hd(Symbols),
+ #symbol{anno = HeadAnno, name = Head} = hd(Symbols),
case member(Head, St0#yecc.nonterminals) of
false ->
- {add_error(HeadLine, {undefined_nonterminal, Head}, St0), Rules};
+ {add_error(HeadAnno, {undefined_nonterminal, Head}, St0), Rules};
true ->
St = check_rhs(tl(Symbols), St0),
- Rule = Rule0#rule{line = HeadLine, symbols = names(Symbols)},
+ Rule = Rule0#rule{anno = HeadAnno, symbols = names(Symbols)},
{St, [Rule | Rules]}
end.
@@ -725,7 +725,7 @@ check_rules(St0) ->
[] ->
add_error(no_grammar_rules, St);
_ ->
- Rule = #rule{line = none,
+ Rule = #rule{anno = none,
symbols = [?ACCEPT, St#yecc.rootsymbol],
tokens = []},
Rules1 = [Rule | Rules0],
@@ -740,9 +740,9 @@ duplicates(List) ->
names(Symbols) ->
map(fun(Symbol) -> Symbol#symbol.name end, Symbols).
-symbol_line(Name, St) ->
- #symbol{line = Line} = symbol_find(Name, St#yecc.all_symbols),
- Line.
+symbol_anno(Name, St) ->
+ #symbol{anno = Anno} = symbol_find(Name, St#yecc.all_symbols),
+ Anno.
symbol_member(Symbol, Symbols) ->
symbol_find(Symbol#symbol.name, Symbols) =/= false.
@@ -894,31 +894,33 @@ report_warnings(St) ->
add_error(E, St) ->
add_error(none, E, St).
-add_error(Line, E, St) ->
- add_error(St#yecc.infile, Line, E, St).
+add_error(Anno, E, St) ->
+ add_error(St#yecc.infile, Anno, E, St).
-add_error(File, Line, E, St) ->
- St#yecc{errors = [{File,{Line,?MODULE,E}}|St#yecc.errors]}.
+add_error(File, Anno, E, St) ->
+ Loc = location(Anno),
+ St#yecc{errors = [{File,{Loc,?MODULE,E}}|St#yecc.errors]}.
add_errors(SymNames, E0, St0) ->
foldl(fun(SymName, St) ->
- add_error(symbol_line(SymName, St), {E0, SymName}, St)
+ add_error(symbol_anno(SymName, St), {E0, SymName}, St)
end, St0, SymNames).
-add_warning(Line, W, St) ->
- St#yecc{warnings = [{St#yecc.infile,{Line,?MODULE,W}}|St#yecc.warnings]}.
+add_warning(Anno, W, St) ->
+ Loc = location(Anno),
+ St#yecc{warnings = [{St#yecc.infile,{Loc,?MODULE,W}}|St#yecc.warnings]}.
add_warnings(SymNames, W0, St0) ->
foldl(fun(SymName, St) ->
- add_warning(symbol_line(SymName, St), {W0, SymName}, St)
+ add_warning(symbol_anno(SymName, St), {W0, SymName}, St)
end, St0, SymNames).
check_rhs([#symbol{name = '$empty'}], St) ->
St;
check_rhs(Rhs, St0) ->
case symbol_find('$empty', Rhs) of
- #symbol{line = Line} ->
- add_error(Line, illegal_empty, St0);
+ #symbol{anno = Anno} ->
+ add_error(Anno, illegal_empty, St0);
false ->
foldl(fun(Sym, St) ->
case symbol_member(Sym, St#yecc.all_symbols) of
@@ -926,13 +928,13 @@ check_rhs(Rhs, St0) ->
St;
false ->
E = {undefined_symbol,Sym#symbol.name},
- add_error(Sym#symbol.line, E, St)
+ add_error(Sym#symbol.anno, E, St)
end
end, St0, Rhs)
end.
check_action(Tokens) ->
- case erl_parse:parse_exprs(add_roberts_dot(Tokens, 0)) of
+ case erl_parse:parse_exprs(add_roberts_dot(Tokens, erl_anno:new(0))) of
{error, _Error} ->
{false, false};
{ok, [Expr | Exprs]} ->
@@ -940,10 +942,10 @@ check_action(Tokens) ->
{IsGuard, true}
end.
-add_roberts_dot([], Line) ->
- [{'dot', Line}];
-add_roberts_dot([{'dot', Line} | _], _) ->
- [{'dot', Line}];
+add_roberts_dot([], Anno) ->
+ [{'dot', Anno}];
+add_roberts_dot([{'dot', Anno} | _], _) ->
+ [{'dot', Anno}];
add_roberts_dot([Token | Tokens], _) ->
[Token | add_roberts_dot(Tokens, element(2, Token))].
@@ -953,21 +955,22 @@ subst_pseudo_vars([H0 | T0], NmbrOfDaughters, St0) ->
{H, St1} = subst_pseudo_vars(H0, NmbrOfDaughters, St0),
{T, St} = subst_pseudo_vars(T0, NmbrOfDaughters, St1),
{[H | T], St};
-subst_pseudo_vars({atom, Line, Atom}, NmbrOfDaughters, St0) ->
+subst_pseudo_vars({atom, Anno, Atom}, NmbrOfDaughters, St0) ->
case atom_to_list(Atom) of
[$$ | Rest] ->
try list_to_integer(Rest) of
N when N > 0, N =< NmbrOfDaughters ->
- {{var, Line, list_to_atom(append("__", Rest))}, St0};
+ {{var, Anno, list_to_atom(append("__", Rest))}, St0};
_ ->
- St = add_error(Line, {undefined_pseudo_variable, Atom},
+ St = add_error(Anno,
+ {undefined_pseudo_variable, Atom},
St0),
- {{atom, Line, '$undefined'}, St}
+ {{atom, Anno, '$undefined'}, St}
catch
- error: _ -> {{atom, Line, Atom}, St0}
+ error: _ -> {{atom, Anno, Atom}, St0}
end;
_ ->
- {{atom, Line, Atom}, St0}
+ {{atom, Anno, Atom}, St0}
end;
subst_pseudo_vars(Tuple, NmbrOfDaughters, St0) when is_tuple(Tuple) ->
{L, St} = subst_pseudo_vars(tuple_to_list(Tuple), NmbrOfDaughters, St0),
@@ -2295,9 +2298,9 @@ function_name(Name, Suf) ->
list_to_atom(concat([Name, '_' | quoted_atom(Suf)])).
rule(RulePointer, St) ->
- #rule{n = N, line = Line, symbols = Symbols} =
+ #rule{n = N, anno = Anno, symbols = Symbols} =
dict:fetch(RulePointer, St#yecc.rule_pointer2rule),
- {Symbols, Line, N}.
+ {Symbols, Anno, N}.
get_rule(RuleNmbr, St) ->
dict:fetch(RuleNmbr, St#yecc.rule_pointer2rule).
@@ -2463,7 +2466,7 @@ include(St, File, Outport) ->
include1(eof, _, _, _File, L, _St) ->
L;
include1({error, _}=_Error, _Inport, _Outport, File, L, St) ->
- throw(add_error(File, L, cannot_parse, St));
+ throw(add_error(File, erl_anno:new(L), cannot_parse, St));
include1(Line, Inport, Outport, File, L, St) ->
Incr = case member($\n, Line) of
true -> 1;
@@ -2488,7 +2491,7 @@ includefile_version(Includefile) ->
parse_file(Epp) ->
case epp:parse_erl_form(Epp) of
- {ok, {function,_Line,yeccpars1,7,_Clauses}} ->
+ {ok, {function,_Anno,yeccpars1,7,_Clauses}} ->
{1,4};
{eof,_Line} ->
{1,1};
@@ -2503,7 +2506,7 @@ pp_tokens(Tokens, Line0, Enc) ->
pp_tokens1([], _Line0, _Enc, _T0) ->
[];
pp_tokens1([T | Ts], Line0, Enc, T0) ->
- Line = element(2, T),
+ Line = location(anno(T)),
[pp_sep(Line, Line0, T0), pp_symbol(T, Enc)|pp_tokens1(Ts, Line, Enc, T)].
pp_symbol({var,_,Var}, _Enc) -> Var;
@@ -2538,10 +2541,17 @@ output_file_directive(St, _Filename, _Line) ->
St.
first_line(Tokens) ->
- element(2, hd(Tokens)).
+ location(anno(hd(Tokens))).
last_line(Tokens) ->
- element(2, lists:last(Tokens)).
+ location(anno(lists:last(Tokens))).
+
+location(none) -> none;
+location(Anno) ->
+ erl_anno:line(Anno).
+
+anno(Token) ->
+ element(2, Token).
%% Keep track of the current line in the generated file.
fwrite(#yecc{outport = Outport, line = Line}=St, Format, Args) ->
diff --git a/lib/parsetools/src/yeccgramm.yrl b/lib/parsetools/src/yeccgramm.yrl
index c7b2ef6a86..40aa85a43e 100644
--- a/lib/parsetools/src/yeccgramm.yrl
+++ b/lib/parsetools/src/yeccgramm.yrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,43 +39,38 @@ rule -> head '->' symbols attached_code dot: {rule, ['$1' | '$3'], '$4'}.
head -> symbol : '$1'.
symbols -> symbol : ['$1'].
symbols -> symbol symbols : ['$1' | '$2'].
-strings -> string : [string('$1')].
-strings -> string strings : [string('$1') | '$2'].
+strings -> string : ['$1'].
+strings -> string strings : ['$1' | '$2'].
attached_code -> ':' tokens : {erlang_code, '$2'}.
-attached_code -> '$empty' : {erlang_code, [{atom, 0, '$undefined'}]}.
+attached_code -> '$empty' : {erlang_code,
+ [{atom, erl_anno:new(0), '$undefined'}]}.
tokens -> token : ['$1'].
tokens -> token tokens : ['$1' | '$2'].
symbol -> var : symbol('$1').
symbol -> atom : symbol('$1').
symbol -> integer : symbol('$1').
symbol -> reserved_word : symbol('$1').
-token -> var : token('$1').
-token -> atom : token('$1').
-token -> float : token('$1').
-token -> integer : token('$1').
-token -> string : token('$1').
-token -> char : token('$1').
-token -> reserved_symbol : {value_of('$1'), line_of('$1')}.
-token -> reserved_word : {value_of('$1'), line_of('$1')}.
-token -> '->' : {'->', line_of('$1')}. % Have to be treated in this
-token -> ':' : {':', line_of('$1')}. % manner, because they are also
- % special symbols of the metagrammar
+token -> var : '$1'.
+token -> atom : '$1'.
+token -> float : '$1'.
+token -> integer : '$1'.
+token -> string : '$1'.
+token -> char : '$1'.
+token -> reserved_symbol : {value_of('$1'), anno_of('$1')}.
+token -> reserved_word : {value_of('$1'), anno_of('$1')}.
+token -> '->' : {'->', anno_of('$1')}. % Have to be treated in this
+token -> ':' : {':', anno_of('$1')}. % manner, because they are also
+ % special symbols of the metagrammar
Erlang code.
--record(symbol, {line, name}).
+-record(symbol, {anno, name}).
symbol(Symbol) ->
- #symbol{line = line_of(Symbol), name = value_of(Symbol)}.
-
-token(Token) ->
- setelement(2, Token, line_of(Token)).
-
-string(Token) ->
- setelement(2, Token, line_of(Token)).
+ #symbol{anno = anno_of(Symbol), name = value_of(Symbol)}.
value_of(Token) ->
element(3, Token).
-line_of(Token) ->
- erl_anno:line(element(2, Token)).
+anno_of(Token) ->
+ element(2, Token).
diff --git a/lib/parsetools/src/yeccparser.erl b/lib/parsetools/src/yeccparser.erl
index 0025284ccf..6f6f66d56c 100644
--- a/lib/parsetools/src/yeccparser.erl
+++ b/lib/parsetools/src/yeccparser.erl
@@ -1,29 +1,23 @@
-module(yeccparser).
-export([parse/1, parse_and_scan/1, format_error/1]).
--file("yeccgramm.yrl", 63).
+-file("yeccgramm.yrl", 65).
--record(symbol, {line, name}).
+-record(symbol, {anno, name}).
symbol(Symbol) ->
- #symbol{line = line_of(Symbol), name = value_of(Symbol)}.
-
-token(Token) ->
- setelement(2, Token, line_of(Token)).
-
-string(Token) ->
- setelement(2, Token, line_of(Token)).
+ #symbol{anno = anno_of(Symbol), name = value_of(Symbol)}.
value_of(Token) ->
element(3, Token).
-line_of(Token) ->
- erl_anno:line(element(2, Token)).
+anno_of(Token) ->
+ element(2, Token).
--file("lib/parsetools/include/yeccpre.hrl", 0).
+-file("/ldisk/hasse/otp/lib/parsetools/include/yeccpre.hrl", 0).
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -147,21 +141,10 @@ yecc_end(Line) ->
{'$end', Line}.
yecctoken_end_location(Token) ->
- try
- Str = erl_scan:text(Token),
- Line = erl_scan:line(Token),
- Parts = re:split(Str, "\n"),
- Dline = length(Parts) - 1,
- Yline = Line + Dline,
- case erl_scan:column(Token) of
- Column when is_integer(Column) ->
- Col = byte_size(lists:last(Parts)),
- {Yline, Col + if Dline =:= 0 -> Column; true -> 1 end};
- undefined ->
- Yline
- end
- catch _:_ ->
- yecctoken_location(Token)
+ try erl_anno:end_location(element(2, Token)) of
+ undefined -> yecctoken_location(Token);
+ Loc -> Loc
+ catch _:_ -> yecctoken_location(Token)
end.
-compile({nowarn_unused_function, yeccerror/1}).
@@ -172,15 +155,15 @@ yeccerror(Token) ->
-compile({nowarn_unused_function, yecctoken_to_string/1}).
yecctoken_to_string(Token) ->
- case catch erl_scan:text(Token) of
- Txt when is_list(Txt) -> Txt;
- _ -> yecctoken2string(Token)
+ try erl_scan:text(Token) of
+ undefined -> yecctoken2string(Token);
+ Txt -> Txt
+ catch _:_ -> yecctoken2string(Token)
end.
yecctoken_location(Token) ->
- case catch erl_scan:location(Token) of
- Loc when Loc =/= undefined -> Loc;
- _ -> element(2, Token)
+ try erl_scan:location(Token)
+ catch _:_ -> element(2, Token)
end.
-compile({nowarn_unused_function, yecctoken2string/1}).
@@ -204,8 +187,9 @@ yecctoken2string(Other) ->
--file("yeccgramm.erl", 207).
+-file("yeccgramm.erl", 190).
+-dialyzer({nowarn_function, yeccpars2/7}).
yeccpars2(0=S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr);
%% yeccpars2(1=S, Cat, Ss, Stack, T, Ts, Tzr) ->
@@ -281,6 +265,7 @@ yeccpars2(35=S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2(Other, _, _, _, _, _, _) ->
erlang:error({yecc_bug,"1.4",{missing_state_in_action_table, Other}}).
+-dialyzer({nowarn_function, yeccpars2_0/7}).
yeccpars2_0(S, atom, Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 6, Ss, Stack, T, Ts, Tzr);
yeccpars2_0(S, integer, Ss, Stack, T, Ts, Tzr) ->
@@ -308,11 +293,13 @@ yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_2(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccgoto_grammar(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccpars2_3/7}).
yeccpars2_3(S, '->', Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 10, Ss, Stack, T, Ts, Tzr);
yeccpars2_3(_, _, _, _, T, _, _) ->
yeccerror(T).
+-dialyzer({nowarn_function, yeccpars2_4/7}).
yeccpars2_4(_S, '$end', _Ss, Stack, _T, _Ts, _Tzr) ->
{ok, hd(Stack)};
yeccpars2_4(_, _, _, _, T, _, _) ->
@@ -362,11 +349,13 @@ yeccpars2_13(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
NewStack = yeccpars2_13_(Stack),
yeccgoto_symbols(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccpars2_14/7}).
yeccpars2_14(S, dot, Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 29, Ss, Stack, T, Ts, Tzr);
yeccpars2_14(_, _, _, _, T, _, _) ->
yeccerror(T).
+-dialyzer({nowarn_function, yeccpars2_15/7}).
yeccpars2_15(S, '->', Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 18, Ss, Stack, T, Ts, Tzr);
yeccpars2_15(S, ':', Ss, Stack, T, Ts, Tzr) ->
@@ -428,20 +417,16 @@ yeccpars2_19(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
yeccpars2_20(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
- NewStack = yeccpars2_20_(Stack),
- yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
+ yeccgoto_token(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
yeccpars2_21(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
- NewStack = yeccpars2_21_(Stack),
- yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
+ yeccgoto_token(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
yeccpars2_22(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
- NewStack = yeccpars2_22_(Stack),
- yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
+ yeccgoto_token(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
yeccpars2_23(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
- NewStack = yeccpars2_23_(Stack),
- yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
+ yeccgoto_token(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
yeccpars2_24(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
NewStack = yeccpars2_24_(Stack),
@@ -452,12 +437,10 @@ yeccpars2_25(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
yeccpars2_26(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
- NewStack = yeccpars2_26_(Stack),
- yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
+ yeccgoto_token(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
yeccpars2_27(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
- NewStack = yeccpars2_27_(Stack),
- yeccgoto_token(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr).
+ yeccgoto_token(hd(Ss), Cat, Ss, Stack, T, Ts, Tzr).
yeccpars2_28(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
[_|Nss] = Ss,
@@ -469,11 +452,13 @@ yeccpars2_29(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
NewStack = yeccpars2_29_(Stack),
yeccgoto_rule(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccpars2_30/7}).
yeccpars2_30(S, dot, Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr);
yeccpars2_30(_, _, _, _, T, _, _) ->
yeccerror(T).
+-dialyzer({nowarn_function, yeccpars2_31/7}).
yeccpars2_31(S, dot, Ss, Stack, T, Ts, Tzr) ->
yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr);
yeccpars2_31(_, _, _, _, T, _, _) ->
@@ -500,26 +485,33 @@ yeccpars2_35(_S, Cat, Ss, Stack, T, Ts, Tzr) ->
NewStack = yeccpars2_35_(Stack),
yeccgoto_declaration(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccgoto_attached_code/7}).
yeccgoto_attached_code(11, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_14(14, Cat, Ss, Stack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccgoto_declaration/7}).
yeccgoto_declaration(0=_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_5(_S, Cat, Ss, Stack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccgoto_grammar/7}).
yeccgoto_grammar(0, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccgoto_head/7}).
yeccgoto_head(0, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_3(3, Cat, Ss, Stack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccgoto_rule/7}).
yeccgoto_rule(0=_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_2(_S, Cat, Ss, Stack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccgoto_strings/7}).
yeccgoto_strings(1, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_31(31, Cat, Ss, Stack, T, Ts, Tzr);
yeccgoto_strings(32=_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_33(_S, Cat, Ss, Stack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccgoto_symbol/7}).
yeccgoto_symbol(0, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_1(1, Cat, Ss, Stack, T, Ts, Tzr);
yeccgoto_symbol(1, Cat, Ss, Stack, T, Ts, Tzr) ->
@@ -529,6 +521,7 @@ yeccgoto_symbol(10, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccgoto_symbol(12, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_12(12, Cat, Ss, Stack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccgoto_symbols/7}).
yeccgoto_symbols(1, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_30(30, Cat, Ss, Stack, T, Ts, Tzr);
yeccgoto_symbols(10, Cat, Ss, Stack, T, Ts, Tzr) ->
@@ -536,18 +529,20 @@ yeccgoto_symbols(10, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccgoto_symbols(12=_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_13(_S, Cat, Ss, Stack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccgoto_token/7}).
yeccgoto_token(15, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_17(17, Cat, Ss, Stack, T, Ts, Tzr);
yeccgoto_token(17, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_17(17, Cat, Ss, Stack, T, Ts, Tzr).
+-dialyzer({nowarn_function, yeccgoto_tokens/7}).
yeccgoto_tokens(15=_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_16(_S, Cat, Ss, Stack, T, Ts, Tzr);
yeccgoto_tokens(17=_S, Cat, Ss, Stack, T, Ts, Tzr) ->
yeccpars2_28(_S, Cat, Ss, Stack, T, Ts, Tzr).
-compile({inline,yeccpars2_6_/1}).
--file("yeccgramm.yrl", 44).
+-file("yeccgramm.yrl", 46).
yeccpars2_6_(__Stack0) ->
[__1 | __Stack] = __Stack0,
[begin
@@ -555,7 +550,7 @@ yeccpars2_6_(__Stack0) ->
end | __Stack].
-compile({inline,yeccpars2_7_/1}).
--file("yeccgramm.yrl", 45).
+-file("yeccgramm.yrl", 47).
yeccpars2_7_(__Stack0) ->
[__1 | __Stack] = __Stack0,
[begin
@@ -563,7 +558,7 @@ yeccpars2_7_(__Stack0) ->
end | __Stack].
-compile({inline,yeccpars2_8_/1}).
--file("yeccgramm.yrl", 46).
+-file("yeccgramm.yrl", 48).
yeccpars2_8_(__Stack0) ->
[__1 | __Stack] = __Stack0,
[begin
@@ -571,7 +566,7 @@ yeccpars2_8_(__Stack0) ->
end | __Stack].
-compile({inline,yeccpars2_9_/1}).
--file("yeccgramm.yrl", 43).
+-file("yeccgramm.yrl", 45).
yeccpars2_9_(__Stack0) ->
[__1 | __Stack] = __Stack0,
[begin
@@ -579,14 +574,15 @@ yeccpars2_9_(__Stack0) ->
end | __Stack].
-compile({inline,yeccpars2_11_/1}).
--file("yeccgramm.yrl", 40).
+-file("yeccgramm.yrl", 41).
yeccpars2_11_(__Stack0) ->
[begin
- { erlang_code , [ { atom , 0 , '$undefined' } ] }
+ { erlang_code ,
+ [ { atom , erl_anno : new ( 0 ) , '$undefined' } ] }
end | __Stack0].
-compile({inline,yeccpars2_12_/1}).
--file("yeccgramm.yrl", 35).
+-file("yeccgramm.yrl", 36).
yeccpars2_12_(__Stack0) ->
[__1 | __Stack] = __Stack0,
[begin
@@ -594,7 +590,7 @@ yeccpars2_12_(__Stack0) ->
end | __Stack].
-compile({inline,yeccpars2_13_/1}).
--file("yeccgramm.yrl", 36).
+-file("yeccgramm.yrl", 37).
yeccpars2_13_(__Stack0) ->
[__2,__1 | __Stack] = __Stack0,
[begin
@@ -602,7 +598,7 @@ yeccpars2_13_(__Stack0) ->
end | __Stack].
-compile({inline,yeccpars2_16_/1}).
--file("yeccgramm.yrl", 39).
+-file("yeccgramm.yrl", 40).
yeccpars2_16_(__Stack0) ->
[__2,__1 | __Stack] = __Stack0,
[begin
@@ -610,7 +606,7 @@ yeccpars2_16_(__Stack0) ->
end | __Stack].
-compile({inline,yeccpars2_17_/1}).
--file("yeccgramm.yrl", 41).
+-file("yeccgramm.yrl", 43).
yeccpars2_17_(__Stack0) ->
[__1 | __Stack] = __Stack0,
[begin
@@ -618,87 +614,39 @@ yeccpars2_17_(__Stack0) ->
end | __Stack].
-compile({inline,yeccpars2_18_/1}).
--file("yeccgramm.yrl", 55).
+-file("yeccgramm.yrl", 57).
yeccpars2_18_(__Stack0) ->
[__1 | __Stack] = __Stack0,
[begin
- { '->' , line_of ( __1 ) }
+ { '->' , anno_of ( __1 ) }
end | __Stack].
-compile({inline,yeccpars2_19_/1}).
--file("yeccgramm.yrl", 56).
+-file("yeccgramm.yrl", 58).
yeccpars2_19_(__Stack0) ->
[__1 | __Stack] = __Stack0,
[begin
- { ':' , line_of ( __1 ) }
- end | __Stack].
-
--compile({inline,yeccpars2_20_/1}).
--file("yeccgramm.yrl", 48).
-yeccpars2_20_(__Stack0) ->
- [__1 | __Stack] = __Stack0,
- [begin
- token ( __1 )
- end | __Stack].
-
--compile({inline,yeccpars2_21_/1}).
--file("yeccgramm.yrl", 52).
-yeccpars2_21_(__Stack0) ->
- [__1 | __Stack] = __Stack0,
- [begin
- token ( __1 )
- end | __Stack].
-
--compile({inline,yeccpars2_22_/1}).
--file("yeccgramm.yrl", 49).
-yeccpars2_22_(__Stack0) ->
- [__1 | __Stack] = __Stack0,
- [begin
- token ( __1 )
- end | __Stack].
-
--compile({inline,yeccpars2_23_/1}).
--file("yeccgramm.yrl", 50).
-yeccpars2_23_(__Stack0) ->
- [__1 | __Stack] = __Stack0,
- [begin
- token ( __1 )
+ { ':' , anno_of ( __1 ) }
end | __Stack].
-compile({inline,yeccpars2_24_/1}).
--file("yeccgramm.yrl", 53).
+-file("yeccgramm.yrl", 55).
yeccpars2_24_(__Stack0) ->
[__1 | __Stack] = __Stack0,
[begin
- { value_of ( __1 ) , line_of ( __1 ) }
+ { value_of ( __1 ) , anno_of ( __1 ) }
end | __Stack].
-compile({inline,yeccpars2_25_/1}).
--file("yeccgramm.yrl", 54).
+-file("yeccgramm.yrl", 56).
yeccpars2_25_(__Stack0) ->
[__1 | __Stack] = __Stack0,
[begin
- { value_of ( __1 ) , line_of ( __1 ) }
- end | __Stack].
-
--compile({inline,yeccpars2_26_/1}).
--file("yeccgramm.yrl", 51).
-yeccpars2_26_(__Stack0) ->
- [__1 | __Stack] = __Stack0,
- [begin
- token ( __1 )
- end | __Stack].
-
--compile({inline,yeccpars2_27_/1}).
--file("yeccgramm.yrl", 47).
-yeccpars2_27_(__Stack0) ->
- [__1 | __Stack] = __Stack0,
- [begin
- token ( __1 )
+ { value_of ( __1 ) , anno_of ( __1 ) }
end | __Stack].
-compile({inline,yeccpars2_28_/1}).
--file("yeccgramm.yrl", 42).
+-file("yeccgramm.yrl", 44).
yeccpars2_28_(__Stack0) ->
[__2,__1 | __Stack] = __Stack0,
[begin
@@ -706,7 +654,7 @@ yeccpars2_28_(__Stack0) ->
end | __Stack].
-compile({inline,yeccpars2_29_/1}).
--file("yeccgramm.yrl", 33).
+-file("yeccgramm.yrl", 34).
yeccpars2_29_(__Stack0) ->
[__5,__4,__3,__2,__1 | __Stack] = __Stack0,
[begin
@@ -714,23 +662,23 @@ yeccpars2_29_(__Stack0) ->
end | __Stack].
-compile({inline,yeccpars2_32_/1}).
--file("yeccgramm.yrl", 37).
+-file("yeccgramm.yrl", 38).
yeccpars2_32_(__Stack0) ->
[__1 | __Stack] = __Stack0,
[begin
- [ string ( __1 ) ]
+ [ __1 ]
end | __Stack].
-compile({inline,yeccpars2_33_/1}).
--file("yeccgramm.yrl", 38).
+-file("yeccgramm.yrl", 39).
yeccpars2_33_(__Stack0) ->
[__2,__1 | __Stack] = __Stack0,
[begin
- [ string ( __1 ) | __2 ]
+ [ __1 | __2 ]
end | __Stack].
-compile({inline,yeccpars2_34_/1}).
--file("yeccgramm.yrl", 32).
+-file("yeccgramm.yrl", 33).
yeccpars2_34_(__Stack0) ->
[__3,__2,__1 | __Stack] = __Stack0,
[begin
@@ -738,7 +686,7 @@ yeccpars2_34_(__Stack0) ->
end | __Stack].
-compile({inline,yeccpars2_35_/1}).
--file("yeccgramm.yrl", 31).
+-file("yeccgramm.yrl", 32).
yeccpars2_35_(__Stack0) ->
[__3,__2,__1 | __Stack] = __Stack0,
[begin
@@ -746,4 +694,4 @@ yeccpars2_35_(__Stack0) ->
end | __Stack].
--file("yeccgramm.yrl", 82).
+-file("yeccgramm.yrl", 77).
diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl
index 5bd71d5d19..2c37278d4b 100644
--- a/lib/parsetools/test/yecc_SUITE.erl
+++ b/lib/parsetools/test/yecc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1524,7 +1524,7 @@ otp_7945(suite) -> [];
otp_7945(Config) when is_list(Config) ->
A2 = erl_anno:new(2),
A3 = erl_anno:new(3),
- {error,_} = erl_parse:parse([{atom,3,foo},{'.',A2,9,9}]),
+ {error,_} = erl_parse:parse([{atom,A3,foo},{'.',A2,9,9}]),
ok.
otp_8483(doc) ->
diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml
index 74d1a57936..92e314186e 100644
--- a/lib/public_key/doc/src/notes.xml
+++ b/lib/public_key/doc/src/notes.xml
@@ -35,6 +35,34 @@
<file>notes.xml</file>
</header>
+<section><title>Public_Key 1.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ New function <c>pkix_verify_hostname/2,3</c> Implements
+ certificate hostname checking. See the manual and RFC
+ 6125.</p>
+ <p>
+ Own Id: OTP-13009</p>
+ </item>
+ <item>
+ <p>
+ The ssh host key fingerprint generation now also takes a
+ list of algorithms and returns a list of corresponding
+ fingerprints. See
+ <c>public_key:ssh_hostkey_fingerprint/2</c> and the
+ option <c>silently_accept_hosts</c> in
+ <c>ssh:connect</c>.</p>
+ <p>
+ Own Id: OTP-14223</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Public_Key 1.3</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index c97ec361d1..2300ce3937 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -331,13 +331,16 @@
</func>
<func>
- <name>generate_key(Params) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{} </name>
+ <name>generate_key(Params) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{} | {#'RSAPublicKey'{}, #'RSAPrivateKey'{}}</name>
<fsummary>Generates a new keypair.</fsummary>
<type>
- <v>Params = #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{}</v>
+ <v>Params = #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{}
+ | {rsa, Size::integer(), PubExp::integer} </v>
</type>
<desc>
- <p>Generates a new keypair.</p>
+ <p>Generates a new keypair. See also
+ <seealso marker="crypto:crypto#generate_key/2">crypto:generate_key/2</seealso>
+ </p>
</desc>
</func>
diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src
index 88ef07c5a6..dbd732c384 100644
--- a/lib/public_key/src/public_key.app.src
+++ b/lib/public_key/src/public_key.app.src
@@ -14,7 +14,7 @@
{applications, [asn1, crypto, kernel, stdlib]},
{registered, []},
{env, []},
- {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0","crypto-3.3",
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0","crypto-3.8",
"asn1-3.0"]}
]
}.
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 50d4d82d15..8f185bbbd4 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -395,9 +395,15 @@ dh_gex_group(Min, N, Max, Groups) ->
pubkey_ssh:dh_gex_group(Min, N, Max, Groups).
%%--------------------------------------------------------------------
--spec generate_key(#'DHParameter'{} | {namedCurve, Name ::oid()} |
- #'ECParameters'{}) -> {Public::binary(), Private::binary()} |
- #'ECPrivateKey'{}.
+-spec generate_key(#'DHParameter'{}) ->
+ {Public::binary(), Private::binary()};
+ ({namedCurve, Name ::oid()}) ->
+ #'ECPrivateKey'{};
+ (#'ECParameters'{}) ->
+ #'ECPrivateKey'{};
+ ({rsa, Size::pos_integer(), PubExp::pos_integer()}) ->
+ {#'RSAPublicKey'{}, #'RSAPrivateKey'{}}.
+
%% Description: Generates a new keypair
%%--------------------------------------------------------------------
generate_key(#'DHParameter'{prime = P, base = G}) ->
@@ -405,7 +411,49 @@ generate_key(#'DHParameter'{prime = P, base = G}) ->
generate_key({namedCurve, _} = Params) ->
ec_generate_key(Params);
generate_key(#'ECParameters'{} = Params) ->
- ec_generate_key(Params).
+ ec_generate_key(Params);
+generate_key({rsa, ModulusSize, PublicExponent}) ->
+ case crypto:generate_key(rsa, {ModulusSize,PublicExponent}) of
+ {[E, N], [E, N, D, P, Q, D_mod_P_1, D_mod_Q_1, InvQ_mod_P]} ->
+ Nint = crypto:bytes_to_integer(N),
+ Eint = crypto:bytes_to_integer(E),
+ {#'RSAPublicKey'{modulus = Nint,
+ publicExponent = Eint},
+ #'RSAPrivateKey'{version = 0, % Two-factor (I guess since otherPrimeInfos is not given)
+ modulus = Nint,
+ publicExponent = Eint,
+ privateExponent = crypto:bytes_to_integer(D),
+ prime1 = crypto:bytes_to_integer(P),
+ prime2 = crypto:bytes_to_integer(Q),
+ exponent1 = crypto:bytes_to_integer(D_mod_P_1),
+ exponent2 = crypto:bytes_to_integer(D_mod_Q_1),
+ coefficient = crypto:bytes_to_integer(InvQ_mod_P)}
+ };
+
+ {[E, N], [E, N, D]} -> % FIXME: what to set the other fields in #'RSAPrivateKey'?
+ % Answer: Miller [Mil76]
+ % G.L. Miller. Riemann's hypothesis and tests for primality.
+ % Journal of Computer and Systems Sciences,
+ % 13(3):300-307,
+ % 1976.
+ Nint = crypto:bytes_to_integer(N),
+ Eint = crypto:bytes_to_integer(E),
+ {#'RSAPublicKey'{modulus = Nint,
+ publicExponent = Eint},
+ #'RSAPrivateKey'{version = 0, % Two-factor (I guess since otherPrimeInfos is not given)
+ modulus = Nint,
+ publicExponent = Eint,
+ privateExponent = crypto:bytes_to_integer(D),
+ prime1 = '?',
+ prime2 = '?',
+ exponent1 = '?',
+ exponent2 = '?',
+ coefficient = '?'}
+ };
+
+ Other ->
+ Other
+ end.
%%--------------------------------------------------------------------
-spec compute_key(#'ECPoint'{} , #'ECPrivateKey'{}) -> binary().
@@ -1198,8 +1246,11 @@ ec_curve_spec( #'ECParameters'{fieldID = FieldId, curve = PCurve, base = Base, o
FieldId#'FieldID'.parameters},
Curve = {PCurve#'Curve'.a, PCurve#'Curve'.b, none},
{Field, Curve, Base, Order, CoFactor};
-ec_curve_spec({namedCurve, OID}) ->
- pubkey_cert_records:namedCurves(OID).
+ec_curve_spec({namedCurve, OID}) when is_tuple(OID), is_integer(element(1,OID)) ->
+ ec_curve_spec({namedCurve, pubkey_cert_records:namedCurves(OID)});
+ec_curve_spec({namedCurve, Name}) when is_atom(Name) ->
+ crypto:ec_curve(Name).
+
ec_key({PubKey, PrivateKey}, Params) ->
#'ECPrivateKey'{version = 1,
diff --git a/lib/public_key/test/erl_make_certs.erl b/lib/public_key/test/erl_make_certs.erl
index 3dab70784c..00be7dd5b3 100644
--- a/lib/public_key/test/erl_make_certs.erl
+++ b/lib/public_key/test/erl_make_certs.erl
@@ -346,10 +346,24 @@ make_key(ec, _Opts) ->
%% RSA key generation (OBS: for testing only)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+gen_rsa2(Size) ->
+ try
+ %% The numbers 2048,17 is choosen to not cause the cryptolib on
+ %% FIPS-enabled test machines be mad at us.
+ public_key:generate_key({rsa, 2048, 17})
+ of
+ {_Public, Private} -> Private
+ catch
+ error:notsup ->
+ %% Disabled dirty_schedulers => crypto:generate_key not working
+ weak_gen_rsa2(Size)
+ end.
+
+
-define(SMALL_PRIMES, [65537,97,89,83,79,73,71,67,61,59,53,
47,43,41,37,31,29,23,19,17,13,11,7,5,3]).
-gen_rsa2(Size) ->
+weak_gen_rsa2(Size) ->
P = prime(Size),
Q = prime(Size),
N = P*Q,
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index 2f541d8d84..b94768ae77 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 1.3
+PUBLIC_KEY_VSN = 1.4
diff --git a/lib/reltool/doc/src/notes.xml b/lib/reltool/doc/src/notes.xml
index 2365a68feb..b47d451055 100644
--- a/lib/reltool/doc/src/notes.xml
+++ b/lib/reltool/doc/src/notes.xml
@@ -38,7 +38,22 @@
thus constitutes one section in this document. The title of each
section is the version number of Reltool.</p>
- <section><title>Reltool 0.7.2</title>
+ <section><title>Reltool 0.7.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed xml issues in old release notes</p>
+ <p>
+ Own Id: OTP-14269</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.7.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
@@ -52,13 +67,13 @@
Some dependency chains would even be missed for
applications that are included in a 'rel' spec in the
reltool config. E.g.</p>
- <p>
+
<list> <item>Application x has y as included application,
and y in turn has z as included application. Then z is
not included. </item> <item>Application x has y in its
'applications' tag in the .app file, and y in turn has z
as included application. Then z is not included.</item>
- </list></p>
+ </list>
<p>
These bugs are now corrected.</p>
<p>
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index 3b1e868757..c61c3a0c71 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -289,8 +289,8 @@
"^lib",
"^releases"]).
-define(EMBEDDED_EXCL_SYS_FILTERS,
- ["^bin/(erlc|dialyzer|typer)(|\\.exe)\$",
- "^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)\$",
+ ["^bin/(erlc|dialyzer)(|\\.exe)\$",
+ "^erts.*/bin/(erlc|dialyzer)(|\\.exe)\$",
"^erts.*/bin/.*(debug|pdb)"]).
-define(EMBEDDED_INCL_APP_FILTERS, ["^ebin",
"^include",
@@ -303,7 +303,7 @@
"^erts.*/bin",
"^lib\$"]).
-define(STANDALONE_EXCL_SYS_FILTERS,
- ["^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)\$",
+ ["^erts.*/bin/(erlc|dialyzer)(|\\.exe)\$",
"^erts.*/bin/(start|escript|to_erl|run_erl)(|\\.exe)\$",
"^erts.*/bin/.*(debug|pdb)"]).
-define(STANDALONE_INCL_APP_FILTERS, ["^ebin",
diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk
index 2b23ff6f20..2d07eeb8f0 100644
--- a/lib/reltool/vsn.mk
+++ b/lib/reltool/vsn.mk
@@ -1 +1 @@
-RELTOOL_VSN = 0.7.2
+RELTOOL_VSN = 0.7.3
diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml
index 4c79a560ec..0eafc437cc 100644
--- a/lib/runtime_tools/doc/src/notes.xml
+++ b/lib/runtime_tools/doc/src/notes.xml
@@ -32,6 +32,24 @@
<p>This document describes the changes made to the Runtime_Tools
application.</p>
+<section><title>Runtime_Tools 1.11.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ etop erroneously reported the average scheduler
+ utilization since the tool was first started instead of
+ the scheduler utilization since last update. This is now
+ corrected.</p>
+ <p>
+ Own Id: OTP-14090 Aux Id: seq13232 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Runtime_Tools 1.11</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk
index 53fc51c198..8ec532de76 100644
--- a/lib/runtime_tools/vsn.mk
+++ b/lib/runtime_tools/vsn.mk
@@ -1 +1 @@
-RUNTIME_TOOLS_VSN = 1.11
+RUNTIME_TOOLS_VSN = 1.11.1
diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml
index 190b937f03..cd3f0e1864 100644
--- a/lib/sasl/doc/src/notes.xml
+++ b/lib/sasl/doc/src/notes.xml
@@ -31,6 +31,28 @@
</header>
<p>This document describes the changes made to the SASL application.</p>
+<section><title>SASL 3.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When both options 'warnings_as_errors' and 'silent' were
+ given to systools:make_script or systools:make_relup, no
+ error reason would be returned if warnings occurred.
+ Instead only the atom 'error' was returned. This is now
+ corrected.</p>
+ <p>
+ Options 'warnings_as_errors' and 'no_warn_sasl' are now
+ also allowed for systools:make_tar.</p>
+ <p>
+ Own Id: OTP-14170</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SASL 3.0.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk
index e35a0c2977..6aa662a743 100644
--- a/lib/sasl/vsn.mk
+++ b/lib/sasl/vsn.mk
@@ -1 +1 @@
-SASL_VSN = 3.0.2
+SASL_VSN = 3.0.3
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 3323d32878..f1919a6bb1 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -34,7 +34,27 @@
</header>
- <section><title>SNMP 5.2.4</title>
+ <section><title>SNMP 5.2.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The SNMP MIB compiler has been fixed to compile MIBS with
+ refinements on user types such as in RFC 4669
+ RADIUS-AUTH-SERVER-MIB.mib. Problem reported and
+ researched by Kenneth Lakin and Daniel Goertzen.</p>
+ <p>
+ See also: https://bugs.erlang.org/browse/ERL-325</p>
+ <p>
+ Own Id: OTP-14145 Aux Id: ERL-325 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SNMP 5.2.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 1837350284..02a39f030c 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,86 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 4.4.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix bug when opening connections. If the tcp setup
+ failed, that would in some cases not result in an error
+ return value.</p>
+ <p>
+ Own Id: OTP-14108</p>
+ </item>
+ <item>
+ <p>
+ Reduce information leakage in case of decryption errors.</p>
+ <p>
+ Own Id: OTP-14109</p>
+ </item>
+ <item>
+ <p>
+ The key exchange algorithm
+ diffie-hellman-group-exchange-sha* has a server-option
+ <c>{dh_gex_limits,{Min,Max}}</c>. There was a hostkey
+ signature validation error on the client side if the
+ option was used and the <c>Min</c> or the <c>Max</c>
+ differed from the corresponding values obtained from the
+ client.</p>
+ <p>
+ This bug is now corrected.</p>
+ <p>
+ Own Id: OTP-14166</p>
+ </item>
+ <item>
+ <p>
+ The sftpd server now correctly uses <c>root_dir</c> and
+ <c>cwd</c> when resolving file paths if both are
+ provided. The <c>cwd</c> handling is also corrected.</p>
+ <p>
+ Thanks to kape1395!</p>
+ <p>
+ Own Id: OTP-14225 Aux Id: PR-1331, PR-1335 </p>
+ </item>
+ <item>
+ <p>
+ Ssh_cli used a function that does not handle non-utf8
+ unicode correctly.</p>
+ <p>
+ Own Id: OTP-14230 Aux Id: ERL-364 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The implementation of the key exchange algorithms
+ diffie-hellman-group-exchange-sha* are optimized, up to a
+ factor of 11 for the slowest ( = biggest and safest)
+ group size.</p>
+ <p>
+ Own Id: OTP-14169 Aux Id: seq-13261 </p>
+ </item>
+ <item>
+ <p>
+ The ssh host key fingerprint generation now also takes a
+ list of algorithms and returns a list of corresponding
+ fingerprints. See
+ <c>public_key:ssh_hostkey_fingerprint/2</c> and the
+ option <c>silently_accept_hosts</c> in
+ <c>ssh:connect</c>.</p>
+ <p>
+ Own Id: OTP-14223</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index f6e26f5ee8..1f07e826ce 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -726,9 +726,10 @@
</func>
<func>
- <name>daemon_info(Daemon) -> {ok, [{port,Port}]} | {error,Error}</name>
+ <name>daemon_info(Daemon) -> {ok, [DaemonInfo]} | {error,Error}</name>
<fsummary>Get info about a daemon</fsummary>
<type>
+ <v>DaemonInfo = {port,Port::pos_integer()} | {listen_address, any|ip_address()} | {profile,atom()}</v>
<v>Port = integer()</v>
<v>Error = bad_daemon_ref</v>
</type>
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 95d2686094..974292fde1 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -42,10 +42,10 @@
{env, []},
{mod, {ssh_app, []}},
{runtime_dependencies, [
- "crypto-3.3",
+ "crypto-3.7.3",
"erts-6.0",
"kernel-3.0",
- "public_key-1.1",
- "stdlib-3.1"
+ "public_key-1.4",
+ "stdlib-3.3"
]}]}.
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 53aba14458..e2a289d737 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -200,11 +200,13 @@ daemon(Host0, Port, UserOptions0) ->
daemon_info(Pid) ->
case catch ssh_system_sup:acceptor_supervisor(Pid) of
AsupPid when is_pid(AsupPid) ->
- [Port] =
- [Prt || {{ssh_acceptor_sup,any,Prt,default},
+ [{ListenAddr,Port,Profile}] =
+ [{LA,Prt,Prf} || {{ssh_acceptor_sup,LA,Prt,Prf},
_WorkerPid,worker,[ssh_acceptor]} <- supervisor:which_children(AsupPid)],
- {ok, [{port,Port}]};
-
+ {ok, [{port,Port},
+ {listen_address,ListenAddr},
+ {profile,Profile}
+ ]};
_ ->
{error,bad_daemon_ref}
end.
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index c6a5990f41..96c83cb0f7 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.4
+SSH_VSN = 4.4.1
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 29b8e8ff67..d3ab3e9216 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -28,6 +28,70 @@
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 8.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Corrected termination behavior, that caused a PEM cache
+ bug and sometimes resulted in connection failures.</p>
+ <p>
+ Own Id: OTP-14100</p>
+ </item>
+ <item>
+ <p>
+ Fix bug that could hang ssl connection processes when
+ failing to require more data for very large handshake
+ packages. Add option max_handshake_size to mitigate DoS
+ attacks.</p>
+ <p>
+ Own Id: OTP-14138</p>
+ </item>
+ <item>
+ <p>
+ Improved support for CRL handling that could fail to work
+ as intended when an id-ce-extKeyUsage was present in the
+ certificate. Also improvements where needed to
+ distributionpoint handling so that all revocations
+ actually are found and not deemed to be not determinable.</p>
+ <p>
+ Own Id: OTP-14141</p>
+ </item>
+ <item>
+ <p>
+ A TLS handshake might accidentally match old sslv2 format
+ and ssl application would incorrectly aborted TLS
+ handshake with ssl_v2_client_hello_no_supported. Parsing
+ was altered to avoid this problem.</p>
+ <p>
+ Own Id: OTP-14222</p>
+ </item>
+ <item>
+ <p>
+ Correct default cipher list to prefer AES 128 before 3DES</p>
+ <p>
+ Own Id: OTP-14235</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Move PEM cache to a dedicated process, to avoid making
+ the SSL manager process a bottleneck. This improves
+ scalability of TLS connections.</p>
+ <p>
+ Own Id: OTP-13874</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 8.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index 0e8bf3d27c..428d8a6e70 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -31,6 +31,110 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 3.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>An escript with only two lines would not work.</p>
+ <p>
+ Own Id: OTP-14098</p>
+ </item>
+ <item>
+ <p> Characters (<c>$char</c>) can be used in constant
+ pattern expressions. They can also be used in types and
+ contracts. </p>
+ <p>
+ Own Id: OTP-14103 Aux Id: ERL-313 </p>
+ </item>
+ <item>
+ <p> The signatures of <c>erl_parse:anno_to_term/1</c> and
+ <c>erl_parse:anno_from_term/1</c> are corrected. Using
+ these functions no longer results in false Dialyzer
+ warnings. </p>
+ <p>
+ Own Id: OTP-14131</p>
+ </item>
+ <item>
+ <p>Pretty-printing of maps is improved. </p>
+ <p>
+ Own Id: OTP-14175 Aux Id: seq13277 </p>
+ </item>
+ <item>
+ <p>If any of the following functions in the <c>zip</c>
+ module crashed, a file would be left open:
+ <c>extract()</c>, <c>unzip()</c>, <c>create()</c>, or
+ <c>zip()</c>. This has been corrected.</p>
+ <p>A <c>zip</c> file having a "Unix header" could not be
+ unpacked.</p>
+ <p>
+ Own Id: OTP-14189 Aux Id: ERL-348, ERL-349 </p>
+ </item>
+ <item>
+ <p> Improve the Erlang shell's tab-completion of long
+ names. </p>
+ <p>
+ Own Id: OTP-14200 Aux Id: ERL-352 </p>
+ </item>
+ <item>
+ <p>
+ The reference manual for <c>sys</c> had some faulty
+ information about the 'get_modules' message used by
+ processes where modules change dynamically during
+ runtime. The documentation is now corrected.</p>
+ <p>
+ Own Id: OTP-14248 Aux Id: ERL-367 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Bug fixes, new features and improvements to gen_statem:</p>
+ <p>
+ A new type init_result/1 has replaced the old
+ init_result/0, so if you used that old type (that was
+ never documented) you have to change your code, which may
+ be regarded as a potential incompatibility.</p>
+ <p>
+ Changing callback modes after code change did not work
+ since the new callback mode was not recorded. This bug
+ has been fixed.</p>
+ <p>
+ The event types state_timeout and {call,From} could not
+ be generated with a {next_event,EventType,EventContent}
+ action since they did not pass the runtime type check.
+ This bug has now been corrected.</p>
+ <p>
+ State entry calls can now be repeated using (new) state
+ callback returns {repeat_state,...},
+ {repeat_state_and_data,_} and repeat_state_and_data.</p>
+ <p>
+ There have been lots of code cleanup in particular
+ regarding timer handling. For example is async
+ cancel_timer now used. Error handling has also been
+ cleaned up.</p>
+ <p>
+ To align with probable future changes to the rest of
+ gen_*, terminate/3 has now got a fallback and
+ code_change/4 is not mandatory.</p>
+ <p>
+ Own Id: OTP-14114</p>
+ </item>
+ <item>
+ <p><c>filename:safe_relative_path/1</c> to sanitize a
+ relative path has been added.</p>
+ <p>
+ Own Id: OTP-14215</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 3.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl
index 52df2319dd..bb7b485490 100644
--- a/lib/stdlib/src/c.erl
+++ b/lib/stdlib/src/c.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -400,7 +400,7 @@ split_def([], Res) -> {d, list_to_atom(reverse(Res))}.
make_term(Str) ->
case erl_scan:string(Str) of
{ok, Tokens, _} ->
- case erl_parse:parse_term(Tokens ++ [{dot, 1}]) of
+ case erl_parse:parse_term(Tokens ++ [{dot, erl_anno:new(1)}]) of
{ok, Term} -> Term;
{error, {_,_,Reason}} ->
io:format("~ts: ~ts~n", [Reason, Str]),
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 40eba4ad67..61d755ba55 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -286,7 +286,7 @@ parse_file(Epp) ->
{warning,W} ->
[{warning,W}|parse_file(Epp)];
{eof,Location} ->
- [{eof,erl_anno:new(Location)}]
+ [{eof,Location}]
end.
-spec default_encoding() -> source_encoding().
diff --git a/lib/stdlib/src/erl_anno.erl b/lib/stdlib/src/erl_anno.erl
index d32c34dabd..d0310f52e2 100644
--- a/lib/stdlib/src/erl_anno.erl
+++ b/lib/stdlib/src/erl_anno.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@
%% Debug: define DEBUG to make sure that annotations are handled as an
%% opaque type. Note that all abstract code need to be compiled with
-%% DEBUG=true. See also ./erl_pp.erl.
+%% DEBUG=true. See also ./erl_pp.erl and ./erl_parse.yrl.
%-define(DEBUG, true).
@@ -52,7 +52,11 @@
| {'record', record()}
| {'text', string()}.
+-ifdef(DEBUG).
+-opaque anno() :: [annotation(), ...].
+-else.
-opaque anno() :: location() | [annotation(), ...].
+-endif.
-type anno_term() :: term().
-type column() :: pos_integer().
diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl
index a6ae398d03..76db2eeacd 100644
--- a/lib/stdlib/src/erl_compile.erl
+++ b/lib/stdlib/src/erl_compile.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -337,7 +337,7 @@ file_or_directory(Name) ->
make_term(Str) ->
case erl_scan:string(Str) of
{ok, Tokens, _} ->
- case erl_parse:parse_term(Tokens ++ [{dot, 1}]) of
+ case erl_parse:parse_term(Tokens ++ [{dot, erl_anno:new(1)}]) of
{ok, Term} -> Term;
{error, {_,_,Reason}} ->
io:format(?STDERR, "~ts: ~ts~n", [Reason, Str]),
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 1b84234fac..0ffca0886f 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -737,7 +737,12 @@ start_state({attribute,_,module,M}, St0) ->
St1 = St0#lint{module=M},
St1#lint{state=attribute};
start_state(Form, St) ->
- St1 = add_error(element(2, Form), undefined_module, St),
+ Anno = case Form of
+ {eof, L} -> erl_anno:new(L);
+ %% {warning, Warning} and {error, Error} not possible here.
+ _ -> element(2, Form)
+ end,
+ St1 = add_error(Anno, undefined_module, St),
attribute_state(Form, St1#lint{state=attribute}).
%% attribute_state(Form, State) ->
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 922455a6f2..2dcddeb8c2 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -981,6 +981,16 @@ Erlang code.
%% keep track of annotation info in tokens
-define(anno(Tup), element(2, Tup)).
+%-define(DEBUG, true).
+
+-ifdef(DEBUG).
+%% Assumes that erl_anno has been compiled with DEBUG=true.
+-define(ANNO_CHECK(Tokens),
+ [] = [T || T <- Tokens, not is_list(element(2, T))]).
+-else.
+-define(ANNO_CHECK(Tokens), ok).
+-endif.
+
%% Entry points compatible to old erl_parse.
%% These really suck and are only here until Calle gets multiple
%% entry points working.
@@ -990,10 +1000,15 @@ Erlang code.
AbsForm :: abstract_form(),
ErrorInfo :: error_info().
parse_form([{'-',A1},{atom,A2,spec}|Tokens]) ->
- parse([{'-',A1},{'spec',A2}|Tokens]);
+ NewTokens = [{'-',A1},{'spec',A2}|Tokens],
+ ?ANNO_CHECK(NewTokens),
+ parse(NewTokens);
parse_form([{'-',A1},{atom,A2,callback}|Tokens]) ->
- parse([{'-',A1},{'callback',A2}|Tokens]);
+ NewTokens = [{'-',A1},{'callback',A2}|Tokens],
+ ?ANNO_CHECK(NewTokens),
+ parse(NewTokens);
parse_form(Tokens) ->
+ ?ANNO_CHECK(Tokens),
parse(Tokens).
-spec parse_exprs(Tokens) -> {ok, ExprList} | {error, ErrorInfo} when
@@ -1001,6 +1016,7 @@ parse_form(Tokens) ->
ExprList :: [abstract_expr()],
ErrorInfo :: error_info().
parse_exprs(Tokens) ->
+ ?ANNO_CHECK(Tokens),
A = erl_anno:new(0),
case parse([{atom,A,f},{'(',A},{')',A},{'->',A}|Tokens]) of
{ok,{function,_Lf,f,0,[{clause,_Lc,[],[],Exprs}]}} ->
@@ -1013,6 +1029,7 @@ parse_exprs(Tokens) ->
Term :: term(),
ErrorInfo :: error_info().
parse_term(Tokens) ->
+ ?ANNO_CHECK(Tokens),
A = erl_anno:new(0),
case parse([{atom,A,f},{'(',A},{')',A},{'->',A}|Tokens]) of
{ok,{function,_Af,f,0,[{clause,_Ac,[],[],[Expr]}]}} ->
@@ -1531,8 +1548,8 @@ type_preop_prec('#') -> {700,800}.
Fun :: fun((Anno) -> NewAnno),
Anno :: erl_anno:anno(),
NewAnno :: erl_anno:anno(),
- Abstr :: erl_parse_tree(),
- NewAbstr :: erl_parse_tree().
+ Abstr :: erl_parse_tree() | form_info(),
+ NewAbstr :: erl_parse_tree() | form_info().
map_anno(F0, Abstr) ->
F = fun(A, Acc) -> {F0(A), Acc} end,
@@ -1546,7 +1563,7 @@ map_anno(F0, Abstr) ->
Acc1 :: term(),
AccIn :: term(),
AccOut :: term(),
- Abstr :: erl_parse_tree().
+ Abstr :: erl_parse_tree() | form_info().
fold_anno(F0, Acc0, Abstr) ->
F = fun(A, Acc) -> {A, F0(A, Acc)} end,
@@ -1561,15 +1578,15 @@ fold_anno(F0, Acc0, Abstr) ->
Acc1 :: term(),
AccIn :: term(),
AccOut :: term(),
- Abstr :: erl_parse_tree(),
- NewAbstr :: erl_parse_tree().
+ Abstr :: erl_parse_tree() | form_info(),
+ NewAbstr :: erl_parse_tree() | form_info().
mapfold_anno(F, Acc0, Abstr) ->
modify_anno1(Abstr, Acc0, F).
-spec new_anno(Term) -> Abstr when
Term :: term(),
- Abstr :: erl_parse_tree().
+ Abstr :: erl_parse_tree() | form_info().
new_anno(Term) ->
F = fun(L, Acc) -> {erl_anno:new(L), Acc} end,
@@ -1577,14 +1594,14 @@ new_anno(Term) ->
NewAbstr.
-spec anno_to_term(Abstr) -> term() when
- Abstr :: erl_parse_tree().
+ Abstr :: erl_parse_tree() | form_info().
anno_to_term(Abstract) ->
F = fun(Anno, Acc) -> {erl_anno:to_term(Anno), Acc} end,
{NewAbstract, []} = modify_anno1(Abstract, [], F),
NewAbstract.
--spec anno_from_term(Term) -> erl_parse_tree() when
+-spec anno_from_term(Term) -> erl_parse_tree() | form_info() when
Term :: term().
anno_from_term(Term) ->
@@ -1629,6 +1646,8 @@ modify_anno1({warning,W}, Ac, _Mf) ->
{{warning,W},Ac};
modify_anno1({error,W}, Ac, _Mf) ->
{{error,W},Ac};
+modify_anno1({eof,L}, Ac, _Mf) ->
+ {{eof,L},Ac};
%% Expressions.
modify_anno1({clauses,Cs}, Ac, Mf) ->
{Cs1,Ac1} = modify_anno1(Cs, Ac, Mf),
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index d30cd508c1..6068afb293 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -51,6 +51,15 @@
%-define(DEBUG, true).
-ifdef(DEBUG).
+-define(FORM_TEST(T),
+ _ = case T of
+ {eof, _Line} -> ok;
+ {warning, _W} -> ok;
+ {error, _E} -> ok;
+ _ -> ?TEST(T)
+ end).
+-define(EXPRS_TEST(L),
+ [?TEST(E) || E <- L]).
-define(TEST(T),
%% Assumes that erl_anno has been compiled with DEBUG=true.
%% erl_pp does not use the annoations, but test it anyway.
@@ -62,6 +71,8 @@
erlang:error(badarg, [T])
end).
-else.
+-define(FORM_TEST(T), ok).
+-define(EXPRS_TEST(T), ok).
-define(TEST(T), ok).
-endif.
@@ -80,7 +91,7 @@ form(Thing) ->
Options :: options()).
form(Thing, Options) ->
- ?TEST(Thing),
+ ?FORM_TEST(Thing),
State = state(Options),
frmt(lform(Thing, options(Options)), State).
@@ -124,7 +135,7 @@ guard(Gs) ->
Options :: options()).
guard(Gs, Options) ->
- ?TEST(Gs),
+ ?EXPRS_TEST(Gs),
frmt(lguard(Gs, options(Options)), state(Options)).
-spec(exprs(Expressions) -> io_lib:chars() when
@@ -146,7 +157,7 @@ exprs(Es, Options) ->
Options :: options()).
exprs(Es, I, Options) ->
- ?TEST(Es),
+ ?EXPRS_TEST(Es),
frmt({seq,[],[],[$,],lexprs(Es, options(Options))}, I, state(Options)).
-spec(expr(Expression) -> io_lib:chars() when
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index 086e77cd28..a54df939bf 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -1321,7 +1321,11 @@ foldl_read(TarName, Fun, Accu, #read_opts{}=Opts)
when is_function(Fun,4) ->
try open(TarName, [read|Opts#read_opts.open_mode]) of
{ok, #reader{access=read}=Reader} ->
- foldl_read(Reader, Fun, Accu, Opts);
+ try
+ foldl_read(Reader, Fun, Accu, Opts)
+ after
+ _ = close(Reader)
+ end;
{error, _} = Err ->
Err
catch
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index c42ae981e7..6e8f780f7c 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -629,8 +629,7 @@ parse_source(S, File, Fd, StartLine, HeaderSz, CheckOnly) ->
{error, _} ->
epp_parse_file2(Epp, S2, [FileForm], OptModRes);
{eof, LastLine} ->
- Anno = anno(LastLine),
- S#state{forms_or_bin = [FileForm, {eof, Anno}]}
+ S#state{forms_or_bin = [FileForm, {eof, LastLine}]}
end,
ok = epp:close(Epp),
ok = file:close(Fd),
@@ -728,8 +727,7 @@ epp_parse_file2(Epp, S, Forms, Parsed) ->
[S#state.file,Ln,Mod:format_error(Args)]),
epp_parse_file(Epp, S#state{n_errors = S#state.n_errors + 1}, [Form | Forms]);
{eof, LastLine} ->
- Anno = anno(LastLine),
- S#state{forms_or_bin = lists:reverse([{eof, Anno} | Forms])}
+ S#state{forms_or_bin = lists:reverse([{eof, LastLine} | Forms])}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 2a0e3118d0..fda7a2cd8a 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -548,7 +548,7 @@ obsolete_1(queue, lait, 1) ->
obsolete_1(overload, _, _) ->
{removed, "removed in OTP 19"};
obsolete_1(rpc, safe_multi_server_call, A) when A =:= 2; A =:= 3 ->
- {removed, {rpc, multi_server_call, A}};
+ {removed, {rpc, multi_server_call, A}, "removed in OTP 19"};
%% Added in OTP 20.
diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl
index 28221ea75f..4a39f8ae9d 100644
--- a/lib/stdlib/src/qlc_pt.erl
+++ b/lib/stdlib/src/qlc_pt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -439,7 +439,7 @@ compile_forms(Forms0, Options) ->
(_) -> false
end,
Forms = ([F || F <- Forms0, not Exclude(element(1, F))]
- ++ [{eof,anno0()}]),
+ ++ [{eof,0}]),
try
case compile:noenv_forms(Forms, compile_options(Options)) of
{ok, _ModName, Ws0} ->
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 979161fef7..3c9e95e3a9 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -18,7 +18,7 @@
%% %CopyrightEnd%
{"%VSN%",
%% Up from - max one major revision back
- [{<<"3\\.[0-1](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-19.*
+ [{<<"3\\.[0-3](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-19.*
%% Down to - max one major revision back
- [{<<"3\\.[0-1](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-19.*
+ [{<<"3\\.[0-3](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-19.*
}.
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index c7dcd9ae16..df38edf393 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -2549,7 +2549,7 @@ otp_5878(Config) when is_list(Config) ->
{function,9,t,0,[{clause,9,[],[],[{record,10,r,[]}]}]},
{eof,11}],
{error,[{"rec.erl",[{7,erl_lint,old_abstract_code}]}],[]} =
- compile:forms(OldAbstract, [return, report]),
+ compile_forms(OldAbstract, [return, report]),
ok.
@@ -3848,9 +3848,13 @@ otp_11879(_Config) ->
[{1,erl_lint,{spec_fun_undefined,{f,1}}},
{2,erl_lint,spec_wrong_arity},
{22,erl_lint,callback_wrong_arity}]}],
- []} = compile:forms(Fs, [return,report]),
+ []} = compile_forms(Fs, [return,report]),
ok.
+compile_forms(Terms, Opts) ->
+ Forms = [erl_parse:anno_from_term(Term) || Term <- Terms],
+ compile:forms(Forms, Opts).
+
%% OTP-13230: -deprecated without -module.
otp_13230(Config) when is_list(Config) ->
Abstr = <<"-deprecated([{frutt,0,next_version}]).">>,
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index 31ea3210a8..1a028204b4 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1068,10 +1068,10 @@ otp_11100(Config) when is_list(Config) ->
%% There are a few places where the added code ("options(none)")
%% doesn't make a difference (pp:bit_elem_type/1 is an example).
+ A1 = erl_anno:new(1),
%% Cannot trigger the use of the hook function with export/import.
"-export([{fy,a}/b]).\n" =
- pf({attribute,1,export,[{{fy,a},b}]}),
- A1 = erl_anno:new(1),
+ pf({attribute,A1,export,[{{fy,a},b}]}),
"-type foo() :: integer(INVALID-FORM:{foo,bar}:).\n" =
pf({attribute,A1,type,{foo,{type,A1,integer,[{foo,bar}]},[]}}),
pf({attribute,A1,type,
@@ -1100,10 +1100,11 @@ otp_11100(Config) when is_list(Config) ->
%% OTP-11861. behaviour_info() and -callback.
otp_11861(Config) when is_list(Config) ->
+ A3 = erl_anno:new(3),
"-optional_callbacks([bar/0]).\n" =
- pf({attribute,3,optional_callbacks,[{bar,0}]}),
+ pf({attribute,A3,optional_callbacks,[{bar,0}]}),
"-optional_callbacks([{bar,1,bad}]).\n" =
- pf({attribute,4,optional_callbacks,[{bar,1,bad}]}),
+ pf({attribute,A3,optional_callbacks,[{bar,1,bad}]}),
ok.
pf(Form) ->
diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl
index 7d0ba967f9..aca5b1e54f 100644
--- a/lib/stdlib/test/erl_scan_SUITE.erl
+++ b/lib/stdlib/test/erl_scan_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -904,9 +904,9 @@ more_chars() ->
otp_10302(Config) when is_list(Config) ->
%% From unicode():
{ok,[{atom,1,'aсb'}],1} =
- erl_scan:string("'a"++[1089]++"b'", 1),
+ erl_scan_string("'a"++[1089]++"b'", 1),
{ok,[{atom,{1,1},'qaપ'}],{1,12}} =
- erl_scan:string("'qa\\x{aaa}'",{1,1}),
+ erl_scan_string("'qa\\x{aaa}'",{1,1}),
{ok,[{char,1,1089}],1} = erl_scan_string([$$,1089], 1),
{ok,[{char,1,1089}],1} = erl_scan_string([$$,$\\,1089],1),
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index d6b6d3f80c..2e1ae7bcff 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -20,7 +20,9 @@
-module(tar_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2, borderline/1, atomic/1, long_names/1,
+ init_per_group/2, end_per_group/2,
+ init_per_testcase/2,
+ borderline/1, atomic/1, long_names/1,
create_long_names/1, bad_tar/1, errors/1, extract_from_binary/1,
extract_from_binary_compressed/1, extract_filtered/1,
extract_from_open_file/1, symlinks/1, open_add_close/1, cooked_compressed/1,
@@ -56,6 +58,9 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+init_per_testcase(_Case, Config) ->
+ Ports = ordsets:from_list(erlang:ports()),
+ [{ports,Ports}|Config].
%% Test creating, listing and extracting one file from an archive,
%% multiple times with different file sizes. Also check that the file
@@ -85,7 +90,7 @@ borderline(Config) when is_list(Config) ->
%% Clean up.
delete_files([TempDir]),
- ok.
+ verify_ports(Config).
borderline_test(Size, TempDir) ->
io:format("Testing size ~p", [Size]),
@@ -270,7 +275,7 @@ atomic(Config) when is_list(Config) ->
%% Clean up.
delete_files([Tar1,Tar2,Tar3,Tar4|Names]),
- ok.
+ verify_ports(Config).
%% Returns a sequence of characters.
@@ -304,7 +309,9 @@ long_names(Config) when is_list(Config) ->
DataDir = proplists:get_value(data_dir, Config),
Long = filename:join(DataDir, "long_names.tar"),
run_in_short_tempdir(Config,
- fun() -> do_long_names(Long) end).
+ fun() -> do_long_names(Long) end),
+ verify_ports(Config).
+
do_long_names(Long) ->
%% Try table/2 and extract/2.
@@ -336,7 +343,8 @@ do_long_names(Long) ->
%% Creates a tar file from a deep directory structure (filenames are
%% longer than 100 characters).
create_long_names(Config) when is_list(Config) ->
- run_in_short_tempdir(Config, fun create_long_names/0).
+ run_in_short_tempdir(Config, fun create_long_names/0),
+ verify_ports(Config).
create_long_names() ->
{ok,Dir} = file:get_cwd(),
@@ -383,7 +391,7 @@ bad_tar(Config) when is_list(Config) ->
try_bad("bad_octal", invalid_tar_checksum, Config),
try_bad("bad_too_short", eof, Config),
try_bad("bad_even_shorter", eof, Config),
- ok.
+ verify_ports(Config).
try_bad(Name0, Reason, Config) ->
%% Intentionally no macros here.
@@ -433,7 +441,7 @@ errors(Config) when is_list(Config) ->
%% Clean up.
delete_files([GoodTar,BadTar]),
- ok.
+ verify_ports(Config).
try_error(M, F, A, Error) ->
io:format("Trying ~p:~p(~p)", [M, F, A]),
@@ -483,7 +491,7 @@ extract_from_binary(Config) when is_list(Config) ->
%% Clean up.
delete_files([ExtractDir]),
- ok.
+ verify_ports(Config).
extract_from_binary_compressed(Config) when is_list(Config) ->
%% Test extracting a compressed tar archive from a binary.
@@ -516,7 +524,7 @@ extract_from_binary_compressed(Config) when is_list(Config) ->
%% Clean up the rest.
delete_files([ExtractDir]),
- ok.
+ verify_ports(Config).
%% Test extracting a tar archive from a binary.
extract_filtered(Config) when is_list(Config) ->
@@ -537,7 +545,7 @@ extract_filtered(Config) when is_list(Config) ->
%% Clean up.
delete_files([ExtractDir]),
- ok.
+ verify_ports(Config).
%% Test extracting a tar archive from an open file.
extract_from_open_file(Config) when is_list(Config) ->
@@ -562,7 +570,7 @@ extract_from_open_file(Config) when is_list(Config) ->
%% Clean up.
delete_files([ExtractDir]),
- ok.
+ verify_ports(Config).
%% Test that archives containing symlinks can be created and extracted.
symlinks(Config) when is_list(Config) ->
@@ -581,6 +589,7 @@ symlinks(Config) when is_list(Config) ->
%% Clean up.
delete_files([Dir]),
+ verify_ports(Config),
Res.
make_symlink(Path, Link) ->
@@ -697,7 +706,8 @@ init(Config) when is_list(Config) ->
ok = erl_tar:add(Tar, FileOne, []),
ok = erl_tar:close(Tar),
{ok, [FileOne]} = erl_tar:table(TarOne),
- ok.
+
+ verify_ports(Config).
file_op_bad(_) ->
throw({error, should_never_be_called}).
@@ -751,7 +761,7 @@ open_add_close(Config) when is_list(Config) ->
delete_files(["oac_file","oac_small","oac_big",Dir,AnotherDir,ADir]),
- ok.
+ verify_ports(Config).
oac_files() ->
Files = [{"oac_file", 1459, $x},
@@ -782,7 +792,8 @@ cooked_compressed(Config) when is_list(Config) ->
%% Clean up.
delete_files([filename:join(PrivDir, "ddll_SUITE_data")]),
- ok.
+
+ verify_ports(Config).
%% Test that an archive can be created directly from binaries and
%% that an archive can be extracted into binaries.
@@ -810,13 +821,15 @@ memory(Config) when is_list(Config) ->
%% Clean up.
ok = delete_files([Name1,Name2]),
- ok.
+
+ verify_ports(Config).
read_other_implementations(Config) when is_list(Config) ->
DataDir = proplists:get_value(data_dir, Config),
Files = ["v7.tar", "gnu.tar", "bsd.tar",
"star.tar", "pax_mtime.tar"],
- do_read_other_implementations(Files, DataDir).
+ do_read_other_implementations(Files, DataDir),
+ verify_ports(Config).
do_read_other_implementations([], _DataDir) ->
ok;
@@ -836,7 +849,8 @@ sparse(Config) when is_list(Config) ->
Sparse01 = "sparse01.tar",
Sparse10Empty = "sparse10_empty.tar",
Sparse10 = "sparse10.tar",
- do_sparse([Sparse01Empty, Sparse01, Sparse10Empty, Sparse10], DataDir, PrivDir).
+ do_sparse([Sparse01Empty, Sparse01, Sparse10Empty, Sparse10], DataDir, PrivDir),
+ verify_ports(Config).
do_sparse([], _DataDir, _PrivDir) ->
ok;
@@ -994,3 +1008,14 @@ is_ustar(File) ->
$g -> false;
_ -> true
end.
+
+
+verify_ports(Config) ->
+ PortsBefore = proplists:get_value(ports, Config),
+ PortsAfter = ordsets:from_list(erlang:ports()),
+ case ordsets:subtract(PortsAfter, PortsBefore) of
+ [] ->
+ ok;
+ [_|_]=Rem ->
+ error({leaked_ports,Rem})
+ end.
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index e67cb9b08d..f7bd21472c 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 3.2
+STDLIB_VSN = 3.3
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index 415f1b8516..af20200d49 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the Tools application.</p>
+<section><title>Tools 2.9.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Improved edoc support in emacs mode.</p>
+ <p>
+ Own Id: OTP-14217 Aux Id: PR-1282 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Tools 2.9</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/tools/emacs/erldoc.el b/lib/tools/emacs/erldoc.el
index e1fd661348..348800f880 100644
--- a/lib/tools/emacs/erldoc.el
+++ b/lib/tools/emacs/erldoc.el
@@ -407,7 +407,7 @@ up the indexing."
(defvar erldoc-user-guides nil)
(defvar erldoc-missing-user-guides
- '("compiler" "hipe" "kernel" "os_mon" "parsetools" "typer")
+ '("compiler" "hipe" "kernel" "os_mon" "parsetools")
"List of standard Erlang applications with no user guides.")
;; Search in `code:lib_dir/0' using find LIB_DIR -type f -name
@@ -417,7 +417,7 @@ up the indexing."
"runtime_tools" "sasl" "snmp"
"ssl" "test_server"
("ssh" . "SSH") ("stdlib" . "STDLIB")
- ("hipe" . "HiPE") ("typer" . "TypEr"))
+ ("hipe" . "HiPE"))
"List of applications that come with a manual.")
(defun erldoc-user-guide-chapters (user-guide)
diff --git a/lib/tools/test/Makefile b/lib/tools/test/Makefile
index 84c4e56aff..fe65d1484d 100644
--- a/lib/tools/test/Makefile
+++ b/lib/tools/test/Makefile
@@ -52,8 +52,8 @@ RELSYSDIR = $(RELEASE_PATH)/tools_test
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
-ERL_MAKE_FLAGS +=
-ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/percept/include
+ERL_MAKE_FLAGS +=
+ERL_COMPILE_FLAGS +=
EBIN = .
diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk
index 07bc39f76e..f60da27c44 100644
--- a/lib/tools/vsn.mk
+++ b/lib/tools/vsn.mk
@@ -1 +1 @@
-TOOLS_VSN = 2.9
+TOOLS_VSN = 2.9.1
diff --git a/lib/typer/Makefile b/lib/typer/Makefile
deleted file mode 100644
index bd1b6458a8..0000000000
--- a/lib/typer/Makefile
+++ /dev/null
@@ -1,44 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2006-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#=============================================================================
-#
-# File: lib/typer/Makefile
-# Authors: Bingwen He, Tobias Lindahl, and Kostis Sagonas
-#
-#=============================================================================
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-#
-# Macros
-#
-
-SUB_DIRECTORIES = src doc/src
-
-include vsn.mk
-VSN = $(TYPER_VSN)
-
-SPECIAL_TARGETS =
-
-#
-# Default Subdir Targets
-#
-include $(ERL_TOP)/make/otp_subdir.mk
-
diff --git a/lib/typer/RELEASE_NOTES b/lib/typer/RELEASE_NOTES
deleted file mode 100644
index d91a815ee9..0000000000
--- a/lib/typer/RELEASE_NOTES
+++ /dev/null
@@ -1,22 +0,0 @@
-==============================================================================
- Major features, additions and changes between Typer versions
- (in reversed chronological order)
-==============================================================================
-
-Version 0.9 (in Erlang/OTP R14B02)
-----------------------------------
- - Major rewrite; all code has been cleaned up and placed in one file.
- The only reason why this is not version 1.0 yet is that there is no proper
- documentation for typer which can be displayed in the www.erlang.org site.
- - Added ability to receive the set of exported types and report unknown ones.
- - Better handling of overloaded contracts; especially erroneous ones on which
- typer does not crash anymore.
- - Fixed problem that caused typer to hang when given a file whose module name
- did not correspond to the file name.
- - Added two undocumented options that may come very handy when trying to
- understand why typer reports some particular set of types for the functions
- in a module. These options are mainly for typer developers at this point,
- but may become documented in some future version.
-
-Older versions
---------------
diff --git a/lib/typer/doc/Makefile b/lib/typer/doc/Makefile
deleted file mode 100644
index 1015ca78eb..0000000000
--- a/lib/typer/doc/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2006-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-SHELL=/bin/sh
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-clean:
- -rm -f *.html edoc-info stylesheet.css erlang.png
-
-distclean: clean
-realclean: clean
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
diff --git a/lib/typer/doc/html/.gitignore b/lib/typer/doc/html/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/typer/doc/html/.gitignore
+++ /dev/null
diff --git a/lib/typer/doc/pdf/.gitignore b/lib/typer/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/typer/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/typer/doc/src/Makefile b/lib/typer/doc/src/Makefile
deleted file mode 100644
index 3724a2e4d1..0000000000
--- a/lib/typer/doc/src/Makefile
+++ /dev/null
@@ -1,118 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2006-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(TYPER_VSN)
-APPLICATION=typer
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES =
-
-XML_PART_FILES = part_notes.xml
-XML_CHAPTER_FILES = notes.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = \
- $(BOOK_FILES) $(XML_CHAPTER_FILES) \
- $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES)
-
-GIF_FILES =
-
-# ----------------------------------------------------
-
-HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-
-INFO_FILE = ../../info
-EXTRA_FILES = \
- $(DEFAULT_GIF_FILES) \
- $(DEFAULT_HTML_FILES) \
- $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
-
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-
-HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
-
-TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-XML_FLAGS +=
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
-docs: pdf html man
-
-$(TOP_PDF_FILE): $(XML_FILES)
-
-pdf: $(TOP_PDF_FILE)
-
-html: gifs $(HTML_REF_MAN_FILE)
-
-man: $(MAN3_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-debug opt:
-
-clean clean_docs:
- rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
-
-distclean: clean
-realclean: clean
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_docs_spec: docs
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(HTMLDIR)/* \
- "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
-
-
-release_spec:
diff --git a/lib/typer/doc/src/book.xml b/lib/typer/doc/src/book.xml
deleted file mode 100644
index 20da44ae04..0000000000
--- a/lib/typer/doc/src/book.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>2006</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>TypEr</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <pagetext></pagetext>
- <preamble>
- </preamble>
- <pagetext>TypEr</pagetext>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
-</book>
-
diff --git a/lib/typer/doc/src/fascicules.xml b/lib/typer/doc/src/fascicules.xml
deleted file mode 100644
index b15610fa8b..0000000000
--- a/lib/typer/doc/src/fascicules.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
-
-<fascicules>
- <fascicule file="part_notes" href="part_notes_frame.html" entry="yes">
- Release Notes
- </fascicule>
- <fascicule file="" href="../../../../doc/print.html" entry="no">
- Off-Print
- </fascicule>
-</fascicules>
-
diff --git a/lib/typer/doc/src/notes.xml b/lib/typer/doc/src/notes.xml
deleted file mode 100644
index 9ef5ca1c70..0000000000
--- a/lib/typer/doc/src/notes.xml
+++ /dev/null
@@ -1,111 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2014</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>TypEr Release Notes</title>
- <prepared>otp_appnotes</prepared>
- <docno>nil</docno>
- <date>nil</date>
- <rev>nil</rev>
- <file>notes.xml</file>
- </header>
- <p>This document describes the changes made to TypEr.</p>
-
-<section><title>TypEr 0.9.11</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Internal changes</p>
- <p>
- Own Id: OTP-13551</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>TypEr 0.9.10</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>Fix a bug that could result in a crash when printing
- warnings onto standard error. </p>
- <p>
- Own Id: OTP-13010</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>TypEr 0.9.9</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Properly extract annotations from core code. </p>
- <p>
- Own Id: OTP-12727</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>TypEr 0.9.8</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> The name of a compiler option has been fixed in the
- Makefile. </p>
- <p>
- Own Id: OTP-11996</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>TypEr 0.9.7</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Added initial documentation framework for TypEr.</p>
- <p>
- Own Id: OTP-11860</p>
- </item>
- </list>
- </section>
-
-</section>
-
-
-
-</chapter>
-
diff --git a/lib/typer/doc/src/part_notes.xml b/lib/typer/doc/src/part_notes.xml
deleted file mode 100644
index 3234f0903e..0000000000
--- a/lib/typer/doc/src/part_notes.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2006</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>TypEr Release Notes</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <description>
- <p><em>TypEr</em></p>
- </description>
- <xi:include href="notes.xml"/>
-</part>
-
diff --git a/lib/typer/doc/src/ref_man.xml b/lib/typer/doc/src/ref_man.xml
deleted file mode 100644
index c793207443..0000000000
--- a/lib/typer/doc/src/ref_man.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2014</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>TypEr</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- <file>ref_man.xml</file>
- </header>
- <description>
- </description>
- <xi:include href="typer_app.xml"/>
-</application>
-
diff --git a/lib/typer/doc/src/typer_app.xml b/lib/typer/doc/src/typer_app.xml
deleted file mode 100644
index d52df5d0da..0000000000
--- a/lib/typer/doc/src/typer_app.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE appref SYSTEM "appref.dtd">
-
-<appref>
- <header>
- <copyright>
- <year>2014</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>TypEr</title>
- <prepared></prepared>
- <responsible></responsible>
- <docno></docno>
- <approved></approved>
- <checked></checked>
- <date></date>
- <rev></rev>
- <file>typer.xml</file>
- </header>
- <app>TypEr</app>
- <appsummary>The TypEr Application</appsummary>
- <description>
- <p>An Erlang/OTP application that shows type information
- for Erlang modules to the user. Additionally, it can
- annotate the code of files with such type information.</p>
- </description>
-
-</appref>
-
diff --git a/lib/typer/ebin/.gitignore b/lib/typer/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/typer/ebin/.gitignore
+++ /dev/null
diff --git a/lib/typer/info b/lib/typer/info
deleted file mode 100644
index 5145fbcfff..0000000000
--- a/lib/typer/info
+++ /dev/null
@@ -1,2 +0,0 @@
-group: tools
-short: TypEr
diff --git a/lib/typer/src/Makefile b/lib/typer/src/Makefile
deleted file mode 100644
index 6c5d8b0726..0000000000
--- a/lib/typer/src/Makefile
+++ /dev/null
@@ -1,111 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2006-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-#=============================================================================
-#
-# File: lib/typer/src/Makefile
-# Authors: Kostis Sagonas
-#
-#=============================================================================
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(TYPER_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/typer-$(VSN)
-
-# ----------------------------------------------------
-# Orientation information -- find dialyzer's dir
-# ----------------------------------------------------
-DIALYZER_DIR = $(ERL_TOP)/lib/dialyzer
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-MODULES = typer
-
-HRL_FILES=
-ERL_FILES= $(MODULES:%=%.erl)
-INSTALL_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET)
-TARGET_FILES= $(INSTALL_FILES)
-
-APP_FILE= typer.app
-APP_SRC= $(APP_FILE).src
-APP_TARGET= $(EBIN)/$(APP_FILE)
-
-APPUP_FILE= typer.appup
-APPUP_SRC= $(APPUP_FILE).src
-APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_COMPILE_FLAGS += +warn_export_vars +warn_untyped_record +warn_missing_spec
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-docs:
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-$(EBIN)/typer.$(EMULATOR): typer.erl ../vsn.mk Makefile
- $(erlc_verbose)erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) typer.erl
-
-$(APP_TARGET): $(APP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-# ---------------------------------------------------------------------
-# dependencies
-# ---------------------------------------------------------------------
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(YRL_FILES) \
- "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(INSTALL_FILES) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
diff --git a/lib/typer/src/typer.app.src b/lib/typer/src/typer.app.src
deleted file mode 100644
index e0be937cc3..0000000000
--- a/lib/typer/src/typer.app.src
+++ /dev/null
@@ -1,11 +0,0 @@
-% This is an -*- erlang -*- file.
-
-{application, typer,
- [{description, "TYPe annotator for ERlang programs, version %VSN%"},
- {vsn, "%VSN%"},
- {modules, [typer]},
- {registered, []},
- {applications, [compiler, dialyzer, hipe, kernel, stdlib]},
- {env, []},
- {runtime_dependencies, ["stdlib-3.0","kernel-5.0","hipe-3.15.4","erts-8.0",
- "dialyzer-3.1","compiler-7.0"]}]}.
diff --git a/lib/typer/src/typer.appup.src b/lib/typer/src/typer.appup.src
deleted file mode 100644
index 3b7464a97c..0000000000
--- a/lib/typer/src/typer.appup.src
+++ /dev/null
@@ -1,22 +0,0 @@
-%% -*- erlang -*-
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-{"%VSN%",
- [{<<".*">>,[{restart_application, typer}]}],
- [{<<".*">>,[{restart_application, typer}]}]
-}.
diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl
deleted file mode 100644
index 18c4fe902d..0000000000
--- a/lib/typer/src/typer.erl
+++ /dev/null
@@ -1,1110 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-
-%%-----------------------------------------------------------------------
-%% File : typer.erl
-%% Author(s) : The first version of typer was written by Bingwen He
-%% with guidance from Kostis Sagonas and Tobias Lindahl.
-%% Since June 2008 typer is maintained by Kostis Sagonas.
-%% Description : An Erlang/OTP application that shows type information
-%% for Erlang modules to the user. Additionally, it can
-%% annotate the code of files with such type information.
-%%-----------------------------------------------------------------------
-
--module(typer).
-
--export([start/0]).
-
-%%-----------------------------------------------------------------------
-
--define(SHOW, show).
--define(SHOW_EXPORTED, show_exported).
--define(ANNOTATE, annotate).
--define(ANNOTATE_INC_FILES, annotate_inc_files).
-
--type mode() :: ?SHOW | ?SHOW_EXPORTED | ?ANNOTATE | ?ANNOTATE_INC_FILES.
-
-%%-----------------------------------------------------------------------
-
--type files() :: [file:filename()].
--type callgraph() :: dialyzer_callgraph:callgraph().
--type codeserver() :: dialyzer_codeserver:codeserver().
--type plt() :: dialyzer_plt:plt().
-
--record(analysis,
- {mode :: mode() | 'undefined',
- macros = [] :: [{atom(), term()}],
- includes = [] :: files(),
- codeserver = dialyzer_codeserver:new():: codeserver(),
- callgraph = dialyzer_callgraph:new() :: callgraph(),
- files = [] :: files(), % absolute names
- plt = none :: 'none' | file:filename(),
- no_spec = false :: boolean(),
- show_succ = false :: boolean(),
- %% For choosing between specs or edoc @spec comments
- edoc = false :: boolean(),
- %% Files in 'fms' are compilable with option 'to_pp'; we keep them
- %% as {FileName, ModuleName} in case the ModuleName is different
- fms = [] :: [{file:filename(), module()}],
- ex_func = map__new() :: map_dict(),
- record = map__new() :: map_dict(),
- func = map__new() :: map_dict(),
- inc_func = map__new() :: map_dict(),
- trust_plt = dialyzer_plt:new() :: plt()}).
--type analysis() :: #analysis{}.
-
--record(args, {files = [] :: files(),
- files_r = [] :: files(),
- trusted = [] :: files()}).
--type args() :: #args{}.
-
-%%--------------------------------------------------------------------
-
--spec start() -> no_return().
-
-start() ->
- {Args, Analysis} = process_cl_args(),
- %% io:format("Args: ~p\n", [Args]),
- %% io:format("Analysis: ~p\n", [Analysis]),
- Timer = dialyzer_timing:init(false),
- TrustedFiles = filter_fd(Args#args.trusted, [], fun is_erl_file/1),
- Analysis2 = extract(Analysis, TrustedFiles),
- All_Files = get_all_files(Args),
- %% io:format("All_Files: ~p\n", [All_Files]),
- Analysis3 = Analysis2#analysis{files = All_Files},
- Analysis4 = collect_info(Analysis3),
- %% io:format("Final: ~p\n", [Analysis4#analysis.fms]),
- TypeInfo = get_type_info(Analysis4),
- dialyzer_timing:stop(Timer),
- show_or_annotate(TypeInfo),
- %% io:format("\nTyper analysis finished\n"),
- erlang:halt(0).
-
-%%--------------------------------------------------------------------
-
--spec extract(analysis(), files()) -> analysis().
-
-extract(#analysis{macros = Macros,
- includes = Includes,
- trust_plt = TrustPLT} = Analysis, TrustedFiles) ->
- %% io:format("--- Extracting trusted typer_info... "),
- Ds = [{d, Name, Value} || {Name, Value} <- Macros],
- CodeServer = dialyzer_codeserver:new(),
- Fun =
- fun(File, CS) ->
- %% We include one more dir; the one above the one we are trusting
- %% E.g, for /home/tests/typer_ann/test.ann.erl, we should include
- %% /home/tests/ rather than /home/tests/typer_ann/
- AllIncludes = [filename:dirname(filename:dirname(File)) | Includes],
- Is = [{i, Dir} || Dir <- AllIncludes],
- CompOpts = dialyzer_utils:src_compiler_opts() ++ Is ++ Ds,
- case dialyzer_utils:get_abstract_code_from_src(File, CompOpts) of
- {ok, AbstractCode} ->
- case dialyzer_utils:get_record_and_type_info(AbstractCode) of
- {ok, RecDict} ->
- Mod = list_to_atom(filename:basename(File, ".erl")),
- case dialyzer_utils:get_spec_info(Mod, AbstractCode, RecDict) of
- {ok, SpecDict, CbDict} ->
- CS1 = dialyzer_codeserver:store_temp_records(Mod, RecDict, CS),
- dialyzer_codeserver:store_temp_contracts(Mod, SpecDict, CbDict, CS1);
- {error, Reason} -> compile_error([Reason])
- end;
- {error, Reason} -> compile_error([Reason])
- end;
- {error, Reason} -> compile_error(Reason)
- end
- end,
- CodeServer1 = lists:foldl(Fun, CodeServer, TrustedFiles),
- %% Process remote types
- NewCodeServer =
- try
- CodeServer2 =
- dialyzer_utils:merge_types(CodeServer1,
- TrustPLT), % XXX change to the PLT?
- NewExpTypes = dialyzer_codeserver:get_temp_exported_types(CodeServer1),
- case sets:size(NewExpTypes) of 0 -> ok end,
- CodeServer3 = dialyzer_codeserver:finalize_exported_types(NewExpTypes, CodeServer2),
- CodeServer4 = dialyzer_utils:process_record_remote_types(CodeServer3),
- dialyzer_contracts:process_contract_remote_types(CodeServer4)
- catch
- throw:{error, ErrorMsg} ->
- compile_error(ErrorMsg)
- end,
- %% Create TrustPLT
- ContractsDict = dialyzer_codeserver:get_contracts(NewCodeServer),
- Contracts = orddict:from_list(dict:to_list(ContractsDict)),
- NewTrustPLT = dialyzer_plt:insert_contract_list(TrustPLT, Contracts),
- Analysis#analysis{trust_plt = NewTrustPLT}.
-
-%%--------------------------------------------------------------------
-
--spec get_type_info(analysis()) -> analysis().
-
-get_type_info(#analysis{callgraph = CallGraph,
- trust_plt = TrustPLT,
- codeserver = CodeServer} = Analysis) ->
- StrippedCallGraph = remove_external(CallGraph, TrustPLT),
- %% io:format("--- Analyzing callgraph... "),
- try
- NewMiniPlt = dialyzer_succ_typings:analyze_callgraph(StrippedCallGraph,
- TrustPLT,
- CodeServer),
- NewPlt = dialyzer_plt:restore_full_plt(NewMiniPlt),
- Analysis#analysis{callgraph = StrippedCallGraph, trust_plt = NewPlt}
- catch
- error:What ->
- fatal_error(io_lib:format("Analysis failed with message: ~p",
- [{What, erlang:get_stacktrace()}]));
- throw:{dialyzer_succ_typing_error, Msg} ->
- fatal_error(io_lib:format("Analysis failed with message: ~s", [Msg]))
- end.
-
--spec remove_external(callgraph(), plt()) -> callgraph().
-
-remove_external(CallGraph, PLT) ->
- {StrippedCG0, Ext} = dialyzer_callgraph:remove_external(CallGraph),
- case get_external(Ext, PLT) of
- [] -> ok;
- Externals ->
- msg(io_lib:format(" Unknown functions: ~p\n", [lists:usort(Externals)])),
- ExtTypes = rcv_ext_types(),
- case ExtTypes of
- [] -> ok;
- _ -> msg(io_lib:format(" Unknown types: ~p\n", [ExtTypes]))
- end
- end,
- StrippedCG0.
-
--spec get_external([{mfa(), mfa()}], plt()) -> [mfa()].
-
-get_external(Exts, Plt) ->
- Fun = fun ({_From, To = {M, F, A}}, Acc) ->
- case dialyzer_plt:contains_mfa(Plt, To) of
- false ->
- case erl_bif_types:is_known(M, F, A) of
- true -> Acc;
- false -> [To|Acc]
- end;
- true -> Acc
- end
- end,
- lists:foldl(Fun, [], Exts).
-
-%%--------------------------------------------------------------------
-%% Showing type information or annotating files with such information.
-%%--------------------------------------------------------------------
-
--define(TYPER_ANN_DIR, "typer_ann").
-
--type line() :: non_neg_integer().
--type fa() :: {atom(), arity()}.
--type func_info() :: {line(), atom(), arity()}.
-
--record(info, {records = maps:new() :: erl_types:type_table(),
- functions = [] :: [func_info()],
- types = map__new() :: map_dict(),
- edoc = false :: boolean()}).
--record(inc, {map = map__new() :: map_dict(), filter = [] :: files()}).
--type inc() :: #inc{}.
-
--spec show_or_annotate(analysis()) -> 'ok'.
-
-show_or_annotate(#analysis{mode = Mode, fms = Files} = Analysis) ->
- case Mode of
- ?SHOW -> show(Analysis);
- ?SHOW_EXPORTED -> show(Analysis);
- ?ANNOTATE ->
- Fun = fun ({File, Module}) ->
- Info = get_final_info(File, Module, Analysis),
- write_typed_file(File, Info)
- end,
- lists:foreach(Fun, Files);
- ?ANNOTATE_INC_FILES ->
- IncInfo = write_and_collect_inc_info(Analysis),
- write_inc_files(IncInfo)
- end.
-
-write_and_collect_inc_info(Analysis) ->
- Fun = fun ({File, Module}, Inc) ->
- Info = get_final_info(File, Module, Analysis),
- write_typed_file(File, Info),
- IncFuns = get_functions(File, Analysis),
- collect_imported_functions(IncFuns, Info#info.types, Inc)
- end,
- NewInc = lists:foldl(Fun, #inc{}, Analysis#analysis.fms),
- clean_inc(NewInc).
-
-write_inc_files(Inc) ->
- Fun =
- fun (File) ->
- Val = map__lookup(File, Inc#inc.map),
- %% Val is function with its type info
- %% in form [{{Line,F,A},Type}]
- Functions = [Key || {Key, _} <- Val],
- Val1 = [{{F,A},Type} || {{_Line,F,A},Type} <- Val],
- Info = #info{types = map__from_list(Val1),
- records = maps:new(),
- %% Note we need to sort functions here!
- functions = lists:keysort(1, Functions)},
- %% io:format("Types ~p\n", [Info#info.types]),
- %% io:format("Functions ~p\n", [Info#info.functions]),
- %% io:format("Records ~p\n", [Info#info.records]),
- write_typed_file(File, Info)
- end,
- lists:foreach(Fun, dict:fetch_keys(Inc#inc.map)).
-
-show(Analysis) ->
- Fun = fun ({File, Module}) ->
- Info = get_final_info(File, Module, Analysis),
- show_type_info(File, Info)
- end,
- lists:foreach(Fun, Analysis#analysis.fms).
-
-get_final_info(File, Module, Analysis) ->
- Records = get_records(File, Analysis),
- Types = get_types(Module, Analysis, Records),
- Functions = get_functions(File, Analysis),
- Edoc = Analysis#analysis.edoc,
- #info{records = Records, functions = Functions, types = Types, edoc = Edoc}.
-
-collect_imported_functions(Functions, Types, Inc) ->
- %% Coming from other sourses, including:
- %% FIXME: How to deal with yecc-generated file????
- %% --.yrl (yecc-generated file)???
- %% -- yeccpre.hrl (yecc-generated file)???
- %% -- other cases
- Fun = fun ({File, _} = Obj, I) ->
- case is_yecc_gen(File, I) of
- {true, NewI} -> NewI;
- {false, NewI} ->
- check_imported_functions(Obj, NewI, Types)
- end
- end,
- lists:foldl(Fun, Inc, Functions).
-
--spec is_yecc_gen(file:filename(), inc()) -> {boolean(), inc()}.
-
-is_yecc_gen(File, #inc{filter = Fs} = Inc) ->
- case lists:member(File, Fs) of
- true -> {true, Inc};
- false ->
- case filename:extension(File) of
- ".yrl" ->
- Rootname = filename:rootname(File, ".yrl"),
- Obj = Rootname ++ ".erl",
- case lists:member(Obj, Fs) of
- true -> {true, Inc};
- false ->
- NewInc = Inc#inc{filter = [Obj|Fs]},
- {true, NewInc}
- end;
- _ ->
- case filename:basename(File) of
- "yeccpre.hrl" -> {true, Inc};
- _ -> {false, Inc}
- end
- end
- end.
-
-check_imported_functions({File, {Line, F, A}}, Inc, Types) ->
- IncMap = Inc#inc.map,
- FA = {F, A},
- Type = get_type_info(FA, Types),
- case map__lookup(File, IncMap) of
- none -> %% File is not added. Add it
- Obj = {File,[{FA, {Line, Type}}]},
- NewMap = map__insert(Obj, IncMap),
- Inc#inc{map = NewMap};
- Val -> %% File is already in. Check.
- case lists:keyfind(FA, 1, Val) of
- false ->
- %% Function is not in; add it
- Obj = {File, Val ++ [{FA, {Line, Type}}]},
- NewMap = map__insert(Obj, IncMap),
- Inc#inc{map = NewMap};
- Type ->
- %% Function is in and with same type
- Inc;
- _ ->
- %% Function is in but with diff type
- inc_warning(FA, File),
- Elem = lists:keydelete(FA, 1, Val),
- NewMap = case Elem of
- [] -> map__remove(File, IncMap);
- _ -> map__insert({File, Elem}, IncMap)
- end,
- Inc#inc{map = NewMap}
- end
- end.
-
-inc_warning({F, A}, File) ->
- io:format(" ***Warning: Skip function ~p/~p ", [F, A]),
- io:format("in file ~p because of inconsistent type\n", [File]).
-
-clean_inc(Inc) ->
- Inc1 = remove_yecc_generated_file(Inc),
- normalize_obj(Inc1).
-
-remove_yecc_generated_file(#inc{filter = Filter} = Inc) ->
- Fun = fun (Key, #inc{map = Map} = I) ->
- I#inc{map = map__remove(Key, Map)}
- end,
- lists:foldl(Fun, Inc, Filter).
-
-normalize_obj(TmpInc) ->
- Fun = fun (Key, Val, Inc) ->
- NewVal = [{{Line,F,A},Type} || {{F,A},{Line,Type}} <- Val],
- map__insert({Key, NewVal}, Inc)
- end,
- TmpInc#inc{map = map__fold(Fun, map__new(), TmpInc#inc.map)}.
-
-get_records(File, Analysis) ->
- map__lookup(File, Analysis#analysis.record).
-
-get_types(Module, Analysis, Records) ->
- TypeInfoPlt = Analysis#analysis.trust_plt,
- TypeInfo =
- case dialyzer_plt:lookup_module(TypeInfoPlt, Module) of
- none -> [];
- {value, List} -> List
- end,
- CodeServer = Analysis#analysis.codeserver,
- TypeInfoList =
- case Analysis#analysis.show_succ of
- true ->
- [convert_type_info(I) || I <- TypeInfo];
- false ->
- [get_type(I, CodeServer, Records) || I <- TypeInfo]
- end,
- map__from_list(TypeInfoList).
-
-convert_type_info({{_M, F, A}, Range, Arg}) ->
- {{F, A}, {Range, Arg}}.
-
-get_type({{M, F, A} = MFA, Range, Arg}, CodeServer, Records) ->
- case dialyzer_codeserver:lookup_mfa_contract(MFA, CodeServer) of
- error ->
- {{F, A}, {Range, Arg}};
- {ok, {_FileLine, Contract, _Xtra}} ->
- Sig = erl_types:t_fun(Arg, Range),
- case dialyzer_contracts:check_contract(Contract, Sig) of
- ok -> {{F, A}, {contract, Contract}};
- {error, {extra_range, _, _}} ->
- {{F, A}, {contract, Contract}};
- {error, {overlapping_contract, []}} ->
- {{F, A}, {contract, Contract}};
- {error, invalid_contract} ->
- CString = dialyzer_contracts:contract_to_string(Contract),
- SigString = dialyzer_utils:format_sig(Sig, Records),
- Msg = io_lib:format("Error in contract of function ~w:~w/~w\n"
- "\t The contract is: " ++ CString ++ "\n" ++
- "\t but the inferred signature is: ~s",
- [M, F, A, SigString]),
- fatal_error(Msg);
- {error, ErrorStr} when is_list(ErrorStr) -> % ErrorStr is a string()
- Msg = io_lib:format("Error in contract of function ~w:~w/~w: ~s",
- [M, F, A, ErrorStr]),
- fatal_error(Msg)
- end
- end.
-
-get_functions(File, Analysis) ->
- case Analysis#analysis.mode of
- ?SHOW ->
- Funcs = map__lookup(File, Analysis#analysis.func),
- Inc_Funcs = map__lookup(File, Analysis#analysis.inc_func),
- remove_module_info(Funcs) ++ normalize_incFuncs(Inc_Funcs);
- ?SHOW_EXPORTED ->
- Ex_Funcs = map__lookup(File, Analysis#analysis.ex_func),
- remove_module_info(Ex_Funcs);
- ?ANNOTATE ->
- Funcs = map__lookup(File, Analysis#analysis.func),
- remove_module_info(Funcs);
- ?ANNOTATE_INC_FILES ->
- map__lookup(File, Analysis#analysis.inc_func)
- end.
-
-normalize_incFuncs(Functions) ->
- [FunInfo || {_FileName, FunInfo} <- Functions].
-
--spec remove_module_info([func_info()]) -> [func_info()].
-
-remove_module_info(FunInfoList) ->
- F = fun ({_,module_info,0}) -> false;
- ({_,module_info,1}) -> false;
- ({Line,F,A}) when is_integer(Line), is_atom(F), is_integer(A) -> true
- end,
- lists:filter(F, FunInfoList).
-
-write_typed_file(File, Info) ->
- io:format(" Processing file: ~p\n", [File]),
- Dir = filename:dirname(File),
- RootName = filename:basename(filename:rootname(File)),
- Ext = filename:extension(File),
- TyperAnnDir = filename:join(Dir, ?TYPER_ANN_DIR),
- TmpNewFilename = lists:concat([RootName, ".ann", Ext]),
- NewFileName = filename:join(TyperAnnDir, TmpNewFilename),
- case file:make_dir(TyperAnnDir) of
- {error, Reason} ->
- case Reason of
- eexist -> %% TypEr dir exists; remove old typer files if they exist
- case file:delete(NewFileName) of
- ok -> ok;
- {error, enoent} -> ok;
- {error, _} ->
- Msg = io_lib:format("Error in deleting file ~s\n", [NewFileName]),
- fatal_error(Msg)
- end,
- write_typed_file(File, Info, NewFileName);
- enospc ->
- Msg = io_lib:format("Not enough space in ~p\n", [Dir]),
- fatal_error(Msg);
- eacces ->
- Msg = io_lib:format("No write permission in ~p\n", [Dir]),
- fatal_error(Msg);
- _ ->
- Msg = io_lib:format("Unhandled error ~s when writing ~p\n",
- [Reason, Dir]),
- fatal_error(Msg)
- end;
- ok -> %% Typer dir does NOT exist
- write_typed_file(File, Info, NewFileName)
- end.
-
-write_typed_file(File, Info, NewFileName) ->
- {ok, Binary} = file:read_file(File),
- Chars = binary_to_list(Binary),
- write_typed_file(Chars, NewFileName, Info, 1, []),
- io:format(" Saved as: ~p\n", [NewFileName]).
-
-write_typed_file(Chars, File, #info{functions = []}, _LNo, _Acc) ->
- ok = file:write_file(File, list_to_binary(Chars), [append]);
-write_typed_file([Ch|Chs] = Chars, File, Info, LineNo, Acc) ->
- [{Line,F,A}|RestFuncs] = Info#info.functions,
- case Line of
- 1 -> %% This will happen only for inc files
- ok = raw_write(F, A, Info, File, []),
- NewInfo = Info#info{functions = RestFuncs},
- NewAcc = [],
- write_typed_file(Chars, File, NewInfo, Line, NewAcc);
- _ ->
- case Ch of
- 10 ->
- NewLineNo = LineNo + 1,
- {NewInfo, NewAcc} =
- case NewLineNo of
- Line ->
- ok = raw_write(F, A, Info, File, [Ch|Acc]),
- {Info#info{functions = RestFuncs}, []};
- _ ->
- {Info, [Ch|Acc]}
- end,
- write_typed_file(Chs, File, NewInfo, NewLineNo, NewAcc);
- _ ->
- write_typed_file(Chs, File, Info, LineNo, [Ch|Acc])
- end
- end.
-
-raw_write(F, A, Info, File, Content) ->
- TypeInfo = get_type_string(F, A, Info, file),
- ContentList = lists:reverse(Content) ++ TypeInfo ++ "\n",
- ContentBin = list_to_binary(ContentList),
- file:write_file(File, ContentBin, [append]).
-
-get_type_string(F, A, Info, Mode) ->
- Type = get_type_info({F,A}, Info#info.types),
- TypeStr =
- case Type of
- {contract, C} ->
- dialyzer_contracts:contract_to_string(C);
- {RetType, ArgType} ->
- Sig = erl_types:t_fun(ArgType, RetType),
- dialyzer_utils:format_sig(Sig, Info#info.records)
- end,
- case Info#info.edoc of
- false ->
- case {Mode, Type} of
- {file, {contract, _}} -> "";
- _ ->
- Prefix = lists:concat(["-spec ", erl_types:atom_to_string(F)]),
- lists:concat([Prefix, TypeStr, "."])
- end;
- true ->
- Prefix = lists:concat(["%% @spec ", F]),
- lists:concat([Prefix, TypeStr, "."])
- end.
-
-show_type_info(File, Info) ->
- io:format("\n%% File: ~p\n%% ", [File]),
- OutputString = lists:concat(["~.", length(File)+8, "c~n"]),
- io:fwrite(OutputString, [$-]),
- Fun = fun ({_LineNo, F, A}) ->
- TypeInfo = get_type_string(F, A, Info, show),
- io:format("~s\n", [TypeInfo])
- end,
- lists:foreach(Fun, Info#info.functions).
-
-get_type_info(Func, Types) ->
- case map__lookup(Func, Types) of
- none ->
- %% Note: Typeinfo of any function should exist in
- %% the result offered by dialyzer, otherwise there
- %% *must* be something wrong with the analysis
- Msg = io_lib:format("No type info for function: ~p\n", [Func]),
- fatal_error(Msg);
- {contract, _Fun} = C -> C;
- {_RetType, _ArgType} = RA -> RA
- end.
-
-%%--------------------------------------------------------------------
-%% Processing of command-line options and arguments.
-%%--------------------------------------------------------------------
-
--spec process_cl_args() -> {args(), analysis()}.
-
-process_cl_args() ->
- ArgList = init:get_plain_arguments(),
- %% io:format("Args is ~p\n", [ArgList]),
- {Args, Analysis} = analyze_args(ArgList, #args{}, #analysis{}),
- %% if the mode has not been set, set it to the default mode (show)
- {Args, case Analysis#analysis.mode of
- undefined -> Analysis#analysis{mode = ?SHOW};
- Mode when is_atom(Mode) -> Analysis
- end}.
-
-analyze_args([], Args, Analysis) ->
- {Args, Analysis};
-analyze_args(ArgList, Args, Analysis) ->
- {Result, Rest} = cl(ArgList),
- {NewArgs, NewAnalysis} = analyze_result(Result, Args, Analysis),
- analyze_args(Rest, NewArgs, NewAnalysis).
-
-cl(["-h"|_]) -> help_message();
-cl(["--help"|_]) -> help_message();
-cl(["-v"|_]) -> version_message();
-cl(["--version"|_]) -> version_message();
-cl(["--edoc"|Opts]) -> {edoc, Opts};
-cl(["--show"|Opts]) -> {{mode, ?SHOW}, Opts};
-cl(["--show_exported"|Opts]) -> {{mode, ?SHOW_EXPORTED}, Opts};
-cl(["--show-exported"|Opts]) -> {{mode, ?SHOW_EXPORTED}, Opts};
-cl(["--show_success_typings"|Opts]) -> {show_succ, Opts};
-cl(["--show-success-typings"|Opts]) -> {show_succ, Opts};
-cl(["--annotate"|Opts]) -> {{mode, ?ANNOTATE}, Opts};
-cl(["--annotate-inc-files"|Opts]) -> {{mode, ?ANNOTATE_INC_FILES}, Opts};
-cl(["--no_spec"|Opts]) -> {no_spec, Opts};
-cl(["--plt",Plt|Opts]) -> {{plt, Plt}, Opts};
-cl(["-D"++Def|Opts]) ->
- case Def of
- "" -> fatal_error("no variable name specified after -D");
- _ ->
- DefPair = process_def_list(re:split(Def, "=", [{return, list}])),
- {{def, DefPair}, Opts}
- end;
-cl(["-I",Dir|Opts]) -> {{inc, Dir}, Opts};
-cl(["-I"++Dir|Opts]) ->
- case Dir of
- "" -> fatal_error("no include directory specified after -I");
- _ -> {{inc, Dir}, Opts}
- end;
-cl(["-T"|Opts]) ->
- {Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts),
- case Files of
- [] -> fatal_error("no file or directory specified after -T");
- [_|_] -> {{trusted, Files}, RestOpts}
- end;
-cl(["-r"|Opts]) ->
- {Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts),
- {{files_r, Files}, RestOpts};
-cl(["-pa",Dir|Opts]) -> {{pa,Dir}, Opts};
-cl(["-pz",Dir|Opts]) -> {{pz,Dir}, Opts};
-cl(["-"++H|_]) -> fatal_error("unknown option -"++H);
-cl(Opts) ->
- {Files, RestOpts} = dialyzer_cl_parse:collect_args(Opts),
- {{files, Files}, RestOpts}.
-
-process_def_list(L) ->
- case L of
- [Name, Value] ->
- {ok, Tokens, _} = erl_scan:string(Value ++ "."),
- {ok, ErlValue} = erl_parse:parse_term(Tokens),
- {list_to_atom(Name), ErlValue};
- [Name] ->
- {list_to_atom(Name), true}
- end.
-
-%% Get information about files that the user trusts and wants to analyze
-analyze_result({files, Val}, Args, Analysis) ->
- NewVal = Args#args.files ++ Val,
- {Args#args{files = NewVal}, Analysis};
-analyze_result({files_r, Val}, Args, Analysis) ->
- NewVal = Args#args.files_r ++ Val,
- {Args#args{files_r = NewVal}, Analysis};
-analyze_result({trusted, Val}, Args, Analysis) ->
- NewVal = Args#args.trusted ++ Val,
- {Args#args{trusted = NewVal}, Analysis};
-analyze_result(edoc, Args, Analysis) ->
- {Args, Analysis#analysis{edoc = true}};
-%% Get useful information for actual analysis
-analyze_result({mode, Mode}, Args, Analysis) ->
- case Analysis#analysis.mode of
- undefined -> {Args, Analysis#analysis{mode = Mode}};
- OldMode -> mode_error(OldMode, Mode)
- end;
-analyze_result({def, Val}, Args, Analysis) ->
- NewVal = Analysis#analysis.macros ++ [Val],
- {Args, Analysis#analysis{macros = NewVal}};
-analyze_result({inc, Val}, Args, Analysis) ->
- NewVal = Analysis#analysis.includes ++ [Val],
- {Args, Analysis#analysis{includes = NewVal}};
-analyze_result({plt, Plt}, Args, Analysis) ->
- {Args, Analysis#analysis{plt = Plt}};
-analyze_result(show_succ, Args, Analysis) ->
- {Args, Analysis#analysis{show_succ = true}};
-analyze_result(no_spec, Args, Analysis) ->
- {Args, Analysis#analysis{no_spec = true}};
-analyze_result({pa, Dir}, Args, Analysis) ->
- true = code:add_patha(Dir),
- {Args, Analysis};
-analyze_result({pz, Dir}, Args, Analysis) ->
- true = code:add_pathz(Dir),
- {Args, Analysis}.
-
-%%--------------------------------------------------------------------
-%% File processing.
-%%--------------------------------------------------------------------
-
--spec get_all_files(args()) -> [file:filename(),...].
-
-get_all_files(#args{files = Fs, files_r = Ds}) ->
- case filter_fd(Fs, Ds, fun test_erl_file_exclude_ann/1) of
- [] -> fatal_error("no file(s) to analyze");
- AllFiles -> AllFiles
- end.
-
--spec test_erl_file_exclude_ann(file:filename()) -> boolean().
-
-test_erl_file_exclude_ann(File) ->
- case is_erl_file(File) of
- true -> %% Exclude files ending with ".ann.erl"
- case re:run(File, "[\.]ann[\.]erl$") of
- {match, _} -> false;
- nomatch -> true
- end;
- false -> false
- end.
-
--spec is_erl_file(file:filename()) -> boolean().
-
-is_erl_file(File) ->
- filename:extension(File) =:= ".erl".
-
--type test_file_fun() :: fun((file:filename()) -> boolean()).
-
--spec filter_fd(files(), files(), test_file_fun()) -> files().
-
-filter_fd(File_Dir, Dir_R, Fun) ->
- All_File_1 = process_file_and_dir(File_Dir, Fun),
- All_File_2 = process_dir_rec(Dir_R, Fun),
- remove_dup(All_File_1 ++ All_File_2).
-
--spec process_file_and_dir(files(), test_file_fun()) -> files().
-
-process_file_and_dir(File_Dir, TestFun) ->
- Fun =
- fun (Elem, Acc) ->
- case filelib:is_regular(Elem) of
- true -> process_file(Elem, TestFun, Acc);
- false -> check_dir(Elem, false, Acc, TestFun)
- end
- end,
- lists:foldl(Fun, [], File_Dir).
-
--spec process_dir_rec(files(), test_file_fun()) -> files().
-
-process_dir_rec(Dirs, TestFun) ->
- Fun = fun (Dir, Acc) -> check_dir(Dir, true, Acc, TestFun) end,
- lists:foldl(Fun, [], Dirs).
-
--spec check_dir(file:filename(), boolean(), files(), test_file_fun()) -> files().
-
-check_dir(Dir, Recursive, Acc, Fun) ->
- case file:list_dir(Dir) of
- {ok, Files} ->
- {TmpDirs, TmpFiles} = split_dirs_and_files(Files, Dir),
- case Recursive of
- false ->
- FinalFiles = process_file_and_dir(TmpFiles, Fun),
- Acc ++ FinalFiles;
- true ->
- TmpAcc1 = process_file_and_dir(TmpFiles, Fun),
- TmpAcc2 = process_dir_rec(TmpDirs, Fun),
- Acc ++ TmpAcc1 ++ TmpAcc2
- end;
- {error, eacces} ->
- fatal_error("no access permission to dir \""++Dir++"\"");
- {error, enoent} ->
- fatal_error("cannot access "++Dir++": No such file or directory");
- {error, _Reason} ->
- fatal_error("error involving a use of file:list_dir/1")
- end.
-
-%% Same order as the input list
--spec process_file(file:filename(), test_file_fun(), files()) -> files().
-
-process_file(File, TestFun, Acc) ->
- case TestFun(File) of
- true -> Acc ++ [File];
- false -> Acc
- end.
-
-%% Same order as the input list
--spec split_dirs_and_files(files(), file:filename()) -> {files(), files()}.
-
-split_dirs_and_files(Elems, Dir) ->
- Test_Fun =
- fun (Elem, {DirAcc, FileAcc}) ->
- File = filename:join(Dir, Elem),
- case filelib:is_regular(File) of
- false -> {[File|DirAcc], FileAcc};
- true -> {DirAcc, [File|FileAcc]}
- end
- end,
- {Dirs, Files} = lists:foldl(Test_Fun, {[], []}, Elems),
- {lists:reverse(Dirs), lists:reverse(Files)}.
-
-%% Removes duplicate filenames but keeps the order of the input list
--spec remove_dup(files()) -> files().
-
-remove_dup(Files) ->
- Test_Dup = fun (File, Acc) ->
- case lists:member(File, Acc) of
- true -> Acc;
- false -> [File|Acc]
- end
- end,
- Reversed_Elems = lists:foldl(Test_Dup, [], Files),
- lists:reverse(Reversed_Elems).
-
-%%--------------------------------------------------------------------
-%% Collect information.
-%%--------------------------------------------------------------------
-
--type inc_file_info() :: {file:filename(), func_info()}.
-
--record(tmpAcc, {file :: file:filename(),
- module :: atom(),
- funcAcc = [] :: [func_info()],
- incFuncAcc = [] :: [inc_file_info()],
- dialyzerObj = [] :: [{mfa(), {_, _}}]}).
-
--spec collect_info(analysis()) -> analysis().
-
-collect_info(Analysis) ->
- NewPlt =
- try get_dialyzer_plt(Analysis) of
- DialyzerPlt ->
- dialyzer_plt:merge_plts([Analysis#analysis.trust_plt, DialyzerPlt])
- catch
- throw:{dialyzer_error,_Reason} ->
- fatal_error("Dialyzer's PLT is missing or is not up-to-date; please (re)create it")
- end,
- NewAnalysis = lists:foldl(fun collect_one_file_info/2,
- Analysis#analysis{trust_plt = NewPlt},
- Analysis#analysis.files),
- %% Process Remote Types
- TmpCServer = NewAnalysis#analysis.codeserver,
- NewCServer =
- try
- TmpCServer1 = dialyzer_utils:merge_types(TmpCServer, NewPlt),
- NewExpTypes = dialyzer_codeserver:get_temp_exported_types(TmpCServer),
- OldExpTypes = dialyzer_plt:get_exported_types(NewPlt),
- MergedExpTypes = sets:union(NewExpTypes, OldExpTypes),
- TmpCServer2 =
- dialyzer_codeserver:finalize_exported_types(MergedExpTypes, TmpCServer1),
- TmpCServer3 = dialyzer_utils:process_record_remote_types(TmpCServer2),
- dialyzer_contracts:process_contract_remote_types(TmpCServer3)
- catch
- throw:{error, ErrorMsg} ->
- fatal_error(ErrorMsg)
- end,
- NewAnalysis#analysis{codeserver = NewCServer}.
-
-collect_one_file_info(File, Analysis) ->
- Ds = [{d,Name,Val} || {Name,Val} <- Analysis#analysis.macros],
- %% Current directory should also be included in "Includes".
- Includes = [filename:dirname(File)|Analysis#analysis.includes],
- Is = [{i,Dir} || Dir <- Includes],
- Options = dialyzer_utils:src_compiler_opts() ++ Is ++ Ds,
- case dialyzer_utils:get_abstract_code_from_src(File, Options) of
- {error, Reason} ->
- %% io:format("File=~p\n,Options=~p\n,Error=~p\n", [File,Options,Reason]),
- compile_error(Reason);
- {ok, AbstractCode} ->
- case dialyzer_utils:get_core_from_abstract_code(AbstractCode, Options) of
- error -> compile_error(["Could not get core erlang for "++File]);
- {ok, Core} ->
- case dialyzer_utils:get_record_and_type_info(AbstractCode) of
- {error, Reason} -> compile_error([Reason]);
- {ok, Records} ->
- Mod = cerl:concrete(cerl:module_name(Core)),
- case dialyzer_utils:get_spec_info(Mod, AbstractCode, Records) of
- {error, Reason} -> compile_error([Reason]);
- {ok, SpecInfo, CbInfo} ->
- ExpTypes = get_exported_types_from_core(Core),
- analyze_core_tree(Core, Records, SpecInfo, CbInfo,
- ExpTypes, Analysis, File)
- end
- end
- end
- end.
-
-analyze_core_tree(Core, Records, SpecInfo, CbInfo, ExpTypes, Analysis, File) ->
- Module = cerl:concrete(cerl:module_name(Core)),
- TmpTree = cerl:from_records(Core),
- CS1 = Analysis#analysis.codeserver,
- NextLabel = dialyzer_codeserver:get_next_core_label(CS1),
- {Tree, NewLabel} = cerl_trees:label(TmpTree, NextLabel),
- CS2 = dialyzer_codeserver:insert(Module, Tree, CS1),
- CS3 = dialyzer_codeserver:set_next_core_label(NewLabel, CS2),
- CS4 = dialyzer_codeserver:store_temp_records(Module, Records, CS3),
- CS5 =
- case Analysis#analysis.no_spec of
- true -> CS4;
- false ->
- dialyzer_codeserver:store_temp_contracts(Module, SpecInfo, CbInfo, CS4)
- end,
- OldExpTypes = dialyzer_codeserver:get_temp_exported_types(CS5),
- MergedExpTypes = sets:union(ExpTypes, OldExpTypes),
- CS6 = dialyzer_codeserver:insert_temp_exported_types(MergedExpTypes, CS5),
- Ex_Funcs = [{0,F,A} || {_,_,{F,A}} <- cerl:module_exports(Tree)],
- CG = Analysis#analysis.callgraph,
- {V, E} = dialyzer_callgraph:scan_core_tree(Tree, CG),
- dialyzer_callgraph:add_edges(E, V, CG),
- Fun = fun analyze_one_function/2,
- All_Defs = cerl:module_defs(Tree),
- Acc = lists:foldl(Fun, #tmpAcc{file = File, module = Module}, All_Defs),
- Exported_FuncMap = map__insert({File, Ex_Funcs}, Analysis#analysis.ex_func),
- %% we must sort all functions in the file which
- %% originate from this file by *numerical order* of lineNo
- Sorted_Functions = lists:keysort(1, Acc#tmpAcc.funcAcc),
- FuncMap = map__insert({File, Sorted_Functions}, Analysis#analysis.func),
- %% we do not need to sort functions which are imported from included files
- IncFuncMap = map__insert({File, Acc#tmpAcc.incFuncAcc},
- Analysis#analysis.inc_func),
- FMs = Analysis#analysis.fms ++ [{File, Module}],
- RecordMap = map__insert({File, Records}, Analysis#analysis.record),
- Analysis#analysis{fms = FMs,
- callgraph = CG,
- codeserver = CS6,
- ex_func = Exported_FuncMap,
- inc_func = IncFuncMap,
- record = RecordMap,
- func = FuncMap}.
-
-analyze_one_function({Var, FunBody} = Function, Acc) ->
- F = cerl:fname_id(Var),
- A = cerl:fname_arity(Var),
- TmpDialyzerObj = {{Acc#tmpAcc.module, F, A}, Function},
- NewDialyzerObj = Acc#tmpAcc.dialyzerObj ++ [TmpDialyzerObj],
- Anno = cerl:get_ann(FunBody),
- LineNo = get_line(Anno),
- FileName = get_file(Anno),
- BaseName = filename:basename(FileName),
- FuncInfo = {LineNo, F, A},
- OriginalName = Acc#tmpAcc.file,
- {FuncAcc, IncFuncAcc} =
- case (FileName =:= OriginalName) orelse (BaseName =:= OriginalName) of
- true -> %% Coming from original file
- %% io:format("Added function ~p\n", [{LineNo, F, A}]),
- {Acc#tmpAcc.funcAcc ++ [FuncInfo], Acc#tmpAcc.incFuncAcc};
- false ->
- %% Coming from other sourses, including:
- %% -- .yrl (yecc-generated file)
- %% -- yeccpre.hrl (yecc-generated file)
- %% -- other cases
- {Acc#tmpAcc.funcAcc, Acc#tmpAcc.incFuncAcc ++ [{FileName, FuncInfo}]}
- end,
- Acc#tmpAcc{funcAcc = FuncAcc,
- incFuncAcc = IncFuncAcc,
- dialyzerObj = NewDialyzerObj}.
-
-get_line([Line|_]) when is_integer(Line) -> Line;
-get_line([_|T]) -> get_line(T);
-get_line([]) -> none.
-
-get_file([{file,File}|_]) -> File;
-get_file([_|T]) -> get_file(T);
-get_file([]) -> "no_file". % should not happen
-
--spec get_dialyzer_plt(analysis()) -> plt().
-
-get_dialyzer_plt(#analysis{plt = PltFile0}) ->
- PltFile =
- case PltFile0 =:= none of
- true -> dialyzer_plt:get_default_plt();
- false -> PltFile0
- end,
- dialyzer_plt:from_file(PltFile).
-
-%% Exported Types
-
-get_exported_types_from_core(Core) ->
- Attrs = cerl:module_attrs(Core),
- ExpTypes1 = [cerl:concrete(L2) || {L1, L2} <- Attrs,
- cerl:is_literal(L1),
- cerl:is_literal(L2),
- cerl:concrete(L1) =:= 'export_type'],
- ExpTypes2 = lists:flatten(ExpTypes1),
- M = cerl:atom_val(cerl:module_name(Core)),
- sets:from_list([{M, F, A} || {F, A} <- ExpTypes2]).
-
-%%--------------------------------------------------------------------
-%% Utilities for error reporting.
-%%--------------------------------------------------------------------
-
--spec fatal_error(string()) -> no_return().
-
-fatal_error(Slogan) ->
- msg(io_lib:format("typer: ~s\n", [Slogan])),
- erlang:halt(1).
-
--spec mode_error(mode(), mode()) -> no_return().
-
-mode_error(OldMode, NewMode) ->
- Msg = io_lib:format("Mode was previously set to '~s'; "
- "can not set it to '~s' now",
- [OldMode, NewMode]),
- fatal_error(Msg).
-
--spec compile_error([string()]) -> no_return().
-
-compile_error(Reason) ->
- JoinedString = lists:flatten([X ++ "\n" || X <- Reason]),
- Msg = "Analysis failed with error report:\n" ++ JoinedString,
- fatal_error(Msg).
-
--spec msg(string()) -> 'ok'.
-
-msg(Msg) ->
- io:format(standard_error, "~s", [Msg]).
-
-%%--------------------------------------------------------------------
-%% Version and help messages.
-%%--------------------------------------------------------------------
-
--spec version_message() -> no_return().
-
-version_message() ->
- io:format("TypEr version "++?VSN++"\n"),
- erlang:halt(0).
-
--spec help_message() -> no_return().
-
-help_message() ->
- S = <<" Usage: typer [--help] [--version] [--plt PLT] [--edoc]
- [--show | --show-exported | --annotate | --annotate-inc-files]
- [-Ddefine]* [-I include_dir]* [-pa dir]* [-pz dir]*
- [-T application]* [-r] file*
-
- Options:
- -r dir*
- search directories recursively for .erl files below them
- --show
- Prints type specifications for all functions on stdout.
- (this is the default behaviour; this option is not really needed)
- --show-exported (or --show_exported)
- Same as --show, but prints specifications for exported functions only
- Specs are displayed sorted alphabetically on the function's name
- --annotate
- Annotates the specified files with type specifications
- --annotate-inc-files
- Same as --annotate but annotates all -include() files as well as
- all .erl files (use this option with caution - has not been tested much)
- --edoc
- Prints type information as Edoc @spec comments, not as type specs
- --plt PLT
- Use the specified dialyzer PLT file rather than the default one
- -T file*
- The specified file(s) already contain type specifications and these
- are to be trusted in order to print specs for the rest of the files
- (Multiple files or dirs, separated by spaces, can be specified.)
- -Dname (or -Dname=value)
- pass the defined name(s) to TypEr
- (The syntax of defines is the same as that used by \"erlc\".)
- -I include_dir
- pass the include_dir to TypEr
- (The syntax of includes is the same as that used by \"erlc\".)
- -pa dir
- -pz dir
- Set code path options to TypEr
- (This is useful for files that use parse tranforms.)
- --version (or -v)
- prints the Typer version and exits
- --help (or -h)
- prints this message and exits
-
- Note:
- * denotes that multiple occurrences of these options are possible.
-">>,
- io:put_chars(S),
- erlang:halt(0).
-
-%%--------------------------------------------------------------------
-%% Handle messages.
-%%--------------------------------------------------------------------
-
-rcv_ext_types() ->
- Self = self(),
- Self ! {Self, done},
- rcv_ext_types(Self, []).
-
-rcv_ext_types(Self, ExtTypes) ->
- receive
- {Self, ext_types, ExtType} ->
- rcv_ext_types(Self, [ExtType|ExtTypes]);
- {Self, done} ->
- lists:usort(ExtTypes)
- end.
-
-%%--------------------------------------------------------------------
-%% A convenient abstraction of a Key-Value mapping data structure
-%% specialized for the uses in this module
-%%--------------------------------------------------------------------
-
--type map_dict() :: dict:dict().
-
--spec map__new() -> map_dict().
-map__new() ->
- dict:new().
-
--spec map__insert({term(), term()}, map_dict()) -> map_dict().
-map__insert(Object, Map) ->
- {Key, Value} = Object,
- dict:store(Key, Value, Map).
-
--spec map__lookup(term(), map_dict()) -> term().
-map__lookup(Key, Map) ->
- try dict:fetch(Key, Map) catch error:_ -> none end.
-
--spec map__from_list([{fa(), term()}]) -> map_dict().
-map__from_list(List) ->
- dict:from_list(List).
-
--spec map__remove(term(), map_dict()) -> map_dict().
-map__remove(Key, Dict) ->
- dict:erase(Key, Dict).
-
--spec map__fold(fun((term(), term(), term()) -> map_dict()), map_dict(), map_dict()) -> map_dict().
-map__fold(Fun, Acc0, Dict) ->
- dict:fold(Fun, Acc0, Dict).
diff --git a/lib/typer/test/Makefile b/lib/typer/test/Makefile
deleted file mode 100644
index fb5570d9f0..0000000000
--- a/lib/typer/test/Makefile
+++ /dev/null
@@ -1,65 +0,0 @@
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES= \
- typer_SUITE
-
-ERL_FILES= $(MODULES:%=%.erl)
-
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-INSTALL_PROGS= $(TARGET_FILES)
-
-EMAKEFILE=Emakefile
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/typer_test
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-ERL_MAKE_FLAGS +=
-ERL_COMPILE_FLAGS +=
-
-EBIN = .
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-make_emakefile:
- $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \
- > $(EMAKEFILE)
- $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' \
- >> $(EMAKEFILE)
-
-tests debug opt: make_emakefile
- erl $(ERL_MAKE_FLAGS) -make
-
-clean:
- rm -f $(EMAKEFILE)
- rm -f $(TARGET_FILES) $(GEN_FILES)
- rm -f core
-
-docs:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
-
-release_tests_spec: make_emakefile
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) typer.spec "$(RELSYSDIR)"
- chmod -R u+w "$(RELSYSDIR)"
-
-release_docs_spec:
diff --git a/lib/typer/test/typer.spec b/lib/typer/test/typer.spec
deleted file mode 100644
index 79f51b6781..0000000000
--- a/lib/typer/test/typer.spec
+++ /dev/null
@@ -1 +0,0 @@
-{suites,"../typer_test",all}.
diff --git a/lib/typer/test/typer_SUITE.erl b/lib/typer/test/typer_SUITE.erl
deleted file mode 100644
index 25f0229640..0000000000
--- a/lib/typer/test/typer_SUITE.erl
+++ /dev/null
@@ -1,57 +0,0 @@
-%% ``Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-%% AB. All Rights Reserved.''
-%%
--module(typer_SUITE).
-
--compile([export_all]).
--include_lib("common_test/include/ct.hrl").
-
-suite() ->
- [{ct_hooks, [ts_install_cth]}].
-
-all() ->
- case application:ensure_all_started(typer) of
- {ok, Apps} ->
- [application:stop(App) || App <- lists:reverse(Apps)],
- [app, appup];
- _ ->
- [appup]
- end.
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-app() ->
- [{doc, "Test that the typer app file is ok"}].
-app(Config) when is_list(Config) ->
- ok = ?t:app_test(typer).
-
-appup() ->
- [{doc, "Test that the typer appup file is ok"}].
-appup(Config) when is_list(Config) ->
- ok = ?t:appup_test(typer).
diff --git a/lib/typer/vsn.mk b/lib/typer/vsn.mk
deleted file mode 100644
index ed12e067c1..0000000000
--- a/lib/typer/vsn.mk
+++ /dev/null
@@ -1 +0,0 @@
-TYPER_VSN = 0.9.11
diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml
index 12e64537ed..652560f60c 100644
--- a/lib/xmerl/doc/src/notes.xml
+++ b/lib/xmerl/doc/src/notes.xml
@@ -32,6 +32,61 @@
<p>This document describes the changes made to the Xmerl application.</p>
+<section><title>Xmerl 1.3.13</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The namespace_conformant option in xmerl_scan did not
+ work when parsing documents without explicit XML
+ namespace declaration.</p>
+ <p>
+ Own Id: OTP-14139</p>
+ </item>
+ <item>
+ <p> Fix a "well-formedness" bug in the XML Sax parser so
+ it returns an error if there are something more in the
+ file after the matching document. If one using the
+ xmerl_sax_parser:stream() a rest is allowed which then
+ can be sent to a new call of xmerl_sax_parser:stream() to
+ parse next document. </p> <p> This is done to be
+ compliant with XML conformance tests. </p>
+ <p>
+ Own Id: OTP-14211</p>
+ </item>
+ <item>
+ <p> Fixed compiler and dialyzer warnings in the XML SAX
+ parser. </p>
+ <p>
+ Own Id: OTP-14212</p>
+ </item>
+ <item>
+ <p> Change how to interpret end of document in the XML
+ SAX parser to comply with Tim Brays comment on the
+ standard. This makes it possible to handle more than one
+ doc on a stream, the standard makes it impossible to know
+ when the document is ended without waiting for the next
+ document (and not always even that). </p> <p> Tim Brays
+ comment: </p> <p> Trailing "Misc"<br/> The fact that
+ you're allowed some trailing junk after the root element,
+ I decided (but unfortunately too late) is a real design
+ error in XML. If I'm writing a network client, I'm
+ probably going to close the link as soon as a I see the
+ root element end-tag, and not depend on the other end
+ closing it down properly.<br/> Furthermore, if I want to
+ send a succession of XML documents over a network link,
+ if I find a processing instruction after a root element,
+ is it a trailer on the previous document, or part of the
+ prolog of the next? </p>
+ <p>
+ Own Id: OTP-14213</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Xmerl 1.3.12</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk
index 95adaa5bb0..1515a4e37d 100644
--- a/lib/xmerl/vsn.mk
+++ b/lib/xmerl/vsn.mk
@@ -1 +1 @@
-XMERL_VSN = 1.3.12
+XMERL_VSN = 1.3.13