[m-rev.] for review: warn about dead procedures

Fergus Henderson fjh at cs.mu.OZ.AU
Wed Jul 16 21:38:01 AEST 2003


After seeing some dead code in the diff that Ralph posted,
I decided to go ahead and implement a compiler warning for dead code.

This change is not quite right yet; it doesn't handle `pragma type_spec'
procedures properly yet, and it issues some spurious warnings for
procedures introduced when expanding lambda expressions in `.opt' files.

Another problem is that it doesn't handle `pragma foreign_proc' clauses
properly.  Not sure how to fix that one.

Because of these problems, it may be premature to review this.
But I have nevertheless included a log message and diff below,
in case someone is interested.

Here's a list of the warnings that it produces in the standard library.
I deleted the spurious ones for `pragma type_spec' and for lambda
expressions in .opt files.  Some of the remainder are due to `pragma
foreign_proc' problems, the others are genuine.

eqvclass.m:261: Warning: predicate `eqvclass.find_partition/3' mode 0 is never
eqvclass.m:261:   called.
exception.m:303: Warning:
exception.m:303:   predicate `exception.wrap_success_or_failure/2' mode 2 is
exception.m:303:   never called.
exception.m:304: Warning:
exception.m:304:   predicate `exception.wrap_success_or_failure/2' mode 3 is
exception.m:304:   never called.
exception.m:503: Warning: predicate `exception.catch_impl/3' mode 1 is never
exception.m:503:   called.
exception.m:505: Warning: predicate `exception.catch_impl/3' mode 3 is never
exception.m:505:   called.
exception.m:506: Warning: predicate `exception.catch_impl/3' mode 4 is never
exception.m:506:   called.
exception.m:507: Warning: predicate `exception.catch_impl/3' mode 5 is never
exception.m:507:   called.
exception.m:1205: Warning: predicate `exception.call_goal/2' mode 2 is never
exception.m:1205:   called.
exception.m:1211: Warning: predicate `exception.call_handler/3' mode 1 is never
exception.m:1211:   called.
exception.m:1212: Warning: predicate `exception.call_handler/3' mode 2 is never
exception.m:1212:   called.
integer.m:164: Warning: function `integer.highbitmask/0' mode 0 is never
integer.m:164:   called.
integer.m:631: Warning: function `integer.int_max/0' mode 0 is never called.
io.m:2180: Warning: predicate `io.buffer_to_string/2' mode 0 is never called.
io.m:2216: Warning: predicate `io.read_into_array/8' mode 0 is never called.
list.m:1012: Warning: predicate `list.qsort/3' mode 0 is never called.
list.m:1021: Warning: predicate `list.partition/4' mode 0 is never called.
relation.m:908: Warning: predicate `relation.tsort_2/6' mode 0 is never called.
relation.m:919: Warning: predicate `relation.tsort_3/6' mode 0 is never called.
rtti_implementation.m:1563: Warning:
rtti_implementation.m:1563:   predicate `rtti_implementation.type_variable_is_exist_quant/1' mode 0
rtti_implementation.m:1563:   is never called.
rtti_implementation.m:1569: Warning:
rtti_implementation.m:1569:   function `rtti_implementation.pseudotypeinfo_max_var/0' mode 0
rtti_implementation.m:1569:   is never called.
rtti_implementation.m:2151: Warning:
rtti_implementation.m:2151:   function `rtti_implementation.du_functor_arg_type_contains_var/1' mode 0
rtti_implementation.m:2151:   is never called.
rtti_implementation.m:2155: Warning:
rtti_implementation.m:2155:   function `rtti_implementation.du_functor_sectag_locn/1' mode 0
rtti_implementation.m:2155:   is never called.
rtti_implementation.m:2159: Warning:
rtti_implementation.m:2159:   function `rtti_implementation.du_functor_primary/1' mode 0
rtti_implementation.m:2159:   is never called.
rtti_implementation.m:2162: Warning:
rtti_implementation.m:2162:   function `rtti_implementation.du_functor_secondary/1' mode 0
rtti_implementation.m:2162:   is never called.
rtti_implementation.m:2165: Warning:
rtti_implementation.m:2165:   function `rtti_implementation.du_functor_ordinal/1' mode 0
rtti_implementation.m:2165:   is never called.
rtti_implementation.m:2194: Warning:
rtti_implementation.m:2194:   function `rtti_implementation.enum_functor_ordinal/1' mode 0
rtti_implementation.m:2194:   is never called.
rtti_implementation.m:2230: Warning:
rtti_implementation.m:2230:   function `rtti_implementation.unsafe_make_enum/1' mode 0
rtti_implementation.m:2230:   is never called.
set_bbbtree.m:960: Warning: predicate `set_bbbtree.build_node/4' mode 0 is
set_bbbtree.m:960:   never called.
set_bbbtree.m:982: Warning: predicate `set_bbbtree.single_rot_l/4' mode 0 is
set_bbbtree.m:982:   never called.
set_bbbtree.m:998: Warning: predicate `set_bbbtree.single_rot_r/4' mode 0 is
set_bbbtree.m:998:   never called.
set_bbbtree.m:1022: Warning: predicate `set_bbbtree.double_rot_l/4' mode 0 is
set_bbbtree.m:1022:   never called.
set_bbbtree.m:1046: Warning: predicate `set_bbbtree.double_rot_r/4' mode 0 is
set_bbbtree.m:1046:   never called.
string.m:583: Warning: predicate `string.to_int_list/2' mode 0 is never called.
string.m:987: Warning: predicate `string.to_char_list_2/3' mode 0 is never
string.m:987:   called.
string.m:1047: Warning: predicate `string.int_list_to_char_list/2' mode 0 is
string.m:1047:   never called.
string.m:1059: Warning: predicate `string.char_list_to_int_list/2' mode 0 is
string.m:1059:   never called.
string.m:1060: Warning: predicate `string.char_list_to_int_list/2' mode 1 is
string.m:1060:   never called.
string.m:1252: Warning: function `string.join_list_2/2' mode 0 is never called.
string.m:1321: Warning: predicate `string.sub_string_search_2/6' mode 0 is
string.m:1321:   never called.
string.m:2817: Warning: function `string.float_to_string_2/2' mode 0 is never
string.m:2817:   called.
string.m:2835: Warning: function `string.min_precision/0' mode 0 is never
string.m:2835:   called.
string.m:2840: Warning: function `string.max_precision/0' mode 0 is never
string.m:2840:   called.
string.m:2971: Warning: predicate `string.contains_char/4' mode 0 is never
string.m:2971:   called.
string.m:3257: Warning: predicate `string.length_2/3' mode 0 is never called.
string.m:3412: Warning: predicate `string.mercury_append/3' mode 0 is never
string.m:3412:   called.
string.m:3413: Warning: predicate `string.mercury_append/3' mode 1 is never
string.m:3413:   called.
string.m:3414: Warning: predicate `string.mercury_append/3' mode 2 is never
string.m:3414:   called.
string.m:3415: Warning: predicate `string.mercury_append/3' mode 3 is never
string.m:3415:   called.
string.m:3435: Warning: function `string.strchars/3' mode 0 is never called.
term.m:769: Warning: predicate `term.require_equal/2' mode 0 is never called.
term.m:823: Warning: predicate `term.contains_functor/3' mode 0 is never
term.m:823:   called.
term.m:838: Warning: predicate `term.subterm/2' mode 0 is never called.
term.m:839: Warning: predicate `term.subterm/2' mode 1 is never called.
tree234.m:835: Warning: predicate `tree234.insert2/4' mode 0 is never called.
tree234.m:930: Warning: predicate `tree234.insert3/4' mode 0 is never called.


Estimated hours taken: 5
Branches: main

Add a new warning option `--warn-dead-procs' that warns about procedures
which are never called.

doc/user_guide.texi:
	Document the new option.

compiler/options.m:
	Add the new option.

compiler/mercury_compile.m:
	If the new option is enabled, invoke dead_proc_elim
	to issue warnings for dead procedures.
	(The new pass occurs after type_ctor_info generation,
	but before higher-order specialization and inlining.)

compiler/dead_proc_elim.m:
	Add a new `dead_proc_pass' argument to the dead_proc_elim
	predicate, specifying whether it should issue warnings or
	just do the optimizations.  If this argument is warning_pass,
	issue warnings for dead procedures with import_status local,
	and don't eliminate opt_imported procedures.

compiler/magic.m:
	Pass the new argument to dead_proc_elim.

tests/warnings/Mmakefile:
tests/warnings/warn_dead_procs.m:
tests/warnings/warn_dead_procs.exp:
	A test case to test the new warning.

Workspace: /home/ceres/fjh/mercury
Index: compiler/dead_proc_elim.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/dead_proc_elim.m,v
retrieving revision 1.81
diff -u -d -r1.81 dead_proc_elim.m
--- compiler/dead_proc_elim.m	20 Jun 2003 12:45:42 -0000	1.81
+++ compiler/dead_proc_elim.m	16 Jul 2003 10:49:34 -0000
@@ -10,6 +10,8 @@
 % It also computes the usage counts that inlining.m uses for the
 % `--inline-single-use' option.
 %
+% It also issues warnings about unused procedures.
+%
 % Main author: zs.
 %
 %-----------------------------------------------------------------------------%
@@ -24,16 +26,27 @@
 
 :- import_module map, std_util, io.
 
-:- pred dead_proc_elim(module_info, module_info, io__state, io__state).
-:- mode dead_proc_elim(in, out, di, uo) is det.
+:- type dead_proc_pass
+	--->	warning_pass
+	;	final_optimization_pass
+	.
 
+	% Eliminate dead procedures.
+	% If the first argument is `warning_pass',
+	% also warn about any user-defined procedures that are dead.
+	% If the first argument is `final_optimization_pass',
+	% also eliminate any opt_imported procedures.
+:- pred dead_proc_elim(dead_proc_pass, module_info, module_info,
+		io__state, io__state).
+:- mode dead_proc_elim(in, in, out, di, uo) is det.
+
+	% Analyze which entities are needed, and for those entities
+	% which are needed, record how many times they are referenced
+	% (this information is used by our inlining heuristics).
 :- pred dead_proc_elim__analyze(module_info, needed_map).
 :- mode dead_proc_elim__analyze(in, out) is det.
 
-:- pred dead_proc_elim__eliminate(module_info, needed_map, module_info,
-	io__state, io__state).
-:- mode dead_proc_elim__eliminate(in, in, out, di, uo) is det.
-
+	% Optimize away any dead predicates.
 	% This is performed immediately after make_hlds.m to avoid doing
 	% semantic checking and optimization on predicates from `.opt' 
 	% files which are not used in the current module. This assumes that
@@ -56,6 +69,7 @@
 :- import_module hlds__hlds_data.
 :- import_module hlds__hlds_goal.
 :- import_module hlds__passes_aux.
+:- import_module hlds__error_util.
 :- import_module libs__globals.
 :- import_module libs__options.
 :- import_module ll_backend__llds.
@@ -90,9 +104,9 @@
 :- type entity_queue	==	queue(entity).
 :- type examined_set	==	set(entity).
 
-dead_proc_elim(ModuleInfo0, ModuleInfo, State0, State) :-
+dead_proc_elim(Pass, ModuleInfo0, ModuleInfo, State0, State) :-
 	dead_proc_elim__analyze(ModuleInfo0, Needed),
-	dead_proc_elim__eliminate(ModuleInfo0, Needed, ModuleInfo,
+	dead_proc_elim__eliminate(Pass, ModuleInfo0, Needed, ModuleInfo,
 		State0, State).
 
 %-----------------------------------------------------------------------------%
@@ -527,14 +541,21 @@
 			bool		% has anything changed
 		).
 			
-dead_proc_elim__eliminate(ModuleInfo0, Needed0, ModuleInfo, State0, State) :-
+	% Given the information about which entities are needed,
+	% eliminate procedures which are not needed.
+:- pred dead_proc_elim__eliminate(dead_proc_pass, module_info, needed_map,
+		module_info, io__state, io__state).
+:- mode dead_proc_elim__eliminate(in, in, in, out, di, uo) is det.
+
+dead_proc_elim__eliminate(Pass, ModuleInfo0, Needed0, ModuleInfo,
+		State0, State) :-
 	module_info_predids(ModuleInfo0, PredIds),
 	module_info_preds(ModuleInfo0, PredTable0),
 
 	Changed0 = no,
 	ElimInfo0 = elimination_info(Needed0, ModuleInfo0,
 			PredTable0, Changed0),
-	list__foldl2(dead_proc_elim__eliminate_pred, PredIds, ElimInfo0, 
+	list__foldl2(dead_proc_elim__eliminate_pred(Pass), PredIds, ElimInfo0, 
 		ElimInfo, State0, State),
 	ElimInfo = elimination_info(Needed, ModuleInfo1, PredTable, Changed),
 
@@ -557,11 +578,12 @@
 
 		% eliminate any unused procedures for this pred
 
-:- pred dead_proc_elim__eliminate_pred(pred_id, elim_info, elim_info,
-	io__state, io__state).
-:- mode dead_proc_elim__eliminate_pred(in, in, out, di, uo) is det.
+:- pred dead_proc_elim__eliminate_pred(dead_proc_pass, pred_id,
+	elim_info, elim_info, io__state, io__state).
+:- mode dead_proc_elim__eliminate_pred(in, in, in, out, di, uo) is det.
 
-dead_proc_elim__eliminate_pred(PredId, ElimInfo0, ElimInfo, State0, State) :-
+dead_proc_elim__eliminate_pred(Pass, PredId, ElimInfo0, ElimInfo,
+		State0, State) :-
 	ElimInfo0 = elimination_info(Needed, ModuleInfo, PredTable0, Changed0),
 	map__lookup(PredTable0, PredId, PredInfo0),
 	pred_info_import_status(PredInfo0, Status),
@@ -570,25 +592,34 @@
 		% If yes, find out also whether any of its procedures
 		% must be kept.
 		( Status = local,
-			Keep = no
+			Keep = no,
+			WarnForThisProc =
+			    (is_unify_or_compare_pred(PredInfo0) -> no ; yes)
 		; Status = pseudo_imported,
-			Keep = no
+			Keep = no,
+			WarnForThisProc = no
 		; Status = pseudo_exported,
 			hlds_pred__in_in_unification_proc_id(InitProcId),
-			Keep = yes(InitProcId)
+			Keep = yes(InitProcId),
+			WarnForThisProc = no
 		)
 	->
 		pred_info_procids(PredInfo0, ProcIds),
 		pred_info_procedures(PredInfo0, ProcTable0),
-		list__foldl2(dead_proc_elim__eliminate_proc(PredId, Keep, 
-			ElimInfo0),
+		list__foldl2(dead_proc_elim__eliminate_proc(Pass, PredId,
+			Keep, WarnForThisProc, ElimInfo0),
 			ProcIds, Changed0 - ProcTable0, Changed - ProcTable,
 			State0, State),
 		pred_info_set_procedures(PredInfo0, ProcTable, PredInfo),
 		map__det_update(PredTable0, PredId, PredInfo, PredTable)
 	;
 		% Don't generate code in the current module for
-		% unoptimized opt_imported preds
+		% unoptimized opt_imported preds (that is, for
+		% opt_imported preds which we have not by this point
+		% managed to inline or specialize; this code should be
+		% called with `Pass = final_optimization_pass'
+		% only after inlining and specialization is complete).
+		Pass = final_optimization_pass,
 		Status = opt_imported
 	->
 		Changed = yes,
@@ -630,13 +661,15 @@
 
 		% eliminate a procedure, if unused
 
-:- pred dead_proc_elim__eliminate_proc(pred_id, maybe(proc_id), elim_info,
-	proc_id, pair(bool, proc_table), pair(bool, proc_table),
+:- pred dead_proc_elim__eliminate_proc(dead_proc_pass, pred_id, maybe(proc_id),
+	bool, elim_info, proc_id,
+	pair(bool, proc_table), pair(bool, proc_table),
 	io__state, io__state).
-:- mode dead_proc_elim__eliminate_proc(in, in, in, in, in, out, di, uo) is det.
+:- mode dead_proc_elim__eliminate_proc(in, in, in, in, in, in, in, out, di, uo)
+	is det.
 
-dead_proc_elim__eliminate_proc(PredId, Keep, ElimInfo, ProcId, 
-		Changed0 - ProcTable0, Changed - ProcTable) -->
+dead_proc_elim__eliminate_proc(Pass, PredId, Keep, WarnForThisProc, ElimInfo,
+		ProcId, Changed0 - ProcTable0, Changed - ProcTable) -->
 	{ ElimInfo = elimination_info(Needed, ModuleInfo, _PredTable, _) },
 	(
 		% Keep the procedure if it is in the needed map
@@ -657,8 +690,32 @@
 		;
 			[]
 		),
+		(
+			{ Pass = warning_pass },
+			{ WarnForThisProc = yes }
+			% we don't need to check the warn_dead_procs option
+			% since that is already checked by mercury_compile.m
+			% when deciding whether to invoke this warning_pass
+		->
+			{ proc_info_context(ProcTable0 ^ det_elem(ProcId),
+				Context) },
+			warn_dead_proc(PredId, ProcId, Context, ModuleInfo)
+		;
+			[]
+		),
 		{ map__delete(ProcTable0, ProcId, ProcTable) }
 	).
+
+:- pred warn_dead_proc(pred_id, proc_id, prog_context, module_info,
+		io__state, io__state).
+:- mode warn_dead_proc(in, in, in, in, di, uo) is det.
+
+warn_dead_proc(PredId, ProcId, Context, ModuleInfo, !IO) :-
+	error_util__describe_one_proc_name(ModuleInfo, proc(PredId, ProcId), 
+		ProcName),
+	Components = [words("Warning:"), fixed(ProcName),
+			words("is never called.")],
+	error_util__report_warning(Context, 0, Components, !IO).
 
 :- pred dead_proc_elim__eliminate_base_gen_infos(list(type_ctor_gen_info),
 	needed_map, list(type_ctor_gen_info)).
Index: compiler/magic.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/magic.m,v
retrieving revision 1.36
diff -u -d -r1.36 magic.m
--- compiler/magic.m	26 May 2003 08:59:58 -0000	1.36
+++ compiler/magic.m	16 Jul 2003 07:01:47 -0000
@@ -221,7 +221,7 @@
 	%
 	% No optimizations which could optimize away calls to Aditi
 	% procedures (e.g. simplify.m) should be run after this is done.
-	dead_proc_elim(ModuleInfo1, ModuleInfo2),
+	dead_proc_elim(final_optimization_pass, ModuleInfo1, ModuleInfo2),
 
 	{ module_info_ensure_aditi_dependency_info(ModuleInfo2, ModuleInfo3) },
 	{ module_info_aditi_dependency_ordering(ModuleInfo3, Ordering) },
Index: compiler/mercury_compile.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mercury_compile.m,v
retrieving revision 1.287
diff -u -d -r1.287 mercury_compile.m
--- compiler/mercury_compile.m	26 May 2003 09:00:00 -0000	1.287
+++ compiler/mercury_compile.m	16 Jul 2003 10:48:44 -0000
@@ -2100,8 +2100,16 @@
 	mercury_compile__maybe_termination(HLDS27, Verbose, Stats, HLDS28),
 	mercury_compile__maybe_dump_hlds(HLDS28, "28", "termination"),
 
-	mercury_compile__maybe_type_ctor_infos(HLDS28, Verbose, Stats, HLDS30),
-	mercury_compile__maybe_dump_hlds(HLDS30, "30", "type_ctor_infos"),
+	mercury_compile__maybe_type_ctor_infos(HLDS28, Verbose, Stats, HLDS29),
+	mercury_compile__maybe_dump_hlds(HLDS29, "29", "type_ctor_infos"),
+
+	% warn_dead_procs must come after type_ctor_infos, so that it
+	% handles unification & comparison procedures correctly,
+	% but it must also come before optimizations such as higher-order
+	% specialization and inlining, which can make the original code
+	% for a procedure dead by inlining/specializing all uses of it.
+	mercury_compile__maybe_warn_dead_procs(HLDS29, Verbose, Stats, HLDS30),
+	mercury_compile__maybe_dump_hlds(HLDS30, "30", "warn_dead_procs"),
 
 	mercury_compile__maybe_bytecodes(HLDS30, ModuleName, Verbose, Stats),
 
@@ -2148,10 +2156,13 @@
 
 	% Magic sets should be the last thing done to Aditi procedures
 	% before RL code generation, and must come immediately after DNF.
+	% Note that if this pass is done, it will also invokes dead_proc_elim
+	% (XXX which means dead_proc_elim may get done twice).
 	mercury_compile__maybe_magic(HLDS45, Verbose, Stats, HLDS47),
 	mercury_compile__maybe_dump_hlds(HLDS47, "47", "magic"),
 
-	mercury_compile__maybe_dead_procs(HLDS47, Verbose, Stats, HLDS49),
+	mercury_compile__maybe_eliminate_dead_procs(HLDS47, Verbose, Stats,
+		HLDS49),
 	mercury_compile__maybe_dump_hlds(HLDS49, "49", "dead_procs"),
 
 	% Deep profiling transformation should be done late in the piece
@@ -2676,6 +2687,32 @@
 		{ HLDS = HLDS0 }
 	).
 
+:- pred mercury_compile__maybe_warn_dead_procs(module_info, bool, bool,
+	module_info, io__state, io__state).
+:- mode mercury_compile__maybe_warn_dead_procs(in, in, in, out, di, uo)
+	is det.
+
+mercury_compile__maybe_warn_dead_procs(HLDS0, Verbose, Stats, HLDS) -->
+	globals__io_lookup_bool_option(warn_dead_procs, WarnDead),
+	( { WarnDead = yes } ->
+		maybe_write_string(Verbose,
+			"% Warning about dead procedures...\n"),
+		maybe_flush_output(Verbose),
+		dead_proc_elim(warning_pass, HLDS0, HLDS1),
+		maybe_write_string(Verbose, "% done.\n"),
+		maybe_report_stats(Stats),
+
+		globals__io_lookup_bool_option(optimize_dead_procs,
+			OptimizeDead),
+		( { OptimizeDead = yes } ->
+			{ HLDS = HLDS1 }
+		;
+			{ HLDS = HLDS0 }
+		)
+	;
+		{ HLDS = HLDS0 }
+	).
+
 :- pred mercury_compile__simplify(module_info, bool, bool, bool, bool,
 	pred(task, module_info, module_info, io__state, io__state), 
 	module_info, io__state, io__state).
@@ -3177,18 +3214,18 @@
 		{ HLDS0 = HLDS }
 	).
 
-:- pred mercury_compile__maybe_dead_procs(module_info, bool, bool,
+:- pred mercury_compile__maybe_eliminate_dead_procs(module_info, bool, bool,
 	module_info, io__state, io__state).
-:- mode mercury_compile__maybe_dead_procs(in, in, in, out, di, uo)
+:- mode mercury_compile__maybe_eliminate_dead_procs(in, in, in, out, di, uo)
 	is det.
 
-mercury_compile__maybe_dead_procs(HLDS0, Verbose, Stats, HLDS) -->
+mercury_compile__maybe_eliminate_dead_procs(HLDS0, Verbose, Stats, HLDS) -->
 	globals__io_lookup_bool_option(optimize_dead_procs, Dead),
 	( { Dead = yes } ->
 		maybe_write_string(Verbose,
 			"% Eliminating dead procedures...\n"),
 		maybe_flush_output(Verbose),
-		dead_proc_elim(HLDS0, HLDS),
+		dead_proc_elim(final_optimization_pass, HLDS0, HLDS),
 		maybe_write_string(Verbose, "% done.\n"),
 		maybe_report_stats(Stats)
 	;
Index: compiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.413
diff -u -d -r1.413 options.m
--- compiler/options.m	26 May 2003 09:00:03 -0000	1.413
+++ compiler/options.m	16 Jul 2003 05:29:06 -0000
@@ -94,6 +94,7 @@
 		;	warn_target_code
 		;	warn_up_to_date
 		;	warn_stubs
+		;	warn_dead_procs
 	% Verbosity options
 		;	verbose
 		;	very_verbose
@@ -723,7 +724,8 @@
 	warn_non_tail_recursion -	bool(no),
 	warn_target_code	-	bool(yes),
 	warn_up_to_date -		bool(yes),
-	warn_stubs		-	bool(yes)
+	warn_stubs		-	bool(yes),
+	warn_dead_procs	-		bool(no)
 ]).
 option_defaults_2(verbosity_option, [
 		% Verbosity Options
@@ -1334,6 +1336,7 @@
 long_option("warn-target-code",		warn_target_code).
 long_option("warn-up-to-date",		warn_up_to_date).
 long_option("warn-stubs",		warn_stubs).
+long_option("warn-dead-procs",		warn_dead_procs).
 
 % verbosity options
 long_option("verbose",			verbose).
@@ -2020,7 +2023,8 @@
 			warn_undefined_options_variables - bool(Enable),
 			warn_target_code	-	bool(Enable),
 			warn_up_to_date -		bool(Enable),
-			warn_stubs	-		bool(Enable)
+			warn_stubs	-		bool(Enable),
+			warn_dead_procs	-		bool(Enable)
 		], OptionTable0, OptionTable).
 special_handler(infer_all, bool(Infer), OptionTable0, ok(OptionTable)) :-
 	override_options([
@@ -2497,6 +2501,8 @@
 		"\tclauses.  Note that this option only has any effect if",
 		"\tthe `--allow-stubs' option (described in the ""Language",
 		"\tSemantics Options"" section below) is enabled.",
+		"--warn-dead-procs",
+		"\tWarn about procedures which are never called.",
 		"--no-warn-target-code",
 		"\tDisable warnings from the compiler used to process the",
 		"\ttarget code (e.g. gcc)."
Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.370
diff -u -d -r1.370 user_guide.texi
--- doc/user_guide.texi	14 May 2003 04:05:44 -0000	1.370
+++ doc/user_guide.texi	16 Jul 2003 10:53:03 -0000
@@ -4274,6 +4274,11 @@
 clauses.  Note that this option only has any effect if
 the @samp{--allow-stubs} option (@pxref{Language semantics options})
 is enabled.
+
+ at sp 1
+ at item --warn-dead-procs
+ at findex --warn-dead-procs
+Warn about procedures which are never called.
 @end table
 
 @node Verbosity options
Index: tests/warnings/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/warnings/Mmakefile,v
retrieving revision 1.31
diff -u -d -r1.31 Mmakefile
--- tests/warnings/Mmakefile	25 Jun 2003 06:57:34 -0000	1.31
+++ tests/warnings/Mmakefile	16 Jul 2003 11:00:13 -0000
@@ -6,7 +6,8 @@
 
 COMPILE_PROGS=	\
 	arg_order_rearrangment \
-	pragma_term_conflict 
+	pragma_term_conflict \
+	warn_dead_procs
 
 ERRORCHECK_PROGS= \
 	ambiguous_overloading \
Index: tests/warnings/warn_dead_procs.exp
===================================================================
RCS file: tests/warnings/warn_dead_procs.exp
diff -N tests/warnings/warn_dead_procs.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/warnings/warn_dead_procs.exp	16 Jul 2003 10:59:35 -0000
@@ -0,0 +1,7 @@
+warn_dead_procs.m:016: Inferred :- pred baz.
+warn_dead_procs.m:008: Warning: predicate `warn_dead_procs.foo/0' mode 0 is
+warn_dead_procs.m:008:   never called.
+warn_dead_procs.m:012: Warning: predicate `warn_dead_procs.bar/1' mode 0 is
+warn_dead_procs.m:012:   never called.
+warn_dead_procs.m:013: Warning: predicate `warn_dead_procs.bar/1' mode 1 is
+warn_dead_procs.m:013:   never called.
Index: tests/warnings/warn_dead_procs.m
===================================================================
RCS file: tests/warnings/warn_dead_procs.m
diff -N tests/warnings/warn_dead_procs.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/warnings/warn_dead_procs.m	16 Jul 2003 10:56:34 -0000
@@ -0,0 +1,18 @@
+:- module warn_dead_procs.
+:- interface.
+:- type expr ---> div(expr, expr).
+:- implementation.
+
+:- type expr2 ---> div2(expr2, expr2).
+
+:- pred foo is det.
+foo.
+
+:- pred bar(int).
+:- mode bar(in) is semidet.
+:- mode bar(out) is det.
+bar(42).
+
+baz.
+
+:- promise ((X `with_type` int) = (Y `with_type` int) <=> Y = X).



-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list