[m-dev.] for review: fix MLDS static ground term bugs

Fergus Henderson fjh at cs.mu.OZ.AU
Sun Oct 22 18:10:02 AEDT 2000


On 22-Oct-2000, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> This change fixes several closely related bugs where the MLDS compiler
> would generatic static ground terms whose initializers referred to
> variables which weren't in scope.  Unfortunately the fix isn't
> yet complete: AFAIK it fixes all such problems in the MLDS generated
> by the code generator, but the ml_elim_nested pass that follows still
> screws things up.

OK, now I've fixed ml_elim_nested too.
If they pass the bootcheck, I'll go ahead and commit these changes.

I've enclosed below a new full diff and a relative diff.

******* FULL DIFF *******************************************

Estimated hours taken: 16

Fix some bugs in the static ground term optimization for the MLDS
back-end.

compiler/ml_code_util.m:
compiler/ml_code_gen.m:
	Ensure that declarations for a goal are generated in such a
	way that they scope over the C code generated for any
	following goals.  This is needed to ensure that we don't
	generate references to undeclared names in static constants.

compiler/ml_unify_gen.m:
compiler/ml_code_util.m:
	Ensure that all static consts get unique names, so that
	ml_elim_nested.m can hoist them to the top level.
	Also move ml_gen_static_const_decl_flags from ml_unify_gen.m
	to ml_code_util.m, for use by ml_code_gen.m.

compiler/ml_elim_nested.m:
	Hoist out the definitions of static constants to the top level
	in cases where they might be referenced from nested functions.
	Also change the name of the local_vars field of the ml_elim_info
	to local_data, to make it clear that it can hold constants too.

compiler/mark_static_terms.m:
	Fix some typos in the comments.

tests/valid/Mmakefile:
tests/valid/static.m:
	Add some regression tests.

compiler/mlds_to_c.m:
	Fix an XXX: it was not outputting `static' in the right places.

Workspace: /home/pgrad/fjh/ws/hg
Index: compiler/mark_static_terms.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mark_static_terms.m,v
retrieving revision 1.3
diff -u -d -r1.3 mark_static_terms.m
--- compiler/mark_static_terms.m	2000/10/06 10:18:25	1.3
+++ compiler/mark_static_terms.m	2000/10/21 11:41:00
@@ -67,16 +67,16 @@
 	conj_mark_static_terms(Goals0, Goals, SI0, SI).
 
 goal_expr_mark_static_terms(disj(Goals0, B), disj(Goals, B), SI0, SI0) :-
-	% we rever to the original static_info at the end of branched goals
+	% we revert to the original static_info at the end of branched goals
 	disj_mark_static_terms(Goals0, Goals, SI0).
 
 goal_expr_mark_static_terms(switch(A, B, Cases0, D), switch(A, B, Cases, D),
 		SI0, SI0) :-
-	% we rever to the original static_info at the end of branched goals
+	% we revert to the original static_info at the end of branched goals
 	cases_mark_static_terms(Cases0, Cases, SI0).
 
 goal_expr_mark_static_terms(not(Goal0), not(Goal), SI0, SI0) :-
-	% we rever to the original static_info at the end of the negation
+	% we revert to the original static_info at the end of the negation
 	goal_mark_static_terms(Goal0, Goal, SI0, _SI).
 
 goal_expr_mark_static_terms(some(A, B, Goal0), some(A, B, Goal), SI0, SI) :-
Index: compiler/ml_code_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_code_gen.m,v
retrieving revision 1.60
diff -u -d -r1.60 ml_code_gen.m
--- compiler/ml_code_gen.m	2000/10/14 04:00:14	1.60
+++ compiler/ml_code_gen.m	2000/10/22 05:19:21
@@ -83,6 +83,25 @@
 % means that in the situation described by [situation],
 % for the the specified [construct] we will generate the specified [code].
 
+% There is one other important thing which can be considered part of the
+% calling convention for the code that we generate for each goal.
+% If static ground term optimization is enabled, then for the terms
+% marked as static by mark_static_terms.m, we will generate static consts.
+% These static consts can refer to other static consts defined earlier.
+% We need to be careful about the scopes of variables to ensure that
+% for any term that mark_static_terms.m marks as static, the C constants
+% representing the arguments of that term are in scope at the point
+% where that term is constructed.  Basically this means that
+% all the static consts generated inside a goal must be hoist out to
+% the top level scope for that goal, except for goal types where
+% goal_expr_mark_static_terms (in mark_static_terms.m) returns the
+% same static_info unchanged, i.e. branched goals and negations.
+%
+% Handling static constants also requires that the calls to ml_gen_goal
+% for each subgoal must be done in the right order, so that the
+% const_num_map in the ml_gen_info holds the right sequence numbers
+% for the constants in scope.
+
 %-----------------------------------------------------------------------------%
 %
 % Code for wrapping goals
@@ -106,12 +125,10 @@
 %	semi goal in nondet context:
 %		<Goal && SUCCEED()>
 %	===>
-%	{
 %		bool succeeded;
 %	
 %		<succeeded = Goal>
 %		if (succeeded) SUCCEED();
-%	}
 
 %-----------------------------------------------------------------------------%
 %
@@ -244,6 +261,10 @@
 %			<Goal && success()>
 %		}
 
+% Note that for all of these versions, we must hoist any static declarations
+% generated for <Goal> out to the top level; this is needed so that such
+% declarations remain in scope for any following goals.
+
 %-----------------------------------------------------------------------------%
 %
 % Code for empty conjunctions (`true')
@@ -289,12 +310,12 @@
 %		<Goals>
 
 % If the first goal is model_semidet, then there are two cases:
-% if the disj as a whole is semidet, things are simple, and
-% if the disj as a whole is model_non, then we do the same as
+% if the conj as a whole is semidet, things are simple, and
+% if the conj as a whole is model_non, then we do the same as
 % for the semidet case, except that we also (ought to) declare
 % a local `succeeded' variable.
 %
-%	model_semi Goal in model_semi disj:
+%	model_semi Goal in model_semi conj:
 %		<succeeded = (Goal, Goals)>
 % 	===>
 %		<succeeded = Goal>;
@@ -302,17 +323,22 @@
 %			<Goals>;
 %		}
 %
-%	model_semi Goal in model_non disj:
+%	model_semi Goal in model_non conj:
 %		<Goal && Goals>
 % 	===>
-%	{
 %		bool succeeded;
 %
 %		<succeeded = Goal>;
 %		if (succeeded) {
 %			<Goals>;
 %		}
-%	}
+%
+% The actual code generation scheme we use is slightly
+% different to that: we hoist any declarations generated
+% for <Goals> to the outer scope, rather than keeping
+% them inside the `if', so that they remain in
+% scope for any later goals which follow this.
+% This is needed for declarations of static consts.
 
 % For model_non goals, there are a couple of different
 % ways that we could generate code, depending on whether
@@ -325,7 +351,6 @@
 %	model_non Goal (optimized for readability)
 %		<Goal, Goals>
 % 	===>
-%	{
 %		entry_func() {
 %			<Goal && succ_func()>;
 %		}
@@ -334,7 +359,6 @@
 %		}
 %
 %		entry_func();
-%	}
 %
 % The more efficient method generates the goals in
 % reverse order, so it's less readable, but it has fewer
@@ -344,13 +368,11 @@
 %	model_non Goal (optimized for efficiency):
 %		<Goal, Goals>
 % 	===>
-%	{
 %		succ_func() {
 %			<Goals && SUCCEED()>;
 %		}
 %
 %		<Goal && succ_func()>;
-%	}
 %
 % The more efficient method is the one we actually use.
 %
@@ -360,7 +382,6 @@
 %	model_non goals (optimized for readability):
 %		<Goal1, Goal2, Goal3, Goals>
 % 	===>
-%	{
 %		label0_func() {
 %			<Goal1 && label1_func()>;
 %		}
@@ -375,12 +396,10 @@
 %		}
 %
 %		label0_func();
-%	}
 %
 %	model_non goals (optimized for efficiency):
 %		<Goal1, Goal2, Goal3, Goals>
 % 	===>
-%	{
 %		label1_func() {
 %			label2_func() {
 %				label3_func() {
@@ -391,7 +410,6 @@
 %			<Goal2 && label2_func()>;
 %		}
 %		<Goal1 && label1_func()>;
-%	}
 %
 % Note that it might actually make more sense to generate
 % conjunctions of nondet goals like this:
@@ -399,7 +417,6 @@
 %	model_non goals (optimized for efficiency, alternative version):
 %		<Goal1, Goal2, Goal3, Goals>
 % 	===>
-%	{
 %		label3_func() {
 %			<Goals && SUCCEED()>;
 %		}
@@ -411,13 +428,21 @@
 %		}
 %
 %		<Goal1 && label1_func()>;
-%	}
 %
 % This would avoid the undesirable deep nesting that we sometimes get
 % with our current scheme.  However, if we're eliminating nested
 % functions, as is normally the case, then after the ml_elim_nested
 % transformation all the functions and variables have been hoisted
 % to the top level, so there is no difference between these two.
+%
+% As with semidet conjunctions, we hoist declarations
+% out so that they remain in scope for any following goals.
+% This is needed for declarations of static consts.
+% However, we want to keep the declarations of non-static
+% variables local, since accessing local variables is more
+% efficient that accessing variables in the environment
+% from a nested function.  So we only hoist declarations
+% of static constants.
 
 %-----------------------------------------------------------------------------%
 %
@@ -450,32 +475,27 @@
 %	model_semi Goal:
 %		<do (Goal ; Goals)>
 %	===>
-%	{
 %		bool succeeded;
 %	
 %		<succeeded = Goal>;
 %		if (!succeeded) {
 %			<do Goals>;
 %		}
-%	}
 
 % model_semi disj:
 
 %	model_det Goal:
 %		<succeeded = (Goal ; Goals)>
 %	===>
-%	{
 %		bool succeeded;
 %
 %		<do Goal>
 %		succeeded = TRUE
 %		/* <Goals> will never be reached */
-%	}
 
 %	model_semi Goal:
 %		<succeeded = (Goal ; Goals)>
 %	===>
-%	{
 %		bool succeeded;
 %
 %		<succeeded = Goal>;
@@ -495,13 +515,11 @@
 %	model_semi Goal:
 %		<(Goal ; Goals) && SUCCEED()>
 %	===>
-%	{
 %		bool succeeded;
 %	
 %		<succeeded = Goal>
 %		if (succeeded) SUCCEED();
 %		<Goals && SUCCEED()>
-%	}
 %
 %	model_non Goal:
 %		<(Goal ; Goals) && SUCCEED()>
@@ -517,7 +535,6 @@
 %	model_semi Cond:
 %		<(Cond -> Then ; Else)>
 %	===>
-%	{
 %		bool succeeded;
 %	
 %		<succeeded = Cond>
@@ -526,7 +543,6 @@
 %		} else {
 %			<Else>
 %		}
-%	}
 
 %	/*
 %	** XXX The following transformation does not do as good a job of GC
@@ -538,7 +554,6 @@
 %	model_non Cond:
 %		<(Cond -> Then ; Else)>
 %	===>
-%	{
 %		bool cond_<N>;
 %
 %		void then_func() {
@@ -551,7 +566,10 @@
 %		if (!cond_<N>) {
 %			<Else>
 %		}
-%	}
+%	except that we hoist any declarations generated
+%	for <Cond> to the top of the scope, so that they
+%	are in scope for the <Then> goal
+%	(this is needed for declarations of static consts)
 
 %-----------------------------------------------------------------------------%
 %
@@ -561,12 +579,10 @@
 % model_det negation
 %		<not(Goal)>
 %	===>
-%	{
 %		bool succeeded;
 %		<succeeded = Goal>
 %		/* now ignore the value of succeeded,
 %		   which we know will be FALSE */
-%	}
 
 % model_semi negation, model_det Goal:
 %		<succeeded = not(Goal)>
@@ -1349,12 +1365,10 @@
 	% semi goal in nondet context:
 	%	<Goal && SUCCEED()>
 	% ===>
-	% {
 	%	bool succeeded;
 	%
 	%	<succeeded = Goal>
 	%	if (succeeded) SUCCEED()
-	% }
 	%
 	ml_gen_test_success(Succeeded),
 	ml_gen_call_current_success_cont(Context, CallCont),
@@ -1383,6 +1397,7 @@
 ml_gen_commit(Goal, CodeModel, Context, MLDS_Decls, MLDS_Statements) -->
 	{ Goal = _ - GoalInfo },
 	{ goal_info_get_code_model(GoalInfo, GoalCodeModel) },
+	{ goal_info_get_context(GoalInfo, GoalContext) },
 
 	( { GoalCodeModel = model_non, CodeModel = model_semi } ->
 
@@ -1434,7 +1449,13 @@
 		{ SuccessCont = success_cont(SuccessFuncLabelRval,
 			EnvPtrRval, [], []) },
 		ml_gen_info_push_success_cont(SuccessCont),
-		ml_gen_goal(model_non, Goal, GoalStatement),
+		ml_gen_goal(model_non, Goal, GoalDecls, GoalStatements),
+		% hoist any static constant declarations for Goal
+		% out to the top level
+		{ list__filter(ml_decl_is_static_const, GoalDecls,
+			GoalStaticDecls, GoalOtherDecls) },
+		{ GoalStatement = ml_gen_block(GoalOtherDecls,
+			GoalStatements, GoalContext) },
 		ml_gen_info_pop_success_cont,
 		ml_gen_set_success(const(false), Context, SetSuccessFalse),
 		ml_gen_set_success(const(true), Context, SetSuccessTrue),
@@ -1446,7 +1467,8 @@
 		{ TryCommitStatement = mlds__statement(TryCommitStmt,
 			MLDS_Context) },
 
-		{ MLDS_Decls = [CommitRefDecl, SuccessFunc | LocalVarDecls] },
+		{ MLDS_Decls = list__append([CommitRefDecl,
+			SuccessFunc | LocalVarDecls], GoalStaticDecls) },
 		{ MLDS_Statements = [TryCommitStatement] },
 
 		ml_gen_info_set_var_lvals(OrigVarLvalMap)
@@ -1496,7 +1518,13 @@
 		{ SuccessCont = success_cont(SuccessFuncLabelRval,
 			EnvPtrRval, [], []) },
 		ml_gen_info_push_success_cont(SuccessCont),
-		ml_gen_goal(model_non, Goal, GoalStatement),
+		ml_gen_goal(model_non, Goal, GoalDecls, GoalStatements),
+		% hoist any static constant declarations for Goal
+		% out to the top level
+		{ list__filter(ml_decl_is_static_const, GoalDecls,
+			GoalStaticDecls, GoalOtherDecls) },
+		{ GoalStatement = ml_gen_block(GoalOtherDecls,
+			GoalStatements, GoalContext) },
 		ml_gen_info_pop_success_cont,
 
 		{ TryCommitStmt = try_commit(CommitRefLval, GoalStatement,
@@ -1504,7 +1532,8 @@
 		{ TryCommitStatement = mlds__statement(TryCommitStmt,
 			MLDS_Context) },
 
-		{ MLDS_Decls = [CommitRefDecl, SuccessFunc | LocalVarDecls] },
+		{ MLDS_Decls = list__append([CommitRefDecl,
+			SuccessFunc | LocalVarDecls], GoalStaticDecls) },
 		{ MLDS_Statements = [TryCommitStatement] },
 
 		ml_gen_info_set_var_lvals(OrigVarLvalMap)
@@ -2506,7 +2535,6 @@
 		%	model_semi cond:
 		%		<(Cond -> Then ; Else)>
 		%	===>
-		%	{
 		%		bool succeeded;
 		%	
 		%		<succeeded = Cond>
@@ -2515,7 +2543,6 @@
 		%		} else {
 		%			<Else>
 		%		}
-		%	}
 		{ CondCodeModel = model_semi },
 		ml_gen_goal(model_semi, Cond, CondDecls, CondStatements),
 		ml_gen_test_success(Succeeded),
@@ -2541,7 +2568,6 @@
 		%	model_non cond:
 		%		<(Cond -> Then ; Else)>
 		%	===>
-		%	{
 		%		bool cond_<N>;
 		%
 		%		void then_func() {
@@ -2554,17 +2580,33 @@
 		%		if (!cond_<N>) {
 		%			<Else>
 		%		}
-		%	}
+		%	except that we hoist any declarations generated
+		%	for <Cond> to the top of the scope, so that they
+		%	are in scope for the <Then> goal
+		%	(this is needed for declarations of static consts)
+
 
 		{ CondCodeModel = model_non },
 
-		% generate the `cond_<N>' var
+		% generate the `cond_<N>' var and the code to initialize it to false
 		ml_gen_info_new_cond_var(CondVar),
 		{ MLDS_Context = mlds__make_context(Context) },
 		{ CondVarDecl = ml_gen_cond_var_decl(CondVar, MLDS_Context) },
+		ml_gen_set_cond_var(CondVar, const(false), Context,
+			SetCondFalse),
 
-		% generate the `then_func'
+		% allocate a name for the `then_func'
 		ml_gen_new_func_label(no, ThenFuncLabel, ThenFuncLabelRval),
+
+		% generate <Cond && then_func()>
+		ml_get_env_ptr(EnvPtrRval),
+		{ SuccessCont = success_cont(ThenFuncLabelRval, EnvPtrRval,
+			[], []) },
+		ml_gen_info_push_success_cont(SuccessCont),
+		ml_gen_goal(model_non, Cond, CondDecls, CondStatements),
+		ml_gen_info_pop_success_cont,
+
+		% generate the `then_func'
 		/* push nesting level */
 		{ Then = _ - ThenGoalInfo },
 		{ goal_info_get_context(ThenGoalInfo, ThenContext) },
@@ -2577,15 +2619,7 @@
 		ml_gen_nondet_label_func(ThenFuncLabel, ThenContext,
 			ThenFuncBody, ThenFunc),
 
-		% generate the main body
-		ml_gen_set_cond_var(CondVar, const(false), Context,
-			SetCondFalse),
-		ml_get_env_ptr(EnvPtrRval),
-		{ SuccessCont = success_cont(ThenFuncLabelRval, EnvPtrRval,
-			[], []) },
-		ml_gen_info_push_success_cont(SuccessCont),
-		ml_gen_goal(model_non, Cond, CondDecls, CondStatements),
-		ml_gen_info_pop_success_cont,
+		% generate `if (!cond_<N>) { <Else> }'
 		ml_gen_test_cond_var(CondVar, CondSucceeded),
 		ml_gen_goal(CodeModel, Else, ElseStatement),
 		{ IfStmt = if_then_else(unop(std_unop(not), CondSucceeded),
@@ -2593,7 +2627,7 @@
 		{ IfStatement = mlds__statement(IfStmt, MLDS_Context) },
 
 		% package it all up in the right order
-		{ MLDS_Decls = [CondVarDecl, ThenFunc | CondDecls] },
+		{ MLDS_Decls = list__append([CondVarDecl | CondDecls], [ThenFunc]) },
 		{ MLDS_Statements = list__append(
 			[SetCondFalse | CondStatements], [IfStatement]) }
 	).
Index: compiler/ml_code_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_code_util.m,v
retrieving revision 1.23
diff -u -d -r1.23 ml_code_util.m
--- compiler/ml_code_util.m	2000/10/14 04:00:16	1.23
+++ compiler/ml_code_util.m	2000/10/22 05:09:37
@@ -241,6 +241,21 @@
 
 %-----------------------------------------------------------------------------%
 %
+% Routines for dealing with static constants
+%
+
+	% Return the declaration flags appropriate for an
+	% initialized local static constant.
+	%
+:- func ml_static_const_decl_flags = mlds__decl_flags.
+
+	% Succeed iff the specified mlds__defn defines
+	% a static constant.
+	%
+:- pred ml_decl_is_static_const(mlds__defn::in) is semidet.
+
+%-----------------------------------------------------------------------------%
+%
 % Routines for dealing with fields
 %
 
@@ -508,6 +523,26 @@
 		ml_gen_info, ml_gen_info).
 :- mode ml_gen_info_new_conv_var(out, in, out) is det.
 
+	% Generate a new `const' sequence number.
+	% This is used to give unique names to the local constants
+	% generated for --static-ground-terms.
+:- type const_seq == int.
+:- pred ml_gen_info_new_const(const_seq,
+		ml_gen_info, ml_gen_info).
+:- mode ml_gen_info_new_const(out, in, out) is det.
+
+	% Set the `const' sequence number
+	% corresponding to a given HLDS variable.
+	%
+:- pred ml_gen_info_set_const_num(prog_var, const_seq, ml_gen_info, ml_gen_info).
+:- mode ml_gen_info_set_const_num(in, in, in, out) is det.
+
+	% Lookup the `const' sequence number
+	% corresponding to a given HLDS variable.
+	%
+:- pred ml_gen_info_lookup_const_num(prog_var, const_seq, ml_gen_info, ml_gen_info).
+:- mode ml_gen_info_lookup_const_num(in, out, in, out) is det.
+
 	%
 	% A success continuation specifies the (rval for the variable
 	% holding the address of the) function that a nondet procedure
@@ -674,52 +709,58 @@
 		%	model_semi goal:
 		%		<Goal, Goals>
 		% 	===>
-		%	{
 		%		bool succeeded;
 		%
 		%		<succeeded = Goal>;
 		%		if (succeeded) {
 		%			<Goals>;
 		%		}
-		%	}
+		%	except that we hoist any declarations generated
+		%	for <Goals> to the outer scope, rather than
+		%	inside the `if', so that they remain in
+		%	scope for any later goals which follow this
+		%	(this is needed for declarations of static consts)
 		{ FirstCodeModel = model_semi },
 		DoGenFirst(FirstDecls, FirstStatements),
 		ml_gen_test_success(Succeeded),
 		DoGenRest(RestDecls, RestStatements),
-		{ IfBody = ml_gen_block(RestDecls, RestStatements, Context) },
+		{ IfBody = ml_gen_block([], RestStatements, Context) },
 		{ IfStmt = if_then_else(Succeeded, IfBody, no) },
 		{ IfStatement = mlds__statement(IfStmt,
 			mlds__make_context(Context)) },
-		{ MLDS_Decls = FirstDecls },
+		{ MLDS_Decls = list__append(FirstDecls, RestDecls) },
 		{ MLDS_Statements = list__append(FirstStatements,
 			[IfStatement]) }
 	;
 		%	model_non goal:
 		%		<First, Rest>
 		% 	===>
-		%	{
 		%		succ_func() {
 		%			<Rest && SUCCEED()>;
 		%		}
 		%
 		%		<First && succ_func()>;
-		%	}
+		%	except that we hoist any declarations generated
+		%	for <First> and any _static_ declarations generated
+		%	for <Rest> to the top of the scope, rather
+		%	than inside or after the succ_func(), so that they
+		%	remain in scope for any code following them
+		%	(this is needed for declarations of static consts).
 		%
-		% XXX this leads to deep nesting for long conjunctions;
-		%     we should avoid that.
+		%	We take care to only hoist _static_ declarations
+		%	outside nested functions, since access to non-local
+		%	variables is less efficient.
+		%
+		% XXX The pattern above leads to deep nesting for long
+		%     conjunctions; we should avoid that.
+		%
 
 		{ FirstCodeModel = model_non },
 
-		% generate the `succ_func'
+		% allocate a name for the `succ_func'
 		ml_gen_new_func_label(no, RestFuncLabel, RestFuncLabelRval),
-		/* push nesting level */
-		DoGenRest(RestDecls, RestStatements),
-		{ RestStatement = ml_gen_block(RestDecls, RestStatements,
-			Context) },
-		/* pop nesting level */
-		ml_gen_nondet_label_func(RestFuncLabel, Context, RestStatement,
-			RestFunc),
 
+		% generate <First && succ_func()>
 		ml_get_env_ptr(EnvPtrRval),
 		{ SuccessCont = success_cont(RestFuncLabelRval,
 			EnvPtrRval, [], []) },
@@ -727,12 +768,30 @@
 		DoGenFirst(FirstDecls, FirstStatements),
 		ml_gen_info_pop_success_cont,
 
-		% it might be better to put the decls in the other order:
-		/* { MLDS_Decls = list__append(FirstDecls, [RestFunc]) }, */
-		{ MLDS_Decls = [RestFunc | FirstDecls] },
+		% generate the `succ_func'
+		/* push nesting level */
+		DoGenRest(RestDecls, RestStatements),
+		{ list__filter(ml_decl_is_static_const, RestDecls,
+			RestStaticDecls, RestOtherDecls) },
+		{ RestStatement = ml_gen_block(RestOtherDecls, RestStatements,
+			Context) },
+		/* pop nesting level */
+		ml_gen_nondet_label_func(RestFuncLabel, Context, RestStatement,
+			RestFunc),
+
+		{ MLDS_Decls = list__condense(
+			[FirstDecls, RestStaticDecls, [RestFunc]]) },
 		{ MLDS_Statements = FirstStatements }
 	).
 
+	% Succeed iff the specified mlds__defn defines
+	% a static constant.
+	%
+ml_decl_is_static_const(Defn) :-
+	Defn = mlds__defn(Name, _Context, Flags, _DefnBody),
+	Name = data(var(_)),
+	Flags = ml_static_const_decl_flags.
+
 	% Given a function label and the statement which will comprise
 	% the function body for that function, generate an mlds__defn
 	% which defines that function.
@@ -1211,6 +1270,7 @@
 	MLDS_Defn = mlds__defn(Name, Context, DeclFlags, Defn).
 
 	% Return the declaration flags appropriate for a local variable.
+	%
 :- func ml_gen_var_decl_flags = mlds__decl_flags.
 ml_gen_var_decl_flags = MLDS_DeclFlags :-
 	Access = public,
@@ -1222,6 +1282,19 @@
 	MLDS_DeclFlags = init_decl_flags(Access, PerInstance,
 		Virtuality, Finality, Constness, Abstractness).
 
+	% Return the declaration flags appropriate for an
+	% initialized local static constant.
+	%
+ml_static_const_decl_flags = MLDS_DeclFlags :-
+	Access = private,
+	PerInstance = one_copy,
+	Virtuality = non_virtual,
+	Finality = overridable,
+	Constness = const,
+	Abstractness = concrete,
+	MLDS_DeclFlags = init_decl_flags(Access, PerInstance,
+		Virtuality, Finality, Constness, Abstractness).
+
 %-----------------------------------------------------------------------------%
 %
 % Code for dealing with fields
@@ -1532,7 +1605,7 @@
 % The `ml_gen_info' type holds information used during MLDS code generation
 % for a given procedure.
 %
-% Only the `func_label', `commit_label', `cond_var', `conv_var',
+% Only the `func_label', `commit_label', `cond_var', `conv_var', `const_num',
 % `var_lvals', `success_cont_stack', and `extra_defns' fields are mutable;
 % the others are set when the `ml_gen_info' is created and then never
 % modified.
@@ -1560,6 +1633,8 @@
 			commit_label :: commit_sequence_num,
 			cond_var :: cond_seq,
 			conv_var :: conv_seq,
+			const_num :: const_seq,
+			const_num_map :: map(prog_var, const_seq),
 			success_cont_stack :: stack(success_cont),
 				% a partial mapping from vars to lvals,
 				% used to override the normal lval
@@ -1586,6 +1661,8 @@
 	CommitLabelCounter = 0,
 	CondVarCounter = 0,
 	ConvVarCounter = 0,
+	ConstCounter = 0,
+	map__init(ConstNumMap),
 	stack__init(SuccContStack),
 	map__init(VarLvals),
 	ExtraDefns = [],
@@ -1601,6 +1678,8 @@
 			CommitLabelCounter,
 			CondVarCounter,
 			ConvVarCounter,
+			ConstCounter,
+			ConstNumMap,
 			SuccContStack,
 			VarLvals,
 			ExtraDefns
@@ -1644,6 +1723,15 @@
 
 ml_gen_info_new_conv_var(ConvVar, Info, Info^conv_var := ConvVar) :-
 	ConvVar = Info^conv_var + 1.
+
+ml_gen_info_new_const(ConstVar, Info, Info^const_num := ConstVar) :-
+	ConstVar = Info^const_num + 1.
+
+ml_gen_info_set_const_num(Var, ConstVar, Info,
+	Info^const_num_map := map__set(Info^const_num_map, Var, ConstVar)).
+
+ml_gen_info_lookup_const_num(Var, ConstVar, Info, Info) :-
+	ConstVar = map__lookup(Info^const_num_map, Var).
 
 ml_gen_info_push_success_cont(SuccCont, Info,
 	Info^success_cont_stack :=
Index: compiler/mlds_to_c.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_c.m,v
retrieving revision 1.58
diff -u -d -r1.58 mlds_to_c.m
--- compiler/mlds_to_c.m	2000/10/06 10:18:26	1.58
+++ compiler/mlds_to_c.m	2000/10/22 02:26:12
@@ -759,14 +759,7 @@
 		% Now output the declaration for this mlds__defn.
 		%
 		mlds_indent(Context, Indent),
-		( { Name = data(_) } ->
-			% XXX for private data and private functions,
-			% we should use "static"
-			io__write_string("extern ")
-		;
-			[]
-		),
-		mlds_output_decl_flags(Flags),
+		mlds_output_decl_flags(Flags, forward_decl, Name),
 		mlds_output_decl_body(Indent, qual(ModuleName, Name), Context,
 			DefnBody)
 	).
@@ -846,7 +839,7 @@
 		[]
 	),
 	mlds_indent(Context, Indent),
-	mlds_output_decl_flags(Flags),
+	mlds_output_decl_flags(Flags, definition, Name),
 	mlds_output_defn_body(Indent, qual(ModuleName, Name), Context,
 			DefnBody).
 
@@ -1646,41 +1639,88 @@
 % Code to output declaration specifiers
 %
 
-:- pred mlds_output_decl_flags(mlds__decl_flags, io__state, io__state).
-:- mode mlds_output_decl_flags(in, di, uo) is det.
+:- type decl_or_defn
+	--->	forward_decl
+	;	definition.
 
-mlds_output_decl_flags(Flags) -->
-	mlds_output_access(access(Flags)),
-	mlds_output_per_instance(per_instance(Flags)),
+:- pred mlds_output_decl_flags(mlds__decl_flags, decl_or_defn,
+		mlds__entity_name, io__state, io__state).
+:- mode mlds_output_decl_flags(in, in, in, di, uo) is det.
+
+mlds_output_decl_flags(Flags, DeclOrDefn, Name) -->
+	%
+	% mlds_output_extern_or_static handles both the
+	% `access' and the `per_instance' fields of the mlds__decl_flags.
+	% We have to handle them together because C overloads `static'
+	% to mean both `private' and `one_copy', rather than having
+	% separate keywords for each.  To make it clear which MLDS
+	% construct each `static' keyword means, we precede the `static'
+	% without (optionally-enabled) comments saying whether it is
+	% `private', `one_copy', or both.
+	%
+	mlds_output_access_comment(access(Flags)),
+	mlds_output_per_instance_comment(per_instance(Flags)),
+	mlds_output_extern_or_static(access(Flags), per_instance(Flags),
+		DeclOrDefn, Name),
 	mlds_output_virtuality(virtuality(Flags)),
 	mlds_output_finality(finality(Flags)),
 	mlds_output_constness(constness(Flags)),
 	mlds_output_abstractness(abstractness(Flags)).
 
-:- pred mlds_output_access(access, io__state, io__state).
-:- mode mlds_output_access(in, di, uo) is det.
+:- pred mlds_output_access_comment(access, io__state, io__state).
+:- mode mlds_output_access_comment(in, di, uo) is det.
 
-mlds_output_access(Access) -->
+mlds_output_access_comment(Access) -->
 	globals__io_lookup_bool_option(auto_comments, Comments),
 	( { Comments = yes } ->
-		mlds_output_access_2(Access)
+		mlds_output_access_comment_2(Access)
 	;
 		[]
 	).
 
-:- pred mlds_output_access_2(access, io__state, io__state).
-:- mode mlds_output_access_2(in, di, uo) is det.
+:- pred mlds_output_access_comment_2(access, io__state, io__state).
+:- mode mlds_output_access_comment_2(in, di, uo) is det.
 
-mlds_output_access_2(public)    --> [].
-mlds_output_access_2(private)   --> io__write_string("/* private: */ ").
-mlds_output_access_2(protected) --> io__write_string("/* protected: */ ").
-mlds_output_access_2(default)   --> io__write_string("/* default access */ ").
+mlds_output_access_comment_2(public)    --> [].
+mlds_output_access_comment_2(private)   --> io__write_string("/* private: */ ").
+mlds_output_access_comment_2(protected) --> io__write_string("/* protected: */ ").
+mlds_output_access_comment_2(default)   --> io__write_string("/* default access */ ").
 
-:- pred mlds_output_per_instance(per_instance, io__state, io__state).
-:- mode mlds_output_per_instance(in, di, uo) is det.
+:- pred mlds_output_per_instance_comment(per_instance, io__state, io__state).
+:- mode mlds_output_per_instance_comment(in, di, uo) is det.
 
-mlds_output_per_instance(one_copy)     --> io__write_string("static ").
-mlds_output_per_instance(per_instance) --> [].
+mlds_output_per_instance_comment(PerInstance) -->
+	globals__io_lookup_bool_option(auto_comments, Comments),
+	( { Comments = yes } ->
+		mlds_output_per_instance_comment_2(PerInstance)
+	;
+		[]
+	).
+
+:- pred mlds_output_per_instance_comment_2(per_instance, io__state, io__state).
+:- mode mlds_output_per_instance_comment_2(in, di, uo) is det.
+
+mlds_output_per_instance_comment_2(per_instance) --> [].
+mlds_output_per_instance_comment_2(one_copy)     --> io__write_string("/* one_copy */ ").
+
+:- pred mlds_output_extern_or_static(access, per_instance, decl_or_defn,
+		mlds__entity_name, io__state, io__state).
+:- mode mlds_output_extern_or_static(in, in, in, in, di, uo) is det.
+
+mlds_output_extern_or_static(Access, PerInstance, DeclOrDefn, Name) -->
+	(
+		{ Access = private ; PerInstance = one_copy },
+		{ Name \= type(_, _) }
+	->
+		io__write_string("static ")
+	;
+		{ DeclOrDefn = forward_decl },
+		{ Name = data(_) }
+	->
+		io__write_string("extern ")
+	;
+		[]
+	).
 
 :- pred mlds_output_virtuality(virtuality, io__state, io__state).
 :- mode mlds_output_virtuality(in, di, uo) is det.
Index: compiler/ml_elim_nested.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_elim_nested.m,v
retrieving revision 1.13
diff -u -d -r1.13 ml_elim_nested.m
--- compiler/ml_elim_nested.m	2000/10/14 04:00:16	1.13
+++ compiler/ml_elim_nested.m	2000/10/22 06:52:41
@@ -102,7 +102,10 @@
 % Actually the description above is slightly over-simplified: not all local
 % variables need to be put in the environment struct.  Only those local
 % variables which are referenced by nested functions need to be
-% put in the environment struct.
+% put in the environment struct.  Also, if none of the nested functions
+% refer to the locals in the outer function, we don't need to create
+% an environment struct at all, we just need to hoist the definitions
+% of the nested functions out to the top level.
 %
 % The `env_ptr' variables generated here serve as definitions for
 % the (previously dangling) references to such variables that
@@ -130,8 +133,12 @@
 
 :- implementation.
 :- import_module bool, int, list, std_util, string, require.
+
+:- import_module ml_code_util.
+
 % the following imports are needed for mangling pred names
 :- import_module hlds_pred, prog_data, prog_out.
+
 :- import_module globals, options.
 
 	% Eliminated nested functions for the whole MLDS.
@@ -164,22 +171,30 @@
 		%
 		% traverse the function body, finding (and removing)
 		% any nested functions, and fixing up any references
-		% to the arguments or to local variables which
-		% occur in nested functions
+		% to the arguments or to local variables or local
+		% static constants which occur in nested functions
 		%
 		ElimInfo0 = elim_info_init(ModuleName, OuterVars, EnvTypeName),
 		Params = mlds__func_params(Arguments, _RetValues),
 		ml_maybe_add_args(Arguments, FuncBody0, ModuleName,
 			Context, ElimInfo0, ElimInfo1),
 		flatten_statement(FuncBody0, FuncBody1, ElimInfo1, ElimInfo),
-		elim_info_finish(ElimInfo, NestedFuncs0, LocalVars),
+		elim_info_finish(ElimInfo, NestedFuncs0, Locals),
 
 		%
-		% if there were no nested functions, then we're done
+		% Split the locals that we need to process
+		% into local variables and local static constants
+		%
+		list__filter(ml_decl_is_static_const, Locals,
+			LocalStatics, LocalVars),
+
+		%
+		% if there were no nested functions, then we just
+		% hoist the local static constants
 		%
 		( NestedFuncs0 = [] ->
 			FuncBody = FuncBody1,
-			HoistedDefns = []
+			HoistedDefns = LocalStatics
 		;
 			%
 			% Create a struct to hold the local variables,
@@ -195,6 +210,9 @@
 					Globals), NestedFuncs0, NestedFuncs,
 					no, InsertedEnv),
 
+			% Hoist out the local statics and the nested functions
+			HoistedDefns0 = list__append(LocalStatics, NestedFuncs),
+
 			% 
 			% It's possible that none of the nested
 			% functions reference the arguments or locals of
@@ -233,17 +251,15 @@
 						[InitEnv | CodeToCopyArgs], 
 						[FuncBody1]), Context),
 				%
-				% hoist the nested functions out, by
-				% inserting the environment struct type
-				% and the previously nested functions at
-				% the start of the list of definitions,
-				% followed by the new version of the
-				% top-level function
+				% insert the environment struct type
+				% at the start of the list of hoisted definitions
+				% (preceding the previously nested functions
+				% and static constants in HoistedDefns0),
 				%
-				HoistedDefns = [EnvTypeDefn | NestedFuncs]
+				HoistedDefns = [EnvTypeDefn | HoistedDefns0]
 			;
 				FuncBody = FuncBody1,
-				HoistedDefns = NestedFuncs
+				HoistedDefns = HoistedDefns0
 			)
 		),
 		DefnBody = mlds__function(PredProcId, Params, yes(FuncBody)),
@@ -256,7 +272,7 @@
 
 	%
 	% Add any arguments which are used in nested functions
-	% to the local_vars field in the elim_info.
+	% to the local_data field in the elim_info.
 	%
 :- pred ml_maybe_add_args(mlds__arguments, mlds__statement,
 		mlds_module_name, mlds__context, elim_info, elim_info).
@@ -266,10 +282,10 @@
 ml_maybe_add_args([Arg|Args], FuncBody, ModuleName, Context) -->
 	(
 		{ Arg = data(var(VarName)) - _Type },
-		{ ml_should_add_local_var(ModuleName, VarName, [], [FuncBody]) }
+		{ ml_should_add_local_data(ModuleName, VarName, [], [FuncBody]) }
 	->
 		{ ml_conv_arg_to_var(Context, Arg, ArgToCopy) },
-		elim_info_add_local_var(ArgToCopy)
+		elim_info_add_local_data(ArgToCopy)
 	;
 		[]
 	),
@@ -291,7 +307,7 @@
 			ArgsToCopy0, CodeToCopyArgs0),
 	(
 		Arg = data(var(VarName)) - FieldType,
-		ml_should_add_local_var(ModuleName, VarName, [], [FuncBody])
+		ml_should_add_local_data(ModuleName, VarName, [], [FuncBody])
 	->
 		ml_conv_arg_to_var(Context, Arg, ArgToCopy),
 
@@ -721,7 +737,7 @@
 		% If that wasn't the case, we'd need code something
 		% like this:
 		/***************
-		{ LocalVars = elim_info_get_local_vars(ElimInfo) },
+		{ LocalVars = elim_info_get_local_data(ElimInfo) },
 		{ OuterVars0 = elim_info_get_outer_vars(ElimInfo) },
 		{ OuterVars = [LocalVars | OuterVars0] },
 		{ FlattenedDefns = ml_elim_nested_defns(ModuleName,
@@ -746,10 +762,10 @@
 		{ ModuleName = elim_info_get_module_name(ElimInfo) },
 		(
 			{ Name = data(var(VarName)) },
-			{ ml_should_add_local_var(ModuleName, VarName,
+			{ ml_should_add_local_data(ModuleName, VarName,
 				FollowingDefns, FollowingStatements) }
 		->
-			elim_info_add_local_var(Defn0),
+			elim_info_add_local_data(Defn0),
 			{ Defns = [] }
 		;
 			{ Defns = [Defn0] }
@@ -767,14 +783,29 @@
 	).
 
 	%
-	% check for a nested function definition
-	% that references this variable
+	% Succeed iff we should add the definition of this variable
+	% to the local_data field of the ml_elim_info, meaning that
+	% it should be added to the environment struct
+	% (if it's a variable) or hoisted out to the top level
+	% (if it's a static const).
 	%
-:- pred ml_should_add_local_var(mlds_module_name, mlds__var_name,
+	% This checks for a nested function definition
+	% or static initializer that references the variable.
+	% This is conservative; we only need to hoist out
+	% static variables if they are referenced by
+	% static initializers which themselves need to be
+	% hoisted because they are referenced from a nested
+	% function.  But checking the last part of that
+	% is tricky, so currently we just hoist more
+	% of the static consts than we strictly need to.
+	% Perhaps it would be simpler to just hoist *all*
+	% static consts.
+	%
+:- pred ml_should_add_local_data(mlds_module_name, mlds__var_name,
 		mlds__defns, mlds__statements).
-:- mode ml_should_add_local_var(in, in, in, in) is semidet.
+:- mode ml_should_add_local_data(in, in, in, in) is semidet.
 
-ml_should_add_local_var(ModuleName, VarName,
+ml_should_add_local_data(ModuleName, VarName,
 		FollowingDefns, FollowingStatements) :-
 	QualVarName = qual(ModuleName, VarName),
 	(
@@ -783,9 +814,16 @@
 		statements_contains_defn(FollowingStatements,
 			FollowingDefn)
 	),
-	FollowingDefn = mlds__defn(_, _, _,
-		mlds__function(_, _, _)),
-	defn_contains_var(FollowingDefn, QualVarName).
+	(
+		FollowingDefn = mlds__defn(_, _, _,
+			mlds__function(_, _, _)),
+		defn_contains_var(FollowingDefn, QualVarName)
+	;
+		FollowingDefn = mlds__defn(_, _, _,
+			mlds__data(_, Initializer)),
+		ml_decl_is_static_const(FollowingDefn),
+		initializer_contains_var(Initializer, QualVarName)
+	).
 
 %-----------------------------------------------------------------------------%
 
@@ -923,7 +961,7 @@
 fixup_var(ThisVar, Lval, ElimInfo, ElimInfo) :-
 	ThisVar = qual(ThisVarModuleName, ThisVarName),
 	ModuleName = elim_info_get_module_name(ElimInfo),
-	LocalVars = elim_info_get_local_vars(ElimInfo),
+	Locals = elim_info_get_local_data(ElimInfo),
 	ClassType = elim_info_get_env_type_name(ElimInfo),
 	(
 		%
@@ -932,12 +970,13 @@
 		% and replace them with `env_ptr->foo'.
 		%
 		ThisVarModuleName = ModuleName,
-		IsLocal = (pred(VarType::out) is nondet :-
-			list__member(Var, LocalVars),
+		IsLocalVar = (pred(VarType::out) is nondet :-
+			list__member(Var, Locals),
 			Var = mlds__defn(data(var(ThisVarName)), _, _, 
-				data(VarType, _))
+				data(VarType, _)),
+			\+ ml_decl_is_static_const(Var)
 			),
-		solutions(IsLocal, [FieldType])
+		solutions(IsLocalVar, [FieldType])
 	->
 		EnvPtr = lval(var(qual(ModuleName, "env_ptr"))),
 		EnvModuleName = ml_env_module_name(ClassType),
@@ -963,7 +1002,7 @@
 		% for `env.foo'.)
 		%
 		ThisVarModuleName = ModuleName,
-		list__member(Var, LocalVars),
+		list__member(Var, Locals),
 		Var = mlds__defn(data(var(ThisVarName)), _, _, _)
 	->
 		Env = var(qual(ModuleName, "env")),
@@ -1381,7 +1420,7 @@
 				% The list of local variables that we must
 				% put in the environment structure
 				% This list is stored in reverse order.
-			local_vars :: list(mlds__defn),
+			local_data :: list(mlds__defn),
 				
 				% Type of the introduced environment struct
 			env_type_name :: mlds__type
@@ -1402,8 +1441,8 @@
 :- func elim_info_get_outer_vars(elim_info) = outervars.
 elim_info_get_outer_vars(ElimInfo) = ElimInfo ^ outer_vars.
 
-:- func elim_info_get_local_vars(elim_info) = list(mlds__defn).
-elim_info_get_local_vars(ElimInfo) = ElimInfo ^ local_vars.
+:- func elim_info_get_local_data(elim_info) = list(mlds__defn).
+elim_info_get_local_data(ElimInfo) = ElimInfo ^ local_data.
 
 :- func elim_info_get_env_type_name(elim_info) = mlds__type.
 elim_info_get_env_type_name(ElimInfo) = ElimInfo ^ env_type_name.
@@ -1413,15 +1452,15 @@
 elim_info_add_nested_func(NestedFunc, ElimInfo, 
 	ElimInfo ^ nested_funcs := [NestedFunc | ElimInfo ^ nested_funcs]).
 
-:- pred elim_info_add_local_var(mlds__defn, elim_info, elim_info).
-:- mode elim_info_add_local_var(in, in, out) is det.
-elim_info_add_local_var(LocalVar, ElimInfo,
-	ElimInfo ^ local_vars := [LocalVar | ElimInfo ^ local_vars]).
+:- pred elim_info_add_local_data(mlds__defn, elim_info, elim_info).
+:- mode elim_info_add_local_data(in, in, out) is det.
+elim_info_add_local_data(LocalVar, ElimInfo,
+	ElimInfo ^ local_data := [LocalVar | ElimInfo ^ local_data]).
 
 :- pred elim_info_finish(elim_info, list(mlds__defn), list(mlds__defn)).
 :- mode elim_info_finish(in, out, out) is det.
-elim_info_finish(ElimInfo, Funcs, LocalVars) :-
+elim_info_finish(ElimInfo, Funcs, Locals) :-
 	Funcs = list__reverse(ElimInfo ^ nested_funcs),
-	LocalVars = list__reverse(ElimInfo ^ local_vars).
+	Locals = list__reverse(ElimInfo ^ local_data).
 
 %-----------------------------------------------------------------------------%
Index: compiler/ml_unify_gen.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/ml_unify_gen.m,v
retrieving revision 1.19
diff -u -d -r1.19 ml_unify_gen.m
--- compiler/ml_unify_gen.m	2000/10/09 08:48:53	1.19
+++ compiler/ml_unify_gen.m	2000/10/22 06:52:06
@@ -1091,7 +1091,7 @@
 		%
 		% Generate a local static constant for this float
 		%
-		ml_gen_info_new_conv_var(SequenceNum),
+		ml_gen_info_new_const(SequenceNum),
 		{ string__format("float_%d", [i(SequenceNum)], ConstName) },
 		{ Initializer = init_obj(Rval) },
 		{ ConstDefn = ml_gen_static_const_defn(ConstName, Type,
@@ -1124,16 +1124,39 @@
 	{ error("ml_gen_static_const_arg_list: length mismatch") }.
 
 	% Generate the name of the local static constant
-	% for a given variable.
+	% for a given variable.  To ensure that the names
+	% are unique, we qualify them with both the pred_id
+	% number, and a sequence number.  This is needed to
+	% allow ml_elim_nested.m to hoist such constants out
+	% to top level.
 	%
 :- pred ml_gen_static_const_name(prog_var, mlds__var_name,
 		ml_gen_info, ml_gen_info).
 :- mode ml_gen_static_const_name(in, out, in, out) is det.
 ml_gen_static_const_name(Var, ConstName) -->
+	ml_gen_info_new_const(SequenceNum),
+	ml_gen_info_set_const_num(Var, SequenceNum),
+	ml_format_static_const_name(Var, SequenceNum, ConstName).
+
+:- pred ml_lookup_static_const_name(prog_var, mlds__var_name,
+		ml_gen_info, ml_gen_info).
+:- mode ml_lookup_static_const_name(in, out, in, out) is det.
+ml_lookup_static_const_name(Var, ConstName) -->
+	ml_gen_info_lookup_const_num(Var, SequenceNum),
+	ml_format_static_const_name(Var, SequenceNum, ConstName).
+
+:- pred ml_format_static_const_name(prog_var, const_seq, mlds__var_name,
+		ml_gen_info, ml_gen_info).
+:- mode ml_format_static_const_name(in, in, out, in, out) is det.
+
+ml_format_static_const_name(Var, SequenceNum, ConstName) -->
 	=(MLDSGenInfo),
+	{ ml_gen_info_get_pred_id(MLDSGenInfo, PredId) },
+	{ pred_id_to_int(PredId, PredIdNum) },
 	{ ml_gen_info_get_varset(MLDSGenInfo, VarSet) },
 	{ VarName = ml_gen_var_name(VarSet, Var) },
-	{ string__format("const_%s", [s(VarName)], ConstName) }.
+	{ string__format("const_%d_%d_%s", [i(PredIdNum), i(SequenceNum),
+		s(VarName)], ConstName) }.
 
 	% Generate an rval containing the address of the local static constant
 	% for a given variable.
@@ -1142,7 +1165,7 @@
 		ml_gen_info, ml_gen_info).
 :- mode ml_gen_static_const_addr(in, out, in, out) is det.
 ml_gen_static_const_addr(Var, ConstAddrRval) -->
-	ml_gen_static_const_name(Var, ConstName),
+	ml_lookup_static_const_name(Var, ConstName),
 	ml_qualify_var(ConstName, ConstLval),
 	{ ConstAddrRval = mem_addr(ConstLval) }.
 
@@ -1158,20 +1181,6 @@
 	DeclFlags = ml_static_const_decl_flags,
 	MLDS_Context = mlds__make_context(Context),
 	MLDS_Defn = mlds__defn(Name, MLDS_Context, DeclFlags, Defn).
-
-	% Return the declaration flags appropriate for an
-	% initialized local static constant.
-	%
-:- func ml_static_const_decl_flags = mlds__decl_flags.
-ml_static_const_decl_flags = MLDS_DeclFlags :-
-	Access = private,
-	PerInstance = one_copy,
-	Virtuality = non_virtual,
-	Finality = overridable,
-	Constness = const,
-	Abstractness = concrete,
-	MLDS_DeclFlags = init_decl_flags(Access, PerInstance,
-		Virtuality, Finality, Constness, Abstractness).
 
 :- pred ml_cons_name(cons_id, ctor_name, ml_gen_info, ml_gen_info).
 :- mode ml_cons_name(in, out, in, out) is det.
Index: tests/valid/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/valid/Mmakefile,v
retrieving revision 1.74
diff -u -d -r1.74 Mmakefile
--- tests/valid/Mmakefile	2000/10/13 13:56:17	1.74
+++ tests/valid/Mmakefile	2000/10/21 13:50:22
@@ -130,6 +130,7 @@
 	soln_context.m \
 	some_switch.m \
 	stack_alloc.m \
+	static.m \
 	subtype_switch.m \
 	switch_detection_bug.m \
 	switch_detection_bug2.m \
Index: tests/valid/static.m
===================================================================
RCS file: static.m
diff -N static.m
--- /dev/null	Thu Mar 30 14:06:13 2000
+++ static.m	Sun Oct 22 17:09:57 2000
@@ -0,0 +1,106 @@
+% mmc -c --grade hlc.gc static.c
+% static.c(455) : error C2065: 'static__const_Result_5' : undeclared identifier
+:- module static.
+
+:- interface.
+
+:- type t.
+:- type t4.
+:- type t5.
+
+:- pred q(t::in, t5::out) is det.
+:- pred r(t::in, t5::out, int::out) is multi.
+:- pred s(int::in, t5::out) is cc_nondet.
+:- pred t(t::in, t4::out, t5::out) is semidet.
+:- pred u(t4::out, t5::out, int::out) is nondet.
+:- pred v(t4::out, t5::out, int::out) is nondet.
+
+:- implementation.
+:- import_module int, list.
+
+:- type t ---> a ; b ; c.
+:- type t4 ---> f(string, int).
+:- type t5 ---> g(t4, t4) ; i.
+
+% Test for ordinary if-then-else
+q(X, Y) :-
+	(
+		X = a,
+			% This line causes the problem.  Move it into
+			% the then to avoid the above code gen problem.
+			% We can move it into the then because this line
+			% isn't part of the test.
+		Result = f("hello", 0)
+	->
+		Y = g(Result, Result)
+	;
+		Y = i
+	).
+
+% Test for if-then-else with nondet condition
+r(X, Y, Z) :-
+	(
+		X = a,
+		(Z0 = 1 ; Z0 = 2),
+
+			% This line causes the problem.  Move it into
+			% the then to avoid the above code gen problem.
+			% We can move it into the then because this line
+			% isn't part of the test.
+		Result = f("hello", 0)
+	->
+		Z = Z0,
+		Y = g(Result, Result)
+	;
+		Z = 0,
+		Y = i
+	).
+
+% Test for commit
+s(X, Y) :-
+	some [Z] (
+		(Z = 1 ; Z = 2),
+		X = Z * Z,
+		Result = f("hello", 0)
+	),
+	Y = g(Result, Result).
+
+% Test same variable having different constant values in different branches (semidet)
+t(X, Result, Y) :-
+	(
+		X = a,
+		Result = f("hello", 0),
+		Y = g(Result, Result)
+	;
+		X = b,
+		Result = f("goodbye", 0),
+		Y = g(Result, Result)
+	).
+
+% Test same variable having different constant values in different branches (nondet)
+u(Result, Y, Z) :-
+	(
+		Result = f("hello", 0),
+		list__member(Z, [1,2]),
+		Y = g(Result, Result)
+	;
+		Result = f("hello again", 0),
+		Result2 = f("GoodBye", 0),
+		list__member(Z, [3,4]),
+		Y = g(Result, Result2)
+	).
+
+% Exactly the same as u/3, but with different constants;
+% this tests to ensure that any constant values hoisted
+% out to the top level are given distinct names.
+v(Result, Y, Z) :-
+	(
+		Result = f("xxxxx", 0),
+		list__member(Z, [1,2]),
+		Y = g(Result, Result)
+	;
+		Result = f("yyyyyyyyyyy", 0),
+		Result2 = f("zzzzzzz", 0),
+		list__member(Z, [3,4]),
+		Y = g(Result, Result2)
+	).

******* RELATIVE DIFF *******************************************

--- CHANGES.mlds_sgt_bug.old	Sun Oct 22 16:20:02 2000
+++ CHANGES.mlds_sgt_bug	Sun Oct 22 17:42:01 2000
@@ -13,16 +13,24 @@
 
 compiler/ml_unify_gen.m:
 compiler/ml_code_util.m:
-	Move ml_gen_static_const_decl_flags from ml_unify_gen.m
+	Ensure that all static consts get unique names, so that
+	ml_elim_nested.m can hoist them to the top level.
+	Also move ml_gen_static_const_decl_flags from ml_unify_gen.m
 	to ml_code_util.m, for use by ml_code_gen.m.
 
 compiler/ml_elim_nested.m:
-	XXX FIXME This module doesn't handle static constants!
-	
+	Hoist out the definitions of static constants to the top level
+	in cases where they might be referenced from nested functions.
+	Also change the name of the local_vars field of the ml_elim_info
+	to local_data, to make it clear that it can hold constants too.
+
 compiler/mark_static_terms.m:
 	Fix some typos in the comments.
 
 tests/valid/Mmakefile:
 tests/valid/static.m:
 	Add some regression tests.
+
+compiler/mlds_to_c.m:
+	Fix an XXX: it was not outputting `static' in the right places.
 
--- compiler/ml_code_gen.m
+++ compiler/ml_code_gen.m
@@ -99,5 +99,5 @@
-% For branched goals, we must in fact ensure that we do NOT hoist out
-% static variable definitions, since the same Mercury variable can have
-% different constant values in different branches, and so there may be
-% more than one C static const with the same name but with different
-% values and occurring in different scopes.
+%
+% Handling static constants also requires that the calls to ml_gen_goal
+% for each subgoal must be done in the right order, so that the
+% const_num_map in the ml_gen_info holds the right sequence numbers
+% for the constants in scope.
@@ -1455,2 +1455,2 @@
-		{ list__filter(ml_decl_is_static, GoalDecls, GoalStaticDecls,
-			GoalOtherDecls) },
+		{ list__filter(ml_decl_is_static_const, GoalDecls,
+			GoalStaticDecls, GoalOtherDecls) },
@@ -1524,2 +1524,2 @@
-		{ list__filter(ml_decl_is_static, GoalDecls, GoalStaticDecls,
-			GoalOtherDecls) },
+		{ list__filter(ml_decl_is_static_const, GoalDecls,
+			GoalStaticDecls, GoalOtherDecls) },
@@ -2591 +2591 @@
-		% generate the `cond_<N>' var
+		% generate the `cond_<N>' var and the code to initialize it to false
@@ -2594,0 +2595,2 @@
+		ml_gen_set_cond_var(CondVar, const(false), Context,
+			SetCondFalse),
@@ -2596 +2598 @@
-		% generate the `then_func'
+		% allocate a name for the `then_func'
@@ -2597,0 +2600,10 @@
+
+		% generate <Cond && then_func()>
+		ml_get_env_ptr(EnvPtrRval),
+		{ SuccessCont = success_cont(ThenFuncLabelRval, EnvPtrRval,
+			[], []) },
+		ml_gen_info_push_success_cont(SuccessCont),
+		ml_gen_goal(model_non, Cond, CondDecls, CondStatements),
+		ml_gen_info_pop_success_cont,
+
+		% generate the `then_func'
@@ -2610,9 +2622 @@
-		% generate the main body
-		ml_gen_set_cond_var(CondVar, const(false), Context,
-			SetCondFalse),
-		ml_get_env_ptr(EnvPtrRval),
-		{ SuccessCont = success_cont(ThenFuncLabelRval, EnvPtrRval,
-			[], []) },
-		ml_gen_info_push_success_cont(SuccessCont),
-		ml_gen_goal(model_non, Cond, CondDecls, CondStatements),
-		ml_gen_info_pop_success_cont,
+		% generate `if (!cond_<N>) { <Else> }'
--- compiler/ml_code_util.m
+++ compiler/ml_code_util.m
@@ -255 +255 @@
-:- pred ml_decl_is_static(mlds__defn::in) is semidet.
+:- pred ml_decl_is_static_const(mlds__defn::in) is semidet.
@@ -525,0 +526,20 @@
+	% Generate a new `const' sequence number.
+	% This is used to give unique names to the local constants
+	% generated for --static-ground-terms.
+:- type const_seq == int.
+:- pred ml_gen_info_new_const(const_seq,
+		ml_gen_info, ml_gen_info).
+:- mode ml_gen_info_new_const(out, in, out) is det.
+
+	% Set the `const' sequence number
+	% corresponding to a given HLDS variable.
+	%
+:- pred ml_gen_info_set_const_num(prog_var, const_seq, ml_gen_info, ml_gen_info).
+:- mode ml_gen_info_set_const_num(in, in, in, out) is det.
+
+	% Lookup the `const' sequence number
+	% corresponding to a given HLDS variable.
+	%
+:- pred ml_gen_info_lookup_const_num(prog_var, const_seq, ml_gen_info, ml_gen_info).
+:- mode ml_gen_info_lookup_const_num(in, out, in, out) is det.
+
@@ -740 +760 @@
-		% generate the `succ_func'
+		% allocate a name for the `succ_func'
@@ -742,9 +761,0 @@
-		/* push nesting level */
-		DoGenRest(RestDecls, RestStatements),
-		{ list__filter(ml_decl_is_static, RestDecls, RestStaticDecls,
-			RestOtherDecls) },
-		{ RestStatement = ml_gen_block(RestOtherDecls, RestStatements,
-			Context) },
-		/* pop nesting level */
-		ml_gen_nondet_label_func(RestFuncLabel, Context, RestStatement,
-			RestFunc),
@@ -751,0 +763 @@
+		% generate <First && succ_func()>
@@ -758,0 +771,11 @@
+		% generate the `succ_func'
+		/* push nesting level */
+		DoGenRest(RestDecls, RestStatements),
+		{ list__filter(ml_decl_is_static_const, RestDecls,
+			RestStaticDecls, RestOtherDecls) },
+		{ RestStatement = ml_gen_block(RestOtherDecls, RestStatements,
+			Context) },
+		/* pop nesting level */
+		ml_gen_nondet_label_func(RestFuncLabel, Context, RestStatement,
+			RestFunc),
+
@@ -767 +790 @@
-ml_decl_is_static(Defn) :-
+ml_decl_is_static_const(Defn) :-
@@ -1585 +1608 @@
-% Only the `func_label', `commit_label', `cond_var', `conv_var',
+% Only the `func_label', `commit_label', `cond_var', `conv_var', `const_num',
@@ -1612,0 +1636,2 @@
+			const_num :: const_seq,
+			const_num_map :: map(prog_var, const_seq),
@@ -1638,0 +1664,2 @@
+	ConstCounter = 0,
+	map__init(ConstNumMap),
@@ -1653,0 +1681,2 @@
+			ConstCounter,
+			ConstNumMap,
@@ -1696,0 +1726,9 @@
+
+ml_gen_info_new_const(ConstVar, Info, Info^const_num := ConstVar) :-
+	ConstVar = Info^const_num + 1.
+
+ml_gen_info_set_const_num(Var, ConstVar, Info,
+	Info^const_num_map := map__set(Info^const_num_map, Var, ConstVar)).
+
+ml_gen_info_lookup_const_num(Var, ConstVar, Info, Info) :-
+	ConstVar = map__lookup(Info^const_num_map, Var).
--- compiler/ml_unify_gen.m
+++ compiler/ml_unify_gen.m
@@ -1094 +1094 @@
-		ml_gen_info_new_conv_var(SequenceNum),
+		ml_gen_info_new_const(SequenceNum),
@@ -1127 +1127,5 @@
-	% for a given variable.
+	% for a given variable.  To ensure that the names
+	% are unique, we qualify them with both the pred_id
+	% number, and a sequence number.  This is needed to
+	% allow ml_elim_nested.m to hoist such constants out
+	% to top level.
@@ -1132,0 +1137,16 @@
+	ml_gen_info_new_const(SequenceNum),
+	ml_gen_info_set_const_num(Var, SequenceNum),
+	ml_format_static_const_name(Var, SequenceNum, ConstName).
+
+:- pred ml_lookup_static_const_name(prog_var, mlds__var_name,
+		ml_gen_info, ml_gen_info).
+:- mode ml_lookup_static_const_name(in, out, in, out) is det.
+ml_lookup_static_const_name(Var, ConstName) -->
+	ml_gen_info_lookup_const_num(Var, SequenceNum),
+	ml_format_static_const_name(Var, SequenceNum, ConstName).
+
+:- pred ml_format_static_const_name(prog_var, const_seq, mlds__var_name,
+		ml_gen_info, ml_gen_info).
+:- mode ml_format_static_const_name(in, in, out, in, out) is det.
+
+ml_format_static_const_name(Var, SequenceNum, ConstName) -->
@@ -1133,0 +1154,2 @@
+	{ ml_gen_info_get_pred_id(MLDSGenInfo, PredId) },
+	{ pred_id_to_int(PredId, PredIdNum) },
@@ -1136 +1158,2 @@
-	{ string__format("const_%s", [s(VarName)], ConstName) }.
+	{ string__format("const_%d_%d_%s", [i(PredIdNum), i(SequenceNum),
+		s(VarName)], ConstName) }.
@@ -1145 +1168 @@
-	ml_gen_static_const_name(Var, ConstName),
+	ml_lookup_static_const_name(Var, ConstName),
--- static.m
+++ static.m
@@ -13,0 +14,3 @@
+:- pred t(t::in, t4::out, t5::out) is semidet.
+:- pred u(t4::out, t5::out, int::out) is nondet.
+:- pred v(t4::out, t5::out, int::out) is nondet.
@@ -16 +19 @@
-:- import_module int.
+:- import_module int, list.
@@ -63,0 +67,40 @@
+
+% Test same variable having different constant values in different branches (semidet)
+t(X, Result, Y) :-
+	(
+		X = a,
+		Result = f("hello", 0),
+		Y = g(Result, Result)
+	;
+		X = b,
+		Result = f("goodbye", 0),
+		Y = g(Result, Result)
+	).
+
+% Test same variable having different constant values in different branches (nondet)
+u(Result, Y, Z) :-
+	(
+		Result = f("hello", 0),
+		list__member(Z, [1,2]),
+		Y = g(Result, Result)
+	;
+		Result = f("hello again", 0),
+		Result2 = f("GoodBye", 0),
+		list__member(Z, [3,4]),
+		Y = g(Result, Result2)
+	).
+
+% Exactly the same as u/3, but with different constants;
+% this tests to ensure that any constant values hoisted
+% out to the top level are given distinct names.
+v(Result, Y, Z) :-
+	(
+		Result = f("xxxxx", 0),
+		list__member(Z, [1,2]),
+		Y = g(Result, Result)
+	;
+		Result = f("yyyyyyyyyyy", 0),
+		Result2 = f("zzzzzzz", 0),
+		list__member(Z, [3,4]),
+		Y = g(Result, Result2)
+	).
--- compiler/ml_elim_nested.m	2000/10/14 04:00:16	1.13
+++ compiler/ml_elim_nested.m	2000/10/22 06:52:41
@@ -102,7 +102,10 @@
 % Actually the description above is slightly over-simplified: not all local
 % variables need to be put in the environment struct.  Only those local
 % variables which are referenced by nested functions need to be
-% put in the environment struct.
+% put in the environment struct.  Also, if none of the nested functions
+% refer to the locals in the outer function, we don't need to create
+% an environment struct at all, we just need to hoist the definitions
+% of the nested functions out to the top level.
 %
 % The `env_ptr' variables generated here serve as definitions for
 % the (previously dangling) references to such variables that
@@ -130,8 +133,12 @@
 
 :- implementation.
 :- import_module bool, int, list, std_util, string, require.
+
+:- import_module ml_code_util.
+
 % the following imports are needed for mangling pred names
 :- import_module hlds_pred, prog_data, prog_out.
+
 :- import_module globals, options.
 
 	% Eliminated nested functions for the whole MLDS.
@@ -164,22 +171,30 @@
 		%
 		% traverse the function body, finding (and removing)
 		% any nested functions, and fixing up any references
-		% to the arguments or to local variables which
-		% occur in nested functions
+		% to the arguments or to local variables or local
+		% static constants which occur in nested functions
 		%
 		ElimInfo0 = elim_info_init(ModuleName, OuterVars, EnvTypeName),
 		Params = mlds__func_params(Arguments, _RetValues),
 		ml_maybe_add_args(Arguments, FuncBody0, ModuleName,
 			Context, ElimInfo0, ElimInfo1),
 		flatten_statement(FuncBody0, FuncBody1, ElimInfo1, ElimInfo),
-		elim_info_finish(ElimInfo, NestedFuncs0, LocalVars),
+		elim_info_finish(ElimInfo, NestedFuncs0, Locals),
 
 		%
-		% if there were no nested functions, then we're done
+		% Split the locals that we need to process
+		% into local variables and local static constants
+		%
+		list__filter(ml_decl_is_static_const, Locals,
+			LocalStatics, LocalVars),
+
+		%
+		% if there were no nested functions, then we just
+		% hoist the local static constants
 		%
 		( NestedFuncs0 = [] ->
 			FuncBody = FuncBody1,
-			HoistedDefns = []
+			HoistedDefns = LocalStatics
 		;
 			%
 			% Create a struct to hold the local variables,
@@ -195,6 +210,9 @@
 					Globals), NestedFuncs0, NestedFuncs,
 					no, InsertedEnv),
 
+			% Hoist out the local statics and the nested functions
+			HoistedDefns0 = list__append(LocalStatics, NestedFuncs),
+
 			% 
 			% It's possible that none of the nested
 			% functions reference the arguments or locals of
@@ -233,17 +251,15 @@
 						[InitEnv | CodeToCopyArgs], 
 						[FuncBody1]), Context),
 				%
-				% hoist the nested functions out, by
-				% inserting the environment struct type
-				% and the previously nested functions at
-				% the start of the list of definitions,
-				% followed by the new version of the
-				% top-level function
+				% insert the environment struct type
+				% at the start of the list of hoisted definitions
+				% (preceding the previously nested functions
+				% and static constants in HoistedDefns0),
 				%
-				HoistedDefns = [EnvTypeDefn | NestedFuncs]
+				HoistedDefns = [EnvTypeDefn | HoistedDefns0]
 			;
 				FuncBody = FuncBody1,
-				HoistedDefns = NestedFuncs
+				HoistedDefns = HoistedDefns0
 			)
 		),
 		DefnBody = mlds__function(PredProcId, Params, yes(FuncBody)),
@@ -256,7 +272,7 @@
 
 	%
 	% Add any arguments which are used in nested functions
-	% to the local_vars field in the elim_info.
+	% to the local_data field in the elim_info.
 	%
 :- pred ml_maybe_add_args(mlds__arguments, mlds__statement,
 		mlds_module_name, mlds__context, elim_info, elim_info).
@@ -266,10 +282,10 @@
 ml_maybe_add_args([Arg|Args], FuncBody, ModuleName, Context) -->
 	(
 		{ Arg = data(var(VarName)) - _Type },
-		{ ml_should_add_local_var(ModuleName, VarName, [], [FuncBody]) }
+		{ ml_should_add_local_data(ModuleName, VarName, [], [FuncBody]) }
 	->
 		{ ml_conv_arg_to_var(Context, Arg, ArgToCopy) },
-		elim_info_add_local_var(ArgToCopy)
+		elim_info_add_local_data(ArgToCopy)
 	;
 		[]
 	),
@@ -291,7 +307,7 @@
 			ArgsToCopy0, CodeToCopyArgs0),
 	(
 		Arg = data(var(VarName)) - FieldType,
-		ml_should_add_local_var(ModuleName, VarName, [], [FuncBody])
+		ml_should_add_local_data(ModuleName, VarName, [], [FuncBody])
 	->
 		ml_conv_arg_to_var(Context, Arg, ArgToCopy),
 
@@ -721,7 +737,7 @@
 		% If that wasn't the case, we'd need code something
 		% like this:
 		/***************
-		{ LocalVars = elim_info_get_local_vars(ElimInfo) },
+		{ LocalVars = elim_info_get_local_data(ElimInfo) },
 		{ OuterVars0 = elim_info_get_outer_vars(ElimInfo) },
 		{ OuterVars = [LocalVars | OuterVars0] },
 		{ FlattenedDefns = ml_elim_nested_defns(ModuleName,
@@ -746,10 +762,10 @@
 		{ ModuleName = elim_info_get_module_name(ElimInfo) },
 		(
 			{ Name = data(var(VarName)) },
-			{ ml_should_add_local_var(ModuleName, VarName,
+			{ ml_should_add_local_data(ModuleName, VarName,
 				FollowingDefns, FollowingStatements) }
 		->
-			elim_info_add_local_var(Defn0),
+			elim_info_add_local_data(Defn0),
 			{ Defns = [] }
 		;
 			{ Defns = [Defn0] }
@@ -767,14 +783,29 @@
 	).
 
 	%
-	% check for a nested function definition
-	% that references this variable
+	% Succeed iff we should add the definition of this variable
+	% to the local_data field of the ml_elim_info, meaning that
+	% it should be added to the environment struct
+	% (if it's a variable) or hoisted out to the top level
+	% (if it's a static const).
 	%
-:- pred ml_should_add_local_var(mlds_module_name, mlds__var_name,
+	% This checks for a nested function definition
+	% or static initializer that references the variable.
+	% This is conservative; we only need to hoist out
+	% static variables if they are referenced by
+	% static initializers which themselves need to be
+	% hoisted because they are referenced from a nested
+	% function.  But checking the last part of that
+	% is tricky, so currently we just hoist more
+	% of the static consts than we strictly need to.
+	% Perhaps it would be simpler to just hoist *all*
+	% static consts.
+	%
+:- pred ml_should_add_local_data(mlds_module_name, mlds__var_name,
 		mlds__defns, mlds__statements).
-:- mode ml_should_add_local_var(in, in, in, in) is semidet.
+:- mode ml_should_add_local_data(in, in, in, in) is semidet.
 
-ml_should_add_local_var(ModuleName, VarName,
+ml_should_add_local_data(ModuleName, VarName,
 		FollowingDefns, FollowingStatements) :-
 	QualVarName = qual(ModuleName, VarName),
 	(
@@ -783,9 +814,16 @@
 		statements_contains_defn(FollowingStatements,
 			FollowingDefn)
 	),
-	FollowingDefn = mlds__defn(_, _, _,
-		mlds__function(_, _, _)),
-	defn_contains_var(FollowingDefn, QualVarName).
+	(
+		FollowingDefn = mlds__defn(_, _, _,
+			mlds__function(_, _, _)),
+		defn_contains_var(FollowingDefn, QualVarName)
+	;
+		FollowingDefn = mlds__defn(_, _, _,
+			mlds__data(_, Initializer)),
+		ml_decl_is_static_const(FollowingDefn),
+		initializer_contains_var(Initializer, QualVarName)
+	).
 
 %-----------------------------------------------------------------------------%
 
@@ -923,7 +961,7 @@
 fixup_var(ThisVar, Lval, ElimInfo, ElimInfo) :-
 	ThisVar = qual(ThisVarModuleName, ThisVarName),
 	ModuleName = elim_info_get_module_name(ElimInfo),
-	LocalVars = elim_info_get_local_vars(ElimInfo),
+	Locals = elim_info_get_local_data(ElimInfo),
 	ClassType = elim_info_get_env_type_name(ElimInfo),
 	(
 		%
@@ -932,12 +970,13 @@
 		% and replace them with `env_ptr->foo'.
 		%
 		ThisVarModuleName = ModuleName,
-		IsLocal = (pred(VarType::out) is nondet :-
-			list__member(Var, LocalVars),
+		IsLocalVar = (pred(VarType::out) is nondet :-
+			list__member(Var, Locals),
 			Var = mlds__defn(data(var(ThisVarName)), _, _, 
-				data(VarType, _))
+				data(VarType, _)),
+			\+ ml_decl_is_static_const(Var)
 			),
-		solutions(IsLocal, [FieldType])
+		solutions(IsLocalVar, [FieldType])
 	->
 		EnvPtr = lval(var(qual(ModuleName, "env_ptr"))),
 		EnvModuleName = ml_env_module_name(ClassType),
@@ -963,7 +1002,7 @@
 		% for `env.foo'.)
 		%
 		ThisVarModuleName = ModuleName,
-		list__member(Var, LocalVars),
+		list__member(Var, Locals),
 		Var = mlds__defn(data(var(ThisVarName)), _, _, _)
 	->
 		Env = var(qual(ModuleName, "env")),
@@ -1381,7 +1420,7 @@
 				% The list of local variables that we must
 				% put in the environment structure
 				% This list is stored in reverse order.
-			local_vars :: list(mlds__defn),
+			local_data :: list(mlds__defn),
 				
 				% Type of the introduced environment struct
 			env_type_name :: mlds__type
@@ -1402,8 +1441,8 @@
 :- func elim_info_get_outer_vars(elim_info) = outervars.
 elim_info_get_outer_vars(ElimInfo) = ElimInfo ^ outer_vars.
 
-:- func elim_info_get_local_vars(elim_info) = list(mlds__defn).
-elim_info_get_local_vars(ElimInfo) = ElimInfo ^ local_vars.
+:- func elim_info_get_local_data(elim_info) = list(mlds__defn).
+elim_info_get_local_data(ElimInfo) = ElimInfo ^ local_data.
 
 :- func elim_info_get_env_type_name(elim_info) = mlds__type.
 elim_info_get_env_type_name(ElimInfo) = ElimInfo ^ env_type_name.
@@ -1413,15 +1452,15 @@
 elim_info_add_nested_func(NestedFunc, ElimInfo, 
 	ElimInfo ^ nested_funcs := [NestedFunc | ElimInfo ^ nested_funcs]).
 
-:- pred elim_info_add_local_var(mlds__defn, elim_info, elim_info).
-:- mode elim_info_add_local_var(in, in, out) is det.
-elim_info_add_local_var(LocalVar, ElimInfo,
-	ElimInfo ^ local_vars := [LocalVar | ElimInfo ^ local_vars]).
+:- pred elim_info_add_local_data(mlds__defn, elim_info, elim_info).
+:- mode elim_info_add_local_data(in, in, out) is det.
+elim_info_add_local_data(LocalVar, ElimInfo,
+	ElimInfo ^ local_data := [LocalVar | ElimInfo ^ local_data]).
 
 :- pred elim_info_finish(elim_info, list(mlds__defn), list(mlds__defn)).
 :- mode elim_info_finish(in, out, out) is det.
-elim_info_finish(ElimInfo, Funcs, LocalVars) :-
+elim_info_finish(ElimInfo, Funcs, Locals) :-
 	Funcs = list__reverse(ElimInfo ^ nested_funcs),
-	LocalVars = list__reverse(ElimInfo ^ local_vars).
+	Locals = list__reverse(ElimInfo ^ local_data).
 
 %-----------------------------------------------------------------------------%
--- compiler/mlds_to_c.m	2000/10/06 10:18:26	1.58
+++ compiler/mlds_to_c.m	2000/10/22 02:26:12
@@ -759,14 +759,7 @@
 		% Now output the declaration for this mlds__defn.
 		%
 		mlds_indent(Context, Indent),
-		( { Name = data(_) } ->
-			% XXX for private data and private functions,
-			% we should use "static"
-			io__write_string("extern ")
-		;
-			[]
-		),
-		mlds_output_decl_flags(Flags),
+		mlds_output_decl_flags(Flags, forward_decl, Name),
 		mlds_output_decl_body(Indent, qual(ModuleName, Name), Context,
 			DefnBody)
 	).
@@ -846,7 +839,7 @@
 		[]
 	),
 	mlds_indent(Context, Indent),
-	mlds_output_decl_flags(Flags),
+	mlds_output_decl_flags(Flags, definition, Name),
 	mlds_output_defn_body(Indent, qual(ModuleName, Name), Context,
 			DefnBody).
 
@@ -1646,41 +1639,88 @@
 % Code to output declaration specifiers
 %
 
-:- pred mlds_output_decl_flags(mlds__decl_flags, io__state, io__state).
-:- mode mlds_output_decl_flags(in, di, uo) is det.
+:- type decl_or_defn
+	--->	forward_decl
+	;	definition.
 
-mlds_output_decl_flags(Flags) -->
-	mlds_output_access(access(Flags)),
-	mlds_output_per_instance(per_instance(Flags)),
+:- pred mlds_output_decl_flags(mlds__decl_flags, decl_or_defn,
+		mlds__entity_name, io__state, io__state).
+:- mode mlds_output_decl_flags(in, in, in, di, uo) is det.
+
+mlds_output_decl_flags(Flags, DeclOrDefn, Name) -->
+	%
+	% mlds_output_extern_or_static handles both the
+	% `access' and the `per_instance' fields of the mlds__decl_flags.
+	% We have to handle them together because C overloads `static'
+	% to mean both `private' and `one_copy', rather than having
+	% separate keywords for each.  To make it clear which MLDS
+	% construct each `static' keyword means, we precede the `static'
+	% without (optionally-enabled) comments saying whether it is
+	% `private', `one_copy', or both.
+	%
+	mlds_output_access_comment(access(Flags)),
+	mlds_output_per_instance_comment(per_instance(Flags)),
+	mlds_output_extern_or_static(access(Flags), per_instance(Flags),
+		DeclOrDefn, Name),
 	mlds_output_virtuality(virtuality(Flags)),
 	mlds_output_finality(finality(Flags)),
 	mlds_output_constness(constness(Flags)),
 	mlds_output_abstractness(abstractness(Flags)).
 
-:- pred mlds_output_access(access, io__state, io__state).
-:- mode mlds_output_access(in, di, uo) is det.
+:- pred mlds_output_access_comment(access, io__state, io__state).
+:- mode mlds_output_access_comment(in, di, uo) is det.
 
-mlds_output_access(Access) -->
+mlds_output_access_comment(Access) -->
 	globals__io_lookup_bool_option(auto_comments, Comments),
 	( { Comments = yes } ->
-		mlds_output_access_2(Access)
+		mlds_output_access_comment_2(Access)
 	;
 		[]
 	).
 
-:- pred mlds_output_access_2(access, io__state, io__state).
-:- mode mlds_output_access_2(in, di, uo) is det.
+:- pred mlds_output_access_comment_2(access, io__state, io__state).
+:- mode mlds_output_access_comment_2(in, di, uo) is det.
 
-mlds_output_access_2(public)    --> [].
-mlds_output_access_2(private)   --> io__write_string("/* private: */ ").
-mlds_output_access_2(protected) --> io__write_string("/* protected: */ ").
-mlds_output_access_2(default)   --> io__write_string("/* default access */ ").
+mlds_output_access_comment_2(public)    --> [].
+mlds_output_access_comment_2(private)   --> io__write_string("/* private: */ ").
+mlds_output_access_comment_2(protected) --> io__write_string("/* protected: */ ").
+mlds_output_access_comment_2(default)   --> io__write_string("/* default access */ ").
 
-:- pred mlds_output_per_instance(per_instance, io__state, io__state).
-:- mode mlds_output_per_instance(in, di, uo) is det.
+:- pred mlds_output_per_instance_comment(per_instance, io__state, io__state).
+:- mode mlds_output_per_instance_comment(in, di, uo) is det.
 
-mlds_output_per_instance(one_copy)     --> io__write_string("static ").
-mlds_output_per_instance(per_instance) --> [].
+mlds_output_per_instance_comment(PerInstance) -->
+	globals__io_lookup_bool_option(auto_comments, Comments),
+	( { Comments = yes } ->
+		mlds_output_per_instance_comment_2(PerInstance)
+	;
+		[]
+	).
+
+:- pred mlds_output_per_instance_comment_2(per_instance, io__state, io__state).
+:- mode mlds_output_per_instance_comment_2(in, di, uo) is det.
+
+mlds_output_per_instance_comment_2(per_instance) --> [].
+mlds_output_per_instance_comment_2(one_copy)     --> io__write_string("/* one_copy */ ").
+
+:- pred mlds_output_extern_or_static(access, per_instance, decl_or_defn,
+		mlds__entity_name, io__state, io__state).
+:- mode mlds_output_extern_or_static(in, in, in, in, di, uo) is det.
+
+mlds_output_extern_or_static(Access, PerInstance, DeclOrDefn, Name) -->
+	(
+		{ Access = private ; PerInstance = one_copy },
+		{ Name \= type(_, _) }
+	->
+		io__write_string("static ")
+	;
+		{ DeclOrDefn = forward_decl },
+		{ Name = data(_) }
+	->
+		io__write_string("extern ")
+	;
+		[]
+	).
 
 :- pred mlds_output_virtuality(virtuality, io__state, io__state).
 :- mode mlds_output_virtuality(in, di, uo) is det.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
                                    |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list