mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 05:12:33 +00:00
Generate errors for marking procedures with clauses as external.
compiler/add_pragma.m:
When processing a pragma that marks a predicate or function
as external, generate an error message if that predicate or function
has any clauses.
library/profiling_builtin.m:
The predicates that the deep profiler calls at various points
in the code of profiled procedures are marked as external;
their actual implementation is in a script-generated C source file
in the runtime directory. Delete their clauses, since the compiler
would now generate error messages for their external pragmas
in the presence of those clauses.
We don't need those clauses at all, since those predicates should have
no calls to them at all in non-deep-profiling grades. (They are not
documented, and any existing calls to them would have immediately
aborted the program.)
tests/invalid/external2.{m,err_exp}:
A test case for the new functionality.
tests/invalid/Mmakefile:
Enable the new test.
This commit is contained in:
@@ -202,7 +202,8 @@ add_pass_2_pragma(SectionItem, !ModuleInfo, !Specs) :-
|
||||
),
|
||||
(
|
||||
PredIds = [_ | _],
|
||||
list.foldl(mark_pred_as_external, PredIds, !ModuleInfo)
|
||||
list.foldl2(mark_pred_as_external(Context), PredIds,
|
||||
!ModuleInfo, !Specs)
|
||||
;
|
||||
PredIds = [],
|
||||
module_info_get_preds(!.ModuleInfo, PredTable0),
|
||||
@@ -377,15 +378,34 @@ add_pass_2_pragma(SectionItem, !ModuleInfo, !Specs) :-
|
||||
|
||||
%-----------------------------------------------------------------------------%
|
||||
|
||||
:- pred mark_pred_as_external(pred_id::in,
|
||||
module_info::in, module_info::out) is det.
|
||||
:- pred mark_pred_as_external(prog_context::in, pred_id::in,
|
||||
module_info::in, module_info::out,
|
||||
list(error_spec)::in, list(error_spec)::out) is det.
|
||||
|
||||
mark_pred_as_external(PredId, !ModuleInfo) :-
|
||||
mark_pred_as_external(Context, PredId, !ModuleInfo, !Specs) :-
|
||||
module_info_get_preds(!.ModuleInfo, PredTable0),
|
||||
map.lookup(PredTable0, PredId, PredInfo0),
|
||||
pred_info_mark_as_external(PredInfo0, PredInfo),
|
||||
map.det_update(PredId, PredInfo, PredTable0, PredTable),
|
||||
module_info_set_preds(PredTable, !ModuleInfo).
|
||||
pred_info_get_clauses_info(PredInfo0, ClausesInfo0),
|
||||
clauses_info_get_clauses_rep(ClausesInfo0, ClausesRep0, _ItemNumbers),
|
||||
IsEmpty = clause_list_is_empty(ClausesRep0),
|
||||
(
|
||||
IsEmpty = yes,
|
||||
pred_info_mark_as_external(PredInfo0, PredInfo),
|
||||
map.det_update(PredId, PredInfo, PredTable0, PredTable),
|
||||
module_info_set_preds(PredTable, !ModuleInfo)
|
||||
;
|
||||
IsEmpty = no,
|
||||
PredOrFunc = pred_info_is_pred_or_func(PredInfo0),
|
||||
pred_info_get_name(PredInfo0, PredName),
|
||||
Arity = pred_info_orig_arity(PredInfo0),
|
||||
SNA = sym_name_arity(unqualified(PredName), Arity),
|
||||
Pieces = [words("The"), p_or_f(PredOrFunc),
|
||||
unqual_sym_name_and_arity(SNA), words("has clauses,"),
|
||||
words("so it cannot be marked as external."), nl],
|
||||
Spec = simplest_spec(severity_error, phase_parse_tree_to_hlds,
|
||||
Context, Pieces),
|
||||
!:Specs = [Spec | !.Specs]
|
||||
).
|
||||
|
||||
%-----------------------------------------------------------------------------%
|
||||
|
||||
|
||||
@@ -633,63 +633,6 @@ prepare_for_tail_call(_) :-
|
||||
:- pragma external_pred(non_fail_port_code_ac/2).
|
||||
:- pragma external_pred(non_fail_port_code_sr/3).
|
||||
|
||||
det_call_port_code_ac(_, _, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("det_call_port_code_ac").
|
||||
det_call_port_code_sr(_, _, _, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("det_call_port_code_sr").
|
||||
det_exit_port_code_ac(_, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("det_exit_port_code_ac").
|
||||
det_exit_port_code_sr(_, _, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("det_exit_port_code_sr").
|
||||
semi_call_port_code_ac(_, _, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("semi_call_port_code_ac").
|
||||
semi_call_port_code_sr(_, _, _, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("semi_call_port_code_sr").
|
||||
semi_exit_port_code_ac(_, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("semi_exit_port_code_ac").
|
||||
semi_exit_port_code_sr(_, _, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("semi_exit_port_code_sr").
|
||||
semi_fail_port_code_ac(_, _) :-
|
||||
impure private_builtin.imp,
|
||||
semidet_succeed,
|
||||
private_builtin.sorry("semi_fail_port_code_ac").
|
||||
semi_fail_port_code_sr(_, _, _) :-
|
||||
impure private_builtin.imp,
|
||||
semidet_succeed,
|
||||
private_builtin.sorry("semi_fail_port_code_sr").
|
||||
non_call_port_code_ac(_, _, _, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("non_call_port_code_ac").
|
||||
non_call_port_code_sr(_, _, _, _, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("non_call_port_code_sr").
|
||||
non_exit_port_code_ac(_, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("non_exit_port_code_ac").
|
||||
non_exit_port_code_sr(_, _, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("non_exit_port_code_sr").
|
||||
non_redo_port_code_ac(_, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("non_redo_port_code_ac").
|
||||
non_redo_port_code_sr(_, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("non_redo_port_code_sr").
|
||||
non_fail_port_code_ac(_, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("non_fail_port_code_ac").
|
||||
non_fail_port_code_sr(_, _, _) :-
|
||||
impure private_builtin.imp,
|
||||
private_builtin.sorry("non_fail_port_code_sr").
|
||||
|
||||
%---------------------------------------------------------------------------%
|
||||
|
||||
:- pragma foreign_proc("C",
|
||||
|
||||
@@ -145,6 +145,7 @@ SINGLEMODULE= \
|
||||
ext_type \
|
||||
ext_type_bug \
|
||||
external \
|
||||
external2 \
|
||||
extra_info_prompt \
|
||||
field_syntax_error \
|
||||
foreign_enum_import \
|
||||
|
||||
4
tests/invalid/external2.err_exp
Normal file
4
tests/invalid/external2.err_exp
Normal file
@@ -0,0 +1,4 @@
|
||||
external2.m:019: The predicate `p'/2 has clauses, so it cannot be marked as
|
||||
external2.m:019: external.
|
||||
external2.m:020: The function `f'/2 has clauses, so it cannot be marked as
|
||||
external2.m:020: external.
|
||||
30
tests/invalid/external2.m
Normal file
30
tests/invalid/external2.m
Normal file
@@ -0,0 +1,30 @@
|
||||
%---------------------------------------------------------------------------%
|
||||
% vim: ts=4 sw=4 et ft=mercury
|
||||
%---------------------------------------------------------------------------%
|
||||
%
|
||||
% This module tests the error message for a predicate that has one or more
|
||||
% clauses despite being marked as texternal.
|
||||
%
|
||||
|
||||
:- module external2.
|
||||
|
||||
:- interface.
|
||||
|
||||
:- pred p(int::in, int::out) is semidet.
|
||||
|
||||
:- func f(int) = int.
|
||||
|
||||
:- implementation.
|
||||
|
||||
:- pragma external_pred(p/2).
|
||||
:- pragma external_func(f/1).
|
||||
|
||||
p(0, 42).
|
||||
p(1, 43).
|
||||
|
||||
f(A) = X :-
|
||||
( if p(A, B) then
|
||||
X = B
|
||||
else
|
||||
X = 0
|
||||
).
|
||||
Reference in New Issue
Block a user