Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make options in the -compile attribute take precedence #8093

Merged
merged 1 commit into from
Feb 9, 2024

Conversation

bjorng
Copy link
Contributor

@bjorng bjorng commented Feb 7, 2024

Change the compiler option processing order so that options given in the compile() attribute takes precedence over options given to the compiler, which in turn takes precedence over options given in the environment.

This order makes most sense, as each module might need customized options.

Fixes #6979

@bjorng bjorng added the team:VM Assigned to OTP team VM label Feb 7, 2024
@bjorng bjorng self-assigned this Feb 7, 2024
Copy link
Contributor

github-actions bot commented Feb 7, 2024

CT Test Results

    2 files    324 suites   8m 59s ⏱️
  804 tests   802 ✅ 2 💤 0 ❌
5 350 runs  5 348 ✅ 2 💤 0 ❌

Results for commit 06d0e7c.

♻️ This comment has been updated with latest results.

To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass.

See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally.

Artifacts

// Erlang/OTP Github Action Bot

@bjorng bjorng marked this pull request as draft February 7, 2024 09:17
@michalmuskala
Copy link
Contributor

Are we sure all the passes in the compiler use the "last option wins" approach, so that the documentation, which option takes precedence is correct? It's definitely true of erl_lint, but I haven't looked at other passes

@bjorng
Copy link
Contributor Author

bjorng commented Feb 7, 2024

Are we sure all the passes in the compiler use the "last option wins" approach, so that the documentation, which option takes precedence is correct?

No, other passes generally take the first option. However, the other options generally don't come in pairs (one to enable and one to disable a feature), so the order should not matter. I will take another look to see whether there any other option where the order would matter.

@bjorng bjorng marked this pull request as ready for review February 7, 2024 11:48
@bjorng bjorng added the testing currently being tested, tag is used by OTP internal CI label Feb 7, 2024
Change the compiler option processing order so that options given
in the `compile()` attribute takes precedence over options given
to the compiler, which in turn takes precedence over options given
in the environment.

This order makes most sense, as each module might need customized
options.

Fixes erlang#6979
@bjorng bjorng force-pushed the bjorn/compiler/option-order/OTP-18968 branch from cd7d88d to 06d0e7c Compare February 7, 2024 12:10
@michalmuskala
Copy link
Contributor

If that's the case, I wonder if it would make sense to instead change the implementation in erl_lint to take the first option into account, rather than last - it should actually be more efficient too.

@bjorng bjorng force-pushed the bjorn/compiler/option-order/OTP-18968 branch from 06d0e7c to 7a8fa4d Compare February 9, 2024 05:56
@bjorng bjorng merged commit 940fb6a into erlang:master Feb 9, 2024
3 checks passed
@bjorng bjorng deleted the bjorn/compiler/option-order/OTP-18968 branch February 9, 2024 05:56
@ilya-klyuchnikov
Copy link
Contributor

ilya-klyuchnikov commented Feb 9, 2024

Unfortunately, this change doesn't work for the particular combination

  • command line option: +warn_missing_spec
  • module option: -compile(nowarn_missing_spec).

(So, it doesn't fix #6979)

The PR changes the phase compile_directives and this phase is executed AFTER lint_module (erl_lint) phase - see

standard_passes() ->
[?pass(transform_module),
{iff,makedep_side_effect,?pass(makedep_and_output)},
{iff,makedep,[
?pass(makedep),
{unless,binary,?pass(makedep_output)}
]},
{iff,makedep,done},
{iff,'dpp',{listing,"pp"}},
?pass(lint_module),
{unless,no_docs,?pass(beam_docs)},
?pass(remove_doc_attributes),
{iff,'P',{src_listing,"P"}},
{iff,'to_pp',{done,"P"}},
{iff,'dabstr',{listing,"abstr"}}
| abstr_passes(verified_abstr)].
abstr_passes(AbstrStatus) ->
case AbstrStatus of
non_verified_abstr -> [{unless, no_lint, ?pass(lint_module)},
{unless,no_docs,?pass(beam_docs)},
?pass(remove_doc_attributes)];
verified_abstr -> []
end ++
[
%% Add all -compile() directives to #compile.options
?pass(compile_directives),
{delay,[{iff,debug_info,?pass(save_abstract_code)}]},
{iff,line_coverage,{pass,sys_coverage}},
?pass(expand_records),
{iff,'dexp',{listing,"expand"}},
{iff,'E',?pass(legalize_vars)},
{iff,'E',{src_listing,"E"}},
{iff,'to_exp',{done,"E"}},
%% Conversion to Core Erlang.
?pass(core),
{iff,'dcore',{listing,"core"}},
{iff,'to_core0',{done,"core"}}
| core_passes(verified_core)].

Additionally, erl_lint itself reads options from the -compile attribute and puts them in front (of current options):

module(Forms, FileName, Opts0) ->
%% FIXME Hmm, this is not coherent with the semantics of features
%% We want the options given on the command line to take
%% precedence over options in the module.
Opts = compiler_options(Forms) ++ Opts0,
St = forms(Forms, start(FileName, Opts)),
return_status(St).
compiler_options(Forms) ->
lists:flatten([C || {attribute,_,compile,C} <- Forms]).

And lastly, - whether the check is enabled is configured through bool_option :

{missing_spec,
bool_option(warn_missing_spec, nowarn_missing_spec,
false, Opts)},

And since bool_option is encoded using foldl - the last warn_missing_spec wins anyway:

bool_option(On, Off, Default, Opts) ->
foldl(fun (Opt, _Def) when Opt =:= On -> true;
(Opt, _Def) when Opt =:= Off -> false;
(_Opt, Def) -> Def
end, Default, Opts).

bjorng added a commit that referenced this pull request Feb 12, 2024
…der/OTP-18968"

This reverts commit 940fb6a, reversing
changes made to 78ebd83.
@bjorng
Copy link
Contributor Author

bjorng commented Feb 12, 2024

@ilya-klyuchnikov Thanks! I have reverted this PR for now. The plan is to implement it correctly (with test cases) in a new PR and to include it in RC2.

bjorng added a commit to bjorng/otp that referenced this pull request Mar 4, 2024
Change the compiler option processing order so that options given
in the `compile()` attribute takes precedence over options given
to the compiler, which in turn takes precedence over options given
in the environment.

This order makes most sense, as each module might need customized
options.

While at it, remove the undocumented `strict_record_updates` /
`no_strict_record_updates` options. Their naming no longer make any
sense, because record updates are always strict (that is, the source
record must have the correct tag and size). Incorporate the
behavior of `strict_record_updates` to update the record by matching
and building a new tuple into the `dialyzer` option. When dialyzer
is not used, records are updated using `setelement/3`, which is more
efficient in the JIT.

(This is the second attempt to fix erlang#6979, as erlang#8093 did not really
work.)
bjorng added a commit to bjorng/otp that referenced this pull request Mar 4, 2024
Change the compiler option processing order so that options given
in the `compile()` attribute takes precedence over options given
to the compiler, which in turn takes precedence over options given
in the environment.

This order makes most sense, as each module might need customized
options.

While at it, remove the undocumented `strict_record_updates` /
`no_strict_record_updates` options. Their naming no longer make any
sense, because record updates are always strict (that is, the source
record must have the correct tag and size). Incorporate the
behavior of `strict_record_updates` to update the record by matching
and building a new tuple into the `dialyzer` option. When dialyzer
is not used, records are updated using `setelement/3`, which is more
efficient in the JIT.

(This is the second attempt to fix erlang#6979, as erlang#8093 did not really
work.)
bjorng added a commit to bjorng/otp that referenced this pull request Mar 4, 2024
Change the compiler option processing order so that options given
in the `compile()` attribute takes precedence over options given
to the compiler, which in turn takes precedence over options given
in the environment.

This order makes most sense, as each module might need customized
options.

While at it, remove the undocumented `strict_record_updates` /
`no_strict_record_updates` options. Their naming no longer make any
sense, because record updates are always strict (that is, the source
record must have the correct tag and size). Incorporate the
behavior of `strict_record_updates` to update the record by matching
and building a new tuple into the `dialyzer` option. When dialyzer
is not used, records are updated using `setelement/3`, which is more
efficient in the JIT.

(This is the second attempt to fix erlang#6979, as erlang#8093 did not really
work.)
bjorng added a commit to bjorng/otp that referenced this pull request Mar 4, 2024
Change the compiler option processing order so that options given
in the `compile()` attribute takes precedence over options given
to the compiler, which in turn takes precedence over options given
in the environment.

This order makes most sense, as each module might need customized
options.

While at it, remove the undocumented `strict_record_updates` /
`no_strict_record_updates` options. Their naming no longer make any
sense, because record updates are always strict (that is, the source
record must have the correct tag and size). Incorporate the
behavior of `strict_record_updates` to update the record by matching
and building a new tuple into the `dialyzer` option. When dialyzer
is not used, records are updated using `setelement/3`, which is more
efficient in the JIT.

(This is the second attempt to fix erlang#6979, as erlang#8093 did not really
work.)
bjorng added a commit to bjorng/otp that referenced this pull request Mar 4, 2024
Change the compiler option processing order so that options given
in the `compile()` attribute take precedence over options given
to the compiler, which in turn take precedence over options given
in the environment.

This order makes most sense, as each module might need customized
options.

While at it, remove the undocumented `strict_record_updates` /
`no_strict_record_updates` options. Their naming no longer make any
sense, because record updates are always strict (that is, the source
record must have the correct tag and size). Incorporate the
behavior of `strict_record_updates` to update the record by matching
and building a new tuple into the `dialyzer` option. When dialyzer
is not used, records are updated using `setelement/3`, which is more
efficient in the JIT.

(This is the second attempt to fix erlang#6979, as erlang#8093 did not really
work.)
bjorng added a commit to bjorng/otp that referenced this pull request Mar 5, 2024
Change the compiler option processing order so that options given
in the `compile()` attribute take precedence over options given
to the compiler, which in turn take precedence over options given
in the environment.

This order makes most sense, as each module might need customized
options.

While at it, remove the undocumented `strict_record_updates` /
`no_strict_record_updates` options. Their naming no longer make any
sense, because record updates are always strict (that is, the source
record must have the correct tag and size). Incorporate the
behavior of `strict_record_updates` to update the record by matching
and building a new tuple into the `dialyzer` option. When dialyzer
is not used, records are updated using `setelement/3`, which is more
efficient in the JIT.

(This is the second attempt to fix erlang#6979, as erlang#8093 did not really
work.)
bjorng added a commit to bjorng/otp that referenced this pull request Mar 6, 2024
Change the compiler option processing order so that options given
in the `compile()` attribute take precedence over options given
to the compiler, which in turn take precedence over options given
in the environment.

This order makes most sense, as each module might need customized
options.

While at it, remove the undocumented `strict_record_updates` /
`no_strict_record_updates` options. Their naming no longer make any
sense, because record updates are always strict (that is, the source
record must have the correct tag and size). Incorporate the
behavior of `strict_record_updates` to update the record by matching
and building a new tuple into the `dialyzer` option. When dialyzer
is not used, records are updated using `setelement/3`, which is more
efficient in the JIT.

(This is the second attempt to fix erlang#6979, as erlang#8093 did not really
work.)
bjorng added a commit to bjorng/otp that referenced this pull request Mar 6, 2024
Change the compiler option processing order so that options given
in the `compile()` attribute take precedence over options given
to the compiler, which in turn take precedence over options given
in the environment.

This order makes most sense, as each module might need customized
options.

While at it, remove the undocumented `strict_record_updates` /
`no_strict_record_updates` options. Their naming no longer make any
sense, because record updates are always strict (that is, the source
record must have the correct tag and size). Incorporate the
behavior of `strict_record_updates` to update the record by matching
and building a new tuple into the `dialyzer` option. When dialyzer
is not used, records are updated using `setelement/3`, which is more
efficient in the JIT.

(This is the second attempt to fix erlang#6979, as erlang#8093 did not really
work.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
team:VM Assigned to OTP team VM testing currently being tested, tag is used by OTP internal CI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Compiler directives via -compile do not take precedence.
3 participants