diff --git a/compiler/accumulator.m b/compiler/accumulator.m
index 84c9a384c..90dfa58cc 100644
--- a/compiler/accumulator.m
+++ b/compiler/accumulator.m
@@ -313,7 +313,7 @@ accu_transform_proc(ProgressStream, proc(PredId, ProcId), PredInfo,
                 verbose_only(verbose_once, VerbosePieces)]),
             Msgs = [InMsg | WarnMsgs] ++ [EnsureSuppressMsg],
             Severity = severity_warning(warn_accumulator_swaps),
-            Spec = diag_spec($pred, Severity, phase_accumulator_intro, Msgs),
+            Spec = gen_spec($pred, Severity, phase_accumulator_intro, Msgs),
 
             det_univ_to_type(!.Cookie, Specs0),
             Specs = [Spec | Specs0] : list(diag_spec),
diff --git a/compiler/add_class.m b/compiler/add_class.m
index 63aa2a61b..1e2f7b1ee 100644
--- a/compiler/add_class.m
+++ b/compiler/add_class.m
@@ -22,11 +22,11 @@
 
 :- pred add_typeclass_defns(sec_list(item_typeclass_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 :- pred add_instance_defns(ims_list(item_instance_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -86,7 +86,7 @@ add_instance_defns([ImsSubList | ImsSubLists], !ModuleInfo, !Specs) :-
 :- pred add_typeclass_defn(item_mercury_status::in,
     typeclass_status::in, need_qualifier::in, item_typeclass_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_typeclass_defn(ItemMercuryStatus, TypeClassStatus0, NeedQual,
         ItemTypeClassInfo, !ModuleInfo, !Specs) :-
@@ -259,7 +259,7 @@ class_fundeps_are_identical(OldFunDeps, FunDeps) :-
     typeclass_status::in, item_mercury_status::in,
     need_qualifier::in, list(class_decl)::in, list(method_info)::out,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 module_declare_class_method_preds(ClassName, ClassParamVars, TypeClassStatus,
         ItemMercuryStatus, NeedQual, ClassDecls, MethodInfos,
@@ -358,7 +358,7 @@ classify_class_decls([Decl | Decls], !PredOrFuncInfos, !ModeDeclMap) :-
     map(pred_pf_name_arity, cord(class_mode_info))::in,
     map(pred_pf_name_arity, cord(class_mode_info))::out,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_class_pred_or_func_and_mode_decls(ClassName, ClassParamVars,
         ItemMercuryStatus, PredStatus, NeedQual, PredOrFuncInfo,
@@ -477,7 +477,7 @@ add_class_pred_or_func_and_mode_decls(ClassName, ClassParamVars,
     pred_pf_name_arity::in, pred_id::in, class_mode_info::in,
     int::in, int::out, cord(method_info)::in, cord(method_info)::out,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_class_mode_decl(ItemMercuryStatus, PredStatus, MethodPredName, PredId,
         ModeInfo, !MethodProcNum, !MethodInfosCord, !ModuleInfo, !Specs) :-
@@ -502,7 +502,7 @@ add_class_mode_decl(ItemMercuryStatus, PredStatus, MethodPredName, PredId,
 
 :- pred add_instance_defn(instance_status::in, item_instance_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_instance_defn(InstanceStatus0, ItemInstanceInfo, !ModuleInfo, !Specs) :-
     ItemInstanceInfo = item_instance_info(ClassName, Types, OriginalTypes,
@@ -548,7 +548,7 @@ add_instance_defn(InstanceStatus0, ItemInstanceInfo, !ModuleInfo, !Specs) :-
 %---------------------------------------------------------------------------%
 
 :- pred pred_method_with_no_modes_error(pred_info::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 pred_method_with_no_modes_error(PredInfo, !Specs) :-
     PorF = pred_info_is_pred_or_func(PredInfo),
@@ -564,7 +564,7 @@ pred_method_with_no_modes_error(PredInfo, !Specs) :-
     !:Specs = [Spec | !.Specs].
 
 :- pred report_instance_for_undefined_typeclass(class_id::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_instance_for_undefined_typeclass(ClassId, Context, !Specs) :-
     Pieces = [words("Error:"),
@@ -577,7 +577,7 @@ report_instance_for_undefined_typeclass(ClassId, Context, !Specs) :-
 
 :- pred report_mode_decls_for_undeclared_method(pred_pf_name_arity::in,
     cord(class_mode_info)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_mode_decls_for_undeclared_method(MethodPredName, ModeInfosCord,
         !Specs) :-
@@ -587,7 +587,7 @@ report_mode_decls_for_undeclared_method(MethodPredName, ModeInfosCord,
 
 :- pred report_mode_decl_for_undeclared_method(pred_pf_name_arity::in,
     class_mode_info::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_mode_decl_for_undeclared_method(MethodPredName, ModeInfo, !Specs) :-
     MethodPredName = pred_pf_name_arity(PorF, SymName, UserArity),
diff --git a/compiler/add_clause.m b/compiler/add_clause.m
index 31010a97b..988000f5b 100644
--- a/compiler/add_clause.m
+++ b/compiler/add_clause.m
@@ -35,7 +35,8 @@
 :- pred module_add_clause(io.text_output_stream::in, pred_status::in,
     clause_type::in, item_clause_info::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
     % This predicate is exported for use by instance_method_clauses.m.
     %
@@ -45,7 +46,8 @@
     prog_context::in, item_seq_num::in, goal::in, prog_varset::in,
     tvarset::in, tvarset::out, clauses_info::in, clauses_info::out,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -104,7 +106,7 @@
 %-----------------------------------------------------------------------------%
 
 module_add_clause(ProgressStream, PredStatus, ClauseType, ClauseInfo,
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     ClauseInfo = item_clause_info(PredOrFunc, PredSymName, ArgTerms0,
         ClauseVarSet, MaybeBodyGoal, Context, SeqNum),
     (
@@ -141,7 +143,8 @@ module_add_clause(ProgressStream, PredStatus, ClauseType, ClauseInfo,
             add_clause_to_hlds(ProgressStream, PredStatus, ClauseType, PredId,
                 PredOrFunc, PredSymName, ArgTerms, PredFormArity,
                 ClauseVarSet, MaybeBodyGoal, Context, SeqNum,
-                IllegalSVarResult, !ModuleInfo, !QualInfo, !Specs)
+                IllegalSVarResult, !ModuleInfo, !QualInfo,
+                !ErrSpecs, !WarnSpecs)
         else if PredName = ",", Arity = 2 then
             SNA = sym_name_arity(unqualified(","), 2),
             Pieces =
@@ -153,7 +156,7 @@ module_add_clause(ProgressStream, PredStatus, ClauseType, ClauseInfo,
                     words("a period instead of a comma")]) ++
                 [words("at the end of the preceding line."), nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         else
             % A promise will not have a corresponding pred declaration.
             (
@@ -170,27 +173,29 @@ module_add_clause(ProgressStream, PredStatus, ClauseType, ClauseInfo,
                 add_implicit_pred_decl_report_error(PredOrFunc,
                     PredModuleName, PredName, PredFormArity, PredStatus,
                     is_not_a_class_method, Context, Origin,
-                    [words("clause")], PredId, !ModuleInfo, !Specs)
+                    [words("clause")], PredId, !ModuleInfo, !ErrSpecs)
             ),
             add_clause_to_hlds(ProgressStream, PredStatus, ClauseType, PredId,
                 PredOrFunc, PredSymName, ArgTerms, PredFormArity,
                 ClauseVarSet, MaybeBodyGoal, Context, SeqNum,
-                IllegalSVarResult, !ModuleInfo, !QualInfo, !Specs)
+                IllegalSVarResult, !ModuleInfo, !QualInfo,
+                !ErrSpecs, !WarnSpecs)
         )
     ).
 
 :- pred add_clause_to_hlds(io.text_output_stream::in,
     pred_status::in, clause_type::in, pred_id::in,
     pred_or_func::in, sym_name::in, list(prog_term)::in, pred_form_arity::in,
-    prog_varset::in, maybe2(goal, list(warning_spec))::in, prog_context::in,
+    prog_varset::in, parse_result2(goal)::in, prog_context::in,
     item_seq_num::in, maybe({prog_var, prog_context})::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 add_clause_to_hlds(ProgressStream, PredStatus, ClauseType, PredId,
         PredOrFunc, PredSymName, MaybeAnnotatedArgTerms, PredFormArity,
         ClauseVarSet, MaybeBodyGoal, Context, SeqNum, IllegalSVarResult,
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     some [!PredInfo, !PredSpecs] (
         % Lookup the pred_info for this pred, add the clause to the
         % clauses_info in the pred_info, if there are no modes add an
@@ -229,31 +234,35 @@ add_clause_to_hlds(ProgressStream, PredStatus, ClauseType, PredId,
         maybe_add_default_func_mode(!.ModuleInfo, !PredInfo, _),
         (
             !.PredSpecs = [_ | _ ],
-            !:Specs = !.PredSpecs ++
-                get_any_errors_warnings2(MaybeBodyGoal) ++ !.Specs
+            get_all_errors_warnings2(MaybeBodyGoal,
+                BodyGoalErrSpecs, BodyGoalWarnSpecs),
+            !:ErrSpecs = !.PredSpecs ++ BodyGoalErrSpecs ++ !.ErrSpecs,
+            !:WarnSpecs = BodyGoalWarnSpecs ++ !.WarnSpecs
         ;
             !.PredSpecs = [],
             (
-                MaybeBodyGoal = error2(BodyGoalSpecs),
-                !:Specs = one_or_more_to_list(BodyGoalSpecs) ++ !.Specs,
+                MaybeBodyGoal = error2({BodyGoalErrSpecs, BodyGoalWarnSpecs}),
+                !:ErrSpecs =
+                    one_or_more_to_list(BodyGoalErrSpecs) ++ !.ErrSpecs,
+                !:WarnSpecs = BodyGoalWarnSpecs ++ !.WarnSpecs,
                 pred_info_get_clauses_info(!.PredInfo, Clauses0),
                 Clauses = Clauses0 ^ cli_had_syntax_errors :=
                     some_clause_syntax_errors,
                 pred_info_set_clauses_info(Clauses, !PredInfo)
             ;
                 MaybeBodyGoal = ok2(BodyGoal, BodyGoalWarningSpecs),
-                !:Specs = BodyGoalWarningSpecs ++ !.Specs,
+                !:WarnSpecs = BodyGoalWarningSpecs ++ !.WarnSpecs,
                 pred_info_get_clauses_info(!.PredInfo, ClausesInfo0),
                 pred_info_get_typevarset(!.PredInfo, TVarSet0),
                 select_applicable_modes(!.ModuleInfo, MaybeAnnotatedArgTerms,
                     ClauseVarSet, PredStatus, Context, PredId, !.PredInfo,
                     ArgTerms, ProcIdsForThisClause, AllProcIds,
-                    !QualInfo, !Specs),
+                    !QualInfo, !ErrSpecs, !WarnSpecs),
                 add_clause_to_clauses_info(ProcIdsForThisClause, AllProcIds,
                     PredStatus, ClauseType, PredOrFunc, PredSymName,
                     ArgTerms, Context, SeqNum, BodyGoal, ClauseVarSet,
                     TVarSet0, TVarSet, ClausesInfo0, ClausesInfo,
-                    !ModuleInfo, !QualInfo, !Specs),
+                    !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs),
                 pred_info_set_clauses_info(ClausesInfo, !PredInfo),
                 (
                     ClauseType = clause_for_promise(_PromiseType)
@@ -320,7 +329,7 @@ add_clause_progress_msg(ProgressStream, ModuleInfo, PredInfo,
 
 :- pred maybe_add_error_for_field_access_function(module_info::in,
     pred_status::in, pred_or_func::in, sym_name::in, pred_form_arity::in,
-    prog_context::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    prog_context::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 maybe_add_error_for_field_access_function(ModuleInfo, PredStatus,
         PredOrFunc, PredSymName, PredFormArity, Context, !Specs) :-
@@ -352,7 +361,7 @@ maybe_add_error_for_field_access_function(ModuleInfo, PredStatus,
         FieldAccessMsg = simple_msg(Context,
             [always(FieldAccessMainPieces),
             verbose_only(verbose_always, FieldAccessVerbosePieces)]),
-        FieldAccessSpec = diag_spec($pred, severity_error, phase_pt2h,
+        FieldAccessSpec = gen_spec($pred, severity_error, phase_pt2h,
             [FieldAccessMsg]),
         !:Specs = [FieldAccessSpec | !.Specs]
     else
@@ -360,7 +369,7 @@ maybe_add_error_for_field_access_function(ModuleInfo, PredStatus,
     ).
 
 :- pred maybe_add_error_for_builtin(module_info::in, pred_info::in,
-    prog_context::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    prog_context::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 maybe_add_error_for_builtin(ModuleInfo, PredInfo, Context, !Specs) :-
     ( if pred_info_is_builtin(PredInfo) then
@@ -397,11 +406,12 @@ maybe_add_error_for_builtin(ModuleInfo, PredInfo, Context, !Specs) :-
     pred_id::in, pred_info::in, list(prog_term)::out,
     clause_applicable_modes::out, list(proc_id)::out,
     qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 select_applicable_modes(ModuleInfo, MaybeAnnotatedArgTerms, VarSet,
         PredStatus, Context, PredId, PredInfo, ArgTerms,
-        ApplProcIds, AllProcIds, !QualInfo, !Specs) :-
+        ApplProcIds, AllProcIds, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     AllProcIds = pred_info_all_proc_ids(PredInfo),
     PredIdStr = pred_id_to_user_string(ModuleInfo, PredId),
     ContextPieces = cord.from_list([words("In the head of a clause for"),
@@ -410,7 +420,7 @@ select_applicable_modes(ModuleInfo, MaybeAnnotatedArgTerms, VarSet,
         ArgTerms, ArgModes0, ArgsWithoutModes, ModeAnnotationSpecs),
     (
         ModeAnnotationSpecs = [_ | _],
-        !:Specs = ModeAnnotationSpecs ++ !.Specs,
+        !:ErrSpecs = ModeAnnotationSpecs ++ !.ErrSpecs,
         % Apply the clause to all modes.
         % XXX Would it be better to apply it to none?
         ApplProcIds = selected_modes(AllProcIds)
@@ -485,7 +495,7 @@ select_applicable_modes(ModuleInfo, MaybeAnnotatedArgTerms, VarSet,
                         Severity = severity_warning(warn_redundant_code),
                         Spec = spec($pred, Severity, phase_pt2h,
                             Context, Pieces),
-                        !:Specs = [Spec | !.Specs]
+                        !:WarnSpecs = [Spec | !.WarnSpecs]
                     ;
                         Warn = no
                     )
@@ -495,7 +505,7 @@ select_applicable_modes(ModuleInfo, MaybeAnnotatedArgTerms, VarSet,
             else
                 report_undeclared_mode_error(ModuleInfo, PredId, PredInfo,
                     VarSet, ArgModes, [words("clause")], Context, UndefSpec),
-                !:Specs = [UndefSpec | !.Specs],
+                !:ErrSpecs = [UndefSpec | !.ErrSpecs],
                 % Apply the clause to all modes.
                 % XXX Would it be better to apply it to none?
                 ApplProcIds = selected_modes(AllProcIds)
@@ -517,7 +527,7 @@ select_applicable_modes(ModuleInfo, MaybeAnnotatedArgTerms, VarSet,
                     [suffix(".")], ArgsWithoutModePieces) ++
                 [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs],
+            !:ErrSpecs = [Spec | !.ErrSpecs],
 
             % Apply the clause to all modes.
             % XXX Would it be better to apply it to none?
@@ -531,7 +541,7 @@ select_applicable_modes(ModuleInfo, MaybeAnnotatedArgTerms, VarSet,
     %
 :- pred get_mode_annotations(prog_varset::in, cord(format_piece)::in,
     int::in, list(prog_term)::in, list(prog_term)::out,
-    list(mer_mode)::out, list(int)::out, list(diag_spec)::out) is det.
+    list(mer_mode)::out, list(int)::out, list(err_spec)::out) is det.
 
 get_mode_annotations(_, _, _, [], [], [], [], []).
 get_mode_annotations(VarSet, ContextPieces, ArgNum, [MAArgTerm | MAArgTerms],
@@ -598,7 +608,7 @@ get_mode_annotation(VarSet, ContextPieces, ArgNum, MaybeAnnotatedArgTerm,
 add_clause_to_clauses_info(ApplModeIds0, AllModeIds, PredStatus, ClauseType,
         PredOrFunc, PredSymName, ArgTerms, Context, SeqNum, BodyGoal,
         ClauseVarSet, TVarSet0, TVarSet,
-        !ClausesInfo, !ModuleInfo, !QualInfo, !Specs) :-
+        !ClausesInfo, !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     !.ClausesInfo = clauses_info(VarSet0, ExplicitVarTypes0,
         VarTable0, RttiVarMaps0, TVarNameMap0, ArgVector, ClausesRep0,
         ItemNumbers0, HasForeignClauses0, HadSyntaxError0),
@@ -640,7 +650,7 @@ add_clause_to_clauses_info(ApplModeIds0, AllModeIds, PredStatus, ClauseType,
     add_clause_transform(KeepQuantVars, Renaming, PredOrFunc, PredSymName,
         HeadVars, ArgTerms, Context, ClauseType, BodyGoal, Goal0,
         VarSet1, VarSet2, QuantWarnings, StateVarWarnings, UnusedSVarArgMap,
-        !ModuleInfo, !QualInfo, !Specs),
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs),
     qual_info_get_tvarset(!.QualInfo, TVarSet),
     qual_info_get_found_syntax_error(!.QualInfo, FoundSyntaxError),
     (
@@ -662,10 +672,10 @@ add_clause_to_clauses_info(ApplModeIds0, AllModeIds, PredStatus, ClauseType,
             WarnPFSymNameArity = pf_sym_name_arity(PredOrFunc, PredSymName,
                 PredFormArity),
             warn_singletons_in_clause_body(!.ModuleInfo, WarnPFSymNameArity,
-                VarSet2, Goal0, SeenQuant, !Specs),
+                VarSet2, Goal0, SeenQuant, !WarnSpecs),
             % Warn about variables with overlapping scopes.
             add_quant_warnings(!.ModuleInfo, WarnPFSymNameArity, VarSet,
-                QuantWarnings, !Specs),
+                QuantWarnings, !WarnSpecs),
             (
                 SeenQuant = have_not_seen_quant,
                 % Even though we told the call to add_clause_transform above
@@ -804,15 +814,16 @@ should_we_do_singleton_and_quant_warnings(ModuleInfo, PredStatus, ClausesInfo,
     pred_or_func::in, sym_name::in, list(prog_var)::in,
     list(prog_term)::in, prog_context::in, clause_type::in,
     goal::in, hlds_goal::out, prog_varset::in, prog_varset::out,
-    list(quant_warning)::out, list(diag_spec)::out,
+    list(quant_warning)::out, list(warn_spec)::out,
     unused_statevar_arg_map::out,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 add_clause_transform(KeepQuantVars, Renaming, PredOrFunc, PredSymName,
         HeadVars, ArgTerms0, Context, ClauseType, ParseTreeBodyGoal, Goal,
         !VarSet, QuantWarnings, StateVarWarningSpecs, UnusedSVarArgMap,
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     some [!SVarState, !UrInfo] (
         rename_vars_in_term_list(need_not_rename, Renaming,
             ArgTerms0, ArgTerms1),
@@ -858,8 +869,10 @@ add_clause_transform(KeepQuantVars, Renaming, PredOrFunc, PredSymName,
             InitialSVarState, FinalSVarState, HeadUnificationsGoal, BodyGoal,
             Goal0, StateVarWarningSpecs, UnusedSVarArgMap, !UrInfo),
         !.UrInfo = unravel_info(!:ModuleInfo, _FgtThreshold,
-            !:QualInfo, !:VarSet, _SVarStore, UnravelSpecs),
-        !:Specs = UnravelSpecs ++ !.Specs,
+            !:QualInfo, !:VarSet, _SVarStore,
+            ErrUnravelSpecs, WarnUnravelSpecs),
+        !:ErrSpecs = ErrUnravelSpecs ++ !.ErrSpecs,
+        !:WarnSpecs = WarnUnravelSpecs ++ !.WarnSpecs,
 
         trace [compiletime(flag("debug-statevar-lambda")), io(!IO)] (
             module_info_get_globals(!.ModuleInfo, Globals),
diff --git a/compiler/add_foreign_enum.m b/compiler/add_foreign_enum.m
index 5c16937c1..e44f5f6fd 100644
--- a/compiler/add_foreign_enum.m
+++ b/compiler/add_foreign_enum.m
@@ -61,7 +61,7 @@
 :- pred add_pragma_foreign_enum(module_info::in,
     {item_mercury_status, item_foreign_enum_info}::in,
     type_ctor_to_foreign_enums_map::in, type_ctor_to_foreign_enums_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -74,7 +74,7 @@
     %
 :- pred add_pragma_foreign_export_enum(item_foreign_export_enum_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -377,7 +377,7 @@ add_pragma_foreign_export_enum(ItemForeignExportEnum, !ModuleInfo,
     prog_context::in, foreign_language::in, string::in,
     uppercase_export_enum::in, map(string, string)::in,
     list(constructor_repn)::in, map(string, string)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 build_export_enum_name_map(ContextPieces, Context, Lang, Prefix, MakeUpperCase,
         OverrideMap, CtorRepns, NameMap, !Specs) :-
@@ -473,7 +473,7 @@ add_ctor_to_name_map(_Lang, Prefix, MakeUpperCase, OverrideMap, CtorRepn,
     prog_context::in, for_fe_or_fee::in,
     prog_context::in, list(format_piece)::in, list(constructor)::in,
     assoc_list(sym_name, string)::in, bimap(string, string)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 build_mercury_foreign_map(TypeModuleName, TypeCtor, TypeDefnContext, ForWhat,
         Context, ContextPieces, Ctors, Overrides, OverrideMap, !Specs) :-
@@ -518,7 +518,7 @@ find_non_enum_ctors_build_valid_ctor_names([Ctor | Ctors],
 
 :- pred maybe_add_duplicate_foreign_enum_error(type_ctor::in,
     foreign_language::in, type_status::in, prog_context::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 maybe_add_duplicate_foreign_enum_error(TypeCtor, Lang, PragmaStatus,
         OldContext, Context, !Specs) :-
@@ -539,7 +539,7 @@ maybe_add_duplicate_foreign_enum_error(TypeCtor, Lang, PragmaStatus,
             words("was here."), nl],
         CurMsg = msg(Context, CurPieces),
         OldMsg = msg(OldContext, OldPieces),
-        Spec = diag_spec($pred, severity_error, phase_pt2h, [CurMsg, OldMsg]),
+        Spec = gen_spec($pred, severity_error, phase_pt2h, [CurMsg, OldMsg]),
         !:Specs = [Spec | !.Specs]
     ).
 
@@ -549,7 +549,7 @@ maybe_add_duplicate_foreign_enum_error(TypeCtor, Lang, PragmaStatus,
     % for the builtin atomic types.
     %
 :- pred report_if_builtin_type(prog_context::in, string::in, type_ctor::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_if_builtin_type(Context, DeclName, TypeCtor, !Specs) :-
     TypeCtor = type_ctor(TypeSymName, TypeArity),
@@ -577,7 +577,7 @@ report_if_builtin_type(Context, DeclName, TypeCtor, !Specs) :-
 
 :- pred report_not_enum_type_non_du(for_fe_or_fee::in,
     type_ctor::in, hlds_type_body::in(non_du_type_body), prog_context::in,
-    prog_context::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    prog_context::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 report_not_enum_type_non_du(ForWhat, TypeCtor, TypeBody, TypeDefnContext,
         EnumContext, !Specs) :-
@@ -604,7 +604,7 @@ report_not_enum_type_non_du(ForWhat, TypeCtor, TypeBody, TypeDefnContext,
         color_as_incorrect([words("there must not be any"),
             pragma_decl(PragmaName), words("declarations for it.")]) ++ [nl],
     TypePieces = [words("That Mercury definition is here."), nl],
-    Spec = diag_spec($pred, severity_error, phase_pt2h,
+    Spec = gen_spec($pred, severity_error, phase_pt2h,
         [msg(EnumContext, EnumPieces), msg(TypeDefnContext, TypePieces)]),
     !:Specs = [Spec | !.Specs].
 
diff --git a/compiler/add_foreign_proc.m b/compiler/add_foreign_proc.m
index 7496fb4fe..fd63258d0 100644
--- a/compiler/add_foreign_proc.m
+++ b/compiler/add_foreign_proc.m
@@ -21,12 +21,14 @@
 
 :- pred add_foreign_procs(io.text_output_stream::in,
     ims_list(item_foreign_proc_info)::in, module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 :- pred add_foreign_proc(io.text_output_stream::in, item_mercury_status::in,
     pred_status::in, item_foreign_proc_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -74,20 +76,21 @@
 
 %---------------------------------------------------------------------------%
 
-add_foreign_procs(_, [], !ModuleInfo, !Specs).
+add_foreign_procs(_, [], !ModuleInfo, !ErrSpecs, !WarnSpecs).
 add_foreign_procs(ProgressStream, [ImsSubList | ImsSubLists],
-        !ModuleInfo, !Specs) :-
+        !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     ImsSubList = ims_sub_list(ItemMercuryStatus, PragmaFPInfos),
     item_mercury_status_to_pred_status(ItemMercuryStatus, PredStatus),
-    list.foldl2(
+    list.foldl3(
         add_foreign_proc(ProgressStream, ItemMercuryStatus, PredStatus),
-        PragmaFPInfos, !ModuleInfo, !Specs),
-    add_foreign_procs(ProgressStream, ImsSubLists, !ModuleInfo, !Specs).
+        PragmaFPInfos, !ModuleInfo, !ErrSpecs, !WarnSpecs),
+    add_foreign_procs(ProgressStream, ImsSubLists, !ModuleInfo,
+        !ErrSpecs, !WarnSpecs).
 
 %---------------------------------------------------------------------------%
 
 add_foreign_proc(ProgressStream, ItemMercuryStatus, PredStatus, FPInfo,
-        !ModuleInfo, !Specs) :-
+        !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     FPInfo = item_foreign_proc_info(Attributes0, PredSymName, PredOrFunc,
         PragmaVars, ProgVarSet, _InstVarset, PragmaImpl, Context, SeqNum),
     PredFormArity = arg_list_arity(PragmaVars),
@@ -111,7 +114,7 @@ add_foreign_proc(ProgressStream, ItemMercuryStatus, PredStatus, FPInfo,
     % in the proc_table in the pred_info, and save the pred_info.
     some [!PredInfo] (
         add_implicit_pred_decl_if_needed(PFSymNameArity, PredStatus, Context,
-            PredId, !ModuleInfo, !Specs),
+            PredId, !ModuleInfo, !ErrSpecs),
         module_info_pred_info(!.ModuleInfo, PredId, !:PredInfo),
 
         % status_opt_imported preds are initially tagged as status_imported
@@ -130,11 +133,13 @@ add_foreign_proc(ProgressStream, ItemMercuryStatus, PredStatus, FPInfo,
             PFSymNameArity, PragmaVars, Attributes, Context, MaybeProcId),
         check_foreign_proc(!.ModuleInfo, !.PredInfo, PFSymNameArity,
             MaybeProcId, ProgVarSet, PragmaVars, Attributes, PragmaImpl,
-            Context, AllowedToAdd, !.Specs, SpecsAfterCheck),
+            Context, AllowedToAdd,
+            !.ErrSpecs, ErrSpecsAfterCheck, !.WarnSpecs, WarnSpecsAfterCheck),
         ThisModule = pred_status_defined_in_this_module(PredStatus),
         (
             ThisModule = yes,
-            !:Specs = SpecsAfterCheck
+            !:ErrSpecs = ErrSpecsAfterCheck,
+            !:WarnSpecs = WarnSpecsAfterCheck
         ;
             ThisModule = no
         ),
@@ -149,12 +154,12 @@ add_foreign_proc(ProgressStream, ItemMercuryStatus, PredStatus, FPInfo,
                 ForThisBackend = not_for_this_backend(RejectCause),
                 handle_wrong_backend_foreign_proc(ItemMercuryStatus,
                     PredId, !.PredInfo, RejectCause, Context,
-                    !ModuleInfo, !Specs)
+                    !ModuleInfo, !ErrSpecs)
             ;
                 ForThisBackend = for_this_backend,
                 add_nonimported_foreign_proc(PredId, !.PredInfo, ProcId,
                     PFSymNameArity, Attributes, PragmaVars,
-                    PragmaImpl, Context, !ModuleInfo, !Specs)
+                    PragmaImpl, Context, !ModuleInfo, !ErrSpecs)
             )
         else
             true
@@ -170,10 +175,10 @@ add_foreign_proc(ProgressStream, ItemMercuryStatus, PredStatus, FPInfo,
 :- pred add_implicit_pred_decl_if_needed(pf_sym_name_arity::in,
     pred_status::in, prog_context::in, pred_id::out,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_implicit_pred_decl_if_needed(PFSymNameArity, PredStatus, Context, PredId,
-        !ModuleInfo, !Specs) :-
+        !ModuleInfo, !ErrSpecs) :-
     PFSymNameArity = pf_sym_name_arity(PredOrFunc, PredSymName, PredFormArity),
     det_sym_name_get_module_name_and_name(PredSymName,
         PredModuleName, PredName),
@@ -191,7 +196,7 @@ add_implicit_pred_decl_if_needed(PFSymNameArity, PredStatus, Context, PredId,
             PredName, PredFormArity, PredStatus, is_not_a_class_method,
             Context, Origin,
             [pragma_decl("foreign_proc"), words("declaration")],
-            PredId, !ModuleInfo, !Specs)
+            PredId, !ModuleInfo, !ErrSpecs)
     ).
 
     % Record the existence of this "clause".
@@ -276,7 +281,7 @@ is_foreign_proc_for_this_backend(Globals, Attributes, ForThisBackend) :-
     %
 :- pred compute_intended_proc_id(module_info::in, pred_info::in,
     pf_sym_name_arity::in, list(pragma_var)::in, foreign_proc_attributes::in,
-    prog_context::in, maybe_error(proc_id, diag_spec)::out) is det.
+    prog_context::in, maybe_error(proc_id, err_spec)::out) is det.
 
 compute_intended_proc_id(ModuleInfo, PredInfo, PFSymNameArity,
         PragmaVars, Attributes, Context, MaybeProcId) :-
@@ -310,10 +315,10 @@ compute_intended_proc_id(ModuleInfo, PredInfo, PFSymNameArity,
     pf_sym_name_arity::in, foreign_proc_attributes::in, list(pragma_var)::in,
     pragma_foreign_proc_impl::in, prog_context::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_nonimported_foreign_proc(PredId, !.PredInfo, ProcId, PFSymNameArity,
-        Attributes, PragmaVars, PragmaImpl, Context, !ModuleInfo, !Specs) :-
+        Attributes, PragmaVars, PragmaImpl, Context, !ModuleInfo, !ErrSpecs) :-
     PFSymNameArity =
         pf_sym_name_arity(PredOrFunc, PredSymName, _PredFormArity),
     det_sym_name_get_module_name_and_name(PredSymName,
@@ -324,7 +329,7 @@ add_nonimported_foreign_proc(PredId, !.PredInfo, ProcId, PFSymNameArity,
     clauses_info_add_foreign_proc(!.ModuleInfo, PredOrFunc,
         PredModuleName, PredName, PredId, ProcId, PragmaVars,
         ArgTypes, Purity, Attributes, Context, PragmaImpl,
-        ClausesInfo1, ClausesInfo, !Specs),
+        ClausesInfo1, ClausesInfo, !ErrSpecs),
     pred_info_set_clauses_info(ClausesInfo, !PredInfo),
     pred_info_update_goal_type(np_goal_type_foreign, !PredInfo),
     module_info_set_pred_info(PredId, !.PredInfo, !ModuleInfo).
@@ -334,10 +339,10 @@ add_nonimported_foreign_proc(PredId, !.PredInfo, ProcId, PFSymNameArity,
 :- pred handle_wrong_backend_foreign_proc(item_mercury_status::in,
     pred_id::in, pred_info::in, wrong_backend_cause::in, prog_context::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 handle_wrong_backend_foreign_proc(ItemMercuryStatus, PredId, !.PredInfo,
-        WrongBackendCause, Context, !ModuleInfo, !Specs) :-
+        WrongBackendCause, Context, !ModuleInfo, !ErrSpecs) :-
     % This foreign_proc is for the wrong language or the wrong backend.
     % This is ok when coming from a source file, which is allowed
     % to define a predicate by different foreign_procs for different
@@ -349,7 +354,7 @@ handle_wrong_backend_foreign_proc(ItemMercuryStatus, PredId, !.PredInfo,
         item_defined_in_other_module(item_import_opt_int)
     then
         report_bad_foreign_proc_in_dot_opt_file(WrongBackendCause, Context,
-            !Specs)
+            !ErrSpecs)
     else
         true
     ),
@@ -387,11 +392,11 @@ handle_wrong_backend_foreign_proc(ItemMercuryStatus, PredId, !.PredInfo,
     list(pragma_var)::in, list(mer_type)::in, purity::in,
     foreign_proc_attributes::in, prog_context::in,
     pragma_foreign_proc_impl::in, clauses_info::in, clauses_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 clauses_info_add_foreign_proc(ModuleInfo, PredOrFunc,
         PredModuleName, PredName, PredId, ProcId, PragmaVars, OrigArgTypes,
-        Purity, Attributes0, Context, PragmaImpl, !ClausesInfo, !Specs) :-
+        Purity, Attributes0, Context, PragmaImpl, !ClausesInfo, !ErrSpecs) :-
     % Our caller should have already added this foreign_proc to ItemNumbers.
     !.ClausesInfo = clauses_info(VarSet0, ExplicitVarTypes,
         VarTable, RttiVarMaps, TVarNameMap, HeadVars, ClausesRep0,
@@ -413,7 +418,7 @@ clauses_info_add_foreign_proc(ModuleInfo, PredOrFunc,
     get_clause_list_for_replacement(ClausesRep0, Clauses0),
     add_foreign_proc_update_existing_clauses(Globals, PredOrFunc,
         PredModuleName, PredName, PredFormArity, Context, Target, NewLang,
-        AllProcIds, ProcId, Overridden, Clauses0, Clauses1, !Specs),
+        AllProcIds, ProcId, Overridden, Clauses0, Clauses1, !ErrSpecs),
 
     % We used have this code here, but as of 2022 feb 15, and almost certainly
     % for a long, long time before that, it effectively did nothing.
@@ -496,11 +501,12 @@ maybe_rename_user_annotated_sharing_information(Globals,
     compilation_target::in, foreign_language::in,
     list(proc_id)::in, proc_id::in, overridden_by_old_foreign_proc::out,
     list(clause)::in, list(clause)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_foreign_proc_update_existing_clauses(Globals, PredOrFunc,
         PredModuleName, PredName, PredFormArity, NewContext, Target, NewLang,
-        AllProcIds, NewClauseProcId, Overridden, Clauses0, Clauses, !Specs) :-
+        AllProcIds, NewClauseProcId, Overridden, Clauses0, Clauses,
+        !ErrSpecs) :-
     (
         Clauses0 = [],
         Clauses = [],
@@ -510,7 +516,7 @@ add_foreign_proc_update_existing_clauses(Globals, PredOrFunc,
         add_foreign_proc_update_existing_clauses(Globals, PredOrFunc,
             PredModuleName, PredName, PredFormArity, NewContext, Target,
             NewLang, AllProcIds, NewClauseProcId, LaterOverridden,
-            LaterClauses0, LaterClauses, !Specs),
+            LaterClauses0, LaterClauses, !ErrSpecs),
         FirstClause0 = clause(ApplProcIds0, _Body, FirstClauseLang,
             FirstClauseContext, _StateVarWarnings, _UnusedSVarDescs,
             _MaybeFact),
@@ -611,7 +617,7 @@ add_foreign_proc_update_existing_clauses(Globals, PredOrFunc,
                     ( if OldLang = NewLang then
                         report_duplicate_foreign_proc(PredOrFunc,
                             PredModuleName, PredName, PredFormArity, OldLang,
-                            FirstClauseContext, NewContext, !Specs)
+                            FirstClauseContext, NewContext, !ErrSpecs)
                     else
                         true
                     )
@@ -634,20 +640,21 @@ add_foreign_proc_update_existing_clauses(Globals, PredOrFunc,
     % Perform all the checks on a foreign_proc that we can.
     %
 :- pred check_foreign_proc(module_info::in, pred_info::in,
-    pf_sym_name_arity::in, maybe_error(proc_id, diag_spec)::in,
+    pf_sym_name_arity::in, maybe_error(proc_id, err_spec)::in,
     prog_varset::in, list(pragma_var)::in, foreign_proc_attributes::in,
     pragma_foreign_proc_impl::in, prog_context::in,
     maybe_allowed_to_add_foreign_proc::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 check_foreign_proc(ModuleInfo, PredInfo, PFSymNameArity, MaybeProcId,
         ProgVarSet, PragmaVars, Attributes, PragmaImpl, Context,
-        !:AllowedToAdd, !Specs) :-
+        !:AllowedToAdd, !ErrSpecs, !WarnSpecs) :-
     Lang = get_foreign_language(Attributes),
     report_if_fproc_is_for_imported_pred(PredInfo, Lang, Context,
         ImportedPredSpecs),
     report_if_fproc_is_for_builtin(ModuleInfo, PredInfo, Lang, Context,
-        !:AllowedToAdd, !Specs),
+        !:AllowedToAdd, !ErrSpecs),
     pragma_get_vars_and_var_infos(PragmaVars, ArgVars, _ArgInfos),
     check_foreign_proc_arg_list(PFSymNameArity, ProgVarSet, ArgVars,
         Lang, Context, ArgListSpecs),
@@ -656,7 +663,7 @@ check_foreign_proc(ModuleInfo, PredInfo, PFSymNameArity, MaybeProcId,
     ;
         ArgListSpecs = [_ | _],
         !:AllowedToAdd = not_allowed_to_add_foreign_proc,
-        !:Specs = ArgListSpecs ++ !.Specs
+        !:ErrSpecs = ArgListSpecs ++ !.ErrSpecs
     ),
     PragmaImpl = fp_impl_ordinary(Code, _),
     foreign_code_to_identifiers(Lang, Code, IdentifierList, CommentList),
@@ -664,23 +671,23 @@ check_foreign_proc(ModuleInfo, PredInfo, PFSymNameArity, MaybeProcId,
     set.list_to_set(IdentifierList, Identifiers),
     set.list_to_set(CommentIdentifierList, CommentIdentifiers),
     warn_singletons_in_pragma_foreign_proc(PredInfo, PFSymNameArity, Lang,
-        PragmaVars, Identifiers, Context, !Specs),
+        PragmaVars, Identifiers, Context, !WarnSpecs),
     check_fp_body_for_return(PFSymNameArity, Lang, Identifiers, Context,
-        !Specs),
+        !WarnSpecs),
     (
         MaybeProcId = ok(ProcId),
         % Without the ProcId, we cannot look up the procedure's determinism,
         % and the determinism specifies whether the code *should* contain
         % a reference to SUCCESS_INDICATOR.
         check_fp_body_for_success_indicator(PredInfo, PFSymNameArity, ProcId,
-            Lang, Identifiers, Context, !Specs)
+            Lang, Identifiers, Context, !WarnSpecs)
     ;
         MaybeProcId = error(ProcIdSpec),
         % Our caller checks for MaybeProcId = ok(_), but just to be sure ...
         !:AllowedToAdd = not_allowed_to_add_foreign_proc,
-        !:Specs = [ProcIdSpec | !.Specs]
+        !:ErrSpecs = [ProcIdSpec | !.ErrSpecs]
     ),
-    check_foreign_proc_purity(PredInfo, Attributes, Lang, Context, !Specs),
+    check_foreign_proc_purity(PredInfo, Attributes, Lang, Context, !ErrSpecs),
     % We include CommentIdentifiers in the set of identifiers we pass to
     % check_typeinfos_for_existq_tvars, because without doing that,
     % we cannot pass the invalid/foreign_procs_exist_type test case.
@@ -692,7 +699,7 @@ check_foreign_proc(ModuleInfo, PredInfo, PFSymNameArity, MaybeProcId,
     % or in comments (which is much easier).
     set.union(Identifiers, CommentIdentifiers, AllIdentifiers),
     check_typeinfos_for_existq_tvars(PredInfo, Lang, AllIdentifiers, Context,
-        !Specs),
+        !ErrSpecs),
     (
         ImportedPredSpecs = []
     ;
@@ -708,7 +715,7 @@ check_foreign_proc(ModuleInfo, PredInfo, PFSymNameArity, MaybeProcId,
         %
         % However, this kind of bug is so rare, it does not really matter
         % which choice we make here.
-        !:Specs = ImportedPredSpecs
+        !:ErrSpecs = ImportedPredSpecs
     ).
 
 %---------------------------------------------------------------------------%
@@ -718,9 +725,9 @@ check_foreign_proc(ModuleInfo, PredInfo, PFSymNameArity, MaybeProcId,
     % *plain* imported predicates/functions, not the *opt-imported* ones.
     %
 :- pred report_if_fproc_is_for_imported_pred(pred_info::in,
-    foreign_language::in, prog_context::in, list(diag_spec)::out) is det.
+    foreign_language::in, prog_context::in, list(err_spec)::out) is det.
 
-report_if_fproc_is_for_imported_pred(PredInfo, Lang, Context, Specs) :-
+report_if_fproc_is_for_imported_pred(PredInfo, Lang, Context, ErrSpecs) :-
     ( if pred_info_is_imported(PredInfo) then
         LangStr = foreign_language_string(Lang),
         PredOrFunc = pred_info_is_pred_or_func(PredInfo),
@@ -737,9 +744,9 @@ report_if_fproc_is_for_imported_pred(PredInfo, Lang, Context, Specs) :-
             words("only for predicates and functions"),
             words("defined in the current module."), nl],
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        Specs = [Spec]
+        ErrSpecs = [Spec]
     else
-        Specs = []
+        ErrSpecs = []
     ).
 
 %---------------------%
@@ -747,10 +754,10 @@ report_if_fproc_is_for_imported_pred(PredInfo, Lang, Context, Specs) :-
 :- pred report_if_fproc_is_for_builtin(module_info::in, pred_info::in,
     foreign_language::in, prog_context::in,
     maybe_allowed_to_add_foreign_proc::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_if_fproc_is_for_builtin(ModuleInfo, PredInfo, Lang, Context,
-        AllowedToAdd, !Specs) :-
+        AllowedToAdd, !ErrSpecs) :-
     ( if pred_info_is_builtin(PredInfo) then
         AllowedToAdd = not_allowed_to_add_foreign_proc,
         % When bootstrapping a change that defines a builtin using
@@ -775,7 +782,7 @@ report_if_fproc_is_for_builtin(ModuleInfo, PredInfo, Lang, Context,
                 color_as_incorrect([words("not allowed.")]) ++
                 [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         ;
             AllowDefnOfBuiltin = yes
         )
@@ -786,9 +793,10 @@ report_if_fproc_is_for_builtin(ModuleInfo, PredInfo, Lang, Context,
 %---------------------%
 
 :- func report_fproc_for_undeclared_mode(pf_sym_name_arity,
-    foreign_proc_attributes, prog_context) = diag_spec.
+    foreign_proc_attributes, prog_context) = err_spec.
 
-report_fproc_for_undeclared_mode(PFSymNameArity, Attributes, Context) = Spec :-
+report_fproc_for_undeclared_mode(PFSymNameArity, Attributes, Context)
+        = ErrSpec :-
     Lang = get_foreign_language(Attributes),
     LangStr = foreign_language_string(Lang),
     PFSymNameArity = pf_sym_name_arity(PredOrFunc, PredSymName, PredFormArity),
@@ -800,17 +808,17 @@ report_fproc_for_undeclared_mode(PFSymNameArity, Attributes, Context) = Spec :-
         [words("of"), p_or_f(PredOrFunc)] ++
         color_as_subject([qual_sym_name_arity(SNA), suffix(".")]) ++
         [nl],
-    Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces).
+    ErrSpec = spec($pred, severity_error, phase_pt2h, Context, Pieces).
 
 %---------------------%
 
 :- pred report_duplicate_foreign_proc(pred_or_func::in,
     module_name::in, string::in, pred_form_arity::in, foreign_language::in,
     prog_context::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_duplicate_foreign_proc(PredOrFunc, PredModuleName, PredName,
-        PredFormArity, Lang, FirstClauseContext, NewContext, !Specs) :-
+        PredFormArity, Lang, FirstClauseContext, NewContext, !ErrSpecs) :-
     PredSymName = qualified(PredModuleName, PredName),
     PFSymNameArity = pf_sym_name_arity(PredOrFunc, PredSymName, PredFormArity),
     LangStr = foreign_language_string(Lang),
@@ -822,15 +830,16 @@ report_duplicate_foreign_proc(PredOrFunc, PredModuleName, PredName,
     PiecesB = [words("The first one was here."), nl],
     MsgA = msg(NewContext, PiecesA),
     MsgB = msg(FirstClauseContext, PiecesB),
-    Spec = diag_spec($pred, severity_error, phase_pt2h, [MsgA, MsgB]),
-    !:Specs = [Spec | !.Specs].
+    Spec = gen_spec($pred, severity_error, phase_pt2h, [MsgA, MsgB]),
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 %---------------------%
 
 :- pred report_bad_foreign_proc_in_dot_opt_file(wrong_backend_cause::in,
-    prog_context::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    prog_context::in, list(err_spec)::in, list(err_spec)::out) is det.
 
-report_bad_foreign_proc_in_dot_opt_file(WrongBackendCause, Context, !Specs) :-
+report_bad_foreign_proc_in_dot_opt_file(WrongBackendCause, Context,
+        !ErrSpecs) :-
     (
         WrongBackendCause = wrong_lang(PragmaLang, BackendForeignLangs),
         PragmaLangStr = foreign_language_string(PragmaLang),
@@ -870,7 +879,7 @@ report_bad_foreign_proc_in_dot_opt_file(WrongBackendCause, Context, !Specs) :-
         words("You will need to rebuild this file"),
         words("for the current grade."), nl],
     Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 %---------------------%
 
@@ -881,9 +890,9 @@ report_bad_foreign_proc_in_dot_opt_file(WrongBackendCause, Context, !Specs) :-
     %
 :- pred check_foreign_proc_purity(pred_info::in, foreign_proc_attributes::in,
     foreign_language::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-check_foreign_proc_purity(PredInfo, Attributes, Lang, Context, !Specs) :-
+check_foreign_proc_purity(PredInfo, Attributes, Lang, Context, !ErrSpecs) :-
     pred_info_get_markers(PredInfo, PredMarkers),
     ( if
         ( marker_is_present(PredMarkers, marker_promised_pure)
@@ -913,7 +922,7 @@ check_foreign_proc_purity(PredInfo, Attributes, Lang, Context, !Specs) :-
                 words("has been declared")] ++
                 color_as_correct([words(PredPurityStr), suffix(".")]) ++ [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         )
     ).
 
@@ -921,10 +930,10 @@ check_foreign_proc_purity(PredInfo, Attributes, Lang, Context, !Specs) :-
 
 :- pred check_typeinfos_for_existq_tvars(pred_info::in,
     foreign_language::in, set(string)::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_typeinfos_for_existq_tvars(PredInfo, Lang, Identifiers, Context,
-        !Specs) :-
+        !ErrSpecs) :-
     pred_info_get_arg_types(PredInfo, TypeVarSet, ExistQVars, _ArgTypes),
     % NOTE This code will generate a separate diag_spec for each
     % type_info variable that that does should occur, but does not occur,
@@ -935,14 +944,14 @@ check_typeinfos_for_existq_tvars(PredInfo, Lang, Identifiers, Context,
     list.foldl2(
         check_typeinfo_for_existq_tvar(PredInfo, TypeVarSet, Lang,
             Identifiers, Context),
-        ExistQVars, 1u, _N, !Specs).
+        ExistQVars, 1u, _N, !ErrSpecs).
 
 :- pred check_typeinfo_for_existq_tvar(pred_info::in, tvarset::in,
     foreign_language::in, set(string)::in, prog_context::in, tvar::in,
-    uint::in, uint::out, list(diag_spec)::in, list(diag_spec)::out) is det.
+    uint::in, uint::out, list(err_spec)::in, list(err_spec)::out) is det.
 
 check_typeinfo_for_existq_tvar(PredInfo, TypeVarSet, Lang, Identifiers,
-        Context, ExistQVar, !ExistQVarNum, !Specs) :-
+        Context, ExistQVar, !ExistQVarNum, !ErrSpecs) :-
     varset.lookup_name(TypeVarSet, ExistQVar, Name),
     OldVarName = "TypeInfo_for_" ++ Name,
     NewVarName = "TypeInfo_Out_" ++ string.uint_to_string(!.ExistQVarNum),
@@ -962,7 +971,7 @@ check_typeinfo_for_existq_tvar(PredInfo, TypeVarSet, Lang, Identifiers,
             [words("should define the variable")] ++
             color_as_incorrect([quote(OldVarName), suffix(".")]) ++ [nl],
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ).
 
 %---------------------%
@@ -971,10 +980,10 @@ check_typeinfo_for_existq_tvar(PredInfo, TypeVarSet, Lang, Identifiers,
     %
 :- pred check_foreign_proc_arg_list(pf_sym_name_arity::in, prog_varset::in,
     list(prog_var)::in, foreign_language::in, prog_context::in,
-    list(diag_spec)::out) is det.
+    list(err_spec)::out) is det.
 
 check_foreign_proc_arg_list(PFSymNameArity, ProgVarSet, ArgVars, Lang, Context,
-        Specs) :-
+        ErrSpecs) :-
     bag.init(ArgVarBag0),
     bag.insert_list(ArgVars, ArgVarBag0, ArgVarBag),
     bag.to_list_only_duplicates(ArgVarBag, MultiplyOccurringArgVars),
@@ -1004,10 +1013,10 @@ check_foreign_proc_arg_list(PFSymNameArity, ProgVarSet, ArgVars, Lang, Context,
         Pieces3 = [words("in the argument list."), nl],
         Spec = spec($pred, severity_error, phase_pt2h,
             Context, Pieces1 ++ Pieces2 ++ Pieces3),
-        Specs = [Spec]
+        ErrSpecs = [Spec]
     ;
         MultiplyOccurringArgVars = [],
-        Specs = []
+        ErrSpecs = []
     ).
 
 %---------------------%
@@ -1023,10 +1032,10 @@ check_foreign_proc_arg_list(PFSymNameArity, ProgVarSet, ArgVars, Lang, Context,
 :- pred warn_singletons_in_pragma_foreign_proc(pred_info::in,
     pf_sym_name_arity::in, foreign_language::in, list(pragma_var)::in,
     set(string)::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 warn_singletons_in_pragma_foreign_proc(PredInfo, PFSymNameArity,
-        Lang, PragmaVars, Identifiers, Context, !Specs) :-
+        Lang, PragmaVars, Identifiers, Context, !WarnSpecs) :-
     pragma_get_var_infos(PragmaVars, ArgInfos),
     ArgNameModes =
         list.map(foreign_arg_name_mode_box_project_maybe_name_mode, ArgInfos),
@@ -1047,7 +1056,7 @@ warn_singletons_in_pragma_foreign_proc(PredInfo, PFSymNameArity,
             [words("in the"), words(LangStr), words("code."), nl],
         Severity = severity_warning(warn_singleton_vars),
         Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:WarnSpecs = [Spec | !.WarnSpecs]
     else
         true
     ).
@@ -1079,10 +1088,10 @@ variable_warning_start(UnmentionedVars, Pieces, DoDoes) :-
 :- pred check_fp_body_for_success_indicator(pred_info::in,
     pf_sym_name_arity::in, proc_id::in, foreign_language::in,
     set(string)::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 check_fp_body_for_success_indicator(PredInfo, PFSymNameArity, ProcId, Lang,
-        Identifiers, Context, !Specs) :-
+        Identifiers, Context, !WarnSpecs) :-
     pred_info_get_proc_table(PredInfo, ProcTable),
     map.lookup(ProcTable, ProcId, ProcInfo),
     proc_info_get_declared_determinism(ProcInfo, MaybeDeclDetism),
@@ -1105,7 +1114,7 @@ check_fp_body_for_success_indicator(PredInfo, PFSymNameArity, ProcId, Lang,
                     color_as_inconsistent([words("it cannot fail.")]) ++ [nl],
                 Severity = severity_warning(warn_suspicious_foreign_procs),
                 Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),
-                !:Specs = [Spec | !.Specs]
+                !:WarnSpecs = [Spec | !.WarnSpecs]
             else
                 true
             )
@@ -1126,7 +1135,7 @@ check_fp_body_for_success_indicator(PredInfo, PFSymNameArity, ProcId, Lang,
                     color_as_inconsistent([words("it can fail.")]) ++ [nl],
                 Severity = severity_warning(warn_suspicious_foreign_procs),
                 Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),
-                !:Specs = [Spec | !.Specs]
+                !:WarnSpecs = [Spec | !.WarnSpecs]
             )
         ;
             ( Detism = detism_multi
@@ -1145,9 +1154,10 @@ check_fp_body_for_success_indicator(PredInfo, PFSymNameArity, ProcId, Lang,
     %
 :- pred check_fp_body_for_return(pf_sym_name_arity::in, foreign_language::in,
     set(string)::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-check_fp_body_for_return(PFSymNameArity, Lang, Identifiers, Context, !Specs) :-
+check_fp_body_for_return(PFSymNameArity, Lang, Identifiers, Context,
+        !WarnSpecs) :-
     ( if set.member("return", Identifiers) then
         LangStr = foreign_language_string(Lang),
         PFSPiece = unqual_pf_sym_name_pred_form_arity(PFSymNameArity),
@@ -1159,7 +1169,7 @@ check_fp_body_for_return(PFSymNameArity, Lang, Identifiers, Context, !Specs) :-
             [nl],
         Severity = severity_warning(warn_suspicious_foreign_procs),
         Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:WarnSpecs = [Spec | !.WarnSpecs]
     else
         true
     ).
diff --git a/compiler/add_mode.m b/compiler/add_mode.m
index b354a39f0..8ef4915d3 100644
--- a/compiler/add_mode.m
+++ b/compiler/add_mode.m
@@ -29,23 +29,24 @@
 
 :- pred module_add_inst_defn(inst_status::in, item_inst_defn_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------%
 
 :- pred module_add_mode_defn(mode_status::in, item_mode_defn_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------%
 
 :- pred check_inst_defns(module_info::in, ims_list(item_inst_defn_info)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------%
 
 :- pred check_mode_defns(module_info::in, ims_list(item_mode_defn_info)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -72,7 +73,8 @@
 
 %---------------------------------------------------------------------------%
 
-module_add_inst_defn(InstStatus, ItemInstDefnInfo, !ModuleInfo, !Specs) :-
+module_add_inst_defn(InstStatus, ItemInstDefnInfo, !ModuleInfo,
+        !ErrSpecs, !WarnSpecs) :-
     ItemInstDefnInfo = item_inst_defn_info(InstName, InstParams, MaybeForType,
         MaybeAbstractInstDefn, VarSet, Context, _SeqNum),
     (
@@ -85,7 +87,8 @@ module_add_inst_defn(InstStatus, ItemInstDefnInfo, !ModuleInfo, !Specs) :-
         module_info_get_inst_table(!.ModuleInfo, InstTable0),
         inst_table_get_user_insts(InstTable0, UserInstTable0),
         insts_add(VarSet, InstName, InstParams, MaybeForType, InstDefn,
-            Context, InstStatus, UserInstTable0, UserInstTable, !Specs),
+            Context, InstStatus, UserInstTable0, UserInstTable,
+            !ErrSpecs, !WarnSpecs),
         inst_table_set_user_insts(UserInstTable, InstTable0, InstTable),
         module_info_set_inst_table(InstTable, !ModuleInfo)
     ).
@@ -93,10 +96,11 @@ module_add_inst_defn(InstStatus, ItemInstDefnInfo, !ModuleInfo, !Specs) :-
 :- pred insts_add(inst_varset::in, sym_name::in, list(inst_var)::in,
     maybe(type_ctor)::in, inst_defn::in, prog_context::in,
     inst_status::in, user_inst_table::in, user_inst_table::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 insts_add(VarSet, InstSymName, InstParams, MaybeForType, eqv_inst(EqvInst),
-        Context, InstStatus, !UserInstTable, !Specs) :-
+        Context, InstStatus, !UserInstTable, !ErrSpecs, !WarnSpecs) :-
     list.length(InstParams, InstArity),
     InstCtor = inst_ctor(InstSymName, InstArity),
     (
@@ -115,7 +119,7 @@ insts_add(VarSet, InstSymName, InstParams, MaybeForType, eqv_inst(EqvInst),
                 Severity =
                     severity_warning(warn_insts_with_functors_without_type),
                 Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),
-                !:Specs = [Spec | !.Specs]
+                !:WarnSpecs = [Spec | !.WarnSpecs]
             ;
                 Here = no
             )
@@ -146,7 +150,7 @@ insts_add(VarSet, InstSymName, InstParams, MaybeForType, eqv_inst(EqvInst),
                     words("inst.")]) ++
                 [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         else
             true
         )
@@ -168,7 +172,7 @@ insts_add(VarSet, InstSymName, InstParams, MaybeForType, eqv_inst(EqvInst),
             OrigContext = OrigInstDefn ^ inst_context,
             report_multiply_defined("inst", InstSymName, user_arity(InstArity),
                 Context, OrigContext, [], DupSpec),
-            !:Specs = [DupSpec | !.Specs]
+            !:ErrSpecs = [DupSpec | !.ErrSpecs]
         )
     ).
 
@@ -192,10 +196,10 @@ module_add_mode_defn(ModeStatus, ItemModeDefnInfo, !ModuleInfo, !Specs) :-
 :- pred modes_add(inst_varset::in, sym_name::in, list(inst_var)::in,
     mode_defn::in, prog_context::in, mode_status::in,
     mode_table::in, mode_table::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 modes_add(VarSet, Name, Params, ModeBody, Context, ModeStatus,
-        !ModeTable, !Specs) :-
+        !ModeTable, !ErrSpecs) :-
     list.length(Params, Arity),
     ModeCtor = mode_ctor(Name, Arity),
     ModeBody = eqv_mode(EqvMode),
@@ -216,7 +220,7 @@ modes_add(VarSet, Name, Params, ModeBody, Context, ModeStatus,
             OrigModeDefn = hlds_mode_defn(_, _, _, OrigContext, _),
             report_multiply_defined("mode", Name, user_arity(Arity),
                 Context, OrigContext, [], Spec),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         )
     ).
 
@@ -409,7 +413,7 @@ check_for_cyclic_mode(ModeDefns, OrigModeCtor, ModeCtor0,
     ;       iom_mode.
 
 :- pred cycle_to_diag_spec(module_info::in, inst_or_mode::in, cycle::in,
-    diag_spec::out) is det.
+    err_spec::out) is det.
 
 cycle_to_diag_spec(ModuleInfo, InstOrMode, Cycle, Spec) :-
     (
@@ -480,7 +484,7 @@ cycle_to_diag_spec(ModuleInfo, InstOrMode, Cycle, Spec) :-
             ++ CyclePieces ++ ConsequencePieces
     ),
     HeadMsg = msg(HeadContext, HeadPieces),
-    Spec = diag_spec($pred, severity_error, phase_pt2h,
+    Spec = gen_spec($pred, severity_error, phase_pt2h,
         [HeadMsg | ContextMsgs]).
 
 :- pred sna_context_is_for_module(module_name::in,
diff --git a/compiler/add_mutable_aux_preds.m b/compiler/add_mutable_aux_preds.m
index aa4c1e06c..00f7c94d3 100644
--- a/compiler/add_mutable_aux_preds.m
+++ b/compiler/add_mutable_aux_preds.m
@@ -45,7 +45,7 @@
     list(foreign_decl_code)::out, list(foreign_body_code)::out,
     cord(impl_pragma_fproc_export_info)::out,
     pred_target_names::in, pred_target_names::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -100,7 +100,7 @@ implement_mutables_if_local(ModuleInfo, UndefInstCtors, SecList, PredDecls,
     cord(impl_pragma_fproc_export_info)::in,
         cord(impl_pragma_fproc_export_info)::out,
     pred_target_names::in, pred_target_names::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 implement_mutables_sec_loop(_ModuleInfo, _UndefInstCtors, [], _DefinedMutables,
         !PredDeclCord, !ClauseInfoCord, !ForeignProcCord,
@@ -166,7 +166,7 @@ implement_mutables_sec_loop(ModuleInfo, UndefInstCtors,
     cord(impl_pragma_fproc_export_info)::in,
         cord(impl_pragma_fproc_export_info)::out,
     pred_target_names::in, pred_target_names::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 implement_mutables_loop(_ModuleInfo, _SectionInfo, _ModuleParams,
         [], !DefinedMutables, !PredDeclCord, !ClauseInfoCord, !ForeignProcCord,
@@ -186,7 +186,7 @@ implement_mutables_loop(ModuleInfo, SectionInfo, ModuleParams,
             color_as_incorrect([words("duplicate.")]) ++
             [nl],
         OldPieces = [words("The first definition is here."), nl],
-        Spec = diag_spec($pred, severity_error, phase_pt2h,
+        Spec = gen_spec($pred, severity_error, phase_pt2h,
             [msg(Context, Pieces),
             msg(OldContext, OldPieces)]),
         !:Specs = [Spec | !.Specs]
@@ -211,7 +211,7 @@ implement_mutables_loop(ModuleInfo, SectionInfo, ModuleParams,
 %---------------------------------------------------------------------------%
 
 :- pred check_mutable(module_info::in, module_params::in,
-    item_mutable_info::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    item_mutable_info::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 check_mutable(ModuleInfo, ModuleParams, ItemMutable, !Specs) :-
     ItemMutable = item_mutable_info(_MutableName,
@@ -282,7 +282,7 @@ check_mutable(ModuleInfo, ModuleParams, ItemMutable, !Specs) :-
     %
 :- pred check_mutable_inst(module_info::in, module_params::in,
     prog_context::in, inst_varset::in, list(inst_ctor)::in, mer_inst::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_mutable_inst(ModuleInfo, ModuleParams, Context, InstVarSet,
         ParentInsts, Inst, !Specs) :-
@@ -400,7 +400,7 @@ check_mutable_inst(ModuleInfo, ModuleParams, Context, InstVarSet,
 :- pred check_mutable_bound_functors(module_info::in, module_params::in,
     prog_context::in, inst_varset::in,
     list(inst_ctor)::in, list(bound_functor)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_mutable_bound_functors(_ModuleInfo, _ModuleParams, _Context,
         _InstVarSet, _ParentInsts, [], !Specs).
@@ -414,7 +414,7 @@ check_mutable_bound_functors(ModuleInfo, ModuleParams, Context,
 
 :- pred check_mutable_insts(module_info::in, module_params::in,
     prog_context::in, inst_varset::in, list(inst_ctor)::in, list(mer_inst)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_mutable_insts(_ModuleInfo, _ModuleParams, _Context, _InstVarSet,
         _ParentInsts, [], !Specs).
@@ -429,7 +429,7 @@ check_mutable_insts(ModuleInfo, ModuleParams, Context, InstVarSet,
 
 :- pred check_mutable_inst_uniqueness(module_info::in, prog_context::in,
     inst_varset::in, list(inst_ctor)::in, mer_inst::in, uniqueness::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_mutable_inst_uniqueness(ModuleInfo, Context, InstVarSet, ParentInsts,
         Inst, Uniq, !Specs) :-
@@ -468,7 +468,7 @@ check_mutable_inst_uniqueness(ModuleInfo, Context, InstVarSet, ParentInsts,
     %
 :- pred invalid_inst_in_mutable(module_info::in, prog_context::in,
     inst_varset::in, list(inst_ctor)::in, mer_inst::in, list(format_piece)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 invalid_inst_in_mutable(ModuleInfo, Context, InstVarSet, ParentInsts, Inst,
         ProblemPieces, !Specs) :-
diff --git a/compiler/add_pragma_decl.m b/compiler/add_pragma_decl.m
index e382c0d46..443b3721f 100644
--- a/compiler/add_pragma_decl.m
+++ b/compiler/add_pragma_decl.m
@@ -29,38 +29,44 @@
 :- pred add_decl_pragmas(io.text_output_stream::in,
     ims_list(item_decl_pragma_info)::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out,
+    list(info_spec)::in, list(info_spec)::out) is det.
 
 :- pred add_decl_pragmas_type_spec_constr(io.text_output_stream::in,
     list(decl_pragma_type_spec_constr_info)::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out,
+    list(info_spec)::in, list(info_spec)::out) is det.
 
 :- pred add_decl_pragmas_type_spec(list(decl_pragma_type_spec_info)::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 :- pred add_decl_pragmas_termination(list(decl_pragma_termination_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 :- pred add_decl_pragmas_termination2(list(decl_pragma_termination2_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 :- pred add_decl_pragmas_sharing(list(decl_pragma_struct_sharing_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 :- pred add_decl_pragmas_reuse(list(decl_pragma_struct_reuse_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------%
 
 :- pred add_decl_markers(ims_list(item_decl_marker_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -102,101 +108,110 @@
 % Adding decl pragmas to the HLDS.
 %
 
-add_decl_pragmas(_, [], !ModuleInfo, !QualInfo, !Specs).
+add_decl_pragmas(_, [], !ModuleInfo, !QualInfo,
+        !ErrSpecs, !WarnSpecs, !InfoSpecs).
 add_decl_pragmas(ProgressStream, [ImsList | ImsLists],
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs, !InfoSpecs) :-
     ImsList = ims_sub_list(ItemMercuryStatus, Items),
-    list.foldl3(add_decl_pragma(ProgressStream, ItemMercuryStatus), Items,
-        !ModuleInfo, !QualInfo, !Specs),
-    add_decl_pragmas(ProgressStream, ImsLists, !ModuleInfo, !QualInfo, !Specs).
+    list.foldl5(add_decl_pragma(ProgressStream, ItemMercuryStatus), Items,
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs, !InfoSpecs),
+    add_decl_pragmas(ProgressStream, ImsLists, !ModuleInfo, !QualInfo,
+        !ErrSpecs, !WarnSpecs, !InfoSpecs).
 
-add_decl_pragmas_type_spec_constr(_, [], !ModuleInfo, !QualInfo, !Specs).
+add_decl_pragmas_type_spec_constr(_, [],
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs, !InfoSpecs).
 add_decl_pragmas_type_spec_constr(ProgressStream, [Pragma | Pragmas],
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs, !InfoSpecs) :-
     add_pragma_type_spec_constr(ProgressStream, Pragma,
-        !ModuleInfo, !QualInfo, !Specs),
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs, !InfoSpecs),
     add_decl_pragmas_type_spec_constr(ProgressStream, Pragmas,
-        !ModuleInfo, !QualInfo, !Specs).
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs, !InfoSpecs).
 
-add_decl_pragmas_type_spec([], !ModuleInfo, !QualInfo, !Specs).
-add_decl_pragmas_type_spec([Pragma | Pragmas],
-        !ModuleInfo, !QualInfo, !Specs) :-
-    add_pragma_type_spec(Pragma, !ModuleInfo, !QualInfo, !Specs),
-    add_decl_pragmas_type_spec(Pragmas, !ModuleInfo, !QualInfo, !Specs).
+add_decl_pragmas_type_spec([], !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs).
+add_decl_pragmas_type_spec([Pragma | Pragmas], !ModuleInfo, !QualInfo,
+        !ErrSpecs, !WarnSpecs) :-
+    add_pragma_type_spec(Pragma, !ModuleInfo, !QualInfo,
+        !ErrSpecs, !WarnSpecs),
+    add_decl_pragmas_type_spec(Pragmas, !ModuleInfo, !QualInfo,
+        !ErrSpecs, !WarnSpecs).
 
-add_decl_pragmas_termination([], !ModuleInfo, !Specs).
-add_decl_pragmas_termination([Pragma | Pragmas], !ModuleInfo, !Specs) :-
-    add_pragma_termination(Pragma, !ModuleInfo, !Specs),
-    add_decl_pragmas_termination(Pragmas, !ModuleInfo, !Specs).
+add_decl_pragmas_termination([], !ModuleInfo, !ErrSpecs).
+add_decl_pragmas_termination([Pragma | Pragmas], !ModuleInfo, !ErrSpecs) :-
+    add_pragma_termination(Pragma, !ModuleInfo, !ErrSpecs),
+    add_decl_pragmas_termination(Pragmas, !ModuleInfo, !ErrSpecs).
 
-add_decl_pragmas_termination2([], !ModuleInfo, !Specs).
-add_decl_pragmas_termination2([Pragma | Pragmas], !ModuleInfo, !Specs) :-
-    add_pragma_termination2(Pragma, !ModuleInfo, !Specs),
-    add_decl_pragmas_termination2(Pragmas, !ModuleInfo, !Specs).
+add_decl_pragmas_termination2([], !ModuleInfo, !ErrSpecs).
+add_decl_pragmas_termination2([Pragma | Pragmas], !ModuleInfo, !ErrSpecs) :-
+    add_pragma_termination2(Pragma, !ModuleInfo, !ErrSpecs),
+    add_decl_pragmas_termination2(Pragmas, !ModuleInfo, !ErrSpecs).
 
-add_decl_pragmas_sharing([], !ModuleInfo, !Specs).
-add_decl_pragmas_sharing([Pragma | Pragmas], !ModuleInfo, !Specs) :-
-    add_pragma_struct_sharing(Pragma, !ModuleInfo, !Specs),
-    add_decl_pragmas_sharing(Pragmas, !ModuleInfo, !Specs).
+add_decl_pragmas_sharing([], !ModuleInfo, !ErrSpecs).
+add_decl_pragmas_sharing([Pragma | Pragmas], !ModuleInfo, !ErrSpecs) :-
+    add_pragma_struct_sharing(Pragma, !ModuleInfo, !ErrSpecs),
+    add_decl_pragmas_sharing(Pragmas, !ModuleInfo, !ErrSpecs).
 
-add_decl_pragmas_reuse([], !ModuleInfo, !Specs).
-add_decl_pragmas_reuse([Pragma | Pragmas], !ModuleInfo, !Specs) :-
-    add_pragma_struct_reuse(Pragma, !ModuleInfo, !Specs),
-    add_decl_pragmas_reuse(Pragmas, !ModuleInfo, !Specs).
+add_decl_pragmas_reuse([], !ModuleInfo, !ErrSpecs).
+add_decl_pragmas_reuse([Pragma | Pragmas], !ModuleInfo, !ErrSpecs) :-
+    add_pragma_struct_reuse(Pragma, !ModuleInfo, !ErrSpecs),
+    add_decl_pragmas_reuse(Pragmas, !ModuleInfo, !ErrSpecs).
 
 %---------------------%
 
 :- pred add_decl_pragma(io.text_output_stream::in,
     item_mercury_status::in, item_decl_pragma_info::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out,
+    list(info_spec)::in, list(info_spec)::out) is det.
 
 add_decl_pragma(ProgressStream, ItemMercuryStatus, Pragma,
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs, !InfoSpecs) :-
     (
         Pragma = decl_pragma_obsolete_pred(ObsoletePredInfo),
         mark_pred_as_obsolete(ObsoletePredInfo, ItemMercuryStatus,
-            !ModuleInfo, !Specs)
+            !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         Pragma = decl_pragma_obsolete_proc(ObsoleteProcInfo),
         mark_proc_as_obsolete(ObsoleteProcInfo, ItemMercuryStatus,
-            !ModuleInfo, !Specs)
+            !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         Pragma = decl_pragma_format_call(FormatCallInfo),
         mark_pred_as_format_call(FormatCallInfo, ItemMercuryStatus,
-            !ModuleInfo, !Specs)
+            !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         Pragma = decl_pragma_type_spec_constr(TypeSpecConstrInfo),
         add_pragma_type_spec_constr(ProgressStream, TypeSpecConstrInfo,
-            !ModuleInfo, !QualInfo, !Specs)
+            !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs, !InfoSpecs)
     ;
         Pragma = decl_pragma_type_spec(TypeSpecInfo),
-        add_pragma_type_spec(TypeSpecInfo, !ModuleInfo, !QualInfo, !Specs)
+        add_pragma_type_spec(TypeSpecInfo, !ModuleInfo, !QualInfo,
+            !ErrSpecs, !WarnSpecs)
     ;
         Pragma = decl_pragma_oisu(OISUInfo),
-        add_pragma_oisu(OISUInfo, ItemMercuryStatus, !ModuleInfo, !Specs)
+        add_pragma_oisu(OISUInfo, ItemMercuryStatus, !ModuleInfo, !ErrSpecs)
     ;
         Pragma = decl_pragma_termination(TermInfo),
-        add_pragma_termination(TermInfo, !ModuleInfo, !Specs)
+        add_pragma_termination(TermInfo, !ModuleInfo, !ErrSpecs)
     ;
         Pragma = decl_pragma_termination2(Term2Info),
-        add_pragma_termination2(Term2Info, !ModuleInfo, !Specs)
+        add_pragma_termination2(Term2Info, !ModuleInfo, !ErrSpecs)
     ;
         Pragma = decl_pragma_struct_sharing(SharingInfo),
-        add_pragma_struct_sharing(SharingInfo, !ModuleInfo, !Specs)
+        add_pragma_struct_sharing(SharingInfo, !ModuleInfo, !ErrSpecs)
     ;
         Pragma = decl_pragma_struct_reuse(ReuseInfo),
-        add_pragma_struct_reuse(ReuseInfo, !ModuleInfo, !Specs)
+        add_pragma_struct_reuse(ReuseInfo, !ModuleInfo, !ErrSpecs)
     ).
 
 %---------------------%
 
 :- pred mark_pred_as_obsolete(decl_pragma_obsolete_pred_info::in,
     item_mercury_status::in, module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 mark_pred_as_obsolete(ObsoletePredInfo, PragmaStatus,
-        !ModuleInfo, !Specs) :-
+        !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     ObsoletePredInfo = decl_pragma_obsolete_pred_info(PredSpec,
         ObsoleteInFavourOf, Context, _),
     PredSpec = pred_pfu_name_arity(PFU, SymName, UserArity),
@@ -204,29 +219,31 @@ mark_pred_as_obsolete(ObsoletePredInfo, PragmaStatus,
         pragma_does_not_allow_modes, Context, PFU, SymName, UserArity,
         MatchingPredIdResult),
     (
-        MatchingPredIdResult = mpids_ok(HeadPredId, TailPredIds, WarnSpecs),
+        MatchingPredIdResult = mpids_ok(HeadPredId, TailPredIds, IdWarnSpecs),
         PredIds = [HeadPredId | TailPredIds],
-        !:Specs = WarnSpecs ++ !.Specs,
+        !:WarnSpecs = IdWarnSpecs ++ !.WarnSpecs,
         module_info_get_pred_id_table(!.ModuleInfo, PredIdTable0),
         mark_pred_ids_as_obsolete(ObsoleteInFavourOf, PragmaStatus, Context,
-            PredIds, PredIdTable0, PredIdTable, !Specs),
+            PredIds, PredIdTable0, PredIdTable, !ErrSpecs, !WarnSpecs),
         module_info_set_pred_id_table(PredIdTable, !ModuleInfo)
     ;
-        MatchingPredIdResult = mpids_error(ErrorSpecs),
-        !:Specs = ErrorSpecs ++ !.Specs
+        MatchingPredIdResult = mpids_error(IdErrSpecs, IdWarnSpecs),
+        !:ErrSpecs = one_or_more_to_list(IdErrSpecs) ++ !.ErrSpecs,
+        !:WarnSpecs = IdWarnSpecs ++ !.WarnSpecs
     ).
 
 :- pred mark_pred_ids_as_obsolete(list(sym_name_arity)::in,
     item_mercury_status::in, prog_context::in, list(pred_id)::in,
     pred_id_table::in, pred_id_table::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-mark_pred_ids_as_obsolete(_, _, _, [], !PredTable, !Specs).
+mark_pred_ids_as_obsolete(_, _, _, [], !PredTable, !ErrSpecs, !WarnSpecs).
 mark_pred_ids_as_obsolete(ObsoleteInFavourOf, PragmaStatus, Context,
-        [PredId | PredIds], !PredTable, !Specs) :-
+        [PredId | PredIds], !PredTable, !ErrSpecs, !WarnSpecs) :-
     map.lookup(!.PredTable, PredId, PredInfo0),
     check_pragma_status("obsolete", psc_decl, PragmaStatus, Context,
-        PredInfo0, !Specs),
+        PredInfo0, !ErrSpecs, !WarnSpecs),
     pred_info_get_obsolete_in_favour_of(PredInfo0, MaybeObsoleteInFavourOf0),
     (
         MaybeObsoleteInFavourOf0 = no,
@@ -240,15 +257,17 @@ mark_pred_ids_as_obsolete(ObsoleteInFavourOf, PragmaStatus, Context,
         PredInfo0, PredInfo),
     map.det_update(PredId, PredInfo, !PredTable),
     mark_pred_ids_as_obsolete(ObsoleteInFavourOf, PragmaStatus, Context,
-        PredIds, !PredTable, !Specs).
+        PredIds, !PredTable, !ErrSpecs, !WarnSpecs).
 
 %---------------------%
 
 :- pred mark_proc_as_obsolete(decl_pragma_obsolete_proc_info::in,
     item_mercury_status::in, module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-mark_proc_as_obsolete(ObsoleteProcInfo, PragmaStatus, !ModuleInfo, !Specs) :-
+mark_proc_as_obsolete(ObsoleteProcInfo, PragmaStatus, !ModuleInfo,
+        !ErrSpecs, !WarnSpecs) :-
     ObsoleteProcInfo = decl_pragma_obsolete_proc_info(PredNameModesPF,
         ObsoleteInFavourOf, Context, _),
     PredNameModesPF = proc_pf_name_modes(PredOrFunc, SymName, Modes),
@@ -262,7 +281,7 @@ mark_proc_as_obsolete(ObsoleteProcInfo, PragmaStatus, !ModuleInfo, !Specs) :-
         MaybePredId = ok1(PredId),
         module_info_pred_info(!.ModuleInfo, PredId, PredInfo0),
         check_pragma_status("obsolete_proc", psc_decl, PragmaStatus, Context,
-            PredInfo0, !Specs),
+            PredInfo0, !ErrSpecs, !WarnSpecs),
         PFNameArity = pred_pf_name_arity(PredOrFunc, SymName, UserArity),
         ProcTransform =
             ( pred(ProcInfo0::in, ProcInfo::out) is det :-
@@ -280,19 +299,21 @@ mark_proc_as_obsolete(ObsoleteProcInfo, PragmaStatus, !ModuleInfo, !Specs) :-
                     ProcInfo0, ProcInfo)
             ),
         transform_selected_mode_of_pred(PredId, PFNameArity, Modes,
-            "obsolete_proc", Context, ProcTransform, !ModuleInfo, !Specs)
+            "obsolete_proc", Context, ProcTransform, !ModuleInfo, !ErrSpecs)
     ;
-        MaybePredId = error1(Specs),
-        !:Specs = Specs ++ !.Specs
+        MaybePredId = error1(IdErrSpecs),
+        !:ErrSpecs = IdErrSpecs ++ !.ErrSpecs
     ).
 
 %---------------------%
 
 :- pred mark_pred_as_format_call(decl_pragma_format_call_info::in,
     item_mercury_status::in, module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-mark_pred_as_format_call(FormatCallInfo, PragmaStatus, !ModuleInfo, !Specs) :-
+mark_pred_as_format_call(FormatCallInfo, PragmaStatus, !ModuleInfo,
+        !ErrSpecs, !WarnSpecs) :-
     FormatCallInfo =
         decl_pragma_format_call_info(PredSpec, OoMArgSpecs, Context, _),
     PredSpec = pred_pf_name_arity(PredOrFunc, SymName, UserArity),
@@ -300,14 +321,14 @@ mark_pred_as_format_call(FormatCallInfo, PragmaStatus, !ModuleInfo, !Specs) :-
         lfh_user_error, Context, "format_call",
         PredOrFunc, SymName, UserArity, MaybePredId),
     (
-        MaybePredId = error1(PredIdSpecs),
-        !:Specs = PredIdSpecs ++ !.Specs
+        MaybePredId = error1(IdErrSpecs),
+        !:ErrSpecs = IdErrSpecs ++ !.ErrSpecs
     ;
         MaybePredId = ok1(PredId),
         module_info_get_pred_id_table(!.ModuleInfo, PredIdTable0),
         map.lookup(PredIdTable0, PredId, PredInfo0),
         check_pragma_status("format_call", psc_decl, PragmaStatus, Context,
-            PredInfo0, !Specs),
+            PredInfo0, !ErrSpecs, !WarnSpecs),
         pred_info_get_format_call_info(PredInfo0, MaybeFormatCall0),
         (
             MaybeFormatCall0 = no,
@@ -336,9 +357,9 @@ mark_pred_as_format_call(FormatCallInfo, PragmaStatus, !ModuleInfo, !Specs) :-
                 pragma_decl("format_call"), words("declaration"),
                 words("was here."), nl],
             SecondMsg = msg(OldContext, SecondPieces),
-            Spec = diag_spec($pred, severity_error, phase_pt2h,
+            Spec = gen_spec($pred, severity_error, phase_pt2h,
                 [FirstMsg, SecondMsg]),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         )
     ).
 
@@ -346,9 +367,9 @@ mark_pred_as_format_call(FormatCallInfo, PragmaStatus, !ModuleInfo, !Specs) :-
 
 :- pred add_pragma_oisu(decl_pragma_oisu_info::in, item_mercury_status::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-add_pragma_oisu(OISUInfo, ItemMercuryStatus, !ModuleInfo, !Specs) :-
+add_pragma_oisu(OISUInfo, ItemMercuryStatus, !ModuleInfo, !ErrSpecs) :-
     OISUInfo = decl_pragma_oisu_info(TypeCtor, Creators, Mutators, Destructors,
         Context, _),
     some [!OISUSpecs] (
@@ -386,7 +407,7 @@ add_pragma_oisu(OISUInfo, ItemMercuryStatus, !ModuleInfo, !Specs) :-
 %               TypePieces = [words("The type in this"), quote("pragma oisu"),
 %                   words("declaration is undefined."), nl],
 %               TypeMsg = simple_msg(Context, [always(TypePieces)]),
-%               TypeSpec = diag_spec(severity_error, phase_pt2h, [TypeMsg]),
+%               TypeSpec = gen_spec(severity_error, phase_pt2h, [TypeMsg]),
 %               !:OISUSpecs = [TypeSpec | !.OISUSpecs]
                 % Module qualification will already have reported the error.
                 % Any message we could generate here would be a duplicate.
@@ -418,20 +439,20 @@ add_pragma_oisu(OISUInfo, ItemMercuryStatus, !ModuleInfo, !Specs) :-
                     suffix("."), nl],
                 DupSpec = spec($pred, severity_error, phase_pt2h,
                     Context, DupPieces),
-                !:Specs = [DupSpec | !.Specs]
+                !:ErrSpecs = [DupSpec | !.ErrSpecs]
             )
         ;
             !.OISUSpecs = [_ | _],
-            !:Specs = !.OISUSpecs ++ !.Specs
+            !:ErrSpecs = !.OISUSpecs ++ !.ErrSpecs
         )
     ).
 
 :- pred find_unique_pred_for_oisu(module_info::in, prog_context::in,
     type_ctor::in, string::in, pred_pf_name_arity::in, pred_id::out,
-    int::in, int::out, list(diag_spec)::in, list(diag_spec)::out) is det.
+    int::in, int::out, list(err_spec)::in, list(err_spec)::out) is det.
 
 find_unique_pred_for_oisu(ModuleInfo, Context, TypeCtor, Kind,
-        PredSpec, PredId, !SeqNum, !Specs) :-
+        PredSpec, PredId, !SeqNum, !ErrSpecs) :-
     module_info_get_predicate_table(ModuleInfo, PredicateTable),
     PredSpec = pred_pf_name_arity(PredOrFunc, PredName, UserArity),
     user_arity_pred_form_arity(PredOrFunc, UserArity, PredFormArity),
@@ -483,7 +504,7 @@ find_unique_pred_for_oisu(ModuleInfo, Context, TypeCtor, Kind,
                 words("expected arity is")] ++ ExpArities ++ [suffix("."), nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces)
         ),
-        !:Specs = [Spec | !.Specs],
+        !:ErrSpecs = [Spec | !.ErrSpecs],
         PredId = invalid_pred_id
     ;
         PredIds = [PredId]
@@ -499,7 +520,7 @@ find_unique_pred_for_oisu(ModuleInfo, Context, TypeCtor, Kind,
             qual_sym_name_arity(sym_name_arity(PredName, UserArityInt)),
             suffix("."), nl],
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs],
+        !:ErrSpecs = [Spec | !.ErrSpecs],
         PredId = invalid_pred_id
     ),
     !:SeqNum = !.SeqNum + 1.
@@ -516,9 +537,9 @@ lookup_pred_orig_arity(ModuleInfo, PredId, Piece) :-
 
 :- pred add_pragma_termination(decl_pragma_termination_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-add_pragma_termination(TermInfo, !ModuleInfo, !Specs) :-
+add_pragma_termination(TermInfo, !ModuleInfo, !ErrSpecs) :-
     TermInfo = decl_pragma_termination_info(PredNameModesPF,
         MaybePragmaArgSizeInfo, MaybePragmaTerminationInfo, Context, _),
     PredNameModesPF = proc_pf_name_modes(PredOrFunc, SymName, Modes),
@@ -544,7 +565,7 @@ add_pragma_termination(TermInfo, !ModuleInfo, !Specs) :-
                     ProcInfo1, ProcInfo)
             ),
         transform_selected_mode_of_pred(PredId, PFNameArity, Modes,
-            "termination_info", Context, ProcTransform, !ModuleInfo, !Specs)
+            "termination_info", Context, ProcTransform, !ModuleInfo, !ErrSpecs)
     ;
         MaybePredId = error1(_Specs)
     ).
@@ -553,9 +574,9 @@ add_pragma_termination(TermInfo, !ModuleInfo, !Specs) :-
 
 :- pred add_pragma_termination2(decl_pragma_termination2_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-add_pragma_termination2(Term2Info, !ModuleInfo, !Specs) :-
+add_pragma_termination2(Term2Info, !ModuleInfo, !ErrSpecs) :-
     Term2Info = decl_pragma_termination2_info(PredNameModesPF,
         MaybePragmaSuccessArgSizeInfo, MaybePragmaFailureArgSizeInfo,
         MaybePragmaTerminationInfo, Context, _),
@@ -587,7 +608,8 @@ add_pragma_termination2(Term2Info, !ModuleInfo, !Specs) :-
                 )
             ),
         transform_selected_mode_of_pred(PredId, PFNameArity, Modes,
-            "termination2_info", Context, ProcTransform, !ModuleInfo, !Specs)
+            "termination2_info", Context, ProcTransform,
+            !ModuleInfo, !ErrSpecs)
     ;
         MaybePredId = error1(_Specs)
     ).
@@ -596,9 +618,9 @@ add_pragma_termination2(Term2Info, !ModuleInfo, !Specs) :-
 
 :- pred add_pragma_struct_sharing(decl_pragma_struct_sharing_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-add_pragma_struct_sharing(SharingInfo, !ModuleInfo, !Specs):-
+add_pragma_struct_sharing(SharingInfo, !ModuleInfo, !ErrSpecs):-
     SharingInfo = decl_pragma_struct_sharing_info(PredNameModesPF,
         HeadVars, Types, _VarSet, _TVarSet, MaybeSharingDomain, Context, _),
     (
@@ -619,15 +641,15 @@ add_pragma_struct_sharing(SharingInfo, !ModuleInfo, !Specs):-
                 Types, SharingDomain),
             transform_selected_mode_of_pred(PredId, PFNameArity, Modes,
                 "structure_sharing", Context, ProcTransform,
-                !ModuleInfo, !Specs)
+                !ModuleInfo, !ErrSpecs)
         ;
-            MaybePredId = error1(Specs),
+            MaybePredId = error1(IdErrSpecs),
             % XXX There used to be a comment here which said:
             %   XXX lfh_ignore:
             %   This happens in .trans_opt files sometimes, so just ignore it.
             % This was probably because the original code writing out these
             % pragmas was writing Modes with output_debug, not output_mercury.
-            !:Specs = Specs ++ !.Specs
+            !:ErrSpecs = IdErrSpecs ++ !.ErrSpecs
         )
     ).
 
@@ -635,9 +657,9 @@ add_pragma_struct_sharing(SharingInfo, !ModuleInfo, !Specs):-
 
 :- pred add_pragma_struct_reuse(decl_pragma_struct_reuse_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-add_pragma_struct_reuse(ReuseInfo, !ModuleInfo, !Specs):-
+add_pragma_struct_reuse(ReuseInfo, !ModuleInfo, !ErrSpecs):-
     ReuseInfo = decl_pragma_struct_reuse_info(PredNameModesPF,
         HeadVars, Types, _VarSet, _TVarSet, MaybeReuseDomain, Context, _),
     (
@@ -657,7 +679,8 @@ add_pragma_struct_reuse(ReuseInfo, !ModuleInfo, !Specs):-
             ProcTransform = proc_info_set_imported_structure_reuse(HeadVars,
                 Types, ReuseDomain),
             transform_selected_mode_of_pred(PredId, PFNameArity, Modes,
-                "structure_reuse", Context, ProcTransform, !ModuleInfo, !Specs)
+                "structure_reuse", Context, ProcTransform, !ModuleInfo,
+                !ErrSpecs)
         ;
             MaybePredId = error1(Specs),
             % XXX There used to be a comment here which said:
@@ -665,7 +688,7 @@ add_pragma_struct_reuse(ReuseInfo, !ModuleInfo, !Specs):-
             %   This happens in .trans_opt files sometimes, so just ignore it.
             % This was probably because the original code writing out these
             % pragmas was writing Modes with output_debug, not output_mercury.
-            !:Specs = Specs ++ !.Specs
+            !:ErrSpecs = Specs ++ !.ErrSpecs
         )
     ).
 
@@ -674,38 +697,41 @@ add_pragma_struct_reuse(ReuseInfo, !ModuleInfo, !Specs):-
 % Adding decl markers to the HLDS.
 %
 
-add_decl_markers([], !ModuleInfo, !Specs).
-add_decl_markers([ImsList | ImsLists], !ModuleInfo, !Specs) :-
+add_decl_markers([], !ModuleInfo, !ErrSpecs, !WarnSpecs).
+add_decl_markers([ImsList | ImsLists], !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     ImsList = ims_sub_list(ItemMercuryStatus, Items),
-    list.foldl2(add_decl_marker(ItemMercuryStatus), Items,
-        !ModuleInfo, !Specs),
-    add_decl_markers(ImsLists, !ModuleInfo, !Specs).
+    list.foldl3(add_decl_marker(ItemMercuryStatus), Items,
+        !ModuleInfo, !ErrSpecs, !WarnSpecs),
+    add_decl_markers(ImsLists, !ModuleInfo, !ErrSpecs, !WarnSpecs).
 
 %---------------------%
 
 :- pred add_decl_marker(item_mercury_status::in, item_decl_marker_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-add_decl_marker(ItemMercuryStatus, DeclMarker, !ModuleInfo, !Specs) :-
+add_decl_marker(ItemMercuryStatus, DeclMarker, !ModuleInfo,
+        !ErrSpecs, !WarnSpecs) :-
     DeclMarker = item_decl_marker_info(MarkerKind, PFUNameArity, Context, _),
     (
         MarkerKind = dpmk_terminates,
         add_pred_marker(PFUNameArity, "terminates", psc_decl,
             ItemMercuryStatus, Context, marker_terminates,
             [marker_check_termination, marker_does_not_terminate],
-            !ModuleInfo, !Specs)
+            !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         MarkerKind = dpmk_does_not_terminate,
         add_pred_marker(PFUNameArity, "does_not_terminate", psc_decl,
             ItemMercuryStatus, Context, marker_does_not_terminate,
-            [marker_check_termination, marker_terminates], !ModuleInfo, !Specs)
+            [marker_check_termination, marker_terminates],
+            !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         MarkerKind = dpmk_check_termination,
         add_pred_marker(PFUNameArity, "check_termination", psc_decl,
             ItemMercuryStatus, Context, marker_check_termination,
             [marker_terminates, marker_does_not_terminate],
-            !ModuleInfo, !Specs)
+            !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ).
 
 %---------------------------------------------------------------------------%
diff --git a/compiler/add_pragma_gen.m b/compiler/add_pragma_gen.m
index 61b891d01..1cd3fe29a 100644
--- a/compiler/add_pragma_gen.m
+++ b/compiler/add_pragma_gen.m
@@ -25,19 +25,19 @@
 
 :- pred add_gen_pragma_unused_args(gen_pragma_unused_args_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 :- pred add_gen_pragma_exceptions(gen_pragma_exceptions_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 :- pred add_gen_pragma_trailing(gen_pragma_trailing_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 :- pred add_gen_pragma_mm_tabling(gen_pragma_mm_tabling_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
diff --git a/compiler/add_pragma_impl.m b/compiler/add_pragma_impl.m
index 2ae50e034..2cd111c4f 100644
--- a/compiler/add_pragma_impl.m
+++ b/compiler/add_pragma_impl.m
@@ -31,22 +31,25 @@
     ims_cord(impl_pragma_tabled_info)::in,
         ims_cord(impl_pragma_tabled_info)::out,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 :- pred add_impl_pragmas_tabled(io.text_output_stream::in,
     ims_list(impl_pragma_tabled_info)::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 :- pred add_pragma_foreign_proc_export(impl_pragma_fproc_export_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------%
 
 :- pred add_impl_markers(ims_list(item_impl_marker_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -87,6 +90,7 @@
 :- import_module cord.
 :- import_module map.
 :- import_module maybe.
+:- import_module one_or_more.
 :- import_module pair.
 :- import_module require.
 :- import_module set.
@@ -97,12 +101,13 @@
 % Adding impl pragmas to the HLDS.
 %
 
-add_impl_pragmas(_, [], !PragmaTabledListCord, !ModuleInfo, !Specs).
+add_impl_pragmas(_, [], !PragmaTabledListCord, !ModuleInfo,
+        !ErrSpecs, !WarnSpecs).
 add_impl_pragmas(ProgressStream, [ImsList | ImsLists],
-        !PragmaTabledListCord, !ModuleInfo, !Specs) :-
+        !PragmaTabledListCord, !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     ImsList = ims_sub_list(ItemMercuryStatus, Items),
-    list.foldl3(add_impl_pragma(ProgressStream, ItemMercuryStatus), Items,
-        cord.init, PragmaTabledCord, !ModuleInfo, !Specs),
+    list.foldl4(add_impl_pragma(ProgressStream, ItemMercuryStatus), Items,
+        cord.init, PragmaTabledCord, !ModuleInfo, !ErrSpecs, !WarnSpecs),
     PragmaTabledList = cord.list(PragmaTabledCord),
     (
         PragmaTabledList = []
@@ -112,17 +117,17 @@ add_impl_pragmas(ProgressStream, [ImsList | ImsLists],
         cord.snoc(SubList, !PragmaTabledListCord)
     ),
     add_impl_pragmas(ProgressStream, ImsLists,
-        !PragmaTabledListCord, !ModuleInfo, !Specs).
+        !PragmaTabledListCord, !ModuleInfo, !ErrSpecs, !WarnSpecs).
 
-add_impl_pragmas_tabled(_, [], !ModuleInfo, !QualInfo, !Specs).
+add_impl_pragmas_tabled(_, [], !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs).
 add_impl_pragmas_tabled(ProgressStream, [ImsList | ImsLists],
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     ImsList = ims_sub_list(ItemMercuryStatus, Items),
-    list.foldl3(
+    list.foldl4(
         add_impl_pragma_tabled(ProgressStream, ItemMercuryStatus), Items,
-        !ModuleInfo, !QualInfo, !Specs),
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs),
     add_impl_pragmas_tabled(ProgressStream, ImsLists,
-        !ModuleInfo, !QualInfo, !Specs).
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs).
 
 %---------------------%
 
@@ -130,10 +135,11 @@ add_impl_pragmas_tabled(ProgressStream, [ImsList | ImsLists],
     item_impl_pragma_info::in,
     cord(impl_pragma_tabled_info)::in, cord(impl_pragma_tabled_info)::out,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 add_impl_pragma(ProgressStream, ItemMercuryStatus, Pragma, !PragmaTabledCord,
-        !ModuleInfo, !Specs) :-
+        !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     (
         Pragma = impl_pragma_foreign_decl(FDInfo),
         % XXX STATUS Check ItemMercuryStatus
@@ -145,37 +151,37 @@ add_impl_pragma(ProgressStream, ItemMercuryStatus, Pragma, !PragmaTabledCord,
         Pragma = impl_pragma_foreign_code(FCInfo),
         % XXX STATUS Check ItemMercuryStatus
         FCInfo = impl_pragma_foreign_code_info(Lang, BodyCode, Context, _),
-        warn_suspicious_foreign_code(Lang, BodyCode, Context, !Specs),
+        warn_suspicious_foreign_code(Lang, BodyCode, Context, !WarnSpecs),
         ForeignBodyCode = foreign_body_code(Lang, BodyCode, Context),
         module_add_foreign_body_code(ForeignBodyCode, !ModuleInfo)
     ;
         Pragma = impl_pragma_fproc_export(FEInfo),
-        add_pragma_foreign_proc_export(FEInfo, !ModuleInfo, !Specs)
+        add_pragma_foreign_proc_export(FEInfo, !ModuleInfo, !ErrSpecs)
     ;
         Pragma = impl_pragma_external_proc(ExternalInfo),
-        add_pragma_external_proc(ExternalInfo, !ModuleInfo, !Specs)
+        add_pragma_external_proc(ExternalInfo, !ModuleInfo, !ErrSpecs)
     ;
         Pragma = impl_pragma_fact_table(FTInfo),
         item_mercury_status_to_pred_status(ItemMercuryStatus, PredStatus),
         add_pragma_fact_table(ProgressStream, ItemMercuryStatus, PredStatus,
-            FTInfo, !ModuleInfo, !Specs)
+            FTInfo, !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         Pragma = impl_pragma_tabled(TabledInfo),
         cord.snoc(TabledInfo, !PragmaTabledCord)
     ;
         Pragma = impl_pragma_req_tail_rec(TailrecWarningPragma),
         add_pragma_require_tail_rec(TailrecWarningPragma,
-            !ModuleInfo, !Specs)
+            !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         Pragma = impl_pragma_req_feature_set(RFSInfo),
         RFSInfo = impl_pragma_req_feature_set_info(FeatureSet, Context, _),
         check_required_feature_set(!.ModuleInfo, FeatureSet,
-            ItemMercuryStatus, Context, !Specs)
+            ItemMercuryStatus, Context, !ErrSpecs)
     ).
 
 %---------------------%
 
-add_pragma_foreign_proc_export(FPEInfo, !ModuleInfo, !Specs) :-
+add_pragma_foreign_proc_export(FPEInfo, !ModuleInfo, !ErrSpecs) :-
     FPEInfo = impl_pragma_fproc_export_info(Origin, Lang,
         PredNameModesPF, ExportedName, VarSet, Context, _),
     PredNameModesPF = proc_pf_name_modes(PredOrFunc, SymName, ArgModes),
@@ -220,7 +226,7 @@ add_pragma_foreign_proc_export(FPEInfo, !ModuleInfo, !Specs) :-
                     [nl],
                 Spec = spec($pred, severity_error, phase_pt2h,
                     Context, Pieces),
-                !:Specs = [Spec | !.Specs]
+                !:ErrSpecs = [Spec | !.ErrSpecs]
             else
                 % Only add the foreign export if the specified language matches
                 % one of the foreign languages available for this backend.
@@ -256,7 +262,7 @@ add_pragma_foreign_proc_export(FPEInfo, !ModuleInfo, !Specs) :-
                     [pragma_decl("foreign_export"), words("declaration")],
                 report_undeclared_mode_error(!.ModuleInfo, PredId, PredInfo,
                     VarSet, ArgModes, DescPieces, Context, Spec),
-                !:Specs = [Spec | !.Specs]
+                !:ErrSpecs = [Spec | !.ErrSpecs]
             ;
                 Origin = item_origin_compiler(_CompilerAttrs)
                 % We do not warn about errors in export pragmas created by
@@ -268,7 +274,7 @@ add_pragma_foreign_proc_export(FPEInfo, !ModuleInfo, !Specs) :-
         MaybePredId = error1(Specs),
         (
             Origin = item_origin_user,
-            !:Specs = Specs ++ !.Specs
+            !:ErrSpecs = Specs ++ !.ErrSpecs
         ;
             Origin = item_origin_compiler(_CompilerAttrs)
             % We do not warn about errors in export pragmas created by
@@ -281,9 +287,9 @@ add_pragma_foreign_proc_export(FPEInfo, !ModuleInfo, !Specs) :-
 
 :- pred add_pragma_external_proc(impl_pragma_external_proc_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-add_pragma_external_proc(ExternalInfo, !ModuleInfo, !Specs) :-
+add_pragma_external_proc(ExternalInfo, !ModuleInfo, !ErrSpecs) :-
     % XXX STATUS Check ItemMercuryStatus
     ExternalInfo = impl_pragma_external_proc_info(PFNameArity, MaybeBackend,
         Context, _),
@@ -319,7 +325,7 @@ add_pragma_external_proc(ExternalInfo, !ModuleInfo, !Specs) :-
         (
             PredIds = [_ | _],
             list.foldl2(mark_pred_as_external(Context), PredIds,
-                !ModuleInfo, !Specs)
+                !ModuleInfo, !ErrSpecs)
         ;
             PredIds = [],
             module_info_get_pred_id_table(!.ModuleInfo, PredIdTable0),
@@ -327,7 +333,8 @@ add_pragma_external_proc(ExternalInfo, !ModuleInfo, !Specs) :-
                 UserArity, OtherUserArities),
             report_undefined_pred_or_func_error(yes(PredOrFunc),
                 SymName, UserArity, OtherUserArities, Context,
-                DeclPieces, !Specs)
+                DeclPieces, UndefErrSpec),
+            !:ErrSpecs = [UndefErrSpec | !.ErrSpecs]
         )
     else
         true
@@ -335,9 +342,9 @@ add_pragma_external_proc(ExternalInfo, !ModuleInfo, !Specs) :-
 
 :- pred mark_pred_as_external(prog_context::in, pred_id::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-mark_pred_as_external(Context, PredId, !ModuleInfo, !Specs) :-
+mark_pred_as_external(Context, PredId, !ModuleInfo, !ErrSpecs) :-
     module_info_pred_info(!.ModuleInfo, PredId, PredInfo0),
     pred_info_get_clauses_info(PredInfo0, ClausesInfo0),
     clauses_info_get_clauses_rep(ClausesInfo0, ClausesRep0, _ItemNumbers),
@@ -358,7 +365,7 @@ mark_pred_as_external(Context, PredId, !ModuleInfo, !Specs) :-
             color_as_incorrect([words("it cannot be marked as external.")]) ++
             [nl],
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ).
 
 %---------------------%
@@ -375,10 +382,11 @@ mark_pred_as_external(Context, PredId, !ModuleInfo, !Specs) :-
 :- pred add_pragma_fact_table(io.text_output_stream::in,
     item_mercury_status::in, pred_status::in, impl_pragma_fact_table_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 add_pragma_fact_table(ProgressStream, ItemMercuryStatus, PredStatus, FTInfo,
-        !ModuleInfo, !Specs) :-
+        !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     FTInfo = impl_pragma_fact_table_info(PredSpec, FileName, Context, _),
     PredSpec = pred_pfu_name_arity(PFU, PredSymName, UserArity),
     get_matching_pred_ids(!.ModuleInfo, "fact_table", require_one_match,
@@ -391,7 +399,7 @@ add_pragma_fact_table(ProgressStream, ItemMercuryStatus, PredStatus, FTInfo,
             CheckResult),
         (
             CheckResult = fact_table_args_not_ok(CheckSpecs),
-            !:Specs = CheckSpecs ++ !.Specs,
+            !:ErrSpecs = CheckSpecs ++ !.ErrSpecs,
             pred_info_get_markers(PredInfo0, PredMarkers0),
             add_marker(marker_fact_table_semantic_errors,
                 PredMarkers0, PredMarkers),
@@ -409,7 +417,7 @@ add_pragma_fact_table(ProgressStream, ItemMercuryStatus, PredStatus, FTInfo,
                     semipure io.unsafe_get_io_state(!:IO),
                     fact_table_compile_facts(ProgressStream, !.ModuleInfo,
                         FileName, Context, GenInfo, C_HeaderCode,
-                        PrimaryProcId, PredInfo0, PredInfo1, !Specs, !IO),
+                        PrimaryProcId, PredInfo0, PredInfo1, !ErrSpecs, !IO),
                     impure io.unsafe_set_io_state(!.IO)
                 )
             ),
@@ -436,11 +444,12 @@ add_pragma_fact_table(ProgressStream, ItemMercuryStatus, PredStatus, FTInfo,
             % Create foreign_procs to access the table in each mode.
             add_fact_table_procs(ProgressStream, PredOrFunc, PredSymName,
                 ItemMercuryStatus, PredStatus, ProcTable,  PrimaryProcId,
-                Context, GenInfo, ProcIds, !ModuleInfo, !Specs)
+                Context, GenInfo, ProcIds, !ModuleInfo, !ErrSpecs, !WarnSpecs)
         )
     ;
-        MatchingPredIdResult = mpids_error(ErrorSpecs),
-        !:Specs = ErrorSpecs ++ !.Specs
+        MatchingPredIdResult = mpids_error(IdErrSpecs, IdWarnSpecs),
+        !:ErrSpecs = one_or_more_to_list(IdErrSpecs) ++ !.ErrSpecs,
+        !:WarnSpecs = IdWarnSpecs ++ !.WarnSpecs
     ).
 
     % Add a `pragma foreign_proc' for each mode of the fact table lookup
@@ -453,29 +462,32 @@ add_pragma_fact_table(ProgressStream, ItemMercuryStatus, PredStatus, FTInfo,
     sym_name::in, item_mercury_status::in, pred_status::in,
     proc_table::in, proc_id::in, prog_context::in, fact_table_gen_info::in,
     list(proc_id)::in, module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-add_fact_table_procs(_, _, _, _, _, _, _, _, _, [], !ModuleInfo, !Specs).
+add_fact_table_procs(_, _, _, _, _, _, _, _, _, [],
+        !ModuleInfo, !ErrSpecs, !WarnSpecs).
 add_fact_table_procs(ProgressStream, PredOrFunc, SymName,
         ItemMercuryStatus, PredStatus, ProcTable, PrimaryProcId, Context,
-        GenInfo, [ProcId | ProcIds], !ModuleInfo, !Specs) :-
+        GenInfo, [ProcId | ProcIds], !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     add_fact_table_proc(ProgressStream, PredOrFunc, SymName,
         ItemMercuryStatus, PredStatus, ProcTable, PrimaryProcId, Context,
-        GenInfo, ProcId, !ModuleInfo, !Specs),
+        GenInfo, ProcId, !ModuleInfo, !ErrSpecs, !WarnSpecs),
     add_fact_table_procs(ProgressStream, PredOrFunc, SymName,
         ItemMercuryStatus, PredStatus, ProcTable, PrimaryProcId, Context,
-        GenInfo, ProcIds, !ModuleInfo, !Specs).
+        GenInfo, ProcIds, !ModuleInfo, !ErrSpecs, !WarnSpecs).
 
 :- pred add_fact_table_proc(io.text_output_stream::in,
     pred_or_func::in, sym_name::in,
     item_mercury_status::in, pred_status::in, proc_table::in, proc_id::in,
     prog_context::in, fact_table_gen_info::in, proc_id::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 add_fact_table_proc(ProgressStream, PredOrFunc, SymName,
         ItemMercuryStatus, PredStatus, ProcTable, PrimaryProcId, Context,
-        GenInfo, ProcId, !ModuleInfo, !Specs) :-
+        GenInfo, ProcId, !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     map.lookup(ProcTable, ProcId, ProcInfo),
     proc_info_get_inst_varset(ProcInfo, InstVarSet),
 
@@ -494,7 +506,7 @@ add_fact_table_proc(ProgressStream, PredOrFunc, SymName,
         Context, item_no_seq_num),
     % XXX Should return this instead.
     add_foreign_proc(ProgressStream, ItemMercuryStatus, PredStatus, FCInfo,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs, !WarnSpecs),
     ( if C_ExtraCode = "" then
         true
     else
@@ -508,9 +520,10 @@ add_fact_table_proc(ProgressStream, PredOrFunc, SymName,
 
 :- pred add_pragma_require_tail_rec(impl_pragma_req_tail_rec_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-add_pragma_require_tail_rec(Pragma, !ModuleInfo, !Specs) :-
+add_pragma_require_tail_rec(Pragma, !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     Pragma = impl_pragma_req_tail_rec_info(PredSpec, RequireTailrec,
         Context, _),
     PredSpec = pred_or_proc_pfumm_name(PFUMM, PredSymName),
@@ -549,7 +562,7 @@ add_pragma_require_tail_rec(Pragma, !ModuleInfo, !Specs) :-
                 map.lookup(Procs0, ProcId, Proc),
                 add_pragma_require_tail_rec_proc(RequireTailrec, Context,
                     MaybePredOrFunc, MaybeModes, SNA, ProcId - Proc,
-                    PredInfo0, PredInfo, !Specs)
+                    PredInfo0, PredInfo, !ErrSpecs)
             else
                 PredInfo = PredInfo0,
                 PredOrFunc = pred_info_is_pred_or_func(PredInfo),
@@ -565,29 +578,30 @@ add_pragma_require_tail_rec(Pragma, !ModuleInfo, !Specs) :-
                     [nl],
                 Spec = spec($pred, severity_error, phase_pt2h,
                     Context, Pieces),
-                !:Specs = [Spec | !.Specs]
+                !:ErrSpecs = [Spec | !.ErrSpecs]
             )
         ;
             MaybeModes = no,
             list.foldl2(
                 add_pragma_require_tail_rec_proc(RequireTailrec, Context,
                     MaybePredOrFunc, MaybeModes, SNA),
-                Procs, PredInfo0, PredInfo, !Specs)
+                Procs, PredInfo0, PredInfo, !ErrSpecs)
         ),
         module_info_set_pred_info(PredId, PredInfo, !ModuleInfo)
     ;
-        MatchingPredIdResult = mpids_error(ErrorSpecs),
-        !:Specs = ErrorSpecs ++ !.Specs
+        MatchingPredIdResult = mpids_error(IdErrSpecs, IdWarnSpecs),
+        !:ErrSpecs = one_or_more_to_list(IdErrSpecs) ++ !.ErrSpecs,
+        !:WarnSpecs = IdWarnSpecs ++ !.WarnSpecs
     ).
 
 :- pred add_pragma_require_tail_rec_proc(require_tail_recursion::in,
     prog_context::in, maybe(pred_or_func)::in, maybe(list(mer_mode))::in,
     sym_name_arity::in, pair(proc_id, proc_info)::in,
     pred_info::in, pred_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_pragma_require_tail_rec_proc(RequireTailrec, Context, MaybePredOrFunc,
-        MaybeModes, SNA, ProcId - ProcInfo0, !PredInfo, !Specs) :-
+        MaybeModes, SNA, ProcId - ProcInfo0, !PredInfo, !ErrSpecs) :-
     proc_info_get_maybe_require_tailrec_info(ProcInfo0,
         MaybeRequireTailrecOrig),
     (
@@ -616,10 +630,10 @@ add_pragma_require_tail_rec_proc(RequireTailrec, Context, MaybePredOrFunc,
         ( RequireTailrecOrig = disable_nontailrec_reports(ContextOrig)
         ; RequireTailrecOrig = enable_nontailrec_reports(_, _, _, ContextOrig)
         ),
-        Spec = diag_spec($pred, severity_error, phase_pt2h,
+        Spec = gen_spec($pred, severity_error, phase_pt2h,
             [msg(Context, MainPieces),
             msg(ContextOrig, OrigPieces)]),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ;
         MaybeRequireTailrecOrig = no,
         proc_info_set_require_tailrec_info(RequireTailrec,
@@ -631,10 +645,10 @@ add_pragma_require_tail_rec_proc(RequireTailrec, Context, MaybePredOrFunc,
 
 :- pred check_required_feature_set(module_info::in, set(required_feature)::in,
     item_mercury_status::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_required_feature_set(ModuleInfo, FeatureSet, ItemMercuryStatus, Context,
-        !Specs) :-
+        !ErrSpecs) :-
     (
         ItemMercuryStatus = item_defined_in_other_module(_),
         % `require_feature_set' pragmas are not included in interface files
@@ -643,14 +657,15 @@ check_required_feature_set(ModuleInfo, FeatureSet, ItemMercuryStatus, Context,
     ;
         ItemMercuryStatus = item_defined_in_this_module(_),
         module_info_get_globals(ModuleInfo, Globals),
-        set.fold(check_required_feature(Globals, Context), FeatureSet, !Specs)
+        set.fold(check_required_feature(Globals, Context), FeatureSet,
+            !ErrSpecs)
     ).
 
 :- pred check_required_feature(globals::in,
     prog_context::in, required_feature::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-check_required_feature(Globals, Context, Feature, !Specs) :-
+check_required_feature(Globals, Context, Feature, !ErrSpecs) :-
     (
         Feature = reqf_concurrency,
         current_grade_supports_concurrency(Globals, IsConcurrencySupported),
@@ -661,7 +676,7 @@ check_required_feature(Globals, Context, Feature, !Specs) :-
                     words("supports concurrent execution.")]) ++
                 [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         ;
             IsConcurrencySupported = yes
         )
@@ -680,8 +695,8 @@ check_required_feature(Globals, Context, Feature, !Specs) :-
                 quote("spf"), suffix("."), nl],
             Msg = simple_msg(Context,
                 [always(Pieces), verbose_only(verbose_once, VerbosePieces)]),
-            Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg]),
-            !:Specs = [Spec | !.Specs]
+            Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg]),
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         ;
             SinglePrecFloat = yes
         )
@@ -700,8 +715,8 @@ check_required_feature(Globals, Context, Feature, !Specs) :-
                 quote("spf"), suffix("."), nl],
             Msg = simple_msg(Context,
                 [always(Pieces), verbose_only(verbose_once, VerbosePieces)]),
-            Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg]),
-            !:Specs = [Spec | !.Specs]
+            Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg]),
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         ;
             SinglePrecFloat = no
         )
@@ -716,7 +731,7 @@ check_required_feature(Globals, Context, Feature, !Specs) :-
                     words("supports memoisation.")]) ++
                 [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         ;
             IsTablingSupported = yes
         )
@@ -730,7 +745,7 @@ check_required_feature(Globals, Context, Feature, !Specs) :-
                     words("supports executing conjuntions in parallel.")]) ++
                 [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         ;
             IsParConjSupported = yes
         )
@@ -747,8 +762,8 @@ check_required_feature(Globals, Context, Feature, !Specs) :-
                 words("the grade modifier"), quote("tr"), suffix("."), nl],
             Msg = simple_msg(Context,
                 [always(Pieces), verbose_only(verbose_once, VerbosePieces)]),
-            Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg]),
-            !:Specs = [Spec | !.Specs]
+            Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg]),
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         ;
             UseTrail = yes
         )
@@ -769,7 +784,7 @@ check_required_feature(Globals, Context, Feature, !Specs) :-
                     words("sequential semantics.")]) ++
                 [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         )
     ;
         Feature = reqf_conservative_gc,
@@ -792,7 +807,7 @@ check_required_feature(Globals, Context, Feature, !Specs) :-
                     words("uses conservative garbage collection.")]) ++
                 [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         )
     ).
 
@@ -801,17 +816,19 @@ check_required_feature(Globals, Context, Feature, !Specs) :-
 :- pred add_impl_pragma_tabled(io.text_output_stream::in,
     item_mercury_status::in, impl_pragma_tabled_info::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 add_impl_pragma_tabled(ProgressStream, ItemMercuryStatus, Tabled,
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     module_info_get_globals(!.ModuleInfo, Globals),
     globals.lookup_bool_option(Globals, type_layout, TypeLayout),
     (
         TypeLayout = yes,
         item_mercury_status_to_pred_status(ItemMercuryStatus, PredStatus),
         module_add_pragma_tabled(ProgressStream, Tabled,
-            ItemMercuryStatus, PredStatus, !ModuleInfo, !QualInfo, !Specs)
+            ItemMercuryStatus, PredStatus, !ModuleInfo, !QualInfo,
+            !ErrSpecs, !WarnSpecs)
     ;
         TypeLayout = no,
         Tabled = impl_pragma_tabled_info(TabledMethod, _, _, Context, _),
@@ -823,7 +840,7 @@ add_impl_pragma_tabled(ProgressStream, ItemMercuryStatus, Tabled,
                 [words("requires type_ctor_layout structures.")]) ++
             [words("Don't use --no-type-layout to disable them."), nl],
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ).
 
 %---------------------------------------------------------------------------%
@@ -831,20 +848,22 @@ add_impl_pragma_tabled(ProgressStream, ItemMercuryStatus, Tabled,
 % Adding impl markers to the HLDS.
 %
 
-add_impl_markers([], !ModuleInfo, !Specs).
-add_impl_markers([ImsList | ImsLists], !ModuleInfo, !Specs) :-
+add_impl_markers([], !ModuleInfo, !ErrSpecs, !WarnSpecs).
+add_impl_markers([ImsList | ImsLists], !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     ImsList = ims_sub_list(ItemMercuryStatus, Items),
-    list.foldl2(add_impl_marker(ItemMercuryStatus), Items,
-        !ModuleInfo, !Specs),
-    add_impl_markers(ImsLists, !ModuleInfo, !Specs).
+    list.foldl3(add_impl_marker(ItemMercuryStatus), Items,
+        !ModuleInfo, !ErrSpecs, !WarnSpecs),
+    add_impl_markers(ImsLists, !ModuleInfo, !ErrSpecs, !WarnSpecs).
 
 %---------------------%
 
 :- pred add_impl_marker(item_mercury_status::in, item_impl_marker_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-add_impl_marker(ItemMercuryStatus, ImplMarker, !ModuleInfo, !Specs) :-
+add_impl_marker(ItemMercuryStatus, ImplMarker, !ModuleInfo,
+        !ErrSpecs, !WarnSpecs) :-
     ImplMarker = item_impl_marker_info(MarkerKind, PFUNameArity, Context, _),
     (
         MarkerKind = ipmk_inline,
@@ -853,22 +872,22 @@ add_impl_marker(ItemMercuryStatus, ImplMarker, !ModuleInfo, !Specs) :-
         add_pred_marker(PFUNameArity, "inline", psc_impl,
             ItemMercuryStatus, Context, marker_user_marked_inline,
             [marker_user_marked_no_inline, marker_mode_check_clauses],
-            !ModuleInfo, !Specs)
+            !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         MarkerKind = ipmk_no_inline,
         add_pred_marker(PFUNameArity, "no_inline", psc_impl,
             ItemMercuryStatus, Context, marker_user_marked_no_inline,
-            [marker_user_marked_inline], !ModuleInfo, !Specs)
+            [marker_user_marked_inline], !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         MarkerKind = ipmk_consider_used,
         add_pred_marker(PFUNameArity, "consider_used", psc_impl,
             ItemMercuryStatus, Context, marker_consider_used,
-            [], !ModuleInfo, !Specs)
+            [], !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         MarkerKind = ipmk_mode_check_clauses,
         add_pred_marker(PFUNameArity, "mode_check_clauses", psc_impl,
             ItemMercuryStatus, Context, marker_mode_check_clauses,
-            [], !ModuleInfo, !Specs),
+            [], !ModuleInfo, !ErrSpecs, !WarnSpecs),
         % Allowing the predicate to be inlined could lead to code generator
         % aborts. This is because the caller that inlines this predicate may
         % then push other code into the disjunction or switch's branches,
@@ -876,33 +895,33 @@ add_impl_marker(ItemMercuryStatus, ImplMarker, !ModuleInfo, !Specs) :-
         % marker prevents the recomputation of.
         add_pred_marker(PFUNameArity, "mode_check_clauses", psc_impl,
             ItemMercuryStatus, Context, marker_mmc_marked_no_inline,
-            [marker_user_marked_inline], !ModuleInfo, !Specs)
+            [marker_user_marked_inline], !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         MarkerKind = ipmk_no_detism_warning,
         add_pred_marker(PFUNameArity, "no_determinism_warning", psc_impl,
             ItemMercuryStatus, Context, marker_no_detism_warning,
-            [], !ModuleInfo, !Specs)
+            [], !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         MarkerKind = ipmk_promise_pure,
         add_pred_marker(PFUNameArity, "promise_pure", psc_impl,
             ItemMercuryStatus, Context, marker_promised_pure,
-            [], !ModuleInfo, !Specs)
+            [], !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         MarkerKind = ipmk_promise_semipure,
         add_pred_marker(PFUNameArity, "promise_semipure", psc_impl,
             ItemMercuryStatus, Context, marker_promised_semipure,
-            [], !ModuleInfo, !Specs)
+            [], !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         MarkerKind = ipmk_promise_eqv_clauses,
         add_pred_marker(PFUNameArity, "promise_equivalent_clauses", psc_impl,
             ItemMercuryStatus, Context, marker_promised_equivalent_clauses,
-            [], !ModuleInfo, !Specs)
+            [], !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ;
         MarkerKind = ipmk_req_sw_arms_type_order,
         add_pred_marker(PFUNameArity,
             "require_switch_arms_in_type_order", psc_impl,
             ItemMercuryStatus, Context, marker_req_sw_arms_type_order,
-            [], !ModuleInfo, !Specs)
+            [], !ModuleInfo, !ErrSpecs, !WarnSpecs)
     ).
 
 %---------------------------------------------------------------------------%
diff --git a/compiler/add_pragma_tabling.m b/compiler/add_pragma_tabling.m
index eb38fa04e..065694158 100644
--- a/compiler/add_pragma_tabling.m
+++ b/compiler/add_pragma_tabling.m
@@ -22,7 +22,8 @@
 :- pred module_add_pragma_tabled(io.text_output_stream::in,
     impl_pragma_tabled_info::in, item_mercury_status::in, pred_status::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -75,7 +76,8 @@
 :- import_module varset.
 
 module_add_pragma_tabled(ProgressStream, TabledInfo,
-        ItemMercuryStatus, PredStatus, !ModuleInfo, !QualInfo, !Specs) :-
+        ItemMercuryStatus, PredStatus, !ModuleInfo, !QualInfo,
+        !ErrSpecs, !WarnSpecs) :-
     TabledInfo = impl_pragma_tabled_info(TabledMethod, PredOrProcSpec,
         MaybeAttributes, Context, _SeqNum),
     PredOrProcSpec = pred_or_proc_pfumm_name(PFUMM, PredSymName),
@@ -118,7 +120,7 @@ module_add_pragma_tabled(ProgressStream, TabledInfo,
             add_implicit_pred_decl_report_error(PredOrFunc,
                 PredModuleName, PredName, PredFormArity, PredStatus,
                 is_not_a_class_method, Context, Origin, DescPieces,
-                PredId, !ModuleInfo, !Specs),
+                PredId, !ModuleInfo, !ErrSpecs),
             PredIds = [PredId]
         ;
             MaybePredId = yes(PredId),
@@ -128,7 +130,8 @@ module_add_pragma_tabled(ProgressStream, TabledInfo,
         PFUMM = pfumm_unknown(UserArity),
         TabledMethodStr = tabled_eval_method_to_string(TabledMethod),
         maybe_warn_about_pfumm_unknown(!.ModuleInfo, TabledMethodStr, PFUMM,
-            PredSymName, Context, !Specs),
+            PredSymName, Context, PFUMMSpecs),
+        !:WarnSpecs = PFUMMSpecs ++ !.WarnSpecs,
         predicate_table_lookup_m_n_a(PredicateTable0, is_fully_qualified,
             PredModuleName, PredName, UserArity, PredIds0),
         (
@@ -143,7 +146,7 @@ module_add_pragma_tabled(ProgressStream, TabledInfo,
             add_implicit_pred_decl_report_error(pf_predicate,
                 PredModuleName, PredName, PredFormArity, PredStatus,
                 is_not_a_class_method, Context, Origin,
-                DescPieces, PredId, !ModuleInfo, !Specs),
+                DescPieces, PredId, !ModuleInfo, !ErrSpecs),
             PredIds = [PredId]
         ;
             PredIds0 = [_ | _],
@@ -172,7 +175,7 @@ module_add_pragma_tabled(ProgressStream, TabledInfo,
                     words("would have an ambiguous name too."), nl],
                 StatsSpec = spec($pred, severity_error, phase_pt2h,
                     Context, StatsPieces),
-                !:Specs = [StatsSpec | !.Specs]
+                !:ErrSpecs = [StatsSpec | !.ErrSpecs]
             ;
                 Statistics = table_do_not_gather_statistics
             ),
@@ -188,7 +191,7 @@ module_add_pragma_tabled(ProgressStream, TabledInfo,
                     words("would have an ambiguous name too."), nl],
                 ResetSpec = spec($pred, severity_error, phase_pt2h,
                     Context, ResetPieces),
-                !:Specs = [ResetSpec | !.Specs]
+                !:ErrSpecs = [ResetSpec | !.ErrSpecs]
             ;
                 AllowReset = table_do_not_allow_reset
             )
@@ -196,11 +199,11 @@ module_add_pragma_tabled(ProgressStream, TabledInfo,
     ;
         MaybeAttributes = no
     ),
-    list.foldl3(
+    list.foldl4(
         module_add_pragma_tabled_for_pred(ProgressStream, TabledMethod, PFUMM,
             PredModuleName, PredName, MaybeAttributes, Context,
             ItemMercuryStatus, PredStatus),
-        PredIds, !ModuleInfo, !QualInfo, !Specs).
+        PredIds, !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs).
 
 :- pred module_add_pragma_tabled_for_pred(io.text_output_stream::in,
     tabled_eval_method::in,
@@ -208,12 +211,13 @@ module_add_pragma_tabled(ProgressStream, TabledInfo,
     maybe(table_attributes)::in, prog_context::in,
     item_mercury_status::in, pred_status::in, pred_id::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 module_add_pragma_tabled_for_pred(ProgressStream, TabledMethod0, PFUMM,
         PredModuleName, PredName, MaybeAttributes, Context,
         ItemMercuryStatus, PredStatus, PredId,
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     module_info_get_globals(!.ModuleInfo, Globals),
     ( if TabledMethod0 = tabled_minimal(_) then
         globals.lookup_bool_option(Globals, use_minimal_model_own_stacks,
@@ -284,7 +288,7 @@ module_add_pragma_tabled_for_pred(ProgressStream, TabledMethod0, PFUMM,
         Severity = severity_warning(warn_table_with_inline),
         InlineWarningSpec = spec($pred, Severity, phase_pt2h,
             Context, InlineWarningPieces),
-        !:Specs = [InlineWarningSpec | !.Specs]
+        !:WarnSpecs = [InlineWarningSpec | !.WarnSpecs]
     else
         true
     ),
@@ -299,7 +303,7 @@ module_add_pragma_tabled_for_pred(ProgressStream, TabledMethod0, PFUMM,
             color_as_subject([qual_sym_name_arity(SNA), suffix(".")]) ++
             [nl],
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     else
         % Do we have to make sure the tabled preds are stratified?
         NeedsStrat = tabled_eval_method_needs_stratification(TabledMethod),
@@ -325,7 +329,8 @@ module_add_pragma_tabled_for_pred(ProgressStream, TabledMethod0, PFUMM,
                     PredInfo0, PredOrFunc, PredModuleName, PredName, UserArity,
                     ProcId, ProcInfo0, is_single_proc, Context, TabledMethod,
                     MaybeAttributes, ItemMercuryStatus, PredStatus,
-                    ProcTable0, ProcTable, !ModuleInfo, !QualInfo, !Specs),
+                    ProcTable0, ProcTable, !ModuleInfo, !QualInfo,
+                    !ErrSpecs, !WarnSpecs),
                 pred_info_set_proc_table(ProcTable, PredInfo0, PredInfo),
                 module_info_set_pred_info(PredId, PredInfo, !ModuleInfo)
             else
@@ -340,7 +345,7 @@ module_add_pragma_tabled_for_pred(ProgressStream, TabledMethod0, PFUMM,
                     [nl],
                 Spec = spec($pred, severity_error, phase_pt2h,
                     Context, Pieces),
-                !:Specs = [Spec | !.Specs]
+                !:ErrSpecs = [Spec | !.ErrSpecs]
             )
         ;
             MaybeModes = no,
@@ -359,7 +364,7 @@ module_add_pragma_tabled_for_pred(ProgressStream, TabledMethod0, PFUMM,
                     [nl],
                 Spec = spec($pred, severity_error, phase_pt2h,
                     Context, Pieces),
-                !:Specs = [Spec | !.Specs]
+                !:ErrSpecs = [Spec | !.ErrSpecs]
             ;
                 ExistingProcs = [_ | ExistingProcsTail],
                 (
@@ -374,7 +379,7 @@ module_add_pragma_tabled_for_pred(ProgressStream, TabledMethod0, PFUMM,
                     ExistingProcs, SingleProc, Context,
                     TabledMethod, MaybeAttributes,
                     ItemMercuryStatus, PredStatus, ProcTable0, ProcTable,
-                    !ModuleInfo, !QualInfo, !Specs),
+                    !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs),
                 pred_info_set_proc_table(ProcTable, PredInfo0, PredInfo),
                 module_info_set_pred_info(PredId, PredInfo, !ModuleInfo)
             )
@@ -406,23 +411,24 @@ tabled_eval_method_needs_stratification(TabledMethod) = NeedsStratification :-
     item_mercury_status::in, pred_status::in,
     proc_table::in, proc_table::out, module_info::in, module_info::out,
     qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 set_eval_method_create_aux_preds_list(_, _, _, _, _, _, [], _, _, _, _, _, _,
-        !ProcTable, !ModuleInfo, !QualInfo, !Specs).
+        !ProcTable, !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs).
 set_eval_method_create_aux_preds_list(ProgressStream, PredInfo, PredOrFunc,
         PredModuleName, PredName, UserArity,
         [ProcId - ProcInfo0 | ProcIdsInfos], SingleProc, Context,
         TabledMethod, MaybeAttributes, ItemMercuryStatus, PredStatus,
-        !ProcTable, !ModuleInfo, !QualInfo, !Specs) :-
+        !ProcTable, !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     set_eval_method_create_aux_preds(ProgressStream, PredInfo, PredOrFunc,
         PredModuleName, PredName, UserArity, ProcId, ProcInfo0, SingleProc,
         Context, TabledMethod, MaybeAttributes, ItemMercuryStatus, PredStatus,
-        !ProcTable, !ModuleInfo, !QualInfo, !Specs),
+        !ProcTable, !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs),
     set_eval_method_create_aux_preds_list(ProgressStream, PredInfo, PredOrFunc,
         PredModuleName, PredName, UserArity, ProcIdsInfos, SingleProc,
         Context, TabledMethod, MaybeAttributes, ItemMercuryStatus, PredStatus,
-        !ProcTable, !ModuleInfo, !QualInfo, !Specs).
+        !ProcTable, !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs).
 
 :- pred set_eval_method_create_aux_preds(io.text_output_stream::in,
     pred_info::in, pred_or_func::in, module_name::in, string::in,
@@ -432,12 +438,13 @@ set_eval_method_create_aux_preds_list(ProgressStream, PredInfo, PredOrFunc,
     item_mercury_status::in, pred_status::in,
     proc_table::in, proc_table::out, module_info::in, module_info::out,
     qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 set_eval_method_create_aux_preds(ProgressStream, PredInfo, PredOrFunc,
         PredModuleName, PredName, UserArity, ProcId, ProcInfo0, SingleProc,
         Context, TabledMethod, MaybeAttributes, ItemMercuryStatus, PredStatus,
-        !ProcTable, !ModuleInfo, !QualInfo, !Specs) :-
+        !ProcTable, !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     proc_info_get_eval_method(ProcInfo0, OldEvalMethod),
     PredSymName = qualified(PredModuleName, PredName),
     PFSymNameArity = pred_pf_name_arity(PredOrFunc, PredSymName, UserArity),
@@ -458,7 +465,7 @@ set_eval_method_create_aux_preds(ProgressStream, PredInfo, PredOrFunc,
                 color_as_incorrect([words("no declared modes.")]) ++
                 [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         ;
             MaybeDeclaredArgModes = yes(DeclaredArgModes),
             pred_info_get_arg_types(PredInfo, ArgTypes),
@@ -498,7 +505,7 @@ set_eval_method_create_aux_preds(ProgressStream, PredInfo, PredOrFunc,
                     suffix(":"), nl | ArgErrorPieces],
                 Spec = spec($pred, severity_error, phase_pt2h,
                     Context, Pieces),
-                !:Specs = [Spec | !.Specs]
+                !:ErrSpecs = [Spec | !.ErrSpecs]
             ),
             EvalMethod = eval_tabled(TabledMethod),
             proc_info_set_eval_method(EvalMethod, ProcInfo0, ProcInfo1),
@@ -520,7 +527,7 @@ set_eval_method_create_aux_preds(ProgressStream, PredInfo, PredOrFunc,
                 create_tabling_statistics_pred(ProgressStream, PredOrFunc,
                     PredModuleName, PredName, UserArity, ProcId, SingleProc,
                     Context, IsTablingSupported, ItemMercuryStatus, PredStatus,
-                    !ModuleInfo, !QualInfo, !Specs)
+                    !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs)
             ;
                 Statistics = table_do_not_gather_statistics
             ),
@@ -529,7 +536,7 @@ set_eval_method_create_aux_preds(ProgressStream, PredInfo, PredOrFunc,
                 create_tabling_reset_pred(ProgressStream, PredOrFunc,
                     PredModuleName, PredName, UserArity, ProcId, SingleProc,
                     Context, IsTablingSupported, ItemMercuryStatus, PredStatus,
-                    !ModuleInfo, !QualInfo, !Specs)
+                    !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs)
             ;
                 AllowReset = table_do_not_allow_reset
             )
@@ -560,7 +567,7 @@ set_eval_method_create_aux_preds(ProgressStream, PredInfo, PredOrFunc,
                 ++ [nl]
         ),
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ).
 
 :- pred create_tabling_statistics_pred(io.text_output_stream::in,
@@ -568,12 +575,13 @@ set_eval_method_create_aux_preds(ProgressStream, PredInfo, PredOrFunc,
     proc_id::in, aux_tabling_maybe_single_proc::in, prog_context::in,
     bool::in, item_mercury_status::in, pred_status::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 create_tabling_statistics_pred(ProgressStream, PredOrFunc,
         PredModuleName, PredName, UserArity, ProcId, SingleProc, Context,
         IsTablingSupported, ItemMercuryStatus, PredStatus,
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     Transform = tn_aux_tabling(PredOrFunc, UserArity, atpk_statistics,
         SingleProc, proc_id_to_int(ProcId)),
     make_transformed_pred_name(PredName, Transform, StatsPredName),
@@ -603,7 +611,7 @@ create_tabling_statistics_pred(ProgressStream, PredOrFunc,
         TypeVarSet, InstVarSet, ExistQVars, purity_pure, Constraints,
         Context, item_no_seq_num),
     module_add_pred_decl(ItemMercuryStatus, PredStatus, may_be_unqualified,
-        PredDecl, _MaybePredProcId, !ModuleInfo, !Specs),
+        PredDecl, _MaybePredProcId, !ModuleInfo, !ErrSpecs),
 
     user_arity_pred_form_arity(PredOrFunc, UserArity, PredFormArity),
     PFSymNameArity = pf_sym_name_arity(PredOrFunc, PredSymName, PredFormArity),
@@ -638,7 +646,7 @@ create_tabling_statistics_pred(ProgressStream, PredOrFunc,
                 !.VarSet, InstVarSet, StatsImpl, Context, item_no_seq_num),
             % XXX Should return this instead.
             add_foreign_proc(ProgressStream, ItemMercuryStatus, PredStatus,
-                StatsFCInfo, !ModuleInfo, !Specs)
+                StatsFCInfo, !ModuleInfo, !ErrSpecs, !WarnSpecs)
         ;
             IsTablingSupported = no,
             DummyStatsFuncSymName = qualified(mercury_table_statistics_module,
@@ -660,7 +668,7 @@ create_tabling_statistics_pred(ProgressStream, PredOrFunc,
             ClauseType = clause_not_for_promise,
             % XXX Should return this instead.
             module_add_clause(ProgressStream, PredStatus, ClauseType,
-                StatsClauseInfo, !ModuleInfo, !QualInfo, !Specs)
+                StatsClauseInfo, !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs)
         )
     ).
 
@@ -669,11 +677,13 @@ create_tabling_statistics_pred(ProgressStream, PredOrFunc,
     proc_id::in, aux_tabling_maybe_single_proc::in, prog_context::in,
     bool::in, item_mercury_status::in, pred_status::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 create_tabling_reset_pred(ProgressStream, PredOrFunc, PredModuleName, PredName,
         UserArity, ProcId, SingleProc, Context, IsTablingSupported,
-        ItemMercuryStatus, PredStatus, !ModuleInfo, !QualInfo, !Specs) :-
+        ItemMercuryStatus, PredStatus, !ModuleInfo, !QualInfo,
+        !ErrSpecs, !WarnSpecs) :-
     Transform = tn_aux_tabling(PredOrFunc, UserArity, atpk_reset,
         SingleProc, proc_id_to_int(ProcId)),
     make_transformed_pred_name(PredName, Transform, ResetPredName),
@@ -698,7 +708,7 @@ create_tabling_reset_pred(ProgressStream, PredOrFunc, PredModuleName, PredName,
         TypeVarSet, InstVarSet, ExistQVars, purity_pure, Constraints,
         Context, item_no_seq_num),
     module_add_pred_decl(ItemMercuryStatus, PredStatus, may_be_unqualified,
-        PredDecl, _MaybePredProcId, !ModuleInfo, !Specs),
+        PredDecl, _MaybePredProcId, !ModuleInfo, !ErrSpecs),
 
     user_arity_pred_form_arity(PredOrFunc, UserArity, PredFormArity),
     PFSymNameArity = pf_sym_name_arity(PredOrFunc, PredSymName, PredFormArity),
@@ -728,7 +738,7 @@ create_tabling_reset_pred(ProgressStream, PredOrFunc, PredModuleName, PredName,
                 !.VarSet, InstVarSet, ResetImpl, Context, item_no_seq_num),
             % XXX Should return this instead.
             add_foreign_proc(ProgressStream, ItemMercuryStatus, PredStatus,
-                ResetFCInfo, !ModuleInfo, !Specs)
+                ResetFCInfo, !ModuleInfo, !ErrSpecs, !WarnSpecs)
         ;
             IsTablingSupported = no,
             Args = [variable(IO0, Context), variable(IO, Context)],
@@ -739,7 +749,7 @@ create_tabling_reset_pred(ProgressStream, PredOrFunc, PredModuleName, PredName,
             ClauseType = clause_not_for_promise,
             % XXX Should return this instead.
             module_add_clause(ProgressStream, PredStatus, ClauseType,
-                ResetClauseInfo, !ModuleInfo, !QualInfo, !Specs)
+                ResetClauseInfo, !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs)
         )
     ).
 
diff --git a/compiler/add_pragma_type_spec.m b/compiler/add_pragma_type_spec.m
index e0c554cf9..04e1a9df4 100644
--- a/compiler/add_pragma_type_spec.m
+++ b/compiler/add_pragma_type_spec.m
@@ -19,7 +19,8 @@
 
 :- pred add_pragma_type_spec(decl_pragma_type_spec_info::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -74,7 +75,8 @@
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
 
-add_pragma_type_spec(TypeSpec, !ModuleInfo, !QualInfo, !Specs) :-
+add_pragma_type_spec(TypeSpec, !ModuleInfo, !QualInfo,
+        !ErrSpecs, !WarnSpecs) :-
     TypeSpec = decl_pragma_type_spec_info(PFUMM, SymName, _, _, _, _,
         Context, _),
     module_info_get_predicate_table(!.ModuleInfo, PredTable),
@@ -102,7 +104,8 @@ add_pragma_type_spec(TypeSpec, !ModuleInfo, !QualInfo, !Specs) :-
     ;
         PFUMM = pfumm_unknown(UserArity),
         maybe_warn_about_pfumm_unknown(!.ModuleInfo, "type_spec",
-            PFUMM, SymName, Context, !Specs),
+            PFUMM, SymName, Context, UnknownWarnSpecs),
+        !:WarnSpecs = UnknownWarnSpecs ++ !.WarnSpecs,
         MaybePredOrFunc = no,
         predicate_table_lookup_sym_arity(PredTable, is_fully_qualified,
             SymName, UserArity, PredIds),
@@ -116,11 +119,12 @@ add_pragma_type_spec(TypeSpec, !ModuleInfo, !QualInfo, !Specs) :-
             OtherUserArities),
         report_undefined_pred_or_func_error(MaybePredOrFunc, SymName,
             UserArity, OtherUserArities, Context,
-            [pragma_decl("type_spec"), words("declaration")], !Specs)
+            [pragma_decl("type_spec"), words("declaration")], UndefSpec),
+        !:ErrSpecs = [UndefSpec | !.ErrSpecs]
     ;
         PredIds = [_ | _],
         list.foldl3(add_pragma_type_spec_for_pred(TypeSpec),
-            PredIds, !ModuleInfo, !QualInfo, !Specs)
+            PredIds, !ModuleInfo, !QualInfo, !ErrSpecs)
     ).
 
 %---------------------%
@@ -128,7 +132,7 @@ add_pragma_type_spec(TypeSpec, !ModuleInfo, !QualInfo, !Specs) :-
 :- pred add_pragma_type_spec_for_pred(decl_pragma_type_spec_info::in,
     pred_id::in, module_info::in, module_info::out,
     qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_pragma_type_spec_for_pred(TypeSpec, PredId,
         !ModuleInfo, !QualInfo, !Specs) :-
@@ -556,7 +560,7 @@ maybe_record_type_spec_in_qual_info(PredOrFunc, SymName, UserArity, PredStatus,
 %---------------------------------------------------------------------------%
 
 :- pred report_subst_existq_tvars(pred_info::in, prog_context::in,
-    list(tvar)::in, diag_spec::out) is det.
+    list(tvar)::in, err_spec::out) is det.
 
 report_subst_existq_tvars(PredInfo, Context, SubExistQVars, Spec) :-
     pred_info_get_typevarset(PredInfo, TVarSet),
@@ -571,7 +575,7 @@ report_subst_existq_tvars(PredInfo, Context, SubExistQVars, Spec) :-
     Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces).
 
 :- pred report_recursive_subst(pred_info::in, prog_context::in, tvarset::in,
-    list(tvar)::in, diag_spec::out) is det.
+    list(tvar)::in, err_spec::out) is det.
 
 report_recursive_subst(PredInfo, Context, TVarSet, RecursiveVars, Spec) :-
     OccurOrOccurs =
@@ -585,7 +589,7 @@ report_recursive_subst(PredInfo, Context, TVarSet, RecursiveVars, Spec) :-
     Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces).
 
 :- pred report_multiple_subst_vars(pred_info::in, prog_context::in,
-    tvarset::in, list(tvar)::in, diag_spec::out) is det.
+    tvarset::in, list(tvar)::in, err_spec::out) is det.
 
 report_multiple_subst_vars(PredInfo, Context, TVarSet, MultiSubstVars, Spec) :-
     HasOrHave = choose_number(MultiSubstVars, "has", "have"),
@@ -598,7 +602,7 @@ report_multiple_subst_vars(PredInfo, Context, TVarSet, MultiSubstVars, Spec) :-
     Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces).
 
 :- pred report_unknown_vars_to_subst(pred_info::in, prog_context::in,
-    tvarset::in, list(tvar)::in, diag_spec::out) is det.
+    tvarset::in, list(tvar)::in, err_spec::out) is det.
 
 report_unknown_vars_to_subst(PredInfo, Context, TVarSet, UnknownVars, Spec) :-
     PredOrFunc = pred_info_is_pred_or_func(PredInfo),
diff --git a/compiler/add_pragma_type_spec_constr.m b/compiler/add_pragma_type_spec_constr.m
index fb6cc09fe..3d00d6cfd 100644
--- a/compiler/add_pragma_type_spec_constr.m
+++ b/compiler/add_pragma_type_spec_constr.m
@@ -21,7 +21,9 @@
 :- pred add_pragma_type_spec_constr(io.text_output_stream::in,
     decl_pragma_type_spec_constr_info::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out,
+    list(info_spec)::in, list(info_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -69,7 +71,7 @@
 %---------------------------------------------------------------------------%
 
 add_pragma_type_spec_constr(ProgressStream, TypeSpecConstr,
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs, !InfoSpecs) :-
     % The general approach we use to implement type_spec_constrained_preds
     % pragmas is to compute the set of ordinary type_spec pragmas they
     % correspond to, and add *those* to !ModuleInfo.
@@ -150,7 +152,7 @@ add_pragma_type_spec_constr(ProgressStream, TypeSpecConstr,
             Severity =
                 severity_informational(inform_generated_type_spec_pragmas),
             Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:InfoSpecs = [Spec | !.InfoSpecs]
         ),
         % Actually add the generated type_spec pragmas to !ModuleInfo.
         %
@@ -158,11 +160,11 @@ add_pragma_type_spec_constr(ProgressStream, TypeSpecConstr,
         % to !ModuleInfo results in any errors, they are the compiler's fault,
         % not the user's. But for now, we want to report them, because if
         % we ignored them, we would never be alerted to their existence.
-        list.foldl3(add_pragma_type_spec, SortedPragmas,
-            !ModuleInfo, !QualInfo, !Specs)
+        list.foldl4(add_pragma_type_spec, SortedPragmas,
+            !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs)
     ;
         ClassSpecs = [_ | _],
-        !:Specs = ClassSpecs ++ !.Specs
+        !:ErrSpecs = ClassSpecs ++ !.ErrSpecs
     ).
 
 %---------------------%
@@ -189,10 +191,10 @@ add_pragma_type_spec_constr(ProgressStream, TypeSpecConstr,
 :- pred build_class_constraint_map(io.text_output_stream::in, class_table::in,
     maybe_apply_to_supers::in, tvarset::in, var_or_ground_constraint::in,
     type_spec_constraint_map::in, type_spec_constraint_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 build_class_constraint_map(ProgressStream, ClassTable, ApplyToSupers,
-        PragmaTVarSet, Constraint, !ClassConstraintMap, !Specs) :-
+        PragmaTVarSet, Constraint, !ClassConstraintMap, !ErrSpecs) :-
     Constraint =
         var_or_ground_constraint(ClassSymName, VarOrGroundTypes, Context),
     list.length(VarOrGroundTypes, NumTypes),
@@ -256,7 +258,7 @@ build_class_constraint_map(ProgressStream, ClassTable, ApplyToSupers,
         % XXX Make any code for doing that general enough to handle
         % all other error messages about references to unknown classes.
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ).
 
     % This predicate does the same job as build_class_constraint_map above,
diff --git a/compiler/add_pragma_util.m b/compiler/add_pragma_util.m
index 2d1a1f336..c61b80635 100644
--- a/compiler/add_pragma_util.m
+++ b/compiler/add_pragma_util.m
@@ -31,6 +31,7 @@
 :- import_module parse_tree.prog_item.
 
 :- import_module list.
+:- import_module one_or_more.
 :- import_module set.
 
 %---------------------------------------------------------------------------%
@@ -50,14 +51,6 @@
     string::in, pred_or_func::in, sym_name::in, user_arity::in, int::in,
     maybe4el(pred_id, proc_id, pred_info, proc_info)::out) is det.
 
-%---------------------%
-
-:- func report_unknown_pred_or_func(spec_severity, string, prog_context,
-    pred_or_func, sym_name, user_arity) = diag_spec.
-
-:- func report_ambiguous_pred_or_func(spec_severity, string, prog_context,
-    pred_or_func, sym_name, user_arity) = diag_spec.
-
 %---------------------%
 
     % Symnames in pragmas always include a module name. Usually,
@@ -102,7 +95,8 @@
 
 :- pred check_pragma_status(string::in, pragma_status_class::in,
     item_mercury_status::in, prog_context::in, pred_info::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------%
 
@@ -118,7 +112,8 @@
     pragma_status_class::in, item_mercury_status::in, prog_context::in,
     pred_marker::in, list(pred_marker)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------%
 
@@ -141,7 +136,8 @@
     item_mercury_status::in, prog_context::in,
     add_marker_pred_info::in(add_marker_pred_info),
     list(pred_id)::in, pred_id_table::in, pred_id_table::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------%
 
@@ -152,7 +148,7 @@
 
 :- pred pragma_conflict_error(pred_pfu_name_arity::in, prog_context::in,
     string::in, set(pred_marker)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------%
 
@@ -161,8 +157,8 @@
     ;       require_one_match.
 
 :- type matching_pred_ids_result
-    --->    mpids_ok(pred_id, list(pred_id), list(diag_spec))
-    ;       mpids_error(list(diag_spec)).
+    --->    mpids_ok(pred_id, list(pred_id), list(warn_spec))
+    ;       mpids_error(one_or_more(err_spec), list(warn_spec)).
 
     % Given maybe a pred_or_func, a symname and arity, return all
     % the pred_ids that match. Reasons for the possible return of more than one
@@ -188,7 +184,7 @@
     list(mer_mode)::in, string::in, prog_context::in,
     pred(proc_info, proc_info)::in(pred(in, out) is det),
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -227,11 +223,12 @@ look_up_pragma_pf_sym_arity(ModuleInfo, IsFullyQualified, FailHandling,
                 UserArity, OtherUserArities),
             DeclPieces = [pragma_decl(PragmaName), words("declaration")],
             report_undefined_pred_or_func_error(yes(PredOrFunc), SymName,
-                UserArity, OtherUserArities, Context, DeclPieces, [], Specs)
+                UserArity, OtherUserArities, Context, DeclPieces, Spec),
+            Specs = [Spec]
         ;
             FailHandling = lfh_internal_error,
-            Spec = report_unknown_pred_or_func(severity_error,
-                PragmaName, Context, PredOrFunc, SymName, UserArity),
+            Spec = report_unknown_pred_or_func(PragmaName, Context,
+                PredOrFunc, SymName, UserArity),
             Specs = [Spec]
         ;
             FailHandling = lfh_ignore,
@@ -243,8 +240,8 @@ look_up_pragma_pf_sym_arity(ModuleInfo, IsFullyQualified, FailHandling,
                 Specs = []
             ;
                 InformIgnored = yes,
-                Spec = report_unknown_pred_or_func(severity_error,
-                    PragmaName, Context, PredOrFunc, SymName, UserArity),
+                Spec = report_unknown_pred_or_func(PragmaName, Context,
+                    PredOrFunc, SymName, UserArity),
                 Specs = [Spec]
             )
         ),
@@ -278,12 +275,12 @@ look_up_pragma_pf_sym_arity(ModuleInfo, IsFullyQualified, FailHandling,
             Msg = simple_msg(Context,
                 [always(MainPieces),
                 verbose_only(verbose_always, VerbosePieces)]),
-            Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg]),
+            Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg]),
             Specs = [Spec]
         ;
             FailHandling = lfh_internal_error,
-            Spec = report_ambiguous_pred_or_func(severity_error,
-                PragmaName, Context, PredOrFunc, SymName, UserArity),
+            Spec = report_ambiguous_pred_or_func(PragmaName, Context,
+                PredOrFunc, SymName, UserArity),
             Specs = [Spec]
         ;
             FailHandling = lfh_ignore,
@@ -295,10 +292,13 @@ look_up_pragma_pf_sym_arity(ModuleInfo, IsFullyQualified, FailHandling,
                 Specs = []
             ;
                 InformIgnored = yes,
-                Severity =
-                    severity_informational(inform_ignored_pragma_errors),
-                Spec = report_ambiguous_pred_or_func(Severity, PragmaName,
-                    Context, PredOrFunc, SymName, UserArity),
+                % XXX DIAG_SPEC
+                % This Spec used to have this severity:
+                % Severity =
+                %   severity_informational(inform_ignored_pragma_errors),
+                % Should it stay that way?
+                Spec = report_ambiguous_pred_or_func(PragmaName, Context,
+                    PredOrFunc, SymName, UserArity),
                 Specs = [Spec]
             )
         ),
@@ -339,30 +339,8 @@ look_up_pragma_pf_sym_arity_mode_num(ModuleInfo, IsFullyQualified,
 
 %---------------------------------------------------------------------------%
 
-report_unknown_pred_or_func(Severity, PragmaName, Context,
-        PredOrFunc, SymName, UserArity) = Spec :-
-    UserArity = user_arity(UserArityInt),
-    SNA = sym_name_arity(SymName, UserArityInt),
-    Pieces = [words("Internal compiler error:")] ++
-        color_as_incorrect([words("unknown"), p_or_f(PredOrFunc),
-            qual_sym_name_arity(SNA)]) ++
-        [words("in"), pragma_decl(PragmaName), words("declaration."), nl],
-    Spec = spec($pred, Severity, phase_pt2h, Context, Pieces).
-
-report_ambiguous_pred_or_func(Severity, PragmaName, Context,
-        PredOrFunc, SymName, UserArity) = Spec :-
-    UserArity = user_arity(UserArityInt),
-    SNA = sym_name_arity(SymName, UserArityInt),
-    Pieces = [words("Internal compiler error:")] ++
-        color_as_incorrect([words("ambiguous"), p_or_f(PredOrFunc),
-            words("name"), qual_sym_name_arity(SNA)]) ++
-        [words("in"), pragma_decl(PragmaName), words("declaration."), nl],
-    Spec = spec($pred, Severity, phase_pt2h, Context, Pieces).
-
-%---------------------------------------------------------------------------%
-
 check_pragma_status(PragmaName, StatusClass, PragmaStatus, Context,
-        PredInfo, !Specs) :-
+        PredInfo, !ErrSpecs, !WarnSpecs) :-
     (
         PragmaStatus = item_defined_in_other_module(_)
     ;
@@ -397,7 +375,7 @@ check_pragma_status(PragmaName, StatusClass, PragmaStatus, Context,
                     [nl],
                 Spec = spec($pred, severity_error, phase_pt2h,
                     Context, Pieces),
-                !:Specs = [Spec | !.Specs]
+                !:ErrSpecs = [Spec | !.ErrSpecs]
             )
         ;
             PredExported = yes,
@@ -418,7 +396,7 @@ check_pragma_status(PragmaName, StatusClass, PragmaStatus, Context,
                         [nl],
                     Severity = severity_warning(warn_nonexported_pragma),
                     Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),
-                    !:Specs = [Spec | !.Specs]
+                    !:WarnSpecs = [Spec | !.WarnSpecs]
                 ;
                     StatusClass = psc_impl
                 )
@@ -443,7 +421,7 @@ check_pragma_status(PragmaName, StatusClass, PragmaStatus, Context,
                         words("is exported."), nl],
                     Spec = spec($pred, severity_error, phase_pt2h,
                         Context, Pieces),
-                    !:Specs = [Spec | !.Specs]
+                    !:ErrSpecs = [Spec | !.ErrSpecs]
                 )
             )
         )
@@ -452,19 +430,19 @@ check_pragma_status(PragmaName, StatusClass, PragmaStatus, Context,
 %---------------------------------------------------------------------------%
 
 add_pred_marker(PredSpec, PragmaName, PragmaStatusClass, PragmaStatus, Context,
-        Marker, ConflictMarkers, !ModuleInfo, !Specs) :-
+        Marker, ConflictMarkers, !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     PredSpec = pred_pfu_name_arity(PFU, PredSymName, UserArity),
     get_matching_pred_ids(!.ModuleInfo, PragmaName, do_not_require_one_match,
         pragma_does_not_allow_modes, Context, PFU, PredSymName, UserArity,
         MatchingPredIdResult),
     (
-        MatchingPredIdResult = mpids_ok(HeadPredId, TailPredIds, WarnSpecs),
+        MatchingPredIdResult = mpids_ok(HeadPredId, TailPredIds, IdWarnSpecs),
         PredIds = [HeadPredId | TailPredIds],
-        !:Specs = WarnSpecs ++ !.Specs,
+        !:WarnSpecs = IdWarnSpecs ++ !.WarnSpecs,
         module_info_get_pred_id_table(!.ModuleInfo, PredIdTable0),
         pragma_add_marker(PragmaName, PragmaStatusClass, PragmaStatus, Context,
             add_marker_pred_info(Marker), PredIds,
-            PredIdTable0, PredIdTable, !Specs),
+            PredIdTable0, PredIdTable, !ErrSpecs, !WarnSpecs),
         module_info_set_pred_id_table(PredIdTable, !ModuleInfo),
 
         list.map(get_pred_markers(PredIdTable), PredIds, PredMarkerSets),
@@ -475,27 +453,29 @@ add_pred_marker(PredSpec, PragmaName, PragmaStatusClass, PragmaStatus, Context,
             true
         else
             pragma_conflict_error(PredSpec, Context, PragmaName,
-                BadPredMarkers, !Specs)
+                BadPredMarkers, !ErrSpecs)
         )
     ;
-        MatchingPredIdResult = mpids_error(ErrorSpecs),
-        !:Specs = ErrorSpecs ++ !.Specs
+        MatchingPredIdResult = mpids_error(IdErrSpecs, IdWarnSpecs),
+        !:ErrSpecs = one_or_more_to_list(IdErrSpecs) ++ !.ErrSpecs,
+        !:WarnSpecs = IdWarnSpecs ++ !.WarnSpecs
     ).
 
 get_pred_markers(PredIdTable, PredId, Markers) :-
     map.lookup(PredIdTable, PredId, PredInfo),
     pred_info_get_markers(PredInfo, Markers).
 
-pragma_add_marker(_, _, _, _, _, [], !PredTable, !Specs).
+pragma_add_marker(_, _, _, _, _, [], !PredTable, !ErrSpecs, !WarnSpecs).
 pragma_add_marker(PragmaName, PragmaStatusClass, PragmaStatus, Context,
-        UpdatePredInfo, [PredId | PredIds], !PredTable, !Specs) :-
+        UpdatePredInfo, [PredId | PredIds], !PredTable,
+        !ErrSpecs, !WarnSpecs) :-
     map.lookup(!.PredTable, PredId, PredInfo0),
     UpdatePredInfo(PredInfo0, PredInfo),
     map.det_update(PredId, PredInfo, !PredTable),
     check_pragma_status(PragmaName, PragmaStatusClass, PragmaStatus, Context,
-        PredInfo, !Specs),
+        PredInfo, !ErrSpecs, !WarnSpecs),
     pragma_add_marker(PragmaName, PragmaStatusClass, PragmaStatus,
-        Context, UpdatePredInfo, PredIds, !PredTable, !Specs).
+        Context, UpdatePredInfo, PredIds, !PredTable, !ErrSpecs, !WarnSpecs).
 
 add_marker_pred_info(Marker, !PredInfo) :-
     pred_info_get_markers(!.PredInfo, Markers0),
@@ -577,8 +557,8 @@ get_matching_pred_ids(ModuleInfo, Pragma, RequireOneMatch, PragmaAllowsModes,
             DescPieces = [pragma_decl(Pragma), words("declaration")],
             report_undefined_pred_or_func_error(pfu_to_maybe_pred_or_func(PFU),
                 SymName, UserArity, OtherUserArities, Context, DescPieces,
-                [], NoMatchSpecs),
-            Result = mpids_error(NoMatchSpecs ++ WarnSpecs)
+                NoMatchSpec),
+            Result = mpids_error(one_or_more(NoMatchSpec, []), WarnSpecs)
         ;
             PredIds = [HeadPredId],
             Result = mpids_ok(HeadPredId, [], WarnSpecs)
@@ -631,7 +611,7 @@ get_matching_pred_ids(ModuleInfo, Pragma, RequireOneMatch, PragmaAllowsModes,
                         [nl],
                 ErrorSpec = spec($pred, severity_error, phase_pt2h,
                     Context, ErrorPieces),
-                Result = mpids_error([ErrorSpec])
+                Result = mpids_error(one_or_more(ErrorSpec, []), [])
             )
         )
     ).
@@ -639,7 +619,7 @@ get_matching_pred_ids(ModuleInfo, Pragma, RequireOneMatch, PragmaAllowsModes,
 %---------------------%
 
 transform_selected_mode_of_pred(PredId, PFNameArity, Modes,
-        PragmaName, Context, ProcTransform, !ModuleInfo, !Specs) :-
+        PragmaName, Context, ProcTransform, !ModuleInfo, !ErrSpecs) :-
     module_info_pred_info(!.ModuleInfo, PredId, PredInfo0),
     pred_info_get_proc_table(PredInfo0, ProcTable0),
     map.to_assoc_list(ProcTable0, ProcList),
@@ -658,9 +638,37 @@ transform_selected_mode_of_pred(PredId, PFNameArity, Modes,
             [words("of"), qual_pf_sym_name_user_arity(PFNameArity),
             suffix("."), nl],
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ).
 
+%---------------------------------------------------------------------------%
+
+:- func report_unknown_pred_or_func(string, prog_context,
+    pred_or_func, sym_name, user_arity) = err_spec.
+
+report_unknown_pred_or_func(PragmaName, Context,
+        PredOrFunc, SymName, UserArity) = Spec :-
+    UserArity = user_arity(UserArityInt),
+    SNA = sym_name_arity(SymName, UserArityInt),
+    Pieces = [words("Internal compiler error:")] ++
+        color_as_incorrect([words("unknown"), p_or_f(PredOrFunc),
+            qual_sym_name_arity(SNA)]) ++
+        [words("in"), pragma_decl(PragmaName), words("declaration."), nl],
+    Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces).
+
+:- func report_ambiguous_pred_or_func(string, prog_context,
+    pred_or_func, sym_name, user_arity) = err_spec.
+
+report_ambiguous_pred_or_func(PragmaName, Context,
+        PredOrFunc, SymName, UserArity) = Spec :-
+    UserArity = user_arity(UserArityInt),
+    SNA = sym_name_arity(SymName, UserArityInt),
+    Pieces = [words("Internal compiler error:")] ++
+        color_as_incorrect([words("ambiguous"), p_or_f(PredOrFunc),
+            words("name"), qual_sym_name_arity(SNA)]) ++
+        [words("in"), pragma_decl(PragmaName), words("declaration."), nl],
+    Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces).
+
 %---------------------------------------------------------------------------%
 :- end_module hlds.make_hlds.add_pragma_util.
 %---------------------------------------------------------------------------%
diff --git a/compiler/add_pred.m b/compiler/add_pred.m
index 3880368ba..047082b43 100644
--- a/compiler/add_pred.m
+++ b/compiler/add_pred.m
@@ -47,7 +47,7 @@
     need_qualifier::in, item_pred_decl_info::in,
     maybe(pair(pred_id, maybe(proc_id)))::out,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
     % Is the mode declaration we are adding to the HLDS derived from
     % a combined predmode declaration?
@@ -60,7 +60,7 @@
 :- pred module_add_mode_decl(part_of_predmode::in, maybe_class_method::in,
     item_mercury_status::in, pred_status::in, item_mode_decl_info::in,
     pred_proc_id::out, module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
     % report_mode_decl_after_predmode(PFNameArity, Context):
     %
@@ -74,7 +74,7 @@
     % to be the same inside class definitions as they are outside.
     %
 :- func report_mode_decl_after_predmode(pred_pf_name_arity, prog_context)
-    = diag_spec.
+    = err_spec.
 
     % Whenever there is a clause or mode declaration for an undeclared
     % predicate, we add an implicit declaration
@@ -86,7 +86,7 @@
     maybe_class_method::in, prog_context::in, pred_origin::in,
     list(format_piece)::in, pred_id::out,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 :- pred add_implicit_pred_decl(pred_or_func::in, module_name::in, string::in,
     pred_form_arity::in, pred_status::in, prog_context::in, pred_origin::in,
@@ -340,7 +340,7 @@ record_pred_origin(PredOrFunc, PredSymName, UserArity, Origin, Context,
 
 :- pred check_for_modeless_predmode_decl(pred_status::in, pred_or_func::in,
     sym_name::in, list(mer_type)::in, maybe(determinism)::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_for_modeless_predmode_decl(PredStatus, PredOrFunc,
         PredSymName, ArgTypes, MaybeDetism, Context, !Specs) :-
@@ -377,7 +377,7 @@ check_for_modeless_predmode_decl(PredStatus, PredOrFunc,
     list(mer_type)::in, univ_exist_constraints::in, maybe_predmode_decl::in,
     purity::in, pred_markers::in, maybe(pred_id)::out,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_new_pred(PredOrigin, Context, SeqNum, PredStatus0, NeedQual, PredOrFunc,
         PredModuleName, PredName, TVarSet, ExistQVars, Types, Constraints,
@@ -503,7 +503,7 @@ item_decl_section(ItemExport) = DeclSection :-
 
 :- pred maybe_report_any_unqualified_types(pred_status::in, sym_name::in,
     prog_context::in, list(mer_type)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 maybe_report_any_unqualified_types(PredStatus0, PredSymName, Context, Types,
         !Specs) :-
@@ -526,7 +526,7 @@ maybe_report_any_unqualified_types(PredStatus0, PredSymName, Context, Types,
     ).
 
 :- pred report_any_unqualified_types(sym_name::in, prog_context::in,
-    list(mer_type)::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(mer_type)::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 report_any_unqualified_types(_PredSymName, _Context, [], !Specs).
 report_any_unqualified_types(PredSymName, Context, [Type | Types], !Specs) :-
@@ -534,7 +534,7 @@ report_any_unqualified_types(PredSymName, Context, [Type | Types], !Specs) :-
     report_any_unqualified_types(PredSymName, Context, Types, !Specs).
 
 :- pred report_any_unqualified_type(sym_name::in, prog_context::in,
-    mer_type::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    mer_type::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 report_any_unqualified_type(PredSymName, Context, Type, !Specs) :-
     (
@@ -825,7 +825,7 @@ module_add_mode_decl(PartOfPredmode, IsClassMethod,
 :- pred module_do_add_mode(module_info::in, part_of_predmode::in,
     maybe_class_method::in, item_mercury_status::in, item_mode_decl_info::in,
     pred_info::in, pred_info::out, proc_id::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 module_do_add_mode(ModuleInfo, PartOfPredmode, IsClassMethod,
         ItemMercuryStatus, ItemModeDecl, !PredInfo, ProcId, !Specs) :-
@@ -872,7 +872,7 @@ module_do_add_mode(ModuleInfo, PartOfPredmode, IsClassMethod,
 :- pred check_that_detism_is_declared(module_info::in, pred_info::in,
     maybe_class_method::in, pred_or_func::in, string::in, pred_form_arity::in,
     maybe(determinism)::in, prog_context::in, detism_decl::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_that_detism_is_declared(ModuleInfo, PredInfo, IsClassMethod, PredOrFunc,
         PredName, PredFormArity, MaybeDetism, Context, DetismDecl, !Specs) :-
@@ -908,7 +908,7 @@ check_that_detism_is_declared(ModuleInfo, PredInfo, IsClassMethod, PredOrFunc,
 
 :- pred check_for_mode_decl_in_wrong_section(decl_section::in, item_export::in,
     pred_or_func::in, string::in, pred_form_arity::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_for_mode_decl_in_wrong_section(PredDeclSection, ItemExport,
         PredOrFunc, PredName, PredFormArity, Context, !Specs) :-
@@ -943,7 +943,7 @@ decl_section_to_string(decl_implementation) = "implementation".
 
 :- pred check_for_mode_decl_after_predmode(maybe_predmode_decl::in,
     pred_or_func::in, string::in, pred_form_arity::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_for_mode_decl_after_predmode(PredIsPredMode, PredOrFunc, PredName,
         PredFormArity, Context, !Specs) :-
@@ -976,7 +976,7 @@ report_mode_decl_after_predmode(PFNameArity, Context) = Spec :-
 
 :- pred report_unspecified_det_for_method(pred_or_func::in, sym_name::in,
     pred_form_arity::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_unspecified_det_for_method(PorF, SymName, PredFormArity, Context,
         !Specs) :-
@@ -993,7 +993,7 @@ report_unspecified_det_for_method(PorF, SymName, PredFormArity, Context,
 
 :- pred report_unspecified_det_for_exported(pred_or_func::in, sym_name::in,
     pred_form_arity::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_unspecified_det_for_exported(PorF, SymName, PredFormArity, Context,
         !Specs) :-
@@ -1009,7 +1009,7 @@ report_unspecified_det_for_exported(PorF, SymName, PredFormArity, Context,
 
 :- pred maybe_report_unspecified_det_for_local(module_info::in,
     pred_or_func::in, sym_name::in, pred_form_arity::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 maybe_report_unspecified_det_for_local(ModuleInfo, PorF, SymName,
         PredFormArity, Context, !Specs) :-
@@ -1036,7 +1036,7 @@ maybe_report_unspecified_det_for_local(ModuleInfo, PorF, SymName,
         Msg = simple_msg(Context,
             [always(MainPieces),
             verbose_only(verbose_once, VerbosePieces)]),
-        Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg]),
+        Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg]),
         !:Specs = [Spec | !.Specs]
     ).
 
diff --git a/compiler/add_type.m b/compiler/add_type.m
index d14f47d05..cd160a64c 100644
--- a/compiler/add_type.m
+++ b/compiler/add_type.m
@@ -35,8 +35,9 @@
     %
 :- pred module_add_type_defn(type_status::in, need_qualifier::in,
     item_type_defn_info::in, module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
     % Add the constructors of du types to the constructor table of the HLDS,
     % check subtype definitions, and check that Mercury types defined solely
@@ -45,8 +46,8 @@
 :- pred add_du_ctors_check_subtype_check_foreign_type(type_table::in,
     type_ctor::in, hlds_type_defn::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -94,7 +95,7 @@
 %
 
 module_add_type_defn(TypeStatus0, NeedQual, ItemTypeDefnInfo,
-        !ModuleInfo, !InvalidTypeSpecs, !Specs) :-
+        !ModuleInfo, !InvalidTypeSpecs, !ErrSpecs, !WarnSpecs) :-
     % XXX We should consider setting !:FoundInvalidType *only* for type
     % errors that can cause later compiler passes to either crash or to
     % report nonexistent problems. If the only effect of a type error
@@ -144,7 +145,7 @@ module_add_type_defn(TypeStatus0, NeedQual, ItemTypeDefnInfo,
     (
         ParseTreeTypeDefn = parse_tree_abstract_type(_),
         module_add_type_defn_abstract(TypeStatus, TypeCtor, Body,
-            HLDSTypeDefn0, Context, !ModuleInfo, !InvalidTypeSpecs)
+            HLDSTypeDefn0, Context, !ModuleInfo, !InvalidTypeSpecs, !WarnSpecs)
     ;
         ( ParseTreeTypeDefn = parse_tree_du_type(_)
         ; ParseTreeTypeDefn = parse_tree_sub_type(_)
@@ -166,7 +167,7 @@ module_add_type_defn(TypeStatus0, NeedQual, ItemTypeDefnInfo,
                 [words("from its defining module."), nl],
             SolverSpec = spec($pred, severity_error, phase_pt2h,
                 Context, SolverPieces),
-            !:Specs = [SolverSpec | !.Specs]
+            !:ErrSpecs = [SolverSpec | !.ErrSpecs]
         else
             true
         ),
@@ -184,16 +185,17 @@ module_add_type_defn(TypeStatus0, NeedQual, ItemTypeDefnInfo,
 :- pred module_add_type_defn_abstract(type_status::in,
     type_ctor::in, hlds_type_body::in, hlds_type_defn::in,
     prog_context::in, module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 module_add_type_defn_abstract(TypeStatus1, TypeCtor, Body, TypeDefn0, Context,
-        !ModuleInfo, !InvalidTypeSpecs) :-
+        !ModuleInfo, !InvalidTypeSpecs, !WarnSpecs) :-
     module_info_get_type_table(!.ModuleInfo, TypeTable0),
     ( if search_type_ctor_defn(TypeTable0, TypeCtor, OldDefn) then
         % Since make_hlds_passes.m adds all abstract definitions first,
         % the previous definition can only be another abstract definition.
         check_for_duplicate_type_declaration(TypeCtor, OldDefn, TypeStatus1,
-            Context, !InvalidTypeSpecs),
+            Context, !InvalidTypeSpecs, !WarnSpecs),
         combine_old_and_new_type_status(OldDefn, TypeStatus1, _TypeStatus,
             TypeDefn0, TypeDefn),
         check_for_inconsistent_solver_nosolver_type(TypeCtor,
@@ -206,10 +208,11 @@ module_add_type_defn_abstract(TypeStatus1, TypeCtor, Body, TypeDefn0, Context,
 
 :- pred check_for_duplicate_type_declaration(type_ctor::in, hlds_type_defn::in,
     type_status::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 check_for_duplicate_type_declaration(TypeCtor, OldDefn, NewStatus, NewContext,
-        !InvalidTypeSpecs) :-
+        !InvalidTypeSpecs, !WarnSpecs) :-
     % Even if the source code includes only one declaration of a type,
     % augmenting a raw compilation unit can yield duplicates of that
     % declaration, included e.g. in both x.int2 and then x.int,
@@ -245,15 +248,20 @@ check_for_duplicate_type_declaration(TypeCtor, OldDefn, NewStatus, NewContext,
             type_status_is_exported_to_non_submodules(FirstStatus),
         SecondIsExported =
             type_status_is_exported_to_non_submodules(SecondStatus),
+        FirstPieces = [words("The previous declaration was here."), nl],
+        FirstMsg = msg(FirstContext, FirstPieces),
         UTC = unqual_type_ctor(TypeCtor),
         ( if FirstIsExported = SecondIsExported then
             Severity = severity_warning(warn_redundant_code),
             DupPieces = [words("Warning:")] ++
                 color_as_incorrect([words("duplicate declaration")]) ++
                 [words("for type")] ++ color_as_subject([UTC, suffix(".")]) ++
-                [nl]
+                [nl],
+            DupMsg = msg(SecondContext, DupPieces),
+            DupSpec = gen_spec($pred, Severity, phase_pt2h,
+                [DupMsg, FirstMsg]),
+            !:WarnSpecs = [DupSpec | !.WarnSpecs]
         else
-            Severity = severity_error,
             % XXX If there were not one but *two or more* previous
             % declarations for the type, then FirstStatus may not have come
             % from the previous declaration at FirstContext; it could have
@@ -277,13 +285,12 @@ check_for_duplicate_type_declaration(TypeCtor, OldDefn, NewStatus, NewContext,
                     color_as_inconsistent([IsPrivate, suffix(",")]) ++
                     [words("while the previous declaration says")] ++
                     color_as_inconsistent([IsExported, suffix(".")]) ++ [nl]
-            )
-        ),
-        DupMsg = msg(SecondContext, DupPieces),
-        FirstPieces = [words("The previous declaration was here."), nl],
-        FirstMsg = msg(FirstContext, FirstPieces),
-        DupSpec = diag_spec($pred, Severity, phase_pt2h, [DupMsg, FirstMsg]),
-        !:InvalidTypeSpecs = [DupSpec | !.InvalidTypeSpecs]
+            ),
+            DupMsg = msg(SecondContext, DupPieces),
+            DupSpec = gen_spec($pred, severity_error, phase_pt2h,
+                [DupMsg, FirstMsg]),
+            !:InvalidTypeSpecs = [DupSpec | !.InvalidTypeSpecs]
+        )
     else
         true
     ).
@@ -300,7 +307,7 @@ check_for_duplicate_type_declaration(TypeCtor, OldDefn, NewStatus, NewContext,
     type_ctor::in, list(type_param)::in, type_defn::in(type_defn_mercury),
     hlds_type_body::in, hlds_type_defn::in, prog_context::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 module_add_type_defn_mercury(TypeStatus1, TypeCtor, TypeParams,
         ParseTreeTypeDefn, Body, TypeDefn0, Context,
@@ -349,7 +356,7 @@ module_add_type_defn_mercury(TypeStatus1, TypeCtor, TypeParams,
 :- pred module_add_type_defn_foreign(type_status::in, type_status::in,
     type_ctor::in, hlds_type_body::in, hlds_type_defn::in, prog_context::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 module_add_type_defn_foreign(TypeStatus0, TypeStatus1, TypeCtor,
         Body, TypeDefn0, Context, !ModuleInfo, !InvalidTypeSpecs) :-
@@ -623,7 +630,7 @@ merge_maybe(no, yes(T), yes(T)).
 
 :- pred maybe_report_multiply_defined_type(type_status::in, type_ctor::in,
     prog_context::in, hlds_type_defn::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 maybe_report_multiply_defined_type(TypeStatus, TypeCtor, Context, OldDefn,
         !InvalidTypeSpecs) :-
@@ -644,7 +651,7 @@ maybe_report_multiply_defined_type(TypeStatus, TypeCtor, Context, OldDefn,
 
 :- pred check_for_invalid_user_defined_unify_compare(type_status::in,
     type_ctor::in, type_details_du::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_for_invalid_user_defined_unify_compare(TypeStatus, TypeCtor, DetailsDu,
         Context, !InvalidTypeSpecs) :-
@@ -675,7 +682,7 @@ check_for_invalid_user_defined_unify_compare(TypeStatus, TypeCtor, DetailsDu,
             DummyMsg = simple_msg(Context,
                 [always(MainPieces),
                 verbose_only(verbose_once, VerbosePieces)]),
-            DummySpec = diag_spec($pred, severity_error, phase_pt2h,
+            DummySpec = gen_spec($pred, severity_error, phase_pt2h,
                 [DummyMsg]),
             !:InvalidTypeSpecs = [DummySpec | !.InvalidTypeSpecs]
         else
@@ -689,7 +696,7 @@ check_for_invalid_user_defined_unify_compare(TypeStatus, TypeCtor, DetailsDu,
 
 :- pred check_for_polymorphic_eqv_type_with_monomorphic_body(type_status::in,
     type_ctor::in, list(type_param)::in, type_details_eqv::in,
-    prog_context::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    prog_context::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 check_for_polymorphic_eqv_type_with_monomorphic_body(TypeStatus, TypeCtor,
         TypeParams, DetailsEqv, Context, !InvalidTypeSpecs) :-
@@ -713,7 +720,7 @@ check_for_polymorphic_eqv_type_with_monomorphic_body(TypeStatus, TypeCtor,
         PolyEqvMsg = simple_msg(Context,
             [always(PolyEqvPieces),
             verbose_only(verbose_once, abstract_monotype_workaround)]),
-        PolyEqvSpec = diag_spec($pred, severity_error, phase_pt2h,
+        PolyEqvSpec = gen_spec($pred, severity_error, phase_pt2h,
             [PolyEqvMsg]),
         !:InvalidTypeSpecs = [PolyEqvSpec | !.InvalidTypeSpecs]
     else
@@ -735,7 +742,7 @@ abstract_monotype_workaround = [
 
 :- pred check_for_inconsistent_solver_nosolver_type(type_ctor::in,
     hlds_type_defn::in, hlds_type_body::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_for_inconsistent_solver_nosolver_type(TypeCtor, OldDefn, NewBody,
         NewContext, !InvalidTypeSpecs) :-
@@ -796,7 +803,7 @@ check_for_inconsistent_solver_nosolver_type(TypeCtor, OldDefn, NewBody,
             nl],
         MainMsg = msg(NewContext, MainPieces),
         OldMsg = msg(OldContext, OldPieces),
-        Spec = diag_spec($pred, severity_error, phase_pt2h,
+        Spec = gen_spec($pred, severity_error, phase_pt2h,
             [MainMsg, OldMsg]),
         !:InvalidTypeSpecs = [Spec | !.InvalidTypeSpecs]
     ).
@@ -841,7 +848,7 @@ get_body_is_solver_type(Body, IsSolverType) :-
     old_defn_maybe_abstract::in, type_status::in, prog_context::in,
     type_status::in, prog_context::in,
     hlds_type_defn::in, hlds_type_defn::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_for_inconsistent_foreign_type_visibility(TypeCtor,
         OldIsAbstract, OldStatus, OldContext, NewStatus, NewContext,
@@ -917,7 +924,7 @@ do_foreign_type_visibilities_match(OldStatus, NewStatus) :-
 %---------------------------------------------------------------------------%
 
 add_du_ctors_check_subtype_check_foreign_type(TypeTable, TypeCtor, TypeDefn,
-        !ModuleInfo, !InvalidTypeSpecs, !Specs) :-
+        !ModuleInfo, !InvalidTypeSpecs, !WarnSpecs) :-
     get_type_defn_context(TypeDefn, Context),
     get_type_defn_tvarset(TypeDefn, TVarSet),
     get_type_defn_tparams(TypeDefn, TypeParams),
@@ -936,7 +943,8 @@ add_du_ctors_check_subtype_check_foreign_type(TypeTable, TypeCtor, TypeDefn,
         (
             MaybeSuperType = subtype_of(SuperType),
             check_subtype_defn(TypeTable, TVarSet, TypeCtor, TypeDefn, BodyDu,
-                SuperType, MaybeSetSubtypeNoncanon, !InvalidTypeSpecs, !Specs),
+                SuperType, MaybeSetSubtypeNoncanon,
+                !InvalidTypeSpecs, !WarnSpecs),
             (
                 MaybeSetSubtypeNoncanon = do_not_set_subtype_noncanon
             ;
@@ -995,30 +1003,30 @@ add_du_ctors_check_subtype_check_foreign_type(TypeTable, TypeCtor, TypeDefn,
     need_qualifier::in, partial_qualifier_info::in, type_status::in,
     ctor_field_table::in, ctor_field_table::out,
     cons_table::in, cons_table::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_type_defn_ctors([], _, _, _, _, _, _, _, _,
-        !FieldNameTable, !ConsTable, !Specs).
+        !FieldNameTable, !ConsTable, !ErrSpecs).
 add_type_defn_ctors([Ctor | Ctors], TypeCtor, TypeCtorModuleName, TVarSet,
         TypeParams, KindMap, NeedQual, PQInfo, TypeStatus,
-        !FieldNameTable, !ConsTable, !Specs) :-
+        !FieldNameTable, !ConsTable, !ErrSpecs) :-
     add_type_defn_ctor(Ctor, TypeCtor, TypeCtorModuleName, TVarSet,
         TypeParams, KindMap, NeedQual, PQInfo, TypeStatus,
-        !FieldNameTable, !ConsTable, !Specs),
+        !FieldNameTable, !ConsTable, !ErrSpecs),
     add_type_defn_ctors(Ctors, TypeCtor, TypeCtorModuleName, TVarSet,
         TypeParams, KindMap, NeedQual, PQInfo, TypeStatus,
-        !FieldNameTable, !ConsTable, !Specs).
+        !FieldNameTable, !ConsTable, !ErrSpecs).
 
 :- pred add_type_defn_ctor(constructor::in, type_ctor::in,
     module_name::in, tvarset::in, list(type_param)::in, tvar_kind_map::in,
     need_qualifier::in, partial_qualifier_info::in, type_status::in,
     ctor_field_table::in, ctor_field_table::out,
     cons_table::in, cons_table::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_type_defn_ctor(Ctor, TypeCtor, TypeCtorModuleName, TVarSet,
         TypeParams, KindMap, NeedQual, PQInfo, TypeStatus,
-        !FieldNameTable, !ConsTable, !Specs) :-
+        !FieldNameTable, !ConsTable, !ErrSpecs) :-
     Ctor = ctor(_Ordinal, MaybeExistConstraints, Name, Args, Arity, Context),
     BaseName = unqualify_name(Name),
     QualifiedName = qualified(TypeCtorModuleName, BaseName),
@@ -1047,7 +1055,7 @@ add_type_defn_ctor(Ctor, TypeCtor, TypeCtorModuleName, TVarSet,
             color_as_subject([unqual_type_ctor(TypeCtor), suffix(".")]) ++
             [nl],
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     else
         some [!OtherSymNames] (
             % Schedule the addition of the fully qualified cons_id
@@ -1172,7 +1180,7 @@ do_add_ctor_field(FieldName, FieldNameDefn, ModuleName, !FieldNameTable) :-
     %
 :- pred check_foreign_type_for_current_target(module_info::in, type_ctor::in,
     foreign_type_body::in, type_defn_prev_errors::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_foreign_type_for_current_target(ModuleInfo, TypeCtor, ForeignTypeBody,
         PrevErrors, Context, !InvalidTypeSpecs) :-
@@ -1200,7 +1208,7 @@ check_foreign_type_for_current_target(ModuleInfo, TypeCtor, ForeignTypeBody,
             words("on other back-ends, but none for this back-end."), nl],
         Msg = simple_msg(Context,
             [always(MainPieces), verbose_only(verbose_always, VerbosePieces)]),
-        Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg]),
+        Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg]),
         !:InvalidTypeSpecs = [Spec | !.InvalidTypeSpecs]
     ).
 
@@ -1214,11 +1222,11 @@ check_foreign_type_for_current_target(ModuleInfo, TypeCtor, ForeignTypeBody,
 :- pred check_subtype_defn(type_table::in, tvarset::in, type_ctor::in,
     hlds_type_defn::in, type_body_du::in, mer_type::in,
     maybe_set_subtype_noncanonical::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 check_subtype_defn(TypeTable, TVarSet, TypeCtor, TypeDefn, TypeBodyDu,
-        SuperType, MaybeSetSubtypeNoncanon, !InvalidTypeSpecs, !Specs) :-
+        SuperType, MaybeSetSubtypeNoncanon, !InvalidTypeSpecs, !WarnSpecs) :-
     ( if type_to_ctor_and_args(SuperType, SuperTypeCtor, SuperTypeArgs) then
         search_super_type_ctor_defn(TypeTable, TypeCtor, TypeDefn,
             SuperTypeCtor, [], SearchResult),
@@ -1238,7 +1246,7 @@ check_subtype_defn(TypeTable, TVarSet, TypeCtor, TypeDefn, TypeBodyDu,
                 ),
                 check_subtype_ctors(TypeTable, TypeCtor, TypeDefn, TypeBodyDu,
                     SuperTypeCtor, SuperTypeDefn, SuperTypeBodyDu,
-                    SuperTypeArgs, !InvalidTypeSpecs, !Specs)
+                    SuperTypeArgs, !InvalidTypeSpecs, !WarnSpecs)
             ;
                 MaybeBaseMaybeCanon = error1(UpToBaseSpecs),
                 !:InvalidTypeSpecs =
@@ -1427,7 +1435,7 @@ check_supertype_is_du_not_foreign(TypeDefn, SuperTypeCtor, SuperTypeDefn,
     ).
 
 :- func supertype_ctor_defn_error_to_spec(type_ctor, hlds_type_defn,
-    list(type_ctor), type_ctor, search_type_ctor_defn_error) = diag_spec.
+    list(type_ctor), type_ctor, search_type_ctor_defn_error) = err_spec.
 
 supertype_ctor_defn_error_to_spec(OrigTypeCtor, OrigTypeDefn,
         PrevSuperTypeCtors, LastSuperTypeCtor, Error) = Spec :-
@@ -1493,7 +1501,7 @@ special_type_ctor_not_du(TypeCtor) :-
 %---------------------%
 
 :- func report_non_du_supertype(tvarset, prog_context, type_ctor,
-    list(type_ctor), mer_type) = diag_spec.
+    list(type_ctor), mer_type) = err_spec.
 
 report_non_du_supertype(TVarSet, OrigTypeContext, OrigTypeCtor,
         PrevSuperTypeCtors1, NextSuperType) = Spec :-
@@ -1551,12 +1559,12 @@ describe_which_is_supertype_of_chain(First, OrigTypeCtor, SuperTypeCtors)
 :- pred check_subtype_ctors(type_table::in,
     type_ctor::in, hlds_type_defn::in, type_body_du::in,
     type_ctor::in, hlds_type_defn::in, type_body_du::in,
-    list(mer_type)::in, list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(mer_type)::in, list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 check_subtype_ctors(TypeTable, TypeCtor, TypeDefn, TypeBodyDu,
         SuperTypeCtor, SuperTypeDefn, SuperTypeBodyDu, SuperTypeArgs,
-        !InvalidTypeSpecs, !Specs) :-
+        !InvalidTypeSpecs, !WarnSpecs) :-
     hlds_data.get_type_defn_tvarset(TypeDefn, TVarSet0),
     hlds_data.get_type_defn_status(TypeDefn, TypeStatus),
     hlds_data.get_type_defn_tvarset(SuperTypeDefn, SuperTVarSet),
@@ -1588,11 +1596,11 @@ check_subtype_ctors(TypeTable, TypeCtor, TypeDefn, TypeBodyDu,
     % Check order of subtype constructors relative to supertype constructors.
     hlds_data.get_type_defn_context(TypeDefn, Context),
     check_subtype_ctors_order(TypeCtor, Ctors, SuperTypeCtor, SuperCtors,
-        Context, !Specs).
+        Context, !WarnSpecs).
 
 :- pred look_up_and_check_subtype_ctor(type_table::in, tvarset::in,
     type_status::in, type_ctor::in, list(constructor)::in, constructor::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 look_up_and_check_subtype_ctor(TypeTable, TVarSet, TypeStatus,
         SuperTypeCtor, SuperCtors, Ctor, !InvalidTypeSpecs) :-
@@ -1633,7 +1641,7 @@ search_ctor_by_unqual_name([HeadCtor | TailCtors], UnqualName, Arity, Ctor) :-
 
 :- pred check_subtype_ctor(type_table::in, tvarset::in, type_status::in,
     constructor::in, constructor::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_subtype_ctor(TypeTable, TVarSet, TypeStatus, Ctor, SuperCtor,
         !InvalidTypeSpecs) :-
@@ -1665,7 +1673,7 @@ check_subtype_ctor(TypeTable, TVarSet, TypeStatus, Ctor, SuperCtor,
 :- pred check_subtype_ctor_exist_constraints(sym_name_arity::in,
     prog_context::in,
     maybe_cons_exist_constraints::in, maybe_cons_exist_constraints::in,
-    maybe1(existq_tvar_mapping, diag_spec)::out) is det.
+    maybe1(existq_tvar_mapping, err_spec)::out) is det.
 
 check_subtype_ctor_exist_constraints(CtorSymNameArity, Context,
         MaybeExistConstraints, MaybeSuperExistConstraints, Result) :-
@@ -1737,7 +1745,7 @@ build_existq_tvars_mapping(VarA, VarB, !ExistQVarsMapping) :-
 :- pred check_subtype_ctor_exist_constraints(sym_name_arity::in,
     prog_context::in, existq_tvar_mapping::in,
     list(prog_constraint)::in, list(prog_constraint)::in,
-    maybe1(existq_tvar_mapping, diag_spec)::out) is det.
+    maybe1(existq_tvar_mapping, err_spec)::out) is det.
 
 check_subtype_ctor_exist_constraints(CtorSymNameArity, Context,
         ExistQVarsMapping, Constraints, SuperConstraints0, Result) :-
@@ -1769,7 +1777,7 @@ check_subtype_ctor_exist_constraints(CtorSymNameArity, Context,
 :- pred check_subtype_ctor_arg(type_table::in, tvarset::in, type_status::in,
     sym_name::in, existq_tvar_mapping::in,
     constructor_arg::in, constructor_arg::in, int::in, int::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_subtype_ctor_arg(TypeTable, TVarSet, OrigTypeStatus, CtorSymName,
         ExistQVarsMapping, CtorArg, SuperCtorArg, ArgNum, ArgNum + 1,
@@ -1971,10 +1979,10 @@ check_is_subtype_higher_order(TypeTable, TVarSet, OrigTypeStatus,
 
 :- pred check_subtype_ctors_order(type_ctor::in, list(constructor)::in,
     type_ctor::in, list(constructor)::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 check_subtype_ctors_order(TypeCtor, Ctors, SuperTypeCtor, SuperCtors, Context,
-        !Specs) :-
+        !WarnSpecs) :-
     compute_subtype_ctors_diff(Ctors, SuperCtors, ChangeHunkPieces),
     (
         ChangeHunkPieces = []
@@ -1994,7 +2002,7 @@ check_subtype_ctors_order(TypeCtor, Ctors, SuperTypeCtor, SuperCtors, Context,
             ChangeHunkPieces,
         Severity = severity_warning(warn_subtype_ctor_order),
         Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:WarnSpecs = [Spec | !.WarnSpecs]
     ).
 
 :- pred compute_subtype_ctors_diff(list(constructor)::in,
diff --git a/compiler/check_field_access_functions.m b/compiler/check_field_access_functions.m
index 7a40a6bcf..13bd4c70e 100644
--- a/compiler/check_field_access_functions.m
+++ b/compiler/check_field_access_functions.m
@@ -34,11 +34,11 @@
 
 :- pred check_preds_if_field_access_function(module_info::in,
     sec_list(item_pred_decl_info)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 :- pred maybe_check_field_access_function(module_info::in,
     sym_name::in, user_arity::in, pred_status::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -69,7 +69,7 @@ check_preds_if_field_access_function(ModuleInfo, [SecList | SecLists],
 
 :- pred check_pred_if_field_access_function(module_info::in, pred_status::in,
     item_pred_decl_info::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_pred_if_field_access_function(ModuleInfo, PredStatus, ItemPredDecl,
         !Specs) :-
@@ -102,7 +102,7 @@ maybe_check_field_access_function(ModuleInfo, FuncSymName, UserArity,
 :- pred check_field_access_function(prog_context::in,
     sym_name::in, user_arity::in, pred_status::in,
     field_access_type::in, sym_name::in, one_or_more(hlds_ctor_field_defn)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_field_access_function(Context, FuncSymName, UserArity,
         FuncStatus, _AccessType, _FieldName, OoMFieldDefns, !Specs) :-
@@ -127,7 +127,7 @@ check_field_access_function(Context, FuncSymName, UserArity,
     ).
 
 :- pred report_field_status_mismatch(prog_context::in, pf_sym_name_arity::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_field_status_mismatch(Context, PFSymNameArity, !Specs) :-
     Pieces = [words("In declaration of"),
diff --git a/compiler/check_import_accessibility.m b/compiler/check_import_accessibility.m
index b48e2b8fb..e5994364d 100644
--- a/compiler/check_import_accessibility.m
+++ b/compiler/check_import_accessibility.m
@@ -75,7 +75,7 @@
 :- pred check_import_accessibility(parse_tree_module_src::in,
     import_accessibility_info::in,
     list(module_name)::out, list(module_name)::out,
-    list(diag_spec)::out, list(diag_spec)::out) is det.
+    list(err_spec)::out, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -263,7 +263,7 @@ record_includes_imports_uses_in_parse_tree_module_src(ParseTreeModuleSrc,
         !SrcIntImportUseMap, !SrcImpImportUseMap) :-
     ParseTreeModuleSrc = parse_tree_module_src(ModuleName, _,
         InclMap, ImportUseMap,
-        _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
+        _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
         _, _, _, _, _, _, _, _, _, _, _, _, _, _, _),
     set.insert(ModuleName, !ReadModules),
     map.foldl(record_include(non_abstract_section, yes(non_abstract_section)),
@@ -820,7 +820,7 @@ update_iu_and_least_context(IoUC, !ImportAndOrUse, !LeastContext) :-
 :- pred report_missing_ancestor(module_name::in,
     missing_where::in, module_name::in, missing_ancestor_info::in,
     list(module_name)::in, list(module_name)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_missing_ancestor(ModuleName, MissingWhere,
         MissingModuleName, MissingAncestorInfo, !ModulesToAdd, !Specs) :-
@@ -886,7 +886,7 @@ report_missing_ancestor(ModuleName, MissingWhere,
     else
         Msgs = [MainMsg]
     ),
-    Spec = diag_spec($pred, severity_error, phase_pt2h, Msgs),
+    Spec = gen_spec($pred, severity_error, phase_pt2h, Msgs),
     !:Specs = [Spec | !.Specs].
 
 %---------------------%
@@ -894,7 +894,7 @@ report_missing_ancestor(ModuleName, MissingWhere,
 :- pred report_any_missing_includes_for_imports(set(module_name)::in,
     seen_includes::in, module_inclusion_map::in,
     module_name::in, one_or_more(import_or_use_context)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_any_missing_includes_for_imports(ReadModules, SeenIncludes, InclMap,
         ModuleName, IoUCs, !Specs) :-
@@ -915,7 +915,7 @@ report_any_missing_includes_for_imports(ReadModules, SeenIncludes, InclMap,
 :- pred report_any_missing_includes(set(module_name)::in,
     seen_includes::in, module_inclusion_map::in,
     module_name::in, list(term_context)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_any_missing_includes(ReadModules, SeenIncludes, InclMap,
         Module, Contexts, !Specs) :-
@@ -966,7 +966,7 @@ report_any_missing_includes(ReadModules, SeenIncludes, InclMap,
     ).
 
 :- pred report_abstract_include(module_name::in, string::in, term_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_abstract_include(ParentModule, SubModule, Context, !Specs) :-
     Pieces = [words("Error:"),
@@ -980,7 +980,7 @@ report_abstract_include(ParentModule, SubModule, Context, !Specs) :-
     !:Specs = [Spec | !.Specs].
 
 :- pred report_missing_include(seen_includes::in, module_name::in, string::in,
-    term_context::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    term_context::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 report_missing_include(SeenIncludes, ParentModule, SubModule, Context,
         !Specs) :-
diff --git a/compiler/check_libgrades.m b/compiler/check_libgrades.m
index fccd0bad8..aabd34c62 100644
--- a/compiler/check_libgrades.m
+++ b/compiler/check_libgrades.m
@@ -102,7 +102,7 @@
     % enabled. If --libgrade-install-check is *not* enabled, we always return
     % an empty list of errors.
     %
-:- pred maybe_check_libraries_are_installed(globals::in, list(diag_spec)::out,
+:- pred maybe_check_libraries_are_installed(globals::in, list(err_spec)::out,
     io::di, io::uo) is det.
 
 %---------------------------------------------------------------------------%
@@ -323,7 +323,7 @@ report_detected_libgrade(Stream, Grade, !IO) :-
                 check_libraries_inputs,
 
                 % ... and result was this.
-                list(diag_spec)
+                list(err_spec)
             ).
 
 :- type check_libraries_inputs
@@ -380,7 +380,7 @@ maybe_check_libraries_are_installed(Globals, Specs, !IO) :-
     % is the Mercury standard library installed?
     %
 :- pred check_stdlib_is_installed(check_libraries_inputs::in,
-    list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::out, io::di, io::uo) is det.
 
 check_stdlib_is_installed(Inputs, Specs, !IO) :-
     MaybeChosenStdLibDir = Inputs ^ cli_chosen_stdlib_dir,
@@ -435,7 +435,7 @@ check_stdlib_is_installed(Inputs, Specs, !IO) :-
     %
 :- pred check_named_libraries_are_installed(globals::in,
     check_libraries_inputs::in, list(string)::in,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 check_named_libraries_are_installed(_, _, [], !Specs, !IO).
 check_named_libraries_are_installed(Globals, Inputs, [LibName | LibNames],
@@ -447,7 +447,7 @@ check_named_libraries_are_installed(Globals, Inputs, [LibName | LibNames],
 
 :- pred check_named_library_is_installed(globals::in,
     check_libraries_inputs::in, string::in,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 check_named_library_is_installed(Globals, Inputs, LibName, !Specs, !IO) :-
     % NOTE This predicate must not use Globals for any purpose except
diff --git a/compiler/check_module_interface.m b/compiler/check_module_interface.m
index 500110a36..b765b69e2 100644
--- a/compiler/check_module_interface.m
+++ b/compiler/check_module_interface.m
@@ -30,7 +30,7 @@
     % report a warning.
     %
 :- pred check_module_interface_for_no_exports(globals::in,
-    parse_tree_module_src::in, list(diag_spec)::out) is det.
+    parse_tree_module_src::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -63,7 +63,7 @@ check_module_interface_for_no_exports(Globals, ParseTreeModuleSrc, Specs) :-
             _IntFIMs, _ImpFIMs, _IntSelfFIMLangs, _ImpSelfFIMLangs,
 
             TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
-            TypeSpecs, InstModeSpecs,
+            TypeErrSpecs, TypeWarnSpecs, InstModeErrSpecs, InstModeWarnSpecs,
 
             IntTypeClasses, IntInstances, IntPredDecls, IntModeDecls,
             IntDeclPragmas, IntDeclMarkers, IntPromises, _IntBadClauses,
@@ -133,8 +133,15 @@ check_module_interface_for_no_exports(Globals, ParseTreeModuleSrc, Specs) :-
             %   a "no exports" warning or not. This means that the warning
             %   is not really needed *now*; it can be generated later,
             %   once the complained-about invalid definitions are fixed.
-            TypeSpecs = [],
-            InstModeSpecs = [],
+            TypeErrSpecs = [],
+            InstModeErrSpecs = [],
+
+            % XXX DIAG_SPECS
+            % These two conditions preserve existing behavior, from a time
+            % where the parse tree stored co-mingled diag_specs. but
+            % I (zs) don't think it should be preserved.
+            TypeWarnSpecs = [],
+            InstModeWarnSpecs = [],
 
             IntTypeClasses = [],
             IntInstances = [],
@@ -164,7 +171,7 @@ check_module_interface_for_no_exports(Globals, ParseTreeModuleSrc, Specs) :-
     ;       1.
 
 :- pred generate_no_exports_warning(module_name::in, prog_context::in,
-    int::in(num_int_incls), diag_spec::out) is det.
+    int::in(num_int_incls), warn_spec::out) is det.
 
 generate_no_exports_warning(ModuleName, Context, NumIntIncls, Spec) :-
     AlwaysPieces =
@@ -201,7 +208,7 @@ generate_no_exports_warning(ModuleName, Context, NumIntIncls, Spec) :-
     Msg = simple_msg(Context,
         [always(AlwaysPieces),
         verbose_only(verbose_always, VerbosePieces)]),
-    Spec = diag_spec($pred, severity_warning(warn_nothing_exported),
+    Spec = gen_spec($pred, severity_warning(warn_nothing_exported),
         phase_t2pt, [Msg]).
 
 %---------------------------------------------------------------------------%
diff --git a/compiler/check_options.m b/compiler/check_options.m
index 085243358..f2f0172bf 100644
--- a/compiler/check_options.m
+++ b/compiler/check_options.m
@@ -709,7 +709,7 @@ check_color_options(!OptionTable, !Specs, !IO) :-
     then
         record_color_scheme_in_options(Source, ColorScheme, ColorSchemeSpecs,
             !OptionTable, !IO),
-        !:Specs = ColorSchemeSpecs ++ !.Specs
+        !:Specs = coerce(ColorSchemeSpecs) ++ !.Specs
     else
         unexpected($pred, "unexpected value in color_scheme_set_by option")
     ),
@@ -718,7 +718,7 @@ check_color_options(!OptionTable, !Specs, !IO) :-
         MaybeConvertColorSpecs = ok1(_)
     ;
         MaybeConvertColorSpecs = error1(ConvertColorSpecs),
-        !:Specs = one_or_more_to_list(ConvertColorSpecs) ++ !.Specs
+        !:Specs = coerce(one_or_more_to_list(ConvertColorSpecs)) ++ !.Specs
     ).
 
 %---------------------------------------------------------------------------%
diff --git a/compiler/check_promise.m b/compiler/check_promise.m
index 70bb14d3b..9ccc0a594 100644
--- a/compiler/check_promise.m
+++ b/compiler/check_promise.m
@@ -364,7 +364,7 @@ report_assertion_interface_error(ModuleName, Context,
         [words("Either move the promise into the implementation section,"),
         words("or move the definition into the interface."), nl],
     Msgs = [always(MainPieces), verbose_only(verbose_always, VerbosePieces)],
-    Spec = diag_spec($pred, severity_error, phase_type_check,
+    Spec = gen_spec($pred, severity_error, phase_type_check,
         [simple_msg(Context, Msgs)]),
     !:Specs = [Spec | !.Specs].
 
@@ -389,7 +389,7 @@ report_assertion_module_error(ModuleName, Context, PredModuleName,
         qual_sym_name(PredModuleName), words("module."),
         words("In most cases, the latter is preferable."), nl],
     Msgs = [always(MainPieces), verbose_only(verbose_always, VerbosePieces)],
-    Spec = diag_spec($pred, severity_error, phase_type_check,
+    Spec = gen_spec($pred, severity_error, phase_type_check,
         [simple_msg(Context, Msgs)]),
     !:Specs = [Spec | !.Specs].
 
diff --git a/compiler/check_type_inst_mode_defns.m b/compiler/check_type_inst_mode_defns.m
index 2dd3a6741..832020a2d 100644
--- a/compiler/check_type_inst_mode_defns.m
+++ b/compiler/check_type_inst_mode_defns.m
@@ -33,7 +33,7 @@
 
     % create_type_ctor_checked_map(InsistOnDefn,
     %   IntTypeDefnMap, ImpTypeDefnMap, ImpForeignEnumMap,
-    %   TypeCtorCheckedMap, !Specs):
+    %   TypeCtorCheckedMap, !ErrSpecs, !WarnSpecs):
     %
     % Given the type definitions in both the interface and implementation
     % sections of a module, and foreign enum definitions in the implementation
@@ -61,10 +61,11 @@
 :- pred create_type_ctor_checked_map(maybe_insist_on_defn::in,
     type_ctor_defn_map::in, type_ctor_defn_map::in,
     type_ctor_foreign_enum_map::in, type_ctor_checked_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
     % report_not_enum_type_du(ForWhat, TypeCtor, TypeDefnContext, NonEnumSNAs,
-    %   EnumContext, !Specs)
+    %   EnumContext, !ErrSpecs)
     %
     % Report a foreign_enum or foreign_export_enum declaration
     % for a non-enum du type.
@@ -73,21 +74,23 @@
     %
 :- pred report_not_enum_type_du(for_fe_or_fee::in, type_ctor::in,
     prog_context::in, list(sym_name_arity)::in,
-    prog_context::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    prog_context::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
 :- pred create_inst_ctor_checked_map(maybe_insist_on_defn::in,
     inst_ctor_defn_map::in, inst_ctor_defn_map::in,
     inst_ctor_checked_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
 :- pred create_mode_ctor_checked_map(maybe_insist_on_defn::in,
     mode_ctor_defn_map::in, mode_ctor_defn_map::in,
     mode_ctor_checked_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -120,7 +123,7 @@
 %---------------------------------------------------------------------------%
 
 create_type_ctor_checked_map(InsistOnDefn, IntTypeDefnMap, ImpTypeDefnMap,
-        ImpForeignEnumMap, CheckedMap, !Specs) :-
+        ImpForeignEnumMap, CheckedMap, !ErrSpecs, !WarnSpecs) :-
     map.keys_as_set(IntTypeDefnMap, IntDefnTypeCtors),
     map.keys_as_set(ImpTypeDefnMap, ImpDefnTypeCtors),
     % Foreign_enum items are not allowed in interface sections.
@@ -132,24 +135,25 @@ create_type_ctor_checked_map(InsistOnDefn, IntTypeDefnMap, ImpTypeDefnMap,
         set.union_list([
             IntDefnTypeCtors, ImpDefnTypeCtors, ImpEnumTypeCtors
         ])),
-    list.foldl2(
+    list.foldl3(
         check_type_ctor_defns(InsistOnDefn, IntTypeDefnMap, ImpTypeDefnMap,
             ImpForeignEnumMap),
-        TypeCtors, map.init, CheckedMap, !Specs),
+        TypeCtors, map.init, CheckedMap, !ErrSpecs, !WarnSpecs),
 
     map.foldl(add_type_ctor_to_field_name_map, CheckedMap,
         map.init, FieldNameMap),
-    map.foldl(report_any_duplicate_field_names, FieldNameMap, !Specs).
+    map.foldl(report_any_duplicate_field_names, FieldNameMap, !ErrSpecs).
 
 :- pred check_type_ctor_defns(maybe_insist_on_defn::in,
     type_ctor_defn_map::in, type_ctor_defn_map::in,
     type_ctor_foreign_enum_map::in, type_ctor::in,
     type_ctor_checked_map::in, type_ctor_checked_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 check_type_ctor_defns(InsistOnDefn,
         IntTypeDefnMap, ImpTypeDefnMap, ImpForeignEnumMap,
-        TypeCtor, !TypeCtorCheckedMap, !Specs) :-
+        TypeCtor, !TypeCtorCheckedMap, !ErrSpecs, !WarnSpecs) :-
     % A given type constructor may have more than one definition in a module.
     % These definitions may be consistent with one another (such as a du
     % definition in Mercury and a foreign type definition in C), or
@@ -180,11 +184,11 @@ check_type_ctor_defns(InsistOnDefn,
     % themselves as violations of the "at most one definition of TypeCtor
     % of a given kind in a given module section" rule.
     check_any_type_ctor_defns_for_duplicates(IntTypeDefnMap, TypeCtor,
-        IntMaybeDefn, !Specs),
+        IntMaybeDefn, !ErrSpecs, !WarnSpecs),
     check_any_type_ctor_defns_for_duplicates(ImpTypeDefnMap, TypeCtor,
-        ImpMaybeDefn, !Specs),
+        ImpMaybeDefn, !ErrSpecs, !WarnSpecs),
     check_any_type_ctor_enums_for_duplicates(ImpForeignEnumMap, TypeCtor,
-        ImpMaybeEnumCJCs, ImpLeftOverEnumsCJCs, !Specs),
+        ImpMaybeEnumCJCs, ImpLeftOverEnumsCJCs, !ErrSpecs),
 
     ( if map.search(ImpForeignEnumMap, TypeCtor, ImpEnumsCJCs) then
         ImpEnumsCJCs = c_java_csharp(ImpEnumsC, ImpEnumsJava, ImpEnumsCsharp),
@@ -267,21 +271,21 @@ check_type_ctor_defns(InsistOnDefn,
 
     report_any_nonabstract_solver_type_in_int(TypeCtor, IntSolverMaybeDefn,
         IntAbstractSolverMaybeDefn0, IntAbstractSolverMaybeDefn,
-        ImpSolverMaybeDefn0, ImpSolverMaybeDefn, !Specs),
+        ImpSolverMaybeDefn0, ImpSolverMaybeDefn, !ErrSpecs),
     ( if
         % Is there a solver type definition (not declaration) in the
         % implementation? There can't be a valid one in the interface.
         ImpSolverMaybeDefn = yes(ImpSolverDefn)
     then
         report_any_redundant_abstract_type_in_imp(TypeCtor, "implementation",
-            ImpAbstractSolverMaybeDefn, !Specs),
+            ImpAbstractSolverMaybeDefn, !WarnSpecs),
         % Print error messages for every Std definition.
         list.foldl(
             report_any_incompatible_type_decl_or_defn(TypeCtor,
                 ImpSolverDefn ^ td_context, "solver type", "implementation",
                 "definition", "declaration"),
             [IntContextAbstractStd, ImpContextAbstractStd],
-            !Specs),
+            !ErrSpecs),
         list.foldl(
             report_any_incompatible_type_decl_or_defn(TypeCtor,
                 ImpSolverDefn ^ td_context, "solver type", "implementation",
@@ -290,11 +294,11 @@ check_type_ctor_defns(InsistOnDefn,
                 IntContextC, IntContextJava, IntContextCsharp,
             ImpContextEqv, ImpContextDu, ImpContextSub,
                 ImpContextC, ImpContextJava, ImpContextCsharp],
-            !Specs),
+            !ErrSpecs),
         list.foldl(
             report_incompatible_foreign_enum(TypeCtor,
                 ImpSolverDefn ^ td_context, "solver type", "implementation"),
-            ImpEnums, !Specs),
+            ImpEnums, !ErrSpecs),
 
         CheckedSolverDefn = solver_type_full(IntAbstractSolverMaybeDefn,
             ImpSolverDefn),
@@ -338,13 +342,13 @@ check_type_ctor_defns(InsistOnDefn,
         )
     then
         report_any_redundant_abstract_type_in_imp(TypeCtor, EqvWhere,
-            ImpAbstractStdMaybeDefn, !Specs),
+            ImpAbstractStdMaybeDefn, !WarnSpecs),
         list.foldl(
             report_any_incompatible_type_decl_or_defn(TypeCtor,
                 EqvDefn ^ td_context, "equivalence type", EqvWhere,
                 "definition", "solver type declaration"),
             [IntContextAbstractSolver, ImpContextAbstractSolver],
-            !Specs),
+            !ErrSpecs),
         list.foldl(
             report_any_incompatible_type_decl_or_defn(TypeCtor,
                 EqvDefn ^ td_context, "equivalence type", EqvWhere,
@@ -353,11 +357,11 @@ check_type_ctor_defns(InsistOnDefn,
                 IntContextC, IntContextJava, IntContextCsharp,
             ImpContextDu, ImpContextSub,
                 ImpContextC, ImpContextJava, ImpContextCsharp],
-            !Specs),
+            !ErrSpecs),
         list.foldl(
             report_incompatible_foreign_enum(TypeCtor,
                 EqvDefn ^ td_context, "equivalence type", EqvWhere),
-            ImpEnums, !Specs),
+            ImpEnums, !ErrSpecs),
         CheckedStdDefn = std_mer_type_eqv(Status, EqvDefn),
         CheckedDefn = checked_defn_std(CheckedStdDefn, SrcDefns),
         map.det_insert(TypeCtor, CheckedDefn, !TypeCtorCheckedMap)
@@ -383,19 +387,19 @@ check_type_ctor_defns(InsistOnDefn,
         )
     then
         report_any_redundant_abstract_type_in_imp(TypeCtor, SubWhere,
-            ImpAbstractStdMaybeDefn, !Specs),
+            ImpAbstractStdMaybeDefn, !WarnSpecs),
         list.foldl(
             report_any_incompatible_type_decl_or_defn(TypeCtor,
                 SubDefn ^ td_context, "subtype", SubWhere,
                 "definition", "solver type declaration"),
             [IntContextAbstractSolver, ImpContextAbstractSolver],
-            !Specs),
+            !ErrSpecs),
         list.foldl(
             report_any_incompatible_type_decl_or_defn(TypeCtor,
                 SubDefn ^ td_context, "subtype", SubWhere,
                 "definition", "definition"),
             [IntContextDu, ImpContextDu],
-            !Specs),
+            !ErrSpecs),
 
         % A subtype's representation is controlled entirely by the
         % representation of its base type. It cannot have its own
@@ -404,9 +408,9 @@ check_type_ctor_defns(InsistOnDefn,
             IntMaybeDefnJava, ImpMaybeDefnJava,
             IntMaybeDefnCsharp, ImpMaybeDefnCsharp]),
         list.foldl(subtype_report_any_foreign_type(TypeCtor, SubDefn),
-            ForeignDefns, !Specs),
+            ForeignDefns, !ErrSpecs),
         list.foldl(subtype_report_any_foreign_enum(TypeCtor, SubDefn),
-            ImpEnums, !Specs),
+            ImpEnums, !ErrSpecs),
 
         decide_subtype_status(TypeCtor, SubDefn, SubSection,
             IntAbstractStdMaybeDefn, Status, SrcDefnsInt, SrcDefnsImp),
@@ -437,13 +441,13 @@ check_type_ctor_defns(InsistOnDefn,
         )
     then
         report_any_redundant_abstract_type_in_imp(TypeCtor, DuWhere,
-            ImpAbstractStdMaybeDefn, !Specs),
+            ImpAbstractStdMaybeDefn, !WarnSpecs),
         list.foldl(
             report_any_incompatible_type_decl_or_defn(TypeCtor,
                 DuDefn ^ td_context, "discriminated union type", DuWhere,
                 "definition", "solver type declaration"),
             [IntContextAbstractSolver, ImpContextAbstractSolver],
-            !Specs),
+            !ErrSpecs),
 
         % XXX TYPE_REPN As part of switching over to this new system,
         % we will have to disable users' ability to specify MaybeDirectArgs
@@ -461,7 +465,7 @@ check_type_ctor_defns(InsistOnDefn,
         check_du_foreign_type_section(TypeCtor, DuDefn, DuSection,
             IntAbstractStdMaybeDefn, IntMaybeDefnCJCs, ImpMaybeDefnCJCs,
             Status, ChosenSectionCJCs, ChosenMaybeDefnCJCs,
-            SrcDefnsDuInt, SrcDefnsDuImp, !Specs),
+            SrcDefnsDuInt, SrcDefnsDuImp, !ErrSpecs),
         ( if
             ctor_is_constant(HeadCtor, HeadName0),
             ctors_are_all_constants(TailCtors, TailNames0)
@@ -501,7 +505,7 @@ check_type_ctor_defns(InsistOnDefn,
                 list.foldl(
                     report_not_enum_type_du(for_foreign_enum, TypeCtor,
                         DuDefnContext, NonEnumSNAs),
-                    ImpEnumContexts, !Specs)
+                    ImpEnumContexts, !ErrSpecs)
             ),
             CheckedStdDefn =
                 std_mer_type_du_not_all_plain_constants(Status, DuDefn,
@@ -517,7 +521,7 @@ check_type_ctor_defns(InsistOnDefn,
                 [HeadName | TailNames], ChosenMaybeDefnCJCs,
                 ImpMaybeEnumCJCs, ImpLeftOverEnumsCJCs,
                 MaybeDefnOrEnumCJCs, SrcForeignDefns, SrcForeignEnums,
-                !Specs),
+                !ErrSpecs),
             CheckedStdDefn = std_mer_type_du_all_plain_constants(Status,
                 DuDefn, HeadName, TailNames, MaybeDefnOrEnumCJCs)
         ),
@@ -567,18 +571,18 @@ check_type_ctor_defns(InsistOnDefn,
                 FirstForeignContext, "foreign type", ForeignWhere,
                 "definition", "solver type declaration"),
             [IntContextAbstractSolver, ImpContextAbstractSolver],
-            !Specs),
+            !ErrSpecs),
         list.foldl(
             report_incompatible_foreign_enum(TypeCtor,
                 FirstForeignContext, "foreign type", ForeignWhere),
-            ImpEnums, !Specs),
+            ImpEnums, !ErrSpecs),
 
         decide_only_foreign_type_section(TypeCtor,
             IntAbstractSolverMaybeDefn, ImpAbstractSolverMaybeDefn,
             IntAbstractStdMaybeDefn, ImpAbstractStdMaybeDefn,
             IntMaybeDefnCJCs, ImpMaybeDefnCJCs,
             Status, ChosenAbstractStdDefn, ChosenMaybeDefnCJCs, SrcDefns,
-            !Specs),
+            !ErrSpecs),
 
         CheckedStdDefn = std_mer_type_abstract(Status,
             ChosenAbstractStdDefn, ChosenMaybeDefnCJCs),
@@ -610,18 +614,18 @@ check_type_ctor_defns(InsistOnDefn,
         )
     then
         maybe_report_declared_but_undefined_type(InsistOnDefn, TypeCtor,
-            AbstractSolverDefn, !Specs),
+            AbstractSolverDefn, !ErrSpecs),
         list.foldl(
             report_any_incompatible_type_decl_or_defn(TypeCtor,
                 AbstractSolverDefn ^ td_context, "solver type",
                 AbstractSolverWhere, "declaration", "declaration"),
             [IntContextAbstractStd, ImpContextAbstractStd],
-            !Specs),
+            !ErrSpecs),
         list.foldl(
             report_incompatible_foreign_enum(TypeCtor,
                 AbstractSolverDefn ^ td_context, "solver type",
                 AbstractSolverWhere),
-            ImpEnums, !Specs),
+            ImpEnums, !ErrSpecs),
         % XXX Should we report any foreign enums using this code?
         % It would say that TypeCtor is not defined, while the code
         % above says it is a solver type.
@@ -629,7 +633,7 @@ check_type_ctor_defns(InsistOnDefn,
         %   report_any_foreign_enum_for_undefined_type(TypeCtor,
         %       "undefined"),
         %   [ImpMaybeEnumC, ImpMaybeEnumJava, ImpMaybeEnumCsharp],
-        %   !Specs),
+        %   !ErrSpecs),
         CheckedSolverDefn = solver_type_abstract(Status, AbstractSolverDefn),
         SrcDefns = src_defns_solver(SrcDefnsInt, SrcDefnsImp),
         CheckedDefn = checked_defn_solver(CheckedSolverDefn, SrcDefns),
@@ -673,10 +677,10 @@ check_type_ctor_defns(InsistOnDefn,
         )
     then
         maybe_report_declared_but_undefined_type(InsistOnDefn, TypeCtor,
-            AbstractStdDefn, !Specs),
+            AbstractStdDefn, !ErrSpecs),
         list.foldl(
             report_foreign_enum_for_undefined_type(TypeCtor, "undefined"),
-            ImpEnums, !Specs),
+            ImpEnums, !ErrSpecs),
         MaybeCJCs = c_java_csharp(no, no, no),
         CheckedStdDefn = std_mer_type_abstract(Status,
             AbstractStdDefn, MaybeCJCs),
@@ -690,7 +694,7 @@ check_type_ctor_defns(InsistOnDefn,
         % we can get here is if it has any foreign enum definitions.
         list.foldl(
             report_foreign_enum_for_undefined_type(TypeCtor, "undeclared"),
-            ImpEnums, !Specs)
+            ImpEnums, !ErrSpecs)
         % There is no actual definition to add to !TypeCtorCheckedMap.
     ).
 
@@ -706,12 +710,12 @@ get_maybe_context(yes(TypeDefnInfo)) = yes(TypeDefnInfo ^ td_context).
     c_j_cs_maybe_defn::in, c_j_cs_maybe_defn::in,
     std_du_type_status::out, module_section::out, c_j_cs_maybe_defn::out,
     list(item_type_defn_info)::out, list(item_type_defn_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_du_foreign_type_section(TypeCtor, DuDefn, DuSection,
         IntAbstractStdMaybeDefn, IntMaybeDefnCJCs, ImpMaybeDefnCJCs,
         Status, ChosenSectionCJCs, ChosenMaybeDefnCJCs,
-        SrcDefnsDuInt, SrcDefnsDuImp, !Specs) :-
+        SrcDefnsDuInt, SrcDefnsDuImp, !ErrSpecs) :-
     IntMaybeDefnCJCs = c_java_csharp(IntMaybeDefnC, IntMaybeDefnJava,
         IntMaybeDefnCsharp),
     ImpMaybeDefnCJCs = c_java_csharp(ImpMaybeDefnC, ImpMaybeDefnJava,
@@ -725,7 +729,7 @@ check_du_foreign_type_section(TypeCtor, DuDefn, DuSection,
         list.foldl(
             report_mer_foreign_section_mismatch(TypeCtor,
                 "definition", "interface", DuDefn),
-            ImpDefnsCJCs, !Specs),
+            ImpDefnsCJCs, !ErrSpecs),
         Status = std_du_type_mer_ft_exported,
         ChosenSectionCJCs = ms_interface,
         ChosenMaybeDefnCJCs = IntMaybeDefnCJCs,
@@ -736,7 +740,7 @@ check_du_foreign_type_section(TypeCtor, DuDefn, DuSection,
         list.foldl(
             report_mer_foreign_section_mismatch(TypeCtor,
                 "definition", "implementation", DuDefn),
-            IntDefnsCJCs, !Specs),
+            IntDefnsCJCs, !ErrSpecs),
         (
             IntAbstractStdMaybeDefn = yes(IntAbstractStdDefn),
             Status = std_du_type_abstract_exported,
@@ -785,13 +789,13 @@ decide_subtype_status(_TypeCtor, SubDefn, SubSection, IntAbstractStdMaybeDefn,
     c_j_cs_maybe_defn::in, c_j_cs_maybe_defn::in,
     std_abs_type_status::out,
     item_type_defn_info_abstract::out, c_j_cs_maybe_defn::out,
-    src_defns_std::out, list(diag_spec)::in, list(diag_spec)::out) is det.
+    src_defns_std::out, list(err_spec)::in, list(err_spec)::out) is det.
 
 decide_only_foreign_type_section(TypeCtor,
         IntAbsSolverMaybeDefn, ImpAbsSolverMaybeDefn,
         IntAbsStdMaybeDefn, ImpAbsStdMaybeDefn,
         IntMaybeDefnCJCs, ImpMaybeDefnCJCs,
-        Status, AbsStdDefn, ChosenMaybeDefnCJCs, SrcDefns, !Specs) :-
+        Status, AbsStdDefn, ChosenMaybeDefnCJCs, SrcDefns, !ErrSpecs) :-
     IntMaybeDefnCJCs = c_java_csharp(IntMaybeDefnC, IntMaybeDefnJava,
         IntMaybeDefnCsharp),
     ImpMaybeDefnCJCs = c_java_csharp(ImpMaybeDefnC, ImpMaybeDefnJava,
@@ -812,7 +816,7 @@ decide_only_foreign_type_section(TypeCtor,
             list.foldl(
                 foreign_int_report_any_foreign_defn_in_imp(TypeCtor,
                     FirstIntContext),
-                ImpDefnsCJCs, !Specs),
+                ImpDefnsCJCs, !ErrSpecs),
             ChosenMaybeDefnCJCs = IntMaybeDefnCJCs,
             SrcDefnsInt = [wrap_abstract_type_defn(IntAbsStdDefn) |
                 list.map(wrap_foreign_type_defn, IntDefnsCJCs)],
@@ -833,7 +837,7 @@ decide_only_foreign_type_section(TypeCtor,
             list.foldl(
                 report_mer_foreign_section_mismatch(TypeCtor,
                     "declaration", "implementation", ImpAbsStdDefn),
-                IntDefnsCJCs, !Specs)
+                IntDefnsCJCs, !ErrSpecs)
         ;
             ImpAbsStdMaybeDefn = no,
             IntImpDefnsCJCs = IntDefnsCJCs ++ ImpDefnsCJCs,
@@ -854,7 +858,7 @@ decide_only_foreign_type_section(TypeCtor,
             else
                 list.foldl(
                     report_any_foreign_type_without_declaration(TypeCtor),
-                    IntImpDefnsCJCs, !Specs)
+                    IntImpDefnsCJCs, !ErrSpecs)
             ),
             % IntImpDefnsCJCs cannot be empty because our caller calls us
             % only if at least one of the foreign language definitions
@@ -883,11 +887,11 @@ decide_only_foreign_type_section(TypeCtor,
     c_j_cs_maybe_enum::in, c_j_cs_enums::in,
     c_j_cs_maybe_defn_or_enum::out,
     list(item_type_defn_info_foreign)::out, list(item_foreign_enum_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 decide_du_repn_foreign_only_constants(TypeCtor, CtorNames,
         MaybeDefnCJCs, MaybeEnumCJCs, LeftOverEnumsCJCs,
-        MaybeDefnOrEnumCJCs, SrcForeignDefns, SrcForeignEnums, !Specs) :-
+        MaybeDefnOrEnumCJCs, SrcForeignDefns, SrcForeignEnums, !ErrSpecs) :-
     % If TypeCtor has more than one enum definition for a given foreign
     % language, we pick on to return in MaybeEnumCJCs, but we return
     % all the others as well in LeftOverEnumsCJCs so that our caller
@@ -901,15 +905,15 @@ decide_du_repn_foreign_only_constants(TypeCtor, CtorNames,
     decide_du_repn_foreign_only_constants_lang(TypeCtor,
         CtorNames, CtorNamesSet, MaybeDefnC,
         MaybeEnumC, LeftOverEnumsC, MaybeDefnOrEnumC,
-        SrcForeignDefnsC, SrcForeignEnumsC, !Specs),
+        SrcForeignDefnsC, SrcForeignEnumsC, !ErrSpecs),
     decide_du_repn_foreign_only_constants_lang(TypeCtor,
         CtorNames, CtorNamesSet, MaybeDefnJava,
         MaybeEnumJava, LeftOverEnumsJava, MaybeDefnOrEnumJava,
-        SrcForeignDefnsJava, SrcForeignEnumsJava, !Specs),
+        SrcForeignDefnsJava, SrcForeignEnumsJava, !ErrSpecs),
     decide_du_repn_foreign_only_constants_lang(TypeCtor,
         CtorNames, CtorNamesSet, MaybeDefnCsharp,
         MaybeEnumCsharp, LeftOverEnumsCsharp, MaybeDefnOrEnumCsharp,
-        SrcForeignDefnsCsharp, SrcForeignEnumsCsharp, !Specs),
+        SrcForeignDefnsCsharp, SrcForeignEnumsCsharp, !ErrSpecs),
 
     SrcForeignDefns =
         SrcForeignDefnsC ++ SrcForeignDefnsJava ++ SrcForeignDefnsCsharp,
@@ -925,11 +929,11 @@ decide_du_repn_foreign_only_constants(TypeCtor, CtorNames,
     maybe(foreign_type_or_enum)::out,
     list(item_type_defn_info_foreign)::out,
     list(item_foreign_enum_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 decide_du_repn_foreign_only_constants_lang(TypeCtor, CtorNames, CtorNamesSet,
         MaybeDefn, MaybeEnum, LeftOverEnums, MaybeDefnOrEnum,
-        SrcForeignDefns, SrcForeignEnums, !Specs) :-
+        SrcForeignDefns, SrcForeignEnums, !ErrSpecs) :-
     (
         MaybeEnum = no,
         expect(unify(LeftOverEnums, []), $pred,
@@ -944,7 +948,7 @@ decide_du_repn_foreign_only_constants_lang(TypeCtor, CtorNames, CtorNamesSet,
             LeftOverEnums, TailMaybeCFEs),
         pick_first_error_free_enum_if_any([HeadMaybeCFE | TailMaybeCFEs],
             MaybeCheckedForeignEnum, CFESpecs),
-        !:Specs = CFESpecs ++ !.Specs
+        !:ErrSpecs = CFESpecs ++ !.ErrSpecs
     ),
     (
         MaybeDefn = yes(Defn),
@@ -970,7 +974,7 @@ decide_du_repn_foreign_only_constants_lang(TypeCtor, CtorNames, CtorNamesSet,
 
 :- pred pick_first_error_free_enum_if_any(
     list(maybe1(checked_foreign_enum))::in,
-    maybe(checked_foreign_enum)::out, list(diag_spec)::out) is det.
+    maybe(checked_foreign_enum)::out, list(err_spec)::out) is det.
 
 pick_first_error_free_enum_if_any([], no, []).
 pick_first_error_free_enum_if_any([HeadMaybeCFE | TailMaybeCFEs],
@@ -1045,7 +1049,7 @@ find_non_enum_ctors([Ctor | Ctors], !NonEnumSNAs) :-
     find_non_enum_ctors(Ctors, !NonEnumSNAs).
 
 report_not_enum_type_du(ForWhat, TypeCtor, TypeDefnContext, NonEnumSNAs,
-        EnumContext, !Specs) :-
+        EnumContext, !ErrSpecs) :-
     (
         NonEnumSNAs = [],
         NonEnumCtorPieces = []
@@ -1076,49 +1080,49 @@ report_not_enum_type_du(ForWhat, TypeCtor, TypeDefnContext, NonEnumSNAs,
             pragma_decl(PragmaName), words("declarations for it.")]) ++ [nl],
     TypePieces = [words("That Mercury definition is here."), nl] ++
         NonEnumCtorPieces,
-    Spec = diag_spec($pred, severity_error, phase_pt2h,
+    Spec = gen_spec($pred, severity_error, phase_pt2h,
         [msg(EnumContext, EnumPieces), msg(TypeDefnContext, TypePieces)]),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 :- pred subtype_report_any_foreign_type(type_ctor::in,
     item_type_defn_info_sub::in, item_type_defn_info_foreign::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-subtype_report_any_foreign_type(TypeCtor, SubTypeDefn, Foreign, !Specs) :-
+subtype_report_any_foreign_type(TypeCtor, SubTypeDefn, Foreign, !ErrSpecs) :-
     ForeignPieces = [words("Error:")] ++
         color_as_subject([unqual_type_ctor(TypeCtor)]) ++
         [words("is defined to be a subtype, so")] ++
         color_as_incorrect([words("there must not be any"),
         pragma_decl("foreign_type"), words("declarations for it.")]) ++ [nl],
     SubTypePieces = [words("That subtype definition is here."), nl],
-    Spec = diag_spec($pred, severity_error, phase_tim_check,
+    Spec = gen_spec($pred, severity_error, phase_tim_check,
         [msg(Foreign ^ td_context, ForeignPieces),
         msg(SubTypeDefn ^ td_context, SubTypePieces)]),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 :- pred subtype_report_any_foreign_enum(type_ctor::in,
     item_type_defn_info_sub::in, item_foreign_enum_info::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-subtype_report_any_foreign_enum(TypeCtor, SubTypeDefn, Enum, !Specs) :-
+subtype_report_any_foreign_enum(TypeCtor, SubTypeDefn, Enum, !ErrSpecs) :-
     EnumPieces = [words("Error:")] ++
         color_as_subject([unqual_type_ctor(TypeCtor)]) ++
         [words("is defined to be a subtype, so")] ++
         color_as_incorrect([words("there must not be any"),
         pragma_decl("foreign_enum"), words("declarations for it.")]) ++ [nl],
     SubTypePieces = [words("That subtype definition is here."), nl],
-    Spec = diag_spec($pred, severity_error, phase_tim_check,
+    Spec = gen_spec($pred, severity_error, phase_tim_check,
         [msg(Enum ^ fe_context, EnumPieces),
         msg(SubTypeDefn ^ td_context, SubTypePieces)]),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 :- pred report_mer_foreign_section_mismatch(type_ctor::in,
     string::in, string::in,
     item_type_defn_info_general(T)::in, item_type_defn_info_foreign::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_mer_foreign_section_mismatch(TypeCtor, DeclOrDefn, MerSection, MerDefn,
-        ForeignDefn, !Specs) :-
+        ForeignDefn, !ErrSpecs) :-
     ForeignPieces = [words("Error: since the Mercury"), words(DeclOrDefn),
         words("of")] ++ color_as_subject([unqual_type_ctor(TypeCtor)]) ++
         color_as_correct([words("is in the"), words(MerSection),
@@ -1129,16 +1133,17 @@ report_mer_foreign_section_mismatch(TypeCtor, DeclOrDefn, MerSection, MerDefn,
         [nl],
     DuPieces = [words("That Mercury"), words(DeclOrDefn),
         words("is here."), nl],
-    Spec = diag_spec($pred, severity_error, phase_tim_check,
+    Spec = gen_spec($pred, severity_error, phase_tim_check,
         [msg(ForeignDefn ^ td_context, ForeignPieces),
         msg(MerDefn ^ td_context, DuPieces)]),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 :- pred report_any_foreign_type_without_declaration(type_ctor::in,
     item_type_defn_info_foreign::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-report_any_foreign_type_without_declaration(TypeCtor, ForeignDefn, !Specs) :-
+report_any_foreign_type_without_declaration(TypeCtor, ForeignDefn,
+        !ErrSpecs) :-
     Pieces = [words("Error: a"),
         pragma_decl("foreign_type"), words("definition for")] ++
         color_as_subject([unqual_type_ctor(TypeCtor)]) ++
@@ -1147,14 +1152,14 @@ report_any_foreign_type_without_declaration(TypeCtor, ForeignDefn, !Specs) :-
         [words("for"), unqual_type_ctor(TypeCtor), suffix("."), nl],
     Spec = spec($pred, severity_error, phase_tim_check_invalid_type,
         ForeignDefn ^ td_context, Pieces),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 :- pred foreign_int_report_any_foreign_defn_in_imp(type_ctor::in,
     prog_context::in, item_type_defn_info_foreign::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 foreign_int_report_any_foreign_defn_in_imp(TypeCtor, IntForeignContext,
-        ImpForeignDefn, !Specs) :-
+        ImpForeignDefn, !ErrSpecs) :-
     ImpPieces = [words("Error: since some foreign language definition"),
         words("of")] ++ color_as_subject([unqual_type_ctor(TypeCtor)]) ++
         [words("is in the interface section,")] ++
@@ -1163,10 +1168,10 @@ foreign_int_report_any_foreign_defn_in_imp(TypeCtor, IntForeignContext,
         [nl],
     IntPieces = [words("That foreign definition in the interface"),
         words("is here."), nl],
-    Spec = diag_spec($pred, severity_error, phase_tim_check,
+    Spec = gen_spec($pred, severity_error, phase_tim_check,
         [msg(ImpForeignDefn ^ td_context, ImpPieces),
         msg(IntForeignContext, IntPieces)]),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 :- pred report_any_nonabstract_solver_type_in_int(type_ctor::in,
     maybe(item_type_defn_info_solver)::in,
@@ -1174,7 +1179,7 @@ foreign_int_report_any_foreign_defn_in_imp(TypeCtor, IntForeignContext,
     maybe(item_type_defn_info_abstract)::out,
     maybe(item_type_defn_info_solver)::in,
     maybe(item_type_defn_info_solver)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_any_nonabstract_solver_type_in_int(TypeCtor, IntMaybeDefn,
         IntMaybeAbstractDefn0, IntMaybeAbstractDefn,
@@ -1218,7 +1223,7 @@ report_any_nonabstract_solver_type_in_int(TypeCtor, IntMaybeDefn,
 
 :- pred report_any_redundant_abstract_type_in_imp(type_ctor::in, string::in,
     maybe(item_type_defn_info_abstract)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 report_any_redundant_abstract_type_in_imp(TypeCtor, Section,
         MaybeImpAbstractDefn, !Specs) :-
@@ -1240,7 +1245,7 @@ report_any_redundant_abstract_type_in_imp(TypeCtor, Section,
 :- pred report_any_incompatible_type_decl_or_defn(type_ctor::in,
     prog_context::in, string::in, string::in, string::in,
     string::in, maybe(prog_context)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_any_incompatible_type_decl_or_defn(TypeCtor, UsedContext, Kind, Section,
         SectionDeclOrDefn, DeclOrDefn, MaybeDefnContext, !Specs) :-
@@ -1255,7 +1260,7 @@ report_any_incompatible_type_decl_or_defn(TypeCtor, UsedContext, Kind, Section,
             words("in the"), words(Section), words("section."), nl],
         UsedPieces = [words("That"), words(SectionDeclOrDefn),
             words("is here."), nl],
-        Spec = diag_spec($pred, severity_error, phase_tim_check_invalid_type,
+        Spec = gen_spec($pred, severity_error, phase_tim_check_invalid_type,
             [msg(DefnContext, MainPieces),
             msg(UsedContext, UsedPieces)]),
         !:Specs = [Spec | !.Specs]
@@ -1263,10 +1268,10 @@ report_any_incompatible_type_decl_or_defn(TypeCtor, UsedContext, Kind, Section,
 
 :- pred report_incompatible_foreign_enum(type_ctor::in, prog_context::in,
     string::in, string::in, item_foreign_enum_info::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_incompatible_foreign_enum(TypeCtor, UsedContext, Kind, Section, Enum,
-        !Specs) :-
+        !ErrSpecs) :-
     MainPieces = [words("Error: this"), pragma_decl("foreign_enum"),
         words("declaration for")] ++
         color_as_subject([unqual_type_ctor(TypeCtor)]) ++
@@ -1274,31 +1279,31 @@ report_incompatible_foreign_enum(TypeCtor, UsedContext, Kind, Section, Enum,
         [words("with the"), words(Kind), words("definition in the"),
         words(Section), words("section."), nl],
     UsedPieces = [words("That definition is here."), nl],
-    Spec = diag_spec($pred, severity_error, phase_tim_check,
+    Spec = gen_spec($pred, severity_error, phase_tim_check,
         [msg(Enum ^ fe_context, MainPieces),
         msg(UsedContext, UsedPieces)]),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 :- pred report_foreign_enum_for_undefined_type(type_ctor::in, string::in,
     item_foreign_enum_info::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_foreign_enum_for_undefined_type(TypeCtor, UndefOrUndecl, Enum,
-        !Specs) :-
+        !ErrSpecs) :-
     Pieces = [words("Error:"), pragma_decl("foreign_enum"),
         words("declaration for the")] ++
         color_as_incorrect([words(UndefOrUndecl), words("type")]) ++
         color_as_subject([unqual_type_ctor(TypeCtor), suffix(".")]) ++ [nl],
     Spec = spec($pred, severity_error, phase_tim_check,
         Enum ^ fe_context, Pieces),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 :- pred maybe_report_declared_but_undefined_type(maybe_insist_on_defn::in,
     type_ctor::in, item_type_defn_info_abstract::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 maybe_report_declared_but_undefined_type(InsistOnDefn, TypeCtor, AbsTypeDefn,
-        !Specs) :-
+        !ErrSpecs) :-
     TypeCtor = type_ctor(TypeCtorSymName, _TypeCtorArity),
     det_sym_name_get_module_name(TypeCtorSymName, TypeCtorModuleName),
     BuiltinTypeCtors = builtin_type_ctors_with_no_hlds_type_defn,
@@ -1319,7 +1324,7 @@ maybe_report_declared_but_undefined_type(InsistOnDefn, TypeCtor, AbsTypeDefn,
         % XXX should be phase_tim_check_invalid_type
         Spec = spec($pred, severity_error, phase_tim_check,
             AbsTypeDefn ^ td_context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     else
         true
     ).
@@ -1335,27 +1340,30 @@ maybe_report_declared_but_undefined_type(InsistOnDefn, TypeCtor, AbsTypeDefn,
     %
 :- pred check_any_type_ctor_defns_for_duplicates(type_ctor_defn_map::in,
     type_ctor::in, type_ctor_maybe_defn::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 check_any_type_ctor_defns_for_duplicates(TypeDefnMap, TypeCtor,
-        MaybeDefn, !Specs) :-
+        MaybeDefn, !ErrSpecs, !WarnSpecs) :-
     ( if map.search(TypeDefnMap, TypeCtor, AllDefns) then
         AllDefns = type_ctor_all_defns(AbsSolverDefns, SolverDefns,
             AbsNonSolverDefns, EqvDefns, DuDefns, SubDefns, ForeignDefns),
         at_most_one_type_decl_or_defn(dd_decl, "abstract solver type",
-            TypeCtor, AbsSolverDefns, AbsSolverMaybeDefn, !Specs),
+            TypeCtor, AbsSolverDefns, AbsSolverMaybeDefn,
+            !ErrSpecs, !WarnSpecs),
         at_most_one_type_decl_or_defn(dd_defn, "solver type",
-            TypeCtor, SolverDefns, SolverMaybeDefn, !Specs),
+            TypeCtor, SolverDefns, SolverMaybeDefn, !ErrSpecs, !WarnSpecs),
         at_most_one_type_decl_or_defn(dd_decl, "abstract type",
-            TypeCtor, AbsNonSolverDefns, AbsNonSolverMaybeDefn, !Specs),
+            TypeCtor, AbsNonSolverDefns, AbsNonSolverMaybeDefn,
+            !ErrSpecs, !WarnSpecs),
         at_most_one_type_decl_or_defn(dd_defn, "equivalence type",
-            TypeCtor, EqvDefns, EqvMaybeDefn, !Specs),
+            TypeCtor, EqvDefns, EqvMaybeDefn, !ErrSpecs, !WarnSpecs),
         at_most_one_type_decl_or_defn(dd_defn, "discriminated union type",
-            TypeCtor, DuDefns, DuMaybeDefn, !Specs),
+            TypeCtor, DuDefns, DuMaybeDefn, !ErrSpecs, !WarnSpecs),
         at_most_one_type_decl_or_defn(dd_defn, "subtype",
-            TypeCtor, SubDefns, SubMaybeDefn, !Specs),
+            TypeCtor, SubDefns, SubMaybeDefn, !ErrSpecs, !WarnSpecs),
         at_most_one_foreign_type_for_all_langs(TypeCtor,
-            ForeignDefns, ForeignMaybeDefn, !Specs),
+            ForeignDefns, ForeignMaybeDefn, !ErrSpecs),
         MaybeDefn = type_ctor_maybe_defn(AbsSolverMaybeDefn, SolverMaybeDefn,
             AbsNonSolverMaybeDefn, EqvMaybeDefn,
             DuMaybeDefn, SubMaybeDefn, ForeignMaybeDefn)
@@ -1371,10 +1379,11 @@ check_any_type_ctor_defns_for_duplicates(TypeDefnMap, TypeCtor,
 :- pred at_most_one_type_decl_or_defn(decl_or_defn::in, string::in,
     type_ctor::in, list(item_type_defn_info_general(T))::in,
     maybe(item_type_defn_info_general(T))::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 at_most_one_type_decl_or_defn(DeclOrDefn, Kind, TypeCtor,
-        TypeDefns, MaybeTypeDefn, !Specs) :-
+        TypeDefns, MaybeTypeDefn, !ErrSpecs, !WarnSpecs) :-
     (
         TypeDefns = [],
         MaybeTypeDefn = no
@@ -1390,37 +1399,37 @@ at_most_one_type_decl_or_defn(DeclOrDefn, Kind, TypeCtor,
         list.sort(CompareTypeDefnsByContext, TypeDefns, SortedTypeDefns),
         list.det_head_tail(SortedTypeDefns, HeadTypeDefn, TailTypeDefns),
         MaybeTypeDefn = yes(HeadTypeDefn),
-        list.foldl(
+        list.foldl2(
             report_duplicate_type_decl_or_defn(DeclOrDefn, Kind, TypeCtor,
                 HeadTypeDefn),
-            TailTypeDefns, !Specs)
+            TailTypeDefns, !ErrSpecs, !WarnSpecs)
     ).
 
 :- pred at_most_one_foreign_type_for_all_langs(type_ctor::in,
     c_j_cs_defns::in, c_j_cs_maybe_defn::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 at_most_one_foreign_type_for_all_langs(TypeCtor, DefnsCJCs, MaybeDefnCJCs,
-        !Specs) :-
+        !ErrSpecs) :-
     DefnsCJCs = c_java_csharp(DefnsC, DefnsJava, DefnsCsharp),
     at_most_one_foreign_type_for_lang(TypeCtor, lang_c,
-        DefnsC, MaybeDefnC, !Specs),
+        DefnsC, MaybeDefnC, !ErrSpecs),
     at_most_one_foreign_type_for_lang(TypeCtor, lang_java,
-        DefnsJava, MaybeDefnJava, !Specs),
+        DefnsJava, MaybeDefnJava, !ErrSpecs),
     at_most_one_foreign_type_for_lang(TypeCtor, lang_csharp,
-        DefnsCsharp, MaybeDefnCsharp, !Specs),
+        DefnsCsharp, MaybeDefnCsharp, !ErrSpecs),
     MaybeDefnCJCs = c_java_csharp(MaybeDefnC, MaybeDefnJava, MaybeDefnCsharp).
 
 :- pred check_any_type_ctor_enums_for_duplicates(
     type_ctor_foreign_enum_map::in, type_ctor::in,
     c_j_cs_maybe_enum::out, c_j_cs_enums::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_any_type_ctor_enums_for_duplicates(ForeignEnumMap, TypeCtor,
-        MaybeEnumCJCs, LeftOverEnumCJCse, !Specs) :-
+        MaybeEnumCJCs, LeftOverEnumCJCse, !ErrSpecs) :-
     ( if map.search(ForeignEnumMap, TypeCtor, AllEnums) then
         at_most_one_foreign_enum_for_all_langs(TypeCtor,
-            AllEnums, MaybeEnumCJCs, LeftOverEnumCJCse, !Specs)
+            AllEnums, MaybeEnumCJCs, LeftOverEnumCJCse, !ErrSpecs)
     else
         MaybeEnumCJCs = c_java_csharp(no, no, no),
         LeftOverEnumCJCse = c_java_csharp([], [], [])
@@ -1428,17 +1437,17 @@ check_any_type_ctor_enums_for_duplicates(ForeignEnumMap, TypeCtor,
 
 :- pred at_most_one_foreign_enum_for_all_langs(type_ctor::in,
     c_j_cs_enums::in, c_j_cs_maybe_enum::out, c_j_cs_enums::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 at_most_one_foreign_enum_for_all_langs(TypeCtor, AllEnumsCJCs,
-        MaybeEnumCJCs, LeftOverEnumsCJCs, !Specs) :-
+        MaybeEnumCJCs, LeftOverEnumsCJCs, !ErrSpecs) :-
     AllEnumsCJCs = c_java_csharp(EnumsC, EnumsJava, EnumsCsharp),
     at_most_one_foreign_enum_for_lang(TypeCtor, lang_c,
-        EnumsC, MaybeEnumC, LeftOverEnumsC, !Specs),
+        EnumsC, MaybeEnumC, LeftOverEnumsC, !ErrSpecs),
     at_most_one_foreign_enum_for_lang(TypeCtor, lang_java,
-        EnumsJava, MaybeEnumJava, LeftOverEnumsJava, !Specs),
+        EnumsJava, MaybeEnumJava, LeftOverEnumsJava, !ErrSpecs),
     at_most_one_foreign_enum_for_lang(TypeCtor, lang_csharp,
-        EnumsCsharp, MaybeEnumCsharp, LeftOverEnumsCsharp, !Specs),
+        EnumsCsharp, MaybeEnumCsharp, LeftOverEnumsCsharp, !ErrSpecs),
     MaybeEnumCJCs = c_java_csharp(MaybeEnumC, MaybeEnumJava, MaybeEnumCsharp),
     LeftOverEnumsCJCs = c_java_csharp(LeftOverEnumsC,
         LeftOverEnumsJava, LeftOverEnumsCsharp).
@@ -1446,20 +1455,19 @@ at_most_one_foreign_enum_for_all_langs(TypeCtor, AllEnumsCJCs,
 :- pred report_duplicate_type_decl_or_defn(decl_or_defn::in, string::in,
     type_ctor::in,
     item_type_defn_info_general(T1)::in, item_type_defn_info_general(T2)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 report_duplicate_type_decl_or_defn(DeclOrDefn, Kind, TypeCtor,
-        OrigTypeDefn, TypeDefn, !Specs) :-
+        OrigTypeDefn, TypeDefn, !ErrSpecs, !WarnSpecs) :-
     (
         DeclOrDefn = dd_decl,
         DeclOrDefnWord = "declaration",
-        SeverityWord = "Warning",
-        Severity = severity_warning(warn_redundant_code)
+        SeverityWord = "Warning"
     ;
         DeclOrDefn = dd_defn,
         DeclOrDefnWord = "definition",
-        SeverityWord = "Error",
-        Severity = severity_error
+        SeverityWord = "Error"
     ),
     MainPieces = [words(SeverityWord), suffix(":")] ++
         color_as_incorrect([words("duplicate"), words(Kind),
@@ -1468,18 +1476,29 @@ report_duplicate_type_decl_or_defn(DeclOrDefn, Kind, TypeCtor,
         color_as_subject([unqual_type_ctor(TypeCtor), suffix(".")]) ++ [nl],
     LeastPieces = [words("The original"), words(DeclOrDefnWord),
         words("is here."), nl],
-    Spec = diag_spec($pred, Severity, phase_tim_check,
-        [msg(TypeDefn ^ td_context, MainPieces),
-        msg(OrigTypeDefn ^ td_context, LeastPieces)]),
-    !:Specs = [Spec | !.Specs].
+    (
+        DeclOrDefn = dd_decl,
+        Severity = severity_warning(warn_redundant_code),
+        Spec = gen_spec($pred, Severity, phase_tim_check,
+            [msg(TypeDefn ^ td_context, MainPieces),
+            msg(OrigTypeDefn ^ td_context, LeastPieces)]),
+        !:WarnSpecs = [Spec | !.WarnSpecs]
+    ;
+        DeclOrDefn = dd_defn,
+        Severity = severity_error,
+        Spec = gen_spec($pred, Severity, phase_tim_check,
+            [msg(TypeDefn ^ td_context, MainPieces),
+            msg(OrigTypeDefn ^ td_context, LeastPieces)]),
+        !:ErrSpecs = [Spec | !.ErrSpecs]
+    ).
 
 :- pred at_most_one_foreign_type_for_lang(type_ctor::in, foreign_language::in,
     list(item_type_defn_info_foreign)::in,
     maybe(item_type_defn_info_foreign)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 at_most_one_foreign_type_for_lang(TypeCtor, Lang, TypeDefns,
-        MaybeTypeDefn, !Specs) :-
+        MaybeTypeDefn, !ErrSpecs) :-
     (
         TypeDefns = [],
         MaybeTypeDefn = no
@@ -1495,7 +1514,7 @@ at_most_one_foreign_type_for_lang(TypeCtor, Lang, TypeDefns,
             set.foldl(
                 report_duplicate_foreign_defn("type", TypeCtor, Lang,
                     LeastContext),
-                OtherContexts, !Specs)
+                OtherContexts, !ErrSpecs)
         else
             unexpected($pred, "nonempty set doesn't have least element")
         )
@@ -1504,10 +1523,10 @@ at_most_one_foreign_type_for_lang(TypeCtor, Lang, TypeDefns,
 :- pred at_most_one_foreign_enum_for_lang(type_ctor::in, foreign_language::in,
     list(item_foreign_enum_info)::in,
     maybe(item_foreign_enum_info)::out, list(item_foreign_enum_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 at_most_one_foreign_enum_for_lang(TypeCtor, Lang, ForeignEnums,
-        MaybeForeignEnum, LeftOverForeignEnums, !Specs) :-
+        MaybeForeignEnum, LeftOverForeignEnums, !ErrSpecs) :-
     list.sort(compare_foreign_enum_infos_by_context,
         ForeignEnums, SortedForeignEnums),
     (
@@ -1529,7 +1548,7 @@ at_most_one_foreign_enum_for_lang(TypeCtor, Lang, ForeignEnums,
         list.foldl(
             report_duplicate_foreign_defn("enum", TypeCtor, Lang,
                 LeastContext),
-            LeftOverContexts, !Specs)
+            LeftOverContexts, !ErrSpecs)
     ).
 
 :- pred compare_foreign_enum_infos_by_context(
@@ -1558,20 +1577,20 @@ get_type_defn_info_context(TypeDefn) = TypeDefn ^ td_context.
 
 :- pred report_duplicate_foreign_defn(string::in,
     type_ctor::in, foreign_language::in, prog_context::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_duplicate_foreign_defn(TypeOrEnum, TypeCtor, Lang,
-        LeastContext, Context, !Specs) :-
+        LeastContext, Context, !ErrSpecs) :-
     MainPieces = [words("Error:")] ++
         color_as_incorrect([words("duplicate foreign"), fixed(TypeOrEnum),
             words("definition in"), fixed(foreign_language_string(Lang))]) ++
         [words("for")] ++
         color_as_subject([unqual_type_ctor(TypeCtor), suffix(".")]) ++ [nl],
     LeastPieces = [words("The original definition is here."), nl],
-    Spec = diag_spec($pred, severity_error, phase_tim_check,
+    Spec = gen_spec($pred, severity_error, phase_tim_check,
         [msg(Context, MainPieces),
         msg(LeastContext, LeastPieces)]),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 :- func get_maybe_type_defns(list(maybe(item_type_defn_info_general(T))))
     = list(item_type_defn_info_general(T)).
@@ -1697,9 +1716,9 @@ add_data_ctor_arg_to_field_name_map(TypeCtor, CtorName, CtorArg,
 
 :- pred report_any_duplicate_field_names(field_name_of_type_ctor::in,
     one_or_more(field_name_locn)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-report_any_duplicate_field_names(FieldNameTypeCtor, OoMFNLocns, !Specs) :-
+report_any_duplicate_field_names(FieldNameTypeCtor, OoMFNLocns, !ErrSpecs) :-
     FNLocns = one_or_more_to_list(OoMFNLocns),
     list.sort(FNLocns, SortedFNLocns),
     (
@@ -1714,14 +1733,15 @@ report_any_duplicate_field_names(FieldNameTypeCtor, OoMFNLocns, !Specs) :-
         % The case we are looking for; FieldName is defined *more* than once
         % in the same type.
         list.foldl(report_duplicate_field_name(FieldNameTypeCtor, HeadFNLocn),
-            TailFNLocns, !Specs)
+            TailFNLocns, !ErrSpecs)
     ).
 
 :- pred report_duplicate_field_name(field_name_of_type_ctor::in,
     field_name_locn::in, field_name_locn::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-report_duplicate_field_name(FieldNameTypeCtor, FirstFNLocn, FNLocn, !Specs) :-
+report_duplicate_field_name(FieldNameTypeCtor, FirstFNLocn, FNLocn,
+        !ErrSpecs) :-
     FieldNameTypeCtor = field_name_of_type_ctor(FieldName, TypeCtor),
     FirstFNLocn = field_name_locn(FirstContext, FirstCtorName),
     FNLocn = field_name_locn(Context, CtorName),
@@ -1741,16 +1761,16 @@ report_duplicate_field_name(FieldNameTypeCtor, FirstFNLocn, FNLocn, !Specs) :-
         unqual_type_ctor(TypeCtor), suffix("."), nl],
     FirstOccurrencePieces = [words("The first occurrence of this field name"),
         words("is here."), nl],
-    Spec = diag_spec($pred, severity_error, phase_tim_check,
+    Spec = gen_spec($pred, severity_error, phase_tim_check,
         [msg(Context, MainPieces),
         msg(FirstContext, FirstOccurrencePieces)]),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
 
 create_inst_ctor_checked_map(InsistOnDefn, IntInstDefnMap, ImpInstDefnMap,
-        CheckedMap, !Specs) :-
+        CheckedMap, !ErrSpecs, !WarnSpecs) :-
     map.keys_as_set(IntInstDefnMap, IntDefnInstCtors),
     map.keys_as_set(ImpInstDefnMap, ImpDefnInstCtors),
     % This union operation depends on the type_ctors in all four maps
@@ -1758,21 +1778,22 @@ create_inst_ctor_checked_map(InsistOnDefn, IntInstDefnMap, ImpInstDefnMap,
     % to be all fully qualified or all fully unqualified; we chose the former.
     InstCtors =
         set.to_sorted_list(set.union(IntDefnInstCtors, ImpDefnInstCtors)),
-    list.foldl2(
+    list.foldl3(
         check_inst_ctor_defns(InsistOnDefn, IntInstDefnMap, ImpInstDefnMap),
-        InstCtors, map.init, CheckedMap, !Specs).
+        InstCtors, map.init, CheckedMap, !ErrSpecs, !WarnSpecs).
 
 :- pred check_inst_ctor_defns(maybe_insist_on_defn::in,
     inst_ctor_defn_map::in, inst_ctor_defn_map::in, inst_ctor::in,
     inst_ctor_checked_map::in, inst_ctor_checked_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 check_inst_ctor_defns(InsistOnDefn, IntInstDefnMap, ImpInstDefnMap, InstCtor,
-        !CheckedMap, !Specs) :-
+        !CheckedMap, !ErrSpecs, !WarnSpecs) :-
     check_any_inst_ctor_defns_for_duplicates(IntInstDefnMap, InstCtor,
-        IntMaybeAbstractDefn, IntMaybeEqvDefn, !Specs),
+        IntMaybeAbstractDefn, IntMaybeEqvDefn, !ErrSpecs),
     check_any_inst_ctor_defns_for_duplicates(ImpInstDefnMap, InstCtor,
-        ImpMaybeAbstractDefn, ImpMaybeEqvDefn, !Specs),
+        ImpMaybeAbstractDefn, ImpMaybeEqvDefn, !ErrSpecs),
     ( if
         % Does InstCtor have a non-abstract definition ...
         ( if
@@ -1810,7 +1831,7 @@ check_inst_ctor_defns(InsistOnDefn, IntInstDefnMap, ImpInstDefnMap, InstCtor,
         % which we publicize, and a non-abstract definition in another
         % interface section, which we don't publicize.
         report_any_redundant_abstract_inst_in_imp(InstCtor,
-            "definition", EqvWhere, ImpMaybeAbstractDefn, !Specs),
+            "definition", EqvWhere, ImpMaybeAbstractDefn, !WarnSpecs),
         StdDefn = std_inst_defn(Status, wrap_eqv_inst_defn(EqvDefn)),
         CheckedDefn = checked_defn_inst(StdDefn, SrcDefns),
         map.det_insert(InstCtor, CheckedDefn, !CheckedMap)
@@ -1821,7 +1842,7 @@ check_inst_ctor_defns(InsistOnDefn, IntInstDefnMap, ImpInstDefnMap, InstCtor,
         (
             IntMaybeAbstractDefn = yes(IntAbstractDefn),
             report_any_redundant_abstract_inst_in_imp(InstCtor,
-                "declaration", "interface", ImpMaybeAbstractDefn, !Specs),
+                "declaration", "interface", ImpMaybeAbstractDefn, !WarnSpecs),
             (
                 InsistOnDefn = do_not_insist_on_defn,
                 Status = std_inst_abstract_exported,
@@ -1834,7 +1855,7 @@ check_inst_ctor_defns(InsistOnDefn, IntInstDefnMap, ImpInstDefnMap, InstCtor,
             ;
                 InsistOnDefn = do_insist_on_defn,
                 report_declared_but_undefined_inst(InstCtor, IntAbstractDefn,
-                    !Specs)
+                    !ErrSpecs)
             )
         ;
             IntMaybeAbstractDefn = no,
@@ -1852,7 +1873,7 @@ check_inst_ctor_defns(InsistOnDefn, IntInstDefnMap, ImpInstDefnMap, InstCtor,
                 ;
                     InsistOnDefn = do_insist_on_defn,
                     report_declared_but_undefined_inst(InstCtor,
-                        ImpAbstractDefn, !Specs)
+                        ImpAbstractDefn, !ErrSpecs)
                 )
             ;
                 ImpMaybeAbstractDefn = no,
@@ -1864,16 +1885,16 @@ check_inst_ctor_defns(InsistOnDefn, IntInstDefnMap, ImpInstDefnMap, InstCtor,
 :- pred check_any_inst_ctor_defns_for_duplicates(inst_ctor_defn_map::in,
     inst_ctor::in, maybe(item_inst_defn_info_abstract)::out,
     maybe(item_inst_defn_info_eqv)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_any_inst_ctor_defns_for_duplicates(InstDefnMap, InstCtor,
-        AbstractMaybeDefn, EqvMaybeDefn, !Specs) :-
+        AbstractMaybeDefn, EqvMaybeDefn, !ErrSpecs) :-
     ( if map.search(InstDefnMap, InstCtor, AllDefns) then
         AllDefns = inst_ctor_all_defns(AbstractDefns, EqvDefns),
         at_most_one_inst_defn("abstract inst", InstCtor,
-            AbstractDefns, AbstractMaybeDefn, !Specs),
+            AbstractDefns, AbstractMaybeDefn, !ErrSpecs),
         at_most_one_inst_defn("inst", InstCtor,
-            EqvDefns, EqvMaybeDefn, !Specs)
+            EqvDefns, EqvMaybeDefn, !ErrSpecs)
     else
         AbstractMaybeDefn = no,
         EqvMaybeDefn = no
@@ -1882,9 +1903,9 @@ check_any_inst_ctor_defns_for_duplicates(InstDefnMap, InstCtor,
 :- pred at_most_one_inst_defn(string::in, inst_ctor::in,
     list(item_inst_defn_info_general(T))::in,
     maybe(item_inst_defn_info_general(T))::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-at_most_one_inst_defn(Kind, InstCtor, InstDefns, MaybeInstDefn, !Specs) :-
+at_most_one_inst_defn(Kind, InstCtor, InstDefns, MaybeInstDefn, !ErrSpecs) :-
     (
         InstDefns = [],
         MaybeInstDefn = no
@@ -1902,32 +1923,33 @@ at_most_one_inst_defn(Kind, InstCtor, InstDefns, MaybeInstDefn, !Specs) :-
         MaybeInstDefn = yes(HeadInstDefn),
         list.foldl(
             report_duplicate_inst_defn(Kind, InstCtor, HeadInstDefn),
-            TailInstDefns, !Specs)
+            TailInstDefns, !ErrSpecs)
     ).
 
 :- pred report_duplicate_inst_defn(string::in, inst_ctor::in,
     item_inst_defn_info_general(T1)::in, item_inst_defn_info_general(T2)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-report_duplicate_inst_defn(Kind, InstCtor, OrigInstDefn, InstDefn, !Specs) :-
+report_duplicate_inst_defn(Kind, InstCtor, OrigInstDefn, InstDefn,
+        !ErrSpecs) :-
     MainPieces = [words("Error")] ++
         color_as_incorrect([words("duplicate"), words(Kind),
             words("definition")]) ++
         [words("for")] ++
         color_as_subject([unqual_inst_ctor(InstCtor), suffix(".")]) ++ [nl],
     LeastPieces = [words("The original definition is here."), nl],
-    Spec = diag_spec($pred, severity_error, phase_tim_check,
+    Spec = gen_spec($pred, severity_error, phase_tim_check,
         [msg(InstDefn ^ id_context, MainPieces),
         msg(OrigInstDefn ^ id_context, LeastPieces)]),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 :- pred report_any_redundant_abstract_inst_in_imp(inst_ctor::in,
     string::in, string::in,
     maybe(item_inst_defn_info_abstract)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 report_any_redundant_abstract_inst_in_imp(InstCtor, DeclOrDefn, Section,
-        MaybeImpAbstractDefn, !Specs) :-
+        MaybeImpAbstractDefn, !WarnSpecs) :-
     (
         MaybeImpAbstractDefn = no
     ;
@@ -1940,27 +1962,27 @@ report_any_redundant_abstract_inst_in_imp(InstCtor, DeclOrDefn, Section,
         Severity = severity_warning(warn_redundant_code),
         Spec = spec($pred, Severity, phase_tim_check,
             ImpAbstractDefn ^ id_context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:WarnSpecs = [Spec | !.WarnSpecs]
     ).
 
 :- pred report_declared_but_undefined_inst(inst_ctor::in,
     item_inst_defn_info_abstract::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-report_declared_but_undefined_inst(InstCtor, AbsInstDefn, !Specs) :-
+report_declared_but_undefined_inst(InstCtor, AbsInstDefn, !ErrSpecs) :-
     Pieces = [words("Error: the inst")] ++
         color_as_subject([unqual_inst_ctor(InstCtor)]) ++
         [words("has this declaration, but")] ++
         color_as_incorrect([words("it has no definition.")]) ++ [nl],
     Spec = spec($pred, severity_error, phase_tim_check_invalid_inst_mode,
         AbsInstDefn ^ id_context, Pieces),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
 
 create_mode_ctor_checked_map(InsistOnDefn, IntModeDefnMap, ImpModeDefnMap,
-        CheckedMap, !Specs) :-
+        CheckedMap, !ErrSpecs, !WarnSpecs) :-
     map.keys_as_set(IntModeDefnMap, IntDefnModeCtors),
     map.keys_as_set(ImpModeDefnMap, ImpDefnModeCtors),
     % This union operation depends on the type_ctors in all four maps
@@ -1968,21 +1990,22 @@ create_mode_ctor_checked_map(InsistOnDefn, IntModeDefnMap, ImpModeDefnMap,
     % to be all fully qualified or all fully unqualified; we chose the former.
     ModeCtors =
         set.to_sorted_list(set.union(IntDefnModeCtors, ImpDefnModeCtors)),
-    list.foldl2(
+    list.foldl3(
         check_mode_ctor_defns(InsistOnDefn, IntModeDefnMap, ImpModeDefnMap),
-        ModeCtors, map.init, CheckedMap, !Specs).
+        ModeCtors, map.init, CheckedMap, !ErrSpecs, !WarnSpecs).
 
 :- pred check_mode_ctor_defns(maybe_insist_on_defn::in,
     mode_ctor_defn_map::in, mode_ctor_defn_map::in, mode_ctor::in,
     mode_ctor_checked_map::in, mode_ctor_checked_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 check_mode_ctor_defns(InsistOnDefn, IntModeDefnMap, ImpModeDefnMap, ModeCtor,
-        !CheckedMap, !Specs) :-
+        !CheckedMap, !ErrSpecs, !WarnSpecs) :-
     check_any_mode_ctor_defns_for_duplicates(IntModeDefnMap, ModeCtor,
-        IntMaybeAbstractDefn, IntMaybeEqvDefn, !Specs),
+        IntMaybeAbstractDefn, IntMaybeEqvDefn, !ErrSpecs),
     check_any_mode_ctor_defns_for_duplicates(ImpModeDefnMap, ModeCtor,
-        ImpMaybeAbstractDefn, ImpMaybeEqvDefn, !Specs),
+        ImpMaybeAbstractDefn, ImpMaybeEqvDefn, !ErrSpecs),
     ( if
         % Does ModeCtor have a non-abstract definition ...
         ( if
@@ -2020,7 +2043,7 @@ check_mode_ctor_defns(InsistOnDefn, IntModeDefnMap, ImpModeDefnMap, ModeCtor,
         % which we publicize, and a non-abstract definition in another
         % interface section, which we don't publicize.
         report_any_redundant_abstract_mode_in_imp(ModeCtor,
-            "definition", EqvWhere, ImpMaybeAbstractDefn, !Specs),
+            "definition", EqvWhere, ImpMaybeAbstractDefn, !WarnSpecs),
         StdDefn = std_mode_defn(Status, wrap_eqv_mode_defn(EqvDefn)),
         CheckedDefn = checked_defn_mode(StdDefn, SrcDefns),
         map.det_insert(ModeCtor, CheckedDefn, !CheckedMap)
@@ -2031,7 +2054,7 @@ check_mode_ctor_defns(InsistOnDefn, IntModeDefnMap, ImpModeDefnMap, ModeCtor,
         (
             IntMaybeAbstractDefn = yes(IntAbstractDefn),
             report_any_redundant_abstract_mode_in_imp(ModeCtor,
-                "declaration", "interface", ImpMaybeAbstractDefn, !Specs),
+                "declaration", "interface", ImpMaybeAbstractDefn, !WarnSpecs),
             (
                 InsistOnDefn = do_not_insist_on_defn,
                 Status = std_mode_abstract_exported,
@@ -2044,7 +2067,7 @@ check_mode_ctor_defns(InsistOnDefn, IntModeDefnMap, ImpModeDefnMap, ModeCtor,
             ;
                 InsistOnDefn = do_insist_on_defn,
                 report_declared_but_undefined_mode(ModeCtor, IntAbstractDefn,
-                    !Specs)
+                    !ErrSpecs)
             )
         ;
             IntMaybeAbstractDefn = no,
@@ -2062,7 +2085,7 @@ check_mode_ctor_defns(InsistOnDefn, IntModeDefnMap, ImpModeDefnMap, ModeCtor,
                 ;
                     InsistOnDefn = do_insist_on_defn,
                     report_declared_but_undefined_mode(ModeCtor,
-                        ImpAbstractDefn, !Specs)
+                        ImpAbstractDefn, !ErrSpecs)
                 )
             ;
                 ImpMaybeAbstractDefn = no,
@@ -2074,16 +2097,16 @@ check_mode_ctor_defns(InsistOnDefn, IntModeDefnMap, ImpModeDefnMap, ModeCtor,
 :- pred check_any_mode_ctor_defns_for_duplicates(mode_ctor_defn_map::in,
     mode_ctor::in, maybe(item_mode_defn_info_abstract)::out,
     maybe(item_mode_defn_info_eqv)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_any_mode_ctor_defns_for_duplicates(ModeDefnMap, ModeCtor,
-        AbstractMaybeDefn, EqvMaybeDefn, !Specs) :-
+        AbstractMaybeDefn, EqvMaybeDefn, !ErrSpecs) :-
     ( if map.search(ModeDefnMap, ModeCtor, AllDefns) then
         AllDefns = mode_ctor_all_defns(AbstractDefns, EqvDefns),
         at_most_one_mode_defn("abstract mode", ModeCtor,
-            AbstractDefns, AbstractMaybeDefn, !Specs),
+            AbstractDefns, AbstractMaybeDefn, !ErrSpecs),
         at_most_one_mode_defn("mode", ModeCtor,
-            EqvDefns, EqvMaybeDefn, !Specs)
+            EqvDefns, EqvMaybeDefn, !ErrSpecs)
     else
         AbstractMaybeDefn = no,
         EqvMaybeDefn = no
@@ -2092,9 +2115,9 @@ check_any_mode_ctor_defns_for_duplicates(ModeDefnMap, ModeCtor,
 :- pred at_most_one_mode_defn(string::in, mode_ctor::in,
     list(item_mode_defn_info_general(T))::in,
     maybe(item_mode_defn_info_general(T))::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-at_most_one_mode_defn(Kind, ModeCtor, ModeDefns, MaybeModeDefn, !Specs) :-
+at_most_one_mode_defn(Kind, ModeCtor, ModeDefns, MaybeModeDefn, !ErrSpecs) :-
     (
         ModeDefns = [],
         MaybeModeDefn = no
@@ -2112,32 +2135,33 @@ at_most_one_mode_defn(Kind, ModeCtor, ModeDefns, MaybeModeDefn, !Specs) :-
         MaybeModeDefn = yes(HeadModeDefn),
         list.foldl(
             report_duplicate_mode_defn(Kind, ModeCtor, HeadModeDefn),
-            TailModeDefns, !Specs)
+            TailModeDefns, !ErrSpecs)
     ).
 
 :- pred report_duplicate_mode_defn(string::in, mode_ctor::in,
     item_mode_defn_info_general(T1)::in, item_mode_defn_info_general(T2)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-report_duplicate_mode_defn(Kind, ModeCtor, OrigModeDefn, ModeDefn, !Specs) :-
+report_duplicate_mode_defn(Kind, ModeCtor, OrigModeDefn, ModeDefn,
+        !ErrSpecs) :-
     MainPieces = [words("Error:")] ++
         color_as_incorrect([words("duplicate"), words(Kind),
             words("definition")]) ++
         [words("for")] ++
         color_as_subject([unqual_mode_ctor(ModeCtor), suffix(".")]) ++ [nl],
     LeastPieces = [words("The original definition is here."), nl],
-    Spec = diag_spec($pred, severity_error, phase_tim_check,
+    Spec = gen_spec($pred, severity_error, phase_tim_check,
         [msg(ModeDefn ^ md_context, MainPieces),
         msg(OrigModeDefn ^ md_context, LeastPieces)]),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 :- pred report_any_redundant_abstract_mode_in_imp(mode_ctor::in,
     string::in, string::in,
     maybe(item_mode_defn_info_abstract)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 report_any_redundant_abstract_mode_in_imp(TypeCtor, DeclOrDefn, Section,
-        MaybeImpAbstractDefn, !Specs) :-
+        MaybeImpAbstractDefn, !WarnSpecs) :-
     (
         MaybeImpAbstractDefn = no
     ;
@@ -2150,21 +2174,21 @@ report_any_redundant_abstract_mode_in_imp(TypeCtor, DeclOrDefn, Section,
         Severity = severity_warning(warn_redundant_code),
         Spec = spec($pred, Severity, phase_tim_check,
             ImpAbstractDefn ^ md_context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:WarnSpecs = [Spec | !.WarnSpecs]
     ).
 
 :- pred report_declared_but_undefined_mode(mode_ctor::in,
     item_mode_defn_info_abstract::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-report_declared_but_undefined_mode(ModeCtor, AbsModeDefn, !Specs) :-
+report_declared_but_undefined_mode(ModeCtor, AbsModeDefn, !ErrSpecs) :-
     Pieces = [words("Error: the mode")] ++
         color_as_subject([unqual_mode_ctor(ModeCtor)]) ++
         [words("has this declaration, but")] ++
         color_as_incorrect([words("it has no definition.")]) ++ [nl],
     Spec = spec($pred, severity_error, phase_tim_check_invalid_inst_mode,
         AbsModeDefn ^ md_context, Pieces),
-    !:Specs = [Spec | !.Specs].
+    !:ErrSpecs = [Spec | !.ErrSpecs].
 
 %---------------------------------------------------------------------------%
 :- end_module parse_tree.check_type_inst_mode_defns.
diff --git a/compiler/check_typeclass.m b/compiler/check_typeclass.m
index 4aeb3578e..11a23c3e4 100644
--- a/compiler/check_typeclass.m
+++ b/compiler/check_typeclass.m
@@ -1250,7 +1250,9 @@ generate_instance_method_pred_and_procs(ClassId, ClassVars, ClassPredId,
 
     produce_instance_method_clauses(InstanceProcDefn, PredOrFunc, ArgTypes,
         Markers, Context, InstanceStatus, ClausesInfo,
-        TVarSet2, TVarSet, !ModuleInfo, !QualInfo, !Specs),
+        TVarSet2, TVarSet, !ModuleInfo, !QualInfo,
+        [], ErrSpecs, [], WarnSpecs),
+    !:Specs = coerce(ErrSpecs) ++ coerce(WarnSpecs) ++ !.Specs,
 
     % Fill in some information in the pred_info which is used by polymorphism
     % to make sure the type-infos and typeclass-infos are added in the correct
@@ -2530,7 +2532,7 @@ report_duplicate_method_defn(ClassId, InstanceDefn, MethodName,
     FirstMsg = msg(FirstContext, FirstPieces),
     LaterPieces = [words("Later definition appears here."), nl],
     LaterMsg = msg(LaterContext, LaterPieces),
-    Spec = diag_spec($pred, severity_error, phase_type_check,
+    Spec = gen_spec($pred, severity_error, phase_type_check,
         [HeaderMsg, FirstMsg, LaterMsg]),
     !:Specs = [Spec | !.Specs].
 
@@ -2642,7 +2644,7 @@ report_overlapping_instances(ClassId, ContextA, ContextB, !Specs) :-
     MsgA = msg(ContextA, PiecesA),
     PiecesB = [words("... and the other is here."), nl],
     MsgB = msg(ContextB, PiecesB),
-    Spec = diag_spec($pred, severity_error, phase_type_check, [MsgA, MsgB]),
+    Spec = gen_spec($pred, severity_error, phase_type_check, [MsgA, MsgB]),
     !:Specs = [Spec | !.Specs].
 
 :- pred report_any_duplicate_instance_defns_in_category(class_id::in,
@@ -2680,7 +2682,7 @@ report_duplicate_instance_defn(ClassId, Severity, SeverityWord, Category,
     LaterMsg = msg(LaterContext, LaterPieces),
     FirstPieces = [words("Previous instance declaration was here."), nl],
     FirstMsg = msg(FirstContext, FirstPieces),
-    Spec = diag_spec($pred, Severity, phase_type_check, [LaterMsg, FirstMsg]),
+    Spec = gen_spec($pred, Severity, phase_type_check, [LaterMsg, FirstMsg]),
     !:Specs = [Spec | !.Specs].
 
 :- pred report_abstract_concrete_constraints_mismatch(class_id::in,
@@ -2701,7 +2703,7 @@ report_abstract_concrete_constraints_mismatch(ClassId,
     ConcretePieces = [words("The corresponding"),
         words("concrete instance declaration is here."), nl],
     ConcreteMsg = msg(ConcreteContext, ConcretePieces),
-    Spec = diag_spec($pred, severity_error, phase_type_check,
+    Spec = gen_spec($pred, severity_error, phase_type_check,
         [AbstractMsg, ConcreteMsg]),
     !:Specs = [Spec | !.Specs].
 
@@ -2746,7 +2748,7 @@ report_local_vs_nonlocal_clash(ClassId, LocalInstance, NonLocalInstance,
     NonLocalPieces = [words("The other instance declaration is here."), nl],
     NonLocalContext = NonLocalInstance ^ instdefn_context,
     NonLocalMsg = msg(NonLocalContext, NonLocalPieces),
-    Spec = diag_spec($pred, severity_error, phase_type_check,
+    Spec = gen_spec($pred, severity_error, phase_type_check,
         [LocalMsg, NonLocalMsg]),
     !:Specs = [Spec | !.Specs].
 
@@ -2814,7 +2816,7 @@ report_consistency_error(ClassId, ClassDefn, InstanceA, InstanceB, FunDep,
     MsgA = msg(ContextA, PiecesA),
     MsgB = gen_msg(yes(ContextB), always_treat_as_first, 0u,
         [always(PiecesB)]),
-    Spec = diag_spec($pred, severity_error, phase_type_check, [MsgA, MsgB]),
+    Spec = gen_spec($pred, severity_error, phase_type_check, [MsgA, MsgB]),
     !:Specs = [Spec | !.Specs].
 
 %---------------------------------------------------------------------------%
@@ -2877,7 +2879,7 @@ report_unbound_tvars_in_pred_context(PredInfo, Vars, !Specs) :-
     Msg = simple_msg(Context,
         [always(Pieces),
         verbose_only(verbose_once, unbound_tvars_explanation_pieces)]),
-    Spec = diag_spec($pred, severity_error, phase_type_check, [Msg]),
+    Spec = gen_spec($pred, severity_error, phase_type_check, [Msg]),
     !:Specs = [Spec | !.Specs].
 
 :- pred report_bad_class_ids_in_pred_decl(module_info::in, pred_info::in,
@@ -2971,7 +2973,7 @@ report_unbound_tvars_in_ctor_context(Vars, TypeCtor, TypeDefn, !Specs) :-
     Msg = simple_msg(Context,
         [always(Pieces),
         verbose_only(verbose_once, unbound_tvars_explanation_pieces)]),
-    Spec = diag_spec($pred, severity_error, phase_type_check, [Msg]),
+    Spec = gen_spec($pred, severity_error, phase_type_check, [Msg]),
     !:Specs = [Spec | !.Specs].
 
 :- pred report_bad_class_ids_in_data_ctor(type_ctor::in,
diff --git a/compiler/clause_to_proc.m b/compiler/clause_to_proc.m
index c2523c5ef..f8892a5af 100644
--- a/compiler/clause_to_proc.m
+++ b/compiler/clause_to_proc.m
@@ -162,12 +162,12 @@ copy_clauses_to_proc_in_proc_info(PredInfo, ProcId, !ProcInfo) :-
     get_clause_list_for_replacement(ClausesRep0, Clauses),
     select_matching_clauses(PredInfo, ProcId, Clauses, MatchingClauses),
     get_clause_disjuncts_and_warnings(MatchingClauses,
-        cord.init, ClausesDisjunctsCord, [], StateVarWarnings),
+        cord.init, ClausesDisjunctsCord, [], StateVarWarnSpecs),
     (
-        StateVarWarnings = [_ | _],
-        proc_info_set_statevar_warnings(StateVarWarnings, !ProcInfo)
+        StateVarWarnSpecs = [_ | _],
+        proc_info_set_statevar_warnings(StateVarWarnSpecs, !ProcInfo)
     ;
-        StateVarWarnings = []
+        StateVarWarnSpecs = []
         % Do not allocate a new proc_info if we do not need to.
     ),
     ClausesDisjuncts = cord.list(ClausesDisjunctsCord),
@@ -336,11 +336,11 @@ select_matching_nonunify_clauses_acc(ProcId, [Clause | Clauses],
 
 :- pred get_clause_disjuncts_and_warnings(list(clause)::in,
     cord(hlds_goal)::in, cord(hlds_goal)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-get_clause_disjuncts_and_warnings([], !DisjunctCord, !Warnings).
+get_clause_disjuncts_and_warnings([], !DisjunctCord, !WarnSpecs).
 get_clause_disjuncts_and_warnings([HeadClause | TailClauses],
-        !Disjuncts, !Warnings) :-
+        !Disjuncts, !WarnSpecs) :-
     HeadGoal0 = HeadClause ^ clause_body,
     ( if HeadGoal0 = hlds_goal(disj(HeadDisjuncts0), _) then
         cord.snoc_list(HeadDisjuncts0, !Disjuncts)
@@ -348,11 +348,11 @@ get_clause_disjuncts_and_warnings([HeadClause | TailClauses],
         goal_add_feature(feature_was_clause, HeadGoal0, HeadGoal),
         cord.snoc(HeadGoal, !Disjuncts)
     ),
-    HeadWarnings = HeadClause ^ clause_statevar_warnings,
+    HeadWarnSpecs = HeadClause ^ clause_statevar_warnings,
     % The order in which we return the warnings does not matter;
     % they will be printed in context order.
-    !:Warnings = HeadWarnings ++ !.Warnings,
-    get_clause_disjuncts_and_warnings(TailClauses, !Disjuncts, !Warnings).
+    !:WarnSpecs = HeadWarnSpecs ++ !.WarnSpecs,
+    get_clause_disjuncts_and_warnings(TailClauses, !Disjuncts, !WarnSpecs).
 
 %-----------------------------------------------------------------------------%
 
diff --git a/compiler/color_schemes.m b/compiler/color_schemes.m
index 87df5fabd..f75dcf09b 100644
--- a/compiler/color_schemes.m
+++ b/compiler/color_schemes.m
@@ -47,7 +47,7 @@
     % explained by the comment below on convert_color_spec_options.
     %
 :- pred record_color_scheme_in_options(list(format_piece)::in,
-    string::in, list(diag_spec)::out, option_table::in, option_table::out,
+    string::in, list(err_spec)::out, option_table::in, option_table::out,
     io::di, io::uo) is det.
 
 %---------------------------------------------------------------------------%
@@ -240,7 +240,7 @@ record_color_scheme_in_options(Source, SchemeName, Specs, !OptionTable, !IO) :-
                 Msg = no_ctxt_msg(Pieces),
                 Severity =
                     severity_informational(inform_incomplete_color_scheme),
-                InformSpec = diag_spec($pred, Severity, phase_options, [Msg]),
+                InformSpec = gen_spec($pred, Severity, phase_options, [Msg]),
                 record_bad_color_scheme(InformSpec, !IO),
                 Specs = []
             )
@@ -266,7 +266,7 @@ record_color_scheme_in_options(Source, SchemeName, Specs, !OptionTable, !IO) :-
 
 :- pred parse_color_specifications(list(format_piece)::in, list(string)::in,
     maybe_color_strings::in, maybe_color_strings::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 parse_color_specifications(_, [], !MaybeColorStrs, !Specs).
 parse_color_specifications(Source, [Setting | Settings],
@@ -480,7 +480,7 @@ standard_color_name("bright-white",     color_8bit(15u8)).
 standard_color_name("bright white",     color_8bit(15u8)).
 
 :- func report_why_not_color(list(format_piece), string, why_not_color)
-    = diag_spec.
+    = err_spec.
 
 report_why_not_color(Source, Value, WhyNot) = Spec :-
     (
diff --git a/compiler/common.m b/compiler/common.m
index 93d9da374..7724f3857 100644
--- a/compiler/common.m
+++ b/compiler/common.m
@@ -1199,7 +1199,7 @@ common_do_optimise_call(SeenCall, InputArgs, OutputArgs, Modes, GoalInfo,
                 PrevMsg = gen_msg(yes(PrevContext), always_treat_as_first,
                     0u, [always(PrevPieces)]),
                 Severity = severity_warning(warn_duplicate_calls),
-                Spec = diag_spec($pred, Severity,
+                Spec = gen_spec($pred, Severity,
                     phase_simplify(report_in_any_mode), [Msg, PrevMsg]),
                 simplify_info_add_message(Spec, !Info)
             else
diff --git a/compiler/comp_unit_interface.m b/compiler/comp_unit_interface.m
index f42b6a637..173d271fd 100644
--- a/compiler/comp_unit_interface.m
+++ b/compiler/comp_unit_interface.m
@@ -233,7 +233,7 @@ create_parse_tree_int3(ParseTreeModuleSrc, ParseTreeInt3) :-
         _IntFIMSpecMap, _ImpFIMSpecMap, _IntSelfFIMLangs, _ImpSelfFIMLangs,
 
         TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
-        _TypeSpecs, _InstModeSpecs,
+        _TypeErrSpecs, _TypeWarnSpecs, _InstModeErrSpecs, _InstModeWarnSpecs,
 
         OrigIntTypeClasses, OrigIntInstances, _IntPredDecls, _IntModeDecls,
         _IntDeclPragmas, _IntDeclMarkers, _IntPromises, _IntBadClauses,
@@ -577,7 +577,8 @@ generate_parse_tree_int0(ProgressStream, Globals, AddToHptm, BurdenedModule,
 
     % Check whether we succeeded.
     GetErrors = Baggage ^ mb_errors,
-    GetSpecs = get_read_module_specs(GetErrors),
+    get_read_module_specs(GetErrors, GetErrSpecs, GetWarnSpecs),
+    GetSpecs = coerce(GetErrSpecs) ++ coerce(GetWarnSpecs),
     GetSpecsEffectivelyErrors =
         contains_errors_or_warnings_treated_as_errors(Globals, GetSpecs),
     ( if
@@ -586,7 +587,10 @@ generate_parse_tree_int0(ProgressStream, Globals, AddToHptm, BurdenedModule,
     then
         % Module-qualify the aug_make_int_unit.
         module_qualify_aug_make_int_unit(Globals,
-            AugMakeIntUnit1, AugMakeIntUnit, [], QualSpecs),
+            AugMakeIntUnit1, AugMakeIntUnit,
+            [], QualErrSpecs, [], QualWarnSpecs),
+        QualSpecs : list(diag_spec) =
+            coerce(QualErrSpecs) ++ coerce(QualWarnSpecs),
         filter_interface_generation_specs(Globals,
             GetSpecs ++ QualSpecs, EffectiveGetQualSpecs),
         (
@@ -616,11 +620,11 @@ generate_parse_tree_int0(ProgressStream, Globals, AddToHptm, BurdenedModule,
             GenerateResult = gpti0_error(ModuleName, [], Specs)
         )
     else
+        maybe_add_delayed_messages(AugMakeIntUnit1, GetSpecs, Specs),
         % The negative indent is to let the rest of the diag_spec
         % start at the left margin.
         PrefixPieces = [words("Error reading .int3 and/or .int0 files."),
             nl_indent_delta(-1)],
-        maybe_add_delayed_messages(AugMakeIntUnit1, GetSpecs, Specs),
         GenerateResult = gpti0_error(ModuleName, PrefixPieces, Specs)
     ).
 
@@ -644,7 +648,7 @@ generate_pre_grab_pre_qual_interface_for_int0(ParseTreeModuleSrc,
         IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,
 
         TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
-        _TypeSpecs, _InstModeSpecs,
+        _TypeErrSpecs, _TypeWarnSpecs, _InstModeErrSpecs, _InstModeWarnSpecs,
 
         IntTypeClasses, IntInstances0, IntPredDecls, IntModeDecls,
         IntDeclPragmas, IntDeclMarkers, IntPromises, _IntBadClausePreds,
@@ -675,7 +679,7 @@ generate_pre_grab_pre_qual_interface_for_int0(ParseTreeModuleSrc,
         IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,
 
         TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
-        [], [],
+        [], [], [], [],
 
         IntTypeClasses, coerce(IntAbsInstances0), IntPredDecls, IntModeDecls,
         IntDeclPragmas, IntDeclMarkers, IntPromises, set.init,
@@ -711,7 +715,7 @@ create_parse_tree_int0(AugMakeIntUnit, ParseTreeInt0) :-
         IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,
 
         TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
-        _TypeSpecs, _InstModeSpecs,
+        _TypeErrSpecs, _TypeWarnSpecs, _InstModeErrSpecs, _InstModeWarnSpecs,
 
         IntTypeClasses, IntInstances, IntPredDecls, IntModeDecls,
         IntDeclPragmas, IntDeclMarkers, IntPromises, _IntBadClausePreds,
@@ -769,7 +773,8 @@ generate_parse_tree_int12(ProgressStream, Globals, AddToHptm,
 
     % Check whether we succeeded.
     GetErrors = Baggage ^ mb_errors,
-    GetSpecs = get_read_module_specs(GetErrors),
+    get_read_module_specs(GetErrors, GetErrSpecs, GetWarnSpecs),
+    GetSpecs = coerce(GetErrSpecs) ++ coerce(GetWarnSpecs),
     GetSpecsEffectivelyErrors =
         contains_errors_or_warnings_treated_as_errors(Globals, GetSpecs),
     ( if
@@ -790,7 +795,10 @@ generate_parse_tree_int12(ProgressStream, Globals, AddToHptm,
         % error messages or foregoing the generation of some non-avalanche
         % error messages. This position of this call makes the latter choice.
         module_qualify_aug_make_int_unit(Globals,
-            AugMakeIntUnit1, AugMakeIntUnit, [], QualSpecs),
+            AugMakeIntUnit1, AugMakeIntUnit,
+            [], QualErrSpecs, [], QualWarnSpecs),
+        QualSpecs : list(diag_spec) =
+            coerce(QualErrSpecs) ++ coerce(QualWarnSpecs),
         filter_interface_generation_specs(Globals,
             GetSpecs ++ QualSpecs, EffectiveGetQualSpecs),
         (
@@ -883,7 +891,7 @@ generate_pre_grab_pre_qual_interface_for_int1_int2(ParseTreeModuleSrc,
         IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,
 
         TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
-        TypeSpecs, InstModeSpecs,
+        TypeErrSpecs, TypeWarnSpecs, InstModeErrSpecs, InstModeWarnSpecs,
 
         IntTypeClasses, IntInstances, IntPredDecls, IntModeDecls,
         IntDeclPragmas, IntDeclMarkers, IntPromises, IntBadClausePreds,
@@ -907,7 +915,7 @@ generate_pre_grab_pre_qual_interface_for_int1_int2(ParseTreeModuleSrc,
         IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,
 
         IntTypeCtorCheckedMap, IntInstCtorCheckedMap, IntModeCtorCheckedMap,
-        TypeSpecs, InstModeSpecs,
+        TypeErrSpecs, TypeWarnSpecs, InstModeErrSpecs, InstModeWarnSpecs,
 
         IntTypeClasses, coerce(IntInstancesAbstract),
         IntPredDecls, IntModeDecls, IntDeclPragmas, IntDeclMarkers,
@@ -1173,7 +1181,7 @@ create_parse_tree_int1(Globals, AugMakeIntUnit,
         IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, _ImpSelfFIMLangs,
 
         TypeCtorCheckedMap0, InstCtorCheckedMap0, ModeCtorCheckedMap0,
-        _TypeSpecs, _InstModeSpecs,
+        _TypeErrSpecs, _TypeWarnSpecs, _InstModeErrSpecs, _InstModeWarnSpecs,
 
         IntTypeClasses, IntInstances0, IntPredDecls, IntModeDecls,
         IntDeclPragmas, IntDeclMarkers, IntPromises0, _IntBadClausePreds,
@@ -1261,13 +1269,17 @@ create_parse_tree_int1(Globals, AugMakeIntUnit,
         IntInstDefns, _ImpInstDefns),
     IntInstDefnMap = inst_ctor_defn_items_to_map(IntInstDefns),
     create_inst_ctor_checked_map(do_not_insist_on_defn,
-        IntInstDefnMap, map.init, IntInstCtorCheckedMap, !Specs),
+        IntInstDefnMap, map.init, IntInstCtorCheckedMap,
+        [], InstErrSpecs, [], InstWarnSpecs),
+    !:Specs = coerce(InstErrSpecs) ++ coerce(InstWarnSpecs) ++ !.Specs,
 
     mode_ctor_checked_map_get_src_defns(ModeCtorCheckedMap0,
         IntModeDefns, _ImpModeDefns),
     IntModeDefnMap = mode_ctor_defn_items_to_map(IntModeDefns),
     create_mode_ctor_checked_map(do_not_insist_on_defn,
-        IntModeDefnMap, map.init, IntModeCtorCheckedMap, !Specs),
+        IntModeDefnMap, map.init, IntModeCtorCheckedMap,
+        [], ModeErrSpecs, [], ModeWarnSpecs),
+    !:Specs = coerce(ModeErrSpecs) ++ coerce(ModeWarnSpecs) ++ !.Specs,
 
     globals.lookup_bool_option(Globals, experiment1, Experiment1),
     (
@@ -1278,7 +1290,7 @@ create_parse_tree_int1(Globals, AugMakeIntUnit,
         decide_repns_for_all_types_for_int1(Globals, ModuleName,
             TypeCtorCheckedMap0, DirectIntSpecs, IndirectIntSpecs,
             TypeCtorRepnMap, RepnSpecs),
-        !:Specs = !.Specs ++ RepnSpecs
+        !:Specs = coerce(RepnSpecs) ++ !.Specs
     ),
 
     IntInstances = list.map(check_instance_is_abstract, IntInstances0),
diff --git a/compiler/convert_import_use.m b/compiler/convert_import_use.m
index 1c07e890b..af49356b0 100644
--- a/compiler/convert_import_use.m
+++ b/compiler/convert_import_use.m
@@ -50,7 +50,7 @@
     module_names_contexts::in, module_names_contexts::out) is det.
 
     % classify_int_imp_import_use_modules(WarnUnsortedAvailBlocks,
-    %   ModuleName, IntAvails, ImpAvails, ImportUseMap, !Specs) :-
+    %   ModuleName, IntAvails, ImpAvails, ImportUseMap, !WarnSpecs) :-
     %
     % The input is item_avails showing which modules are imported and/or used
     % where in the interface and implementation sections. This input
@@ -81,10 +81,10 @@
 :- pred classify_int_imp_import_use_modules(bool::in, module_name::in,
     list(item_avail)::in, list(item_avail)::in,
     section_import_and_or_use_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
     % classify_int_imp_use_modules(ModuleName,
-    %   IntUseContextsMap, ImpUseContextsMap, !:UseMap, !Specs) :-
+    %   IntUseContextsMap, ImpUseContextsMap, !:UseMap, ErrSpecs, WarnSpecs) :-
     %
     % Do the same job as classify_int_imp_import_use_modules above,
     % but for .int and .int2 files, not source files or .int0 files.
@@ -107,7 +107,7 @@
     %
 :- pred classify_int_imp_use_modules(module_name::in,
     module_names_contexts::in, module_names_contexts::in,
-    section_use_map::out, list(diag_spec)::in, list(diag_spec)::out) is det.
+    section_use_map::out, list(err_spec)::out, list(warn_spec)::out) is det.
 
 :- pred import_and_or_use_map_section_to_maybe_implicit(
     section_import_and_or_use_map::in, import_and_or_use_map::out) is det.
@@ -259,31 +259,31 @@ accumulate_imports_uses_maps([Avail | Avails], !ImportMap, !UseMap) :-
 %---------------------%
 
 classify_int_imp_import_use_modules(WarnUnsortedAvailBlocks, ModuleName,
-        IntAvails, ImpAvails, !:ImportUseMap, !Specs) :-
+        IntAvails, ImpAvails, !:ImportUseMap, !WarnSpecs) :-
     get_imports_uses_maps(IntAvails, IntImportContextsMap, IntUseContextsMap),
     get_imports_uses_maps(ImpAvails, ImpImportContextsMap, ImpUseContextsMap),
     map.map_foldl(
         report_any_duplicate_avail_contexts("interface", "import_module"),
-        IntImportContextsMap, IntImportMap, !Specs),
+        IntImportContextsMap, IntImportMap, !WarnSpecs),
     map.map_foldl(
         report_any_duplicate_avail_contexts("interface", "use_module"),
-        IntUseContextsMap, IntUseMap, !Specs),
+        IntUseContextsMap, IntUseMap, !WarnSpecs),
     map.map_foldl(
         report_any_duplicate_avail_contexts("implementation", "import_module"),
-        ImpImportContextsMap, ImpImportMap, !Specs),
+        ImpImportContextsMap, ImpImportMap, !WarnSpecs),
     map.map_foldl(
         report_any_duplicate_avail_contexts("implementation", "use_module"),
-        ImpUseContextsMap, ImpUseMap, !Specs),
+        ImpUseContextsMap, ImpUseMap, !WarnSpecs),
 
     map.init(!:ImportUseMap),
     map.foldl(record_int_import,  IntImportMap, !ImportUseMap),
-    map.foldl2(record_int_use,    IntUseMap,    !ImportUseMap, !Specs),
-    map.foldl2(record_imp_import, ImpImportMap, !ImportUseMap, !Specs),
-    map.foldl2(record_imp_use,    ImpUseMap,    !ImportUseMap, !Specs),
+    map.foldl2(record_int_use,    IntUseMap,    !ImportUseMap, !WarnSpecs),
+    map.foldl2(record_imp_import, ImpImportMap, !ImportUseMap, !WarnSpecs),
+    map.foldl2(record_imp_use,    ImpUseMap,    !ImportUseMap, !WarnSpecs),
 
-    warn_if_avail_for_self(ModuleName, !ImportUseMap, !Specs),
+    warn_if_avail_for_self(ModuleName, !ImportUseMap, !WarnSpecs),
     list.foldl2(warn_if_avail_for_ancestor(ModuleName),
-        get_ancestors(ModuleName), !ImportUseMap, !Specs),
+        get_ancestors(ModuleName), !ImportUseMap, !WarnSpecs),
 
     (
         WarnUnsortedAvailBlocks = no
@@ -294,34 +294,36 @@ classify_int_imp_import_use_modules(WarnUnsortedAvailBlocks, ModuleName,
         % e.g. one import_module declaration in the interface section
         % and another in the implementation section, with a ":- interface"
         % or ":- implementation" marker in between.
-        warn_unsorted_avail_blocks(IntAvails ++ ImpAvails, !Specs)
+        warn_unsorted_avail_blocks(IntAvails ++ ImpAvails, !WarnSpecs)
     ).
 
 classify_int_imp_use_modules(ModuleName, IntUseContextsMap, ImpUseContextsMap,
-        !:UseMap, !Specs) :-
+        !:UseMap, !:ErrSpecs, !:WarnSpecs) :-
+    !:ErrSpecs = [],
+    !:WarnSpecs = [],
     map.map_foldl(
         report_any_duplicate_avail_contexts("interface", "use_module"),
-        IntUseContextsMap, IntUseMap, !Specs),
+        IntUseContextsMap, IntUseMap, !WarnSpecs),
     map.map_foldl(
         report_any_duplicate_avail_contexts("implementation", "use_module"),
-        ImpUseContextsMap, ImpUseMap, !Specs),
+        ImpUseContextsMap, ImpUseMap, !WarnSpecs),
 
     map.init(!:UseMap),
     map.foldl(record_int_use_only, IntUseMap, !UseMap),
-    map.foldl2(record_imp_use_only, ImpUseMap, !UseMap, !Specs),
+    map.foldl2(record_imp_use_only, ImpUseMap, !UseMap, !WarnSpecs),
 
-    error_if_use_for_self(ModuleName, !UseMap, !Specs),
+    error_if_use_for_self(ModuleName, !UseMap, !ErrSpecs),
     list.foldl2(error_if_use_for_ancestor(ModuleName),
-        get_ancestors(ModuleName), !UseMap, !Specs).
+        get_ancestors(ModuleName), !UseMap, !ErrSpecs).
 
 %---------------------%
 
 :- pred report_any_duplicate_avail_contexts(string::in, string::in,
     module_name::in, one_or_more(prog_context)::in, prog_context::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 report_any_duplicate_avail_contexts(Section, DeclName,
-        ModuleName, OoMContexts, HeadSortedContext, !Specs) :-
+        ModuleName, OoMContexts, HeadSortedContext, !WarnSpecs) :-
     OoMContexts = one_or_more(HeadContext, TailContexts),
     % The contexts in OoMContexts are not necessarily in sorted order.
     list.sort([HeadContext | TailContexts], SortedContexts),
@@ -337,16 +339,16 @@ report_any_duplicate_avail_contexts(Section, DeclName,
             list.foldl(
                 report_duplicate_avail_context(Section, DeclName,
                     ModuleName, HeadSortedContext),
-                TailSortedContexts, !Specs)
+                TailSortedContexts, !WarnSpecs)
         )
     ).
 
 :- pred report_duplicate_avail_context(string::in, string::in,
     module_name::in, prog_context::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 report_duplicate_avail_context(Section, DeclName, ModuleName, PrevContext,
-        DuplicateContext, !Specs) :-
+        DuplicateContext, !WarnSpecs) :-
     DupPieces = [words("Warning:")] ++
         color_as_incorrect([words("duplicate"), decl(DeclName),
             words("declaration")]) ++
@@ -358,8 +360,8 @@ report_duplicate_avail_context(Section, DeclName, ModuleName, PrevContext,
     DupMsg = msg(DuplicateContext, DupPieces),
     PrevMsg = msg(PrevContext, PrevPieces),
     Severity = severity_warning(warn_redundant_code),
-    Spec = diag_spec($pred, Severity, phase_pt2h, [DupMsg, PrevMsg]),
-    !:Specs = [Spec | !.Specs].
+    Spec = gen_spec($pred, Severity, phase_pt2h, [DupMsg, PrevMsg]),
+    !:WarnSpecs = [Spec | !.WarnSpecs].
 
 :- pred record_int_import(module_name::in, prog_context::in,
     section_import_and_or_use_map::in, section_import_and_or_use_map::out)
@@ -370,9 +372,9 @@ record_int_import(ModuleName, Context, !ImportUseMap) :-
 
 :- pred record_int_use(module_name::in, prog_context::in,
     section_import_and_or_use_map::in, section_import_and_or_use_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-record_int_use(ModuleName, Context, !ImportUseMap, !Specs) :-
+record_int_use(ModuleName, Context, !ImportUseMap, !WarnSpecs) :-
     ( if map.search(!.ImportUseMap, ModuleName, OldEntry) then
         (
             OldEntry = int_import(PrevContext),
@@ -389,8 +391,8 @@ record_int_use(ModuleName, Context, !ImportUseMap, !Specs) :-
             DupMsg = msg(Context, DupPieces),
             PrevMsg = msg(PrevContext, PrevPieces),
             Severity = severity_warning(warn_redundant_code),
-            Spec = diag_spec($pred, Severity, phase_pt2h, [DupMsg, PrevMsg]),
-            !:Specs = [Spec | !.Specs]
+            Spec = gen_spec($pred, Severity, phase_pt2h, [DupMsg, PrevMsg]),
+            !:WarnSpecs = [Spec | !.WarnSpecs]
         ;
             ( OldEntry = int_use(_)
             ; OldEntry = imp_import(_)
@@ -408,9 +410,9 @@ record_int_use(ModuleName, Context, !ImportUseMap, !Specs) :-
 
 :- pred record_imp_import(module_name::in, prog_context::in,
     section_import_and_or_use_map::in, section_import_and_or_use_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-record_imp_import(ModuleName, Context, !ImportUseMap, !Specs) :-
+record_imp_import(ModuleName, Context, !ImportUseMap, !WarnSpecs) :-
     ( if map.search(!.ImportUseMap, ModuleName, OldEntry) then
         (
             OldEntry = int_import(PrevContext),
@@ -427,8 +429,8 @@ record_imp_import(ModuleName, Context, !ImportUseMap, !Specs) :-
             DupMsg = msg(Context, DupPieces),
             PrevMsg = msg(PrevContext, PrevPieces),
             Severity = severity_warning(warn_redundant_code),
-            Spec = diag_spec($pred, Severity, phase_pt2h, [DupMsg, PrevMsg]),
-            !:Specs = [Spec | !.Specs]
+            Spec = gen_spec($pred, Severity, phase_pt2h, [DupMsg, PrevMsg]),
+            !:WarnSpecs = [Spec | !.WarnSpecs]
         ;
             OldEntry = int_use(IntUseContext),
             map.det_update(ModuleName,
@@ -449,9 +451,9 @@ record_imp_import(ModuleName, Context, !ImportUseMap, !Specs) :-
 
 :- pred record_imp_use(module_name::in, prog_context::in,
     section_import_and_or_use_map::in, section_import_and_or_use_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-record_imp_use(ModuleName, Context, !ImportUseMap, !Specs) :-
+record_imp_use(ModuleName, Context, !ImportUseMap, !WarnSpecs) :-
     ( if map.search(!.ImportUseMap, ModuleName, OldEntry) then
         (
             ( OldEntry = int_import(_)
@@ -495,8 +497,8 @@ record_imp_use(ModuleName, Context, !ImportUseMap, !Specs) :-
             DupMsg = msg(Context, DupPieces),
             PrevMsg = msg(PrevContext, PrevPieces),
             Severity = severity_warning(warn_redundant_code),
-            Spec = diag_spec($pred, Severity, phase_pt2h, [DupMsg, PrevMsg]),
-            !:Specs = [Spec | !.Specs]
+            Spec = gen_spec($pred, Severity, phase_pt2h, [DupMsg, PrevMsg]),
+            !:WarnSpecs = [Spec | !.WarnSpecs]
         ;
             OldEntry = imp_use(_),
             % We haven't yet got around to adding entries of these kinds
@@ -528,9 +530,9 @@ record_int_use_only(ModuleName, Context, !UseMap) :-
 
 :- pred record_imp_use_only(module_name::in, prog_context::in,
     section_use_map::in, section_use_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-record_imp_use_only(ModuleName, Context, !UseMap, !Specs) :-
+record_imp_use_only(ModuleName, Context, !UseMap, !WarnSpecs) :-
     ( if map.search(!.UseMap, ModuleName, OldEntry) then
         (
             OldEntry = int_use(PrevContext),
@@ -546,8 +548,8 @@ record_imp_use_only(ModuleName, Context, !UseMap, !Specs) :-
             DupMsg = msg(Context, DupPieces),
             PrevMsg = msg(PrevContext, PrevPieces),
             Severity = severity_warning(warn_redundant_code),
-            Spec = diag_spec($pred, Severity, phase_pt2h, [DupMsg, PrevMsg]),
-            !:Specs = [Spec | !.Specs]
+            Spec = gen_spec($pred, Severity, phase_pt2h, [DupMsg, PrevMsg]),
+            !:WarnSpecs = [Spec | !.WarnSpecs]
         ;
             OldEntry = imp_use(_),
             % We haven't yet got around to adding entries of these kinds
@@ -569,7 +571,7 @@ record_imp_use_only(ModuleName, Context, !UseMap, !Specs) :-
     %
 :- pred warn_if_avail_for_self(module_name::in,
     section_import_and_or_use_map::in, section_import_and_or_use_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 warn_if_avail_for_self(ModuleName, !SectionImportOrUseMap, !Specs) :-
     ( if map.remove(ModuleName, ImportOrUse, !SectionImportOrUseMap) then
@@ -582,7 +584,7 @@ warn_if_avail_for_self(ModuleName, !SectionImportOrUseMap, !Specs) :-
             [nl],
         Msg = msg(Context, Pieces),
         Severity = severity_warning(warn_dodgy_simple_code),
-        Spec = diag_spec($pred, Severity, phase_pt2h, [Msg]),
+        Spec = gen_spec($pred, Severity, phase_pt2h, [Msg]),
         !:Specs = [Spec | !.Specs]
     else
         true
@@ -596,10 +598,10 @@ warn_if_avail_for_self(ModuleName, !SectionImportOrUseMap, !Specs) :-
     %
 :- pred warn_if_avail_for_ancestor(module_name::in, module_name::in,
     section_import_and_or_use_map::in, section_import_and_or_use_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 warn_if_avail_for_ancestor(ModuleName, AncestorName,
-        !SectionImportOrUseMap, !Specs) :-
+        !SectionImportOrUseMap, !WarnSpecs) :-
     ( if map.remove(AncestorName, ImportOrUse, !SectionImportOrUseMap) then
         section_import_or_use_first_context(ImportOrUse, DeclName, Context),
         MainPieces = [words("Warning: module")] ++
@@ -614,8 +616,8 @@ warn_if_avail_for_ancestor(ModuleName, AncestorName,
         Msg = simple_msg(Context,
             [always(MainPieces), verbose_only(verbose_once, VerbosePieces)]),
         Severity = severity_warning(warn_redundant_code),
-        Spec = diag_spec($pred, Severity, phase_pt2h, [Msg]),
-        !:Specs = [Spec | !.Specs]
+        Spec = gen_spec($pred, Severity, phase_pt2h, [Msg]),
+        !:WarnSpecs = [Spec | !.WarnSpecs]
     else
         true
     ).
@@ -657,9 +659,9 @@ section_import_or_use_first_context(ImportOrUse, DeclName, Context) :-
     %
 :- pred error_if_use_for_self(module_name::in,
     section_use_map::in, section_use_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-error_if_use_for_self(ModuleName, !UseMap, !Specs) :-
+error_if_use_for_self(ModuleName, !UseMap, !ErrSpecs) :-
     ( if map.remove(ModuleName, Use, !UseMap) then
         Pieces = [words("Error: module")] ++
             color_as_subject([qual_sym_name(ModuleName)]) ++
@@ -669,7 +671,7 @@ error_if_use_for_self(ModuleName, !UseMap, !Specs) :-
             [nl],
         Context = section_use_first_context(Use),
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     else
         true
     ).
@@ -682,9 +684,9 @@ error_if_use_for_self(ModuleName, !UseMap, !Specs) :-
     %
 :- pred error_if_use_for_ancestor(module_name::in, module_name::in,
     section_use_map::in, section_use_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-error_if_use_for_ancestor(ModuleName, AncestorName, !UseMap, !Specs) :-
+error_if_use_for_ancestor(ModuleName, AncestorName, !UseMap, !ErrSpecs) :-
     ( if map.remove(ModuleName, Use, !UseMap) then
         Pieces = [words("Error: module")] ++
             color_as_subject([qual_sym_name(ModuleName)]) ++
@@ -694,7 +696,7 @@ error_if_use_for_ancestor(ModuleName, AncestorName, !UseMap, !Specs) :-
             [qual_sym_name(AncestorName), suffix("."), nl],
         Context = section_use_first_context(Use),
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     else
         true
     ).
@@ -711,12 +713,12 @@ section_use_first_context(Use) = Context :-
 %---------------------%
 
 :- pred warn_unsorted_avail_blocks(list(item_avail)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-warn_unsorted_avail_blocks(Avails, !Specs) :-
+warn_unsorted_avail_blocks(Avails, !WarnSpecs) :-
     build_import_use_file_map(Avails, multi_map.init, FileMap),
     map.foldl(generate_unsorted_avail_block_warnings_for_file,
-        FileMap, !Specs).
+        FileMap, !WarnSpecs).
 
     % Values of this type map a file name to the list of import_module
     % and/or use_module declarations in that file.
@@ -759,10 +761,10 @@ build_import_use_file_map([Avail | Avails], !FileMap) :-
 
 :- pred generate_unsorted_avail_block_warnings_for_file(string::in,
     list(import_use_line)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 generate_unsorted_avail_block_warnings_for_file(FileName, ImportUseLines,
-        !Specs) :-
+        !WarnSpecs) :-
     list.sort(ImportUseLines, SortedImportUseLines),
     (
         SortedImportUseLines = []
@@ -770,16 +772,16 @@ generate_unsorted_avail_block_warnings_for_file(FileName, ImportUseLines,
     ;
         SortedImportUseLines = [FirstLine | LaterLines],
         generate_unsorted_avail_block_warnings(FileName, FirstLine,
-            LaterLines, !Specs)
+            LaterLines, !WarnSpecs)
     ).
 
 :- pred generate_unsorted_avail_block_warnings(string::in,
     import_use_line::in, list(import_use_line)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 generate_unsorted_avail_block_warnings(_FileName, _, [], !Specs).
 generate_unsorted_avail_block_warnings(FileName, PrevImportUseLine,
-        [ImportUseLine | ImportUseLines], !Specs) :-
+        [ImportUseLine | ImportUseLines], !WarnSpecs) :-
     PrevImportUseLine = import_use_line(PrevLineNum, PrevModuleNameStr,
         PrevAvailDecl),
     ImportUseLine = import_use_line(CurLineNum, CurModuleNameStr,
@@ -795,7 +797,7 @@ generate_unsorted_avail_block_warnings(FileName, PrevImportUseLine,
         Context = context(FileName, CurLineNum),
         Spec = spec($pred, severity_warning(warn_unsorted_import_blocks),
             phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:WarnSpecs = [Spec | !.WarnSpecs]
     else if
         CurLineNum = PrevLineNum + 1,
         module_names_are_in_order(PrevModuleNameStr, CurModuleNameStr) = no
@@ -810,12 +812,12 @@ generate_unsorted_avail_block_warnings(FileName, PrevImportUseLine,
         Context = context(FileName, CurLineNum),
         Spec = spec($pred, severity_warning(warn_unsorted_import_blocks),
             phase_pt2h, Context, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:WarnSpecs = [Spec | !.WarnSpecs]
     else
         true
     ),
     generate_unsorted_avail_block_warnings(FileName,
-        ImportUseLine, ImportUseLines, !Specs).
+        ImportUseLine, ImportUseLines, !WarnSpecs).
 
 :- func module_names_are_in_order(string, string) = bool.
 
diff --git a/compiler/convert_include.m b/compiler/convert_include.m
index 4c3690653..85826f378 100644
--- a/compiler/convert_include.m
+++ b/compiler/convert_include.m
@@ -39,7 +39,7 @@
     %
 :- pred classify_include_modules(
     list(item_include)::in, list(item_include)::in, include_module_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 :- pred include_map_to_int_imp_modules(include_module_map::in,
     set(module_name)::out, set(module_name)::out) is det.
@@ -69,7 +69,7 @@ classify_include_modules(IntIncludes, ImpIncludes,
 
 :- pred classify_include_module(module_section::in, item_include::in,
     include_module_map::in, include_module_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 classify_include_module(Section, ItemInclude, !InclMap, !Specs) :-
     ItemInclude = item_include(ModuleName, Context, _SeqNum),
@@ -83,7 +83,7 @@ classify_include_module(Section, ItemInclude, !InclMap, !Specs) :-
 
 :- pred report_duplicate_include(module_name::in,
     prog_context::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_duplicate_include(ModuleName, PrevContext, Context, !Specs) :-
     MainPieces = [words("Error:")] ++
@@ -96,7 +96,7 @@ report_duplicate_include(ModuleName, PrevContext, Context, !Specs) :-
     PrevPieces = [words("The previous"),
         decl("include"), words("declaration was here."), nl],
     PrevMsg = msg(PrevContext, PrevPieces),
-    Spec = diag_spec($pred, severity_error, phase_pt2h, [MainMsg, PrevMsg]),
+    Spec = gen_spec($pred, severity_error, phase_pt2h, [MainMsg, PrevMsg]),
     !:Specs = [Spec | !.Specs].
 
 %---------------------%
diff --git a/compiler/convert_parse_tree.m b/compiler/convert_parse_tree.m
index 075667dfd..c579cb32a 100644
--- a/compiler/convert_parse_tree.m
+++ b/compiler/convert_parse_tree.m
@@ -79,16 +79,20 @@
     %
 :- pred check_convert_parse_tree_int_to_int0(
     parse_tree_int::in, parse_tree_int0::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 :- pred check_convert_parse_tree_int_to_int1(
     parse_tree_int::in, parse_tree_int1::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 :- pred check_convert_parse_tree_int_to_int2(
     parse_tree_int::in, parse_tree_int2::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 :- pred check_convert_parse_tree_int_to_int3(
     parse_tree_int::in, parse_tree_int3::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -114,10 +118,10 @@
     %
 :- pred check_convert_parse_tree_opt_to_plain_opt(
     parse_tree_opt::in, parse_tree_plain_opt::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 :- pred check_convert_parse_tree_opt_to_trans_opt(
     parse_tree_opt::in, parse_tree_trans_opt::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -147,7 +151,7 @@
 
 :- pred check_convert_raw_comp_unit_to_module_src(globals::in,
     raw_compilation_unit::in, parse_tree_module_src::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::out, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -183,16 +187,19 @@
 
 %---------------------------------------------------------------------------%
 
-check_convert_parse_tree_int_to_int0(ParseTreeInt, ParseTreeInt0, !Specs) :-
+check_convert_parse_tree_int_to_int0(ParseTreeInt, ParseTreeInt0,
+        !ErrSpecs, !WarnSpecs) :-
     ParseTreeInt = parse_tree_int(ModuleName, IntFileKind, ModuleNameContext,
         MaybeVersionNumbers, IntIncls, ImpIncls, IntAvails, ImpAvails,
         IntFIMs, ImpFIMs, IntItems, ImpItems),
     expect(unify(IntFileKind, ifk_int0), $pred,
         "trying to convert non-ifk_int0 parse_tree_int to parse_tree_int0"),
 
-    classify_include_modules(IntIncls, ImpIncls, InclMap, !Specs),
+    classify_include_modules(IntIncls, ImpIncls, InclMap, [], InclErrSpecs),
+    !:ErrSpecs = InclErrSpecs ++ !.ErrSpecs,
     classify_int_imp_import_use_modules(no, ModuleName, IntAvails, ImpAvails,
-        SectionImportUseMap, !Specs),
+        SectionImportUseMap, [], ImportWarnSpecs),
+    !:WarnSpecs = ImportWarnSpecs ++ !.WarnSpecs,
 
     set.list_to_set(list.map(fim_item_to_spec, IntFIMs), IntFIMSpecs),
     set.list_to_set(list.map(fim_item_to_spec, ImpFIMs), ImpFIMSpecs),
@@ -202,7 +209,8 @@ check_convert_parse_tree_int_to_int0(ParseTreeInt, ParseTreeInt0, !Specs) :-
         [], IntTypeClasses0, [], IntInstances0,
         [], IntPredDecls0, [], RevIntModeDecls,
         [], _IntForeignEnums, [], IntDeclPragmas0, [], IntDeclMarkers0,
-        [], IntPromises0, !Specs),
+        [], IntPromises0, [], ClassifyIntErrSpecs),
+    !:ErrSpecs = ClassifyIntErrSpecs ++ !.ErrSpecs,
     % XXX ITEM_LIST Should we report any misplaced foreign enums in
     % _IntForeignEnums now, or wait until code generation? For now,
     % we do the latter.
@@ -222,7 +230,8 @@ check_convert_parse_tree_int_to_int0(ParseTreeInt, ParseTreeInt0, !Specs) :-
         [], ImpTypeClasses0, [], ImpInstances0,
         [], ImpPredDecls0, [], RevImpModeDecls,
         [], ImpForeignEnums, [], ImpDeclPragmas0, [], ImpDeclMarkers0,
-        [], ImpPromises0, !Specs),
+        [], ImpPromises0, [], ClassifyImpErrSpecs),
+    !:ErrSpecs = ClassifyImpErrSpecs ++ !.ErrSpecs,
     ImpTypeDefnMap = type_ctor_defn_items_to_map(ImpTypeDefns),
     ImpInstDefnMap = inst_ctor_defn_items_to_map(ImpInstDefns),
     ImpModeDefnMap = mode_ctor_defn_items_to_map(ImpModeDefns),
@@ -237,11 +246,13 @@ check_convert_parse_tree_int_to_int0(ParseTreeInt, ParseTreeInt0, !Specs) :-
 
     create_type_ctor_checked_map(do_not_insist_on_defn,
         IntTypeDefnMap, ImpTypeDefnMap, ImpForeignEnumMap,
-        TypeCtorCheckedMap, !Specs),
+        TypeCtorCheckedMap, !ErrSpecs, !WarnSpecs),
     create_inst_ctor_checked_map(do_not_insist_on_defn,
-        IntInstDefnMap, ImpInstDefnMap, InstCtorCheckedMap, !Specs),
+        IntInstDefnMap, ImpInstDefnMap, InstCtorCheckedMap,
+        !ErrSpecs, !WarnSpecs),
     create_mode_ctor_checked_map(do_not_insist_on_defn,
-        IntModeDefnMap, ImpModeDefnMap, ModeCtorCheckedMap, !Specs),
+        IntModeDefnMap, ImpModeDefnMap, ModeCtorCheckedMap,
+        !ErrSpecs, !WarnSpecs),
 
     ParseTreeInt0 = parse_tree_int0(ModuleName, ModuleNameContext,
         MaybeVersionNumbers, InclMap,
@@ -265,15 +276,15 @@ check_convert_parse_tree_int_to_int0(ParseTreeInt, ParseTreeInt0, !Specs) :-
     list(item_decl_pragma_info)::in, list(item_decl_pragma_info)::out,
     list(item_decl_marker_info)::in, list(item_decl_marker_info)::out,
     list(item_promise_info)::in, list(item_promise_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 classify_int0_items_int_or_imp([], !TypeDefns, !InstDefns, !ModeDefns,
         !TypeClasses, !Instances, !PredDecls, !RevModeDecls,
-        !ForeignEnums, !DeclPragmas, !DeclMarkers, !Promises, !Specs).
+        !ForeignEnums, !DeclPragmas, !DeclMarkers, !Promises, !ErrSpecs).
 classify_int0_items_int_or_imp([Item | Items], !TypeDefns,
         !InstDefns, !ModeDefns,
         !TypeClasses, !Instances, !PredDecls, !RevModeDecls,
-        !ForeignEnums, !DeclPragmas, !DeclMarkers, !Promises, !Specs) :-
+        !ForeignEnums, !DeclPragmas, !DeclMarkers, !Promises, !ErrSpecs) :-
     (
         Item = item_type_defn(ItemTypeDefn),
         !:TypeDefns = [ItemTypeDefn | !.TypeDefns]
@@ -301,7 +312,7 @@ classify_int0_items_int_or_imp([Item | Items], !TypeDefns,
             Pieces = [words("A .int0 file may not contain"),
                 words("concrete instance declarations."), nl],
             Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         )
     ;
         Item = item_pred_decl(ItemPredDecl),
@@ -337,26 +348,30 @@ classify_int0_items_int_or_imp([Item | Items], !TypeDefns,
             items_desc_pieces(Item) ++ [suffix("."), nl],
         Spec = spec($pred, severity_error, phase_t2pt,
             get_item_context(Item), Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ),
     classify_int0_items_int_or_imp(Items, !TypeDefns, !InstDefns, !ModeDefns,
         !TypeClasses, !Instances, !PredDecls, !RevModeDecls,
-        !ForeignEnums, !DeclPragmas, !DeclMarkers, !Promises, !Specs).
+        !ForeignEnums, !DeclPragmas, !DeclMarkers, !Promises, !ErrSpecs).
 
 %---------------------------------------------------------------------------%
 
-check_convert_parse_tree_int_to_int1(ParseTreeInt, ParseTreeInt1, !Specs) :-
+check_convert_parse_tree_int_to_int1(ParseTreeInt, ParseTreeInt1,
+        !ErrSpecs, !WarnSpecs) :-
     ParseTreeInt = parse_tree_int(ModuleName, IntFileKind, ModuleNameContext,
         MaybeVersionNumbers, IntIncls, ImpIncls, IntAvails, ImpAvails,
         IntFIMs, ImpFIMs, IntItems, ImpItems),
     expect(unify(IntFileKind, ifk_int1), $pred,
         "trying to convert non-ifk_int1 parse_tree_int to parse_tree_int1"),
 
-    classify_include_modules(IntIncls, ImpIncls, InclMap, !Specs),
+    classify_include_modules(IntIncls, ImpIncls, InclMap, [], InclErrSpecs),
+    !:ErrSpecs = InclErrSpecs ++ !.ErrSpecs,
     classify_int_imp_import_use_modules(no, ModuleName, IntAvails, ImpAvails,
-        SectionImportUseMap, !Specs),
+        SectionImportUseMap, [], ImportWarnSpecs),
+    !:WarnSpecs = ImportWarnSpecs ++ !.WarnSpecs,
     map.foldl2(restrict_to_section_use_map_entry(".int"),
-        SectionImportUseMap, map.init, SectionUseMap, !Specs),
+        SectionImportUseMap, map.init, SectionUseMap, [], RestrictErrSpecs),
+    !:ErrSpecs = RestrictErrSpecs ++ !.ErrSpecs,
 
     set.list_to_set(list.map(fim_item_to_spec, IntFIMs), IntFIMSpecs),
     set.list_to_set(list.map(fim_item_to_spec, ImpFIMs), ImpFIMSpecs),
@@ -366,7 +381,8 @@ check_convert_parse_tree_int_to_int1(ParseTreeInt, ParseTreeInt1, !Specs) :-
         [], IntTypeClasses0, [], IntInstances0,
         [], IntPredDecls0, [], RevIntModeDecls,
         [], _IntForeignEnums, [], IntDeclPragmas0, [], IntDeclMarkers,
-        [], IntPromises0, [], IntTypeRepns, !Specs),
+        [], IntPromises0, [], IntTypeRepns, [], ClassifyIntErrSpecs),
+    !:ErrSpecs = ClassifyIntErrSpecs ++ !.ErrSpecs,
     % XXX ITEM_LIST Should we report any misplaced foreign enums in
     % _IntForeignEnums now, or wait until code generation? For now,
     % we do the latter.
@@ -382,20 +398,23 @@ check_convert_parse_tree_int_to_int1(ParseTreeInt, ParseTreeInt1, !Specs) :-
     IntTypeRepnMap = type_ctor_repn_items_to_map(IntTypeRepns),
 
     classify_int1_items_imp(ImpItems, [], ImpTypeDefns0,
-        [], ImpForeignEnums0, [], ImpTypeClasses0, !Specs),
+        [], ImpForeignEnums0, [], ImpTypeClasses0, [], ClassifyImpErrSpecs),
+    !:ErrSpecs = ClassifyImpErrSpecs ++ !.ErrSpecs,
     ImpTypeDefnMap = type_ctor_defn_items_to_map(ImpTypeDefns0),
     ImpForeignEnumMap = type_ctor_foreign_enum_items_to_map(ImpForeignEnums0),
     list.sort(ImpTypeClasses0, ImpTypeClasses),
 
     create_type_ctor_checked_map(do_not_insist_on_defn,
         IntTypeDefnMap, ImpTypeDefnMap, ImpForeignEnumMap,
-        IntTypeCheckedMap, !Specs),
+        IntTypeCheckedMap, !ErrSpecs, !WarnSpecs),
     map.init(ImpInstDefnMap),
     create_inst_ctor_checked_map(do_not_insist_on_defn,
-        IntInstDefnMap, ImpInstDefnMap, IntInstCheckedMap, !Specs),
+        IntInstDefnMap, ImpInstDefnMap, IntInstCheckedMap,
+        !ErrSpecs, !WarnSpecs),
     map.init(ImpModeDefnMap),
     create_mode_ctor_checked_map(do_not_insist_on_defn,
-        IntModeDefnMap, ImpModeDefnMap, IntModeCheckedMap, !Specs),
+        IntModeDefnMap, ImpModeDefnMap, IntModeCheckedMap,
+        !ErrSpecs, !WarnSpecs),
 
     ParseTreeInt1 = parse_tree_int1(ModuleName, ModuleNameContext,
         MaybeVersionNumbers, InclMap, SectionUseMap, IntFIMSpecs, ImpFIMSpecs,
@@ -418,16 +437,16 @@ check_convert_parse_tree_int_to_int1(ParseTreeInt, ParseTreeInt1, !Specs) :-
     list(item_decl_marker_info)::in, list(item_decl_marker_info)::out,
     list(item_promise_info)::in, list(item_promise_info)::out,
     list(item_type_repn_info)::in, list(item_type_repn_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 classify_int1_items_int([], !TypeDefns, !InstDefns, !ModeDefns,
         !TypeClasses, !Instances, !PredDecls, !ModeDecls,
         !ForeignEnums, !DeclPragmas, !DeclMarkers,
-        !Promises, !TypeRepns, !Specs).
+        !Promises, !TypeRepns, !ErrSpecs).
 classify_int1_items_int([Item | Items], !TypeDefns, !InstDefns, !ModeDefns,
         !TypeClasses, !Instances, !PredDecls, !ModeDecls,
         !ForeignEnums, !DeclPragmas, !DeclMarkers,
-        !Promises, !TypeRepns, !Specs) :-
+        !Promises, !TypeRepns, !ErrSpecs) :-
     (
         Item = item_type_defn(ItemTypeDefn),
         !:TypeDefns = [ItemTypeDefn | !.TypeDefns]
@@ -456,7 +475,7 @@ classify_int1_items_int([Item | Items], !TypeDefns, !InstDefns, !ModeDefns,
                 words("concrete instance declarations"),
                 words("in its interface section."), nl],
             Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         )
     ;
         Item = item_type_repn(ItemTypeRepn),
@@ -491,7 +510,7 @@ classify_int1_items_int([Item | Items], !TypeDefns, !InstDefns, !ModeDefns,
                 items_desc_pieces(Item) ++
                 [words("in its interface section."), nl],
             Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         )
     ;
         ( Item = item_clause(_)
@@ -509,23 +528,24 @@ classify_int1_items_int([Item | Items], !TypeDefns, !InstDefns, !ModeDefns,
             [words("in its interface section."), nl],
         Spec = spec($pred, severity_error, phase_t2pt,
             get_item_context(Item), Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ),
     classify_int1_items_int(Items, !TypeDefns, !InstDefns, !ModeDefns,
         !TypeClasses, !Instances, !PredDecls, !ModeDecls,
         !ForeignEnums, !DeclPragmas, !DeclMarkers,
-        !Promises, !TypeRepns, !Specs).
+        !Promises, !TypeRepns, !ErrSpecs).
 
 :- pred classify_int1_items_imp(list(item)::in,
     list(item_type_defn_info)::in, list(item_type_defn_info)::out,
     list(item_foreign_enum_info)::in, list(item_foreign_enum_info)::out,
     list(item_abstract_typeclass_info)::in,
         list(item_abstract_typeclass_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-classify_int1_items_imp([], !TypeDefns, !ForeignEnums, !TypeClasses, !Specs).
+classify_int1_items_imp([], !TypeDefns, !ForeignEnums,
+        !TypeClasses, !ErrSpecs).
 classify_int1_items_imp([Item | Items], !TypeDefns, !ForeignEnums,
-        !TypeClasses, !Specs) :-
+        !TypeClasses, !ErrSpecs) :-
     (
         Item = item_type_defn(ItemTypeDefn),
         !:TypeDefns = [ItemTypeDefn | !.TypeDefns]
@@ -544,7 +564,7 @@ classify_int1_items_imp([Item | Items], !TypeDefns, !ForeignEnums,
             Pieces = [words("A .int file may not contain"),
                 words("concrete typeclass declarations."), nl],
             Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         )
     ;
         Item = item_foreign_enum(ItemForeignEnum),
@@ -574,14 +594,15 @@ classify_int1_items_imp([Item | Items], !TypeDefns, !ForeignEnums,
             [words("in its implementation section."), nl],
         Spec = spec($pred, severity_error, phase_t2pt,
             get_item_context(Item), Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ),
     classify_int1_items_imp(Items, !TypeDefns, !ForeignEnums,
-        !TypeClasses, !Specs).
+        !TypeClasses, !ErrSpecs).
 
 %---------------------------------------------------------------------------%
 
-check_convert_parse_tree_int_to_int2(ParseTreeInt, ParseTreeInt2, !Specs) :-
+check_convert_parse_tree_int_to_int2(ParseTreeInt, ParseTreeInt2,
+        !ErrSpecs, !WarnSpecs) :-
     ParseTreeInt = parse_tree_int(ModuleName, IntFileKind, ModuleNameContext,
         MaybeVersionNumbers, IntIncls, ImpIncls, IntAvails, ImpAvails,
         IntFIMs, ImpFIMs, IntItems, ImpItems),
@@ -598,22 +619,27 @@ check_convert_parse_tree_int_to_int2(ParseTreeInt, ParseTreeInt2, !Specs) :-
             words("in its implementation section."), nl],
         ImpInclSpec = spec($pred, severity_error, phase_t2pt,
             FirstImpIncl ^ incl_context, ImpInclPieces),
-        !:Specs = [ImpInclSpec | !.Specs]
+        !:ErrSpecs = [ImpInclSpec | !.ErrSpecs]
     ),
-    classify_include_modules(IntIncls, [], InclMap, !Specs),
+    classify_include_modules(IntIncls, [], InclMap, [], InclErrSpecs),
     map.foldl(add_only_int_include, InclMap, map.init, IntInclMap),
+    !:ErrSpecs = InclErrSpecs ++ !.ErrSpecs,
 
     classify_int_imp_import_use_modules(no, ModuleName, IntAvails, ImpAvails,
-        SectionImportUseMap, !Specs),
+        SectionImportUseMap, [], ImportWarnSpecs),
+    !:WarnSpecs = ImportWarnSpecs ++ !.WarnSpecs,
     map.foldl2(restrict_to_section_use_map_entry(".int2"),
-        SectionImportUseMap, map.init, SectionUseMap, !Specs),
+        SectionImportUseMap, map.init, SectionUseMap, [], RestrictErrSpecs),
+    !:ErrSpecs = RestrictErrSpecs ++ !.ErrSpecs,
 
     set.list_to_set(list.map(fim_item_to_spec, IntFIMs), IntFIMSpecs),
     set.list_to_set(list.map(fim_item_to_spec, ImpFIMs), ImpFIMSpecs),
 
     classify_int2_items_int(IntItems, [], IntTypeDefns0,
         [], IntInstDefns0, [], IntModeDefns0,
-        [], IntTypeClasses0, [], IntInstances0, [], IntTypeRepns0, !Specs),
+        [], IntTypeClasses0, [], IntInstances0, [], IntTypeRepns0,
+        [], ClassifyIntErrSpecs),
+    !:ErrSpecs = ClassifyIntErrSpecs ++ !.ErrSpecs,
     IntTypeDefnMap = type_ctor_defn_items_to_map(IntTypeDefns0),
     IntInstDefnMap = inst_ctor_defn_items_to_map(IntInstDefns0),
     IntModeDefnMap = mode_ctor_defn_items_to_map(IntModeDefns0),
@@ -621,19 +647,23 @@ check_convert_parse_tree_int_to_int2(ParseTreeInt, ParseTreeInt2, !Specs) :-
     list.sort(IntInstances0, IntInstances),
     IntTypeRepnMap = type_ctor_repn_items_to_map(IntTypeRepns0),
 
-    classify_int2_items_imp(ImpItems, [], ImpTypeDefns0, !Specs),
+    classify_int2_items_imp(ImpItems, [], ImpTypeDefns0,
+        [], ClassifyImpErrSpecs),
+    !:ErrSpecs = ClassifyImpErrSpecs ++ !.ErrSpecs,
     ImpTypeDefnMap = type_ctor_defn_items_to_map(ImpTypeDefns0),
 
     map.init(ImpForeignEnumMap),
     create_type_ctor_checked_map(do_not_insist_on_defn,
         IntTypeDefnMap, ImpTypeDefnMap, ImpForeignEnumMap,
-        IntTypeCheckedMap, !Specs),
+        IntTypeCheckedMap, !ErrSpecs, !WarnSpecs),
     map.init(ImpInstDefnMap),
     create_inst_ctor_checked_map(do_not_insist_on_defn,
-        IntInstDefnMap, ImpInstDefnMap, IntInstCheckedMap, !Specs),
+        IntInstDefnMap, ImpInstDefnMap, IntInstCheckedMap,
+        !ErrSpecs, !WarnSpecs),
     map.init(ImpModeDefnMap),
     create_mode_ctor_checked_map(do_not_insist_on_defn,
-        IntModeDefnMap, ImpModeDefnMap, IntModeCheckedMap, !Specs),
+        IntModeDefnMap, ImpModeDefnMap, IntModeCheckedMap,
+        !ErrSpecs, !WarnSpecs),
 
     ParseTreeInt2 = parse_tree_int2(ModuleName, ModuleNameContext,
         MaybeVersionNumbers, IntInclMap,
@@ -649,12 +679,12 @@ check_convert_parse_tree_int_to_int2(ParseTreeInt, ParseTreeInt2, !Specs) :-
     list(item_abstract_instance_info)::in,
         list(item_abstract_instance_info)::out,
     list(item_type_repn_info)::in, list(item_type_repn_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 classify_int2_items_int([], !TypeDefns, !InstDefns, !ModeDefns,
-        !TypeClasses, !Instances, !TypeRepns, !Specs).
+        !TypeClasses, !Instances, !TypeRepns, !ErrSpecs).
 classify_int2_items_int([Item | Items], !TypeDefns, !InstDefns, !ModeDefns,
-        !TypeClasses, !Instances, !TypeRepns, !Specs) :-
+        !TypeClasses, !Instances, !TypeRepns, !ErrSpecs) :-
     (
         Item = item_type_defn(ItemTypeDefn),
         !:TypeDefns = [ItemTypeDefn | !.TypeDefns]
@@ -683,7 +713,7 @@ classify_int2_items_int([Item | Items], !TypeDefns, !InstDefns, !ModeDefns,
                 words("concrete instance declarations"),
                 words("in its interface section."), nl],
             Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         )
     ;
         Item = item_type_repn(ItemTypeRepn),
@@ -710,17 +740,17 @@ classify_int2_items_int([Item | Items], !TypeDefns, !InstDefns, !ModeDefns,
             [words("in its interface section."), nl],
         Spec = spec($pred, severity_error, phase_t2pt,
             get_item_context(Item), Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ),
     classify_int2_items_int(Items, !TypeDefns, !InstDefns, !ModeDefns,
-        !TypeClasses, !Instances, !TypeRepns, !Specs).
+        !TypeClasses, !Instances, !TypeRepns, !ErrSpecs).
 
 :- pred classify_int2_items_imp(list(item)::in,
     list(item_type_defn_info)::in, list(item_type_defn_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-classify_int2_items_imp([], !TypeDefns, !Specs).
-classify_int2_items_imp([Item | Items], !TypeDefns, !Specs) :-
+classify_int2_items_imp([], !TypeDefns, !ErrSpecs).
+classify_int2_items_imp([Item | Items], !TypeDefns, !ErrSpecs) :-
     (
         Item = item_type_defn(ItemTypeDefn),
         !:TypeDefns = [ItemTypeDefn | !.TypeDefns]
@@ -751,13 +781,14 @@ classify_int2_items_imp([Item | Items], !TypeDefns, !Specs) :-
             [words("in its implementation section."), nl],
         Spec = spec($pred, severity_error, phase_t2pt,
             get_item_context(Item), Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ),
-    classify_int2_items_imp(Items, !TypeDefns, !Specs).
+    classify_int2_items_imp(Items, !TypeDefns, !ErrSpecs).
 
 %---------------------------------------------------------------------------%
 
-check_convert_parse_tree_int_to_int3(ParseTreeInt, ParseTreeInt3, !Specs) :-
+check_convert_parse_tree_int_to_int3(ParseTreeInt, ParseTreeInt3,
+        !ErrSpecs, !WarnSpecs) :-
     ParseTreeInt = parse_tree_int(ModuleName, IntFileKind, ModuleNameContext,
         MaybeVersionNumbers, IntIncls, ImpIncls, IntAvails, ImpAvails,
         IntFIMs, ImpFIMs, IntItems, ImpItems),
@@ -774,16 +805,19 @@ check_convert_parse_tree_int_to_int3(ParseTreeInt, ParseTreeInt3, !Specs) :-
         % MaybeVersionNumbers itself contains no context information.
         VNSpec = spec($pred, severity_error, phase_t2pt,
             ModuleNameContext, VNPieces),
-        !:Specs = [VNSpec | !.Specs]
+        !:ErrSpecs = [VNSpec | !.ErrSpecs]
     ),
 
-    classify_include_modules(IntIncls, [], InclMap, !Specs),
+    classify_include_modules(IntIncls, [], InclMap, [], InclErrSpecs),
     map.foldl(add_only_int_include, InclMap, map.init, IntInclMap),
+    !:ErrSpecs = InclErrSpecs ++ !.ErrSpecs,
 
     classify_int_imp_import_use_modules(no, ModuleName, IntAvails, ImpAvails,
-        SectionImportUseMap, !Specs),
+        SectionImportUseMap, [], ImportWarnSpecs),
+    !:WarnSpecs = ImportWarnSpecs ++ !.WarnSpecs,
     map.foldl2(restrict_to_int_import_map_entry(".int3"),
-        SectionImportUseMap, map.init, IntImportMap, !Specs),
+        SectionImportUseMap, map.init, IntImportMap, [], RestrictErrSpecs),
+    !:ErrSpecs = RestrictErrSpecs ++ !.ErrSpecs,
 
     (
         IntFIMs = []
@@ -793,12 +827,14 @@ check_convert_parse_tree_int_to_int3(ParseTreeInt, ParseTreeInt3, !Specs) :-
             pragma_decl("foreign_import_module"), words("declarations."), nl],
         IntFIMSpec = spec($pred, severity_error, phase_t2pt,
             FirstIntFIM ^ fim_context, IntFIMPieces),
-        !:Specs = [IntFIMSpec | !.Specs]
+        !:ErrSpecs = [IntFIMSpec | !.ErrSpecs]
     ),
 
     classify_int3_items_int(IntItems, [], IntTypeDefns0,
         [], IntInstDefns0, [], IntModeDefns0,
-        [], IntTypeClasses0, [], IntInstances0, [], IntTypeRepns0, !Specs),
+        [], IntTypeClasses0, [], IntInstances0, [], IntTypeRepns0,
+        [], ClassifyErrSpecs),
+    !:ErrSpecs = ClassifyErrSpecs ++ !.ErrSpecs,
     IntTypeDefnMap = type_ctor_defn_items_to_map(IntTypeDefns0),
     IntInstDefnMap = inst_ctor_defn_items_to_map(IntInstDefns0),
     IntModeDefnMap = mode_ctor_defn_items_to_map(IntModeDefns0),
@@ -810,13 +846,15 @@ check_convert_parse_tree_int_to_int3(ParseTreeInt, ParseTreeInt3, !Specs) :-
     map.init(ImpForeignEnumMap),
     create_type_ctor_checked_map(do_not_insist_on_defn,
         IntTypeDefnMap, ImpTypeDefnMap, ImpForeignEnumMap,
-        IntTypeCheckedMap, !Specs),
+        IntTypeCheckedMap, !ErrSpecs, !WarnSpecs),
     map.init(ImpInstDefnMap),
     create_inst_ctor_checked_map(do_not_insist_on_defn,
-        IntInstDefnMap, ImpInstDefnMap, IntInstCheckedMap, !Specs),
+        IntInstDefnMap, ImpInstDefnMap, IntInstCheckedMap,
+        !ErrSpecs, !WarnSpecs),
     map.init(ImpModeDefnMap),
     create_mode_ctor_checked_map(do_not_insist_on_defn,
-        IntModeDefnMap, ImpModeDefnMap, IntModeCheckedMap, !Specs),
+        IntModeDefnMap, ImpModeDefnMap, IntModeCheckedMap,
+        !ErrSpecs, !WarnSpecs),
 
     some [!ImpContexts]
     (
@@ -854,7 +892,7 @@ check_convert_parse_tree_int_to_int3(ParseTreeInt, ParseTreeInt3, !Specs) :-
                 words("an implementation section."), nl],
             ImpItemSpec = spec($pred, severity_error, phase_t2pt,
                 FirstImpContext, ImpItemPieces),
-            !:Specs = [ImpItemSpec | !.Specs]
+            !:ErrSpecs = [ImpItemSpec | !.ErrSpecs]
         )
     ),
     ParseTreeInt3 = parse_tree_int3(ModuleName, ModuleNameContext,
@@ -871,12 +909,12 @@ check_convert_parse_tree_int_to_int3(ParseTreeInt, ParseTreeInt3, !Specs) :-
     list(item_abstract_instance_info)::in,
         list(item_abstract_instance_info)::out,
     list(item_type_repn_info)::in, list(item_type_repn_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 classify_int3_items_int([], !TypeDefns, !InstDefns, !ModeDefns,
-        !TypeClasses, !Instances, !TypeRepns, !Specs).
+        !TypeClasses, !Instances, !TypeRepns, !ErrSpecs).
 classify_int3_items_int([Item | Items], !TypeDefns, !InstDefns, !ModeDefns,
-        !TypeClasses, !Instances, !TypeRepns, !Specs) :-
+        !TypeClasses, !Instances, !TypeRepns, !ErrSpecs) :-
     (
         Item = item_type_defn(ItemTypeDefn),
         !:TypeDefns = [ItemTypeDefn | !.TypeDefns]
@@ -907,7 +945,7 @@ classify_int3_items_int([Item | Items], !TypeDefns, !InstDefns, !ModeDefns,
                         nl],
                     Spec = spec($pred, severity_error, phase_t2pt,
                         Context, Pieces),
-                    !:Specs = [Spec | !.Specs]
+                    !:ErrSpecs = [Spec | !.ErrSpecs]
                 )
             ;
                 Supers = [_ | _],
@@ -923,14 +961,14 @@ classify_int3_items_int([Item | Items], !TypeDefns, !InstDefns, !ModeDefns,
                     [suffix("."), nl],
                 Spec = spec($pred, severity_error, phase_t2pt,
                     Context, Pieces),
-                !:Specs = [Spec | !.Specs]
+                !:ErrSpecs = [Spec | !.ErrSpecs]
             )
         ;
             Interface = class_interface_concrete(_),
             Pieces = [words("A .int3 file may not contain"),
                 words("concrete typeclass declarations."), nl],
             Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         )
     ;
         Item = item_instance(ItemInstance),
@@ -947,7 +985,7 @@ classify_int3_items_int([Item | Items], !TypeDefns, !InstDefns, !ModeDefns,
             Pieces = [words("A .int3 file may not contain"),
                 words("concrete instance declarations."), nl],
             Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         )
     ;
         Item = item_type_repn(ItemTypeRepn),
@@ -974,10 +1012,10 @@ classify_int3_items_int([Item | Items], !TypeDefns, !InstDefns, !ModeDefns,
             [words("in its interface section."), nl],
         Spec = spec($pred, severity_error, phase_t2pt,
             get_item_context(Item), Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     ),
     classify_int3_items_int(Items, !TypeDefns, !InstDefns, !ModeDefns,
-        !TypeClasses, !Instances, !TypeRepns, !Specs).
+        !TypeClasses, !Instances, !TypeRepns, !ErrSpecs).
 
 %---------------------------------------------------------------------------%
 
@@ -1060,7 +1098,7 @@ check_convert_parse_tree_opt_to_plain_opt(ParseTreeOpt, ParseTreePlainOpt,
         list(decl_pragma_struct_sharing_info)::out,
     list(decl_pragma_struct_reuse_info)::in,
         list(decl_pragma_struct_reuse_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 classify_plain_opt_items([], !TypeDefns, !ForeignEnums,
         !InstDefns, !ModeDefns, !TypeClasses, !Instances,
@@ -1344,7 +1382,7 @@ check_convert_parse_tree_opt_to_trans_opt(ParseTreeOpt, ParseTreeTransOpt,
         list(decl_pragma_struct_sharing_info)::out,
     list(decl_pragma_struct_reuse_info)::in,
         list(decl_pragma_struct_reuse_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 classify_trans_opt_items([], !TermInfos, !Term2Infos,
         !Exceptions, !Trailings, !MMTablings, !Sharings, !Reuses, !Specs).
@@ -1430,7 +1468,7 @@ classify_trans_opt_items([Item | Items], !TermInfos, !Term2Infos,
 %---------------------------------------------------------------------------%
 
 check_convert_raw_comp_unit_to_module_src(Globals, RawCompUnit,
-        ParseTreeModuleSrc, !Specs) :-
+        ParseTreeModuleSrc, !:ErrSpecs, !:WarnSpecs) :-
     RawCompUnit = raw_compilation_unit(ModuleName, ModuleNameContext,
         ItemBlocks),
 
@@ -1466,9 +1504,9 @@ check_convert_raw_comp_unit_to_module_src(Globals, RawCompUnit,
         ImpImplicitAvailNeeds0, ImpImplicitAvailNeeds,
         set.init, ImpSelfFIMLangs,
 
-        !Specs),
+        [], !:ErrSpecs, [], !:WarnSpecs),
 
-    classify_include_modules(IntIncls, ImpIncls, InclMap, !Specs),
+    classify_include_modules(IntIncls, ImpIncls, InclMap, !ErrSpecs),
 
     list.reverse(RevIntTypeDefns, IntTypeDefns),
     list.reverse(RevIntInstDefns, IntInstDefns),
@@ -1520,17 +1558,17 @@ check_convert_raw_comp_unit_to_module_src(Globals, RawCompUnit,
     ImpForeignEnumMap = type_ctor_foreign_enum_items_to_map(ImpForeignEnums),
     create_type_ctor_checked_map(do_insist_on_defn,
         IntTypeDefnMap, ImpTypeDefnMap, ImpForeignEnumMap,
-        TypeCtorCheckedMap, [], TypeSpecs),
+        TypeCtorCheckedMap, [], TypeErrSpecs, [], TypeWarnSpecs),
     IntInstDefnMap = inst_ctor_defn_items_to_map(IntInstDefns),
     ImpInstDefnMap = inst_ctor_defn_items_to_map(ImpInstDefns),
     create_inst_ctor_checked_map(do_insist_on_defn,
         IntInstDefnMap, ImpInstDefnMap, InstCtorCheckedMap,
-        [], InstSpecs),
+        [], InstErrSpecs, [], InstWarnSpecs),
     IntModeDefnMap = mode_ctor_defn_items_to_map(IntModeDefns),
     ImpModeDefnMap = mode_ctor_defn_items_to_map(ImpModeDefns),
     create_mode_ctor_checked_map(do_insist_on_defn,
         IntModeDefnMap, ImpModeDefnMap, ModeCtorCheckedMap,
-        InstSpecs, InstModeSpecs),
+        InstErrSpecs, InstModeErrSpecs, InstWarnSpecs, InstModeWarnSpecs),
 
     % classify_src_items_in_blocks has already generated an error message
     % for each impl pragma in the interface section. However, we then treat
@@ -1554,7 +1592,7 @@ check_convert_raw_comp_unit_to_module_src(Globals, RawCompUnit,
     globals.lookup_bool_option(Globals, warn_unsorted_import_blocks,
         WarnUnsortedImportBlocks),
     classify_int_imp_import_use_modules(WarnUnsortedImportBlocks, ModuleName,
-        IntAvails, ImpAvails, SectionImportUseMap, !Specs),
+        IntAvails, ImpAvails, SectionImportUseMap, !WarnSpecs),
     import_and_or_use_map_section_to_maybe_implicit(SectionImportUseMap,
         ImportUseMap0),
     extend_import_and_or_use_map_with_implicits(Globals,
@@ -1566,14 +1604,14 @@ check_convert_raw_comp_unit_to_module_src(Globals, RawCompUnit,
         map.keys_as_set(ImpFIMSpecMap1),
         IntImpFIMSpecs),
     set.foldl2(report_int_imp_fim(IntFIMSpecMap), IntImpFIMSpecs,
-        ImpFIMSpecMap1, ImpFIMSpecMap, !Specs),
+        ImpFIMSpecMap1, ImpFIMSpecMap, !WarnSpecs),
 
     ParseTreeModuleSrc = parse_tree_module_src(ModuleName, ModuleNameContext,
         InclMap, ImportUseMap,
         IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,
 
         TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
-        TypeSpecs, InstModeSpecs,
+        TypeErrSpecs, TypeWarnSpecs, InstModeErrSpecs, InstModeWarnSpecs,
 
         IntTypeClasses, IntInstances, IntPredDecls, IntModeDecls,
         IntDeclPragmas, IntDeclMarkers, IntPromises, IntBadClausePreds,
@@ -1630,9 +1668,9 @@ split_concrete_int_instances_acc([IntInstance | IntInstances],
 :- pred report_int_imp_fim(map(fim_spec, prog_context)::in,
     fim_spec::in,
     map(fim_spec, prog_context)::in, map(fim_spec, prog_context)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-report_int_imp_fim(IntFIMSpecMap, FIMSpec, !ImpFIMSpecMap, !Specs) :-
+report_int_imp_fim(IntFIMSpecMap, FIMSpec, !ImpFIMSpecMap, !WarnSpecs) :-
     FIMSpec = fim_spec(Lang, ModuleName),
     map.det_remove(FIMSpec, ImpContext, !ImpFIMSpecMap),
     map.lookup(IntFIMSpecMap, FIMSpec, IntContext),
@@ -1649,8 +1687,8 @@ report_int_imp_fim(IntFIMSpecMap, FIMSpec, !ImpFIMSpecMap, !Specs) :-
     ImpMsg = msg(ImpContext, ImpPieces),
     IntMsg = msg(IntContext, IntPieces),
     Severity = severity_warning(warn_redundant_code),
-    Spec = diag_spec($pred, Severity, phase_pt2h, [ImpMsg, IntMsg]),
-    !:Specs = [Spec | !.Specs].
+    Spec = gen_spec($pred, Severity, phase_pt2h, [ImpMsg, IntMsg]),
+    !:WarnSpecs = [Spec | !.WarnSpecs].
 
 %---------------------------------------------------------------------------%
 
@@ -1701,7 +1739,8 @@ report_int_imp_fim(IntFIMSpecMap, FIMSpec, !ImpFIMSpecMap, !Specs) :-
     list(item_mutable_info)::in, list(item_mutable_info)::out,
     implicit_avail_needs::in, implicit_avail_needs::out,
     set(foreign_language)::in, set(foreign_language)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 classify_src_items_in_blocks([],
         !IntIncls, !IntAvails, !IntFIMSpecMap,
@@ -1721,7 +1760,7 @@ classify_src_items_in_blocks([],
         !RevImpDeclPragmas, !RevImpDeclMarkers,
         !RevImpImplPragmas, !RevImpImplMarkers,
         !RevImpPromises, !RevImpInitialises, !RevImpFinalises, !RevImpMutables,
-        !ImpImplicitAvailNeeds, !ImpSelfFIMLangs, !Specs).
+        !ImpImplicitAvailNeeds, !ImpSelfFIMLangs, !ErrSpecs, !WarnSpecs).
 classify_src_items_in_blocks([ItemBlock | ItemBlocks],
         !IntIncls, !IntAvails, !IntFIMSpecMap,
         !RevIntTypeDefns, !RevIntInstDefns, !RevIntModeDefns,
@@ -1740,14 +1779,14 @@ classify_src_items_in_blocks([ItemBlock | ItemBlocks],
         !RevImpDeclPragmas, !RevImpDeclMarkers,
         !RevImpImplPragmas, !RevImpImplMarkers,
         !RevImpPromises, !RevImpInitialises, !RevImpFinalises, !RevImpMutables,
-        !ImpImplicitAvailNeeds, !ImpSelfFIMLangs, !Specs) :-
+        !ImpImplicitAvailNeeds, !ImpSelfFIMLangs, !ErrSpecs, !WarnSpecs) :-
     ItemBlock = item_block(_, Section, Incls, Avails, FIMs, Items),
     (
         Section = ms_interface,
         !:IntIncls = !.IntIncls ++ Incls,
         !:IntAvails = !.IntAvails ++ Avails,
         list.foldl2(classify_foreign_import_module, FIMs, !IntFIMSpecMap,
-            !Specs),
+            !WarnSpecs),
         classify_src_items_int(Items,
             !RevIntTypeDefns, !RevIntInstDefns, !RevIntModeDefns,
             !RevIntTypeClasses, !RevIntInstances,
@@ -1756,13 +1795,13 @@ classify_src_items_in_blocks([ItemBlock | ItemBlocks],
             !RevIntImplPragmas, !RevIntImplMarkers,
             !IntBadClausePreds, !RevIntPromises,
             !RevIntInitialises, !RevIntFinalises, !RevIntMutables,
-            !IntImplicitAvailNeeds, !IntSelfFIMLangs, !Specs)
+            !IntImplicitAvailNeeds, !IntSelfFIMLangs, !ErrSpecs)
     ;
         Section = ms_implementation,
         !:ImpIncls = !.ImpIncls ++ Incls,
         !:ImpAvails = !.ImpAvails ++ Avails,
         list.foldl2(classify_foreign_import_module, FIMs, !ImpFIMSpecMap,
-            !Specs),
+            !WarnSpecs),
         classify_src_items_imp(Items,
             !RevImpTypeDefns, !RevImpInstDefns, !RevImpModeDefns,
             !RevImpTypeClasses, !RevImpInstances,
@@ -1772,7 +1811,8 @@ classify_src_items_in_blocks([ItemBlock | ItemBlocks],
             !RevImpDeclPragmas, !RevImpDeclMarkers,
             !RevImpImplPragmas, !RevImpImplMarkers,
             !RevImpPromises, !RevImpInitialises, !RevImpFinalises,
-            !RevImpMutables, !ImpImplicitAvailNeeds, !ImpSelfFIMLangs, !Specs)
+            !RevImpMutables, !ImpImplicitAvailNeeds, !ImpSelfFIMLangs,
+            !ErrSpecs)
     ),
     classify_src_items_in_blocks(ItemBlocks,
         !IntIncls, !IntAvails, !IntFIMSpecMap,
@@ -1792,11 +1832,11 @@ classify_src_items_in_blocks([ItemBlock | ItemBlocks],
         !RevImpDeclPragmas, !RevImpDeclMarkers,
         !RevImpImplPragmas, !RevImpImplMarkers,
         !RevImpPromises, !RevImpInitialises, !RevImpFinalises, !RevImpMutables,
-        !ImpImplicitAvailNeeds, !ImpSelfFIMLangs, !Specs).
+        !ImpImplicitAvailNeeds, !ImpSelfFIMLangs, !ErrSpecs, !WarnSpecs).
 
 :- pred classify_foreign_import_module(item_fim::in,
     map(fim_spec, prog_context)::in, map(fim_spec, prog_context)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 classify_foreign_import_module(ItemFIM, !FIMSpecMap, !Specs) :-
     ItemFIM = item_fim(Lang, ModuleName, Context, _SeqNum),
@@ -1818,7 +1858,7 @@ classify_foreign_import_module(ItemFIM, !FIMSpecMap, !Specs) :-
             words("is here."), nl],
         PrevMsg = msg(PrevContext, PrevPieces),
         Severity = severity_warning(warn_redundant_code),
-        Spec = diag_spec($pred, Severity, phase_pt2h, [MainMsg, PrevMsg]),
+        Spec = gen_spec($pred, Severity, phase_pt2h, [MainMsg, PrevMsg]),
         !:Specs = [Spec | !.Specs]
     else
         map.det_insert(FIMSpec, Context, !FIMSpecMap)
@@ -1843,7 +1883,7 @@ classify_foreign_import_module(ItemFIM, !FIMSpecMap, !Specs) :-
     list(item_mutable_info)::in, list(item_mutable_info)::out,
     implicit_avail_needs::in, implicit_avail_needs::out,
     set(foreign_language)::in, set(foreign_language)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 classify_src_items_int([],
         !RevTypeDefns, !RevInstDefns, !RevModeDefns,
@@ -1914,7 +1954,7 @@ classify_src_items_int([Item | Items],
             Msg = simple_msg(ItemInstanceInfo ^ ci_context,
                 [always(AlwaysPieces),
                 verbose_only(verbose_once, VerbosePieces)]),
-            Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg]),
+            Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg]),
             !:Specs = [Spec | !.Specs]
         ),
         !:RevInstances = [ItemInstanceInfo | !.RevInstances]
@@ -2079,7 +2119,7 @@ classify_src_items_int([Item | Items],
     list(item_mutable_info)::in, list(item_mutable_info)::out,
     implicit_avail_needs::in, implicit_avail_needs::out,
     set(foreign_language)::in, set(foreign_language)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 classify_src_items_imp([],
         !RevTypeDefns, !RevInstDefns, !RevModeDefns,
@@ -2266,7 +2306,7 @@ acc_implicit_avail_needs_in_promise(ItemPromiseInfo, !ImplicitAvailNeeds) :-
 %---------------------------------------------------------------------------%
 
 :- pred error_item_is_exported(item::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 error_item_is_exported(Item, !Specs) :-
     error_is_exported(get_item_context(Item), items_desc_pieces(Item), !Specs).
@@ -2275,7 +2315,7 @@ error_item_is_exported(Item, !Specs) :-
     % a module interface.
     %
 :- pred error_is_exported(prog_context::in, list(format_piece)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 error_is_exported(Context, DescPieces, !Specs) :-
     Pieces = [words("Error:")] ++
@@ -2302,7 +2342,7 @@ accumulate_uses_maps([Use | Uses], !UseMap) :-
 :- pred restrict_to_section_use_map_entry(string::in,
     module_name::in, section_import_and_or_use::in,
     section_use_map::in, section_use_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 restrict_to_section_use_map_entry(Extension, ModuleName, SectionImportAndOrUse,
         !SectionUseMap, !Specs) :-
@@ -2326,7 +2366,7 @@ restrict_to_section_use_map_entry(Extension, ModuleName, SectionImportAndOrUse,
 :- pred restrict_to_int_import_map_entry(string::in,
     module_name::in, section_import_and_or_use::in,
     int_import_map::in, int_import_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 restrict_to_int_import_map_entry(Extension, ModuleName, SectionImportAndOrUse,
         !IntImportMap, !Specs) :-
@@ -2354,7 +2394,7 @@ restrict_to_int_import_map_entry(Extension, ModuleName, SectionImportAndOrUse,
 %---------------------%
 
 :- pred report_forbidden_avail(string::in, string::in, maybe(string)::in,
-    prog_context::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    prog_context::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 report_forbidden_avail(Extension, Decl, MaybeSection, Context, !Specs) :-
     (
@@ -2371,7 +2411,7 @@ report_forbidden_avail(Extension, Decl, MaybeSection, Context, !Specs) :-
     !:Specs = [Spec | !.Specs].
 
 :- pred report_forbidden_item_in_src(item::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_forbidden_item_in_src(Item, !Specs) :-
     Pieces = [words("A Mercury source file")] ++
diff --git a/compiler/cse_detection.m b/compiler/cse_detection.m
index cdeaf324b..e353faac2 100644
--- a/compiler/cse_detection.m
+++ b/compiler/cse_detection.m
@@ -251,7 +251,7 @@ detect_cse_in_proc(MaybeProgressStream, PassNum, PredId, ProcId,
                     MaybeProgressStream = no
                 ),
                 get_debug_output_stream(!.ModuleInfo, DebugStream, !IO),
-                write_error_specs(DebugStream, Globals, ModeSpecs, !IO)
+                write_diag_specs(DebugStream, Globals, ModeSpecs, !IO)
             ),
             unexpected($pred, "mode check fails when repeated")
         ;
diff --git a/compiler/d_file_deps.m b/compiler/d_file_deps.m
index f1bd40840..976a5ea4f 100644
--- a/compiler/d_file_deps.m
+++ b/compiler/d_file_deps.m
@@ -68,8 +68,7 @@
 
 :- pred compute_dep_graphs_gendep(io.text_output_stream::in, globals::in,
     module_name::in, deps_map::in, dep_graphs::out, list(burdened_module)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    io::di, io::uo) is det.
+    list(err_spec)::out, list(warn_spec)::out, io::di, io::uo) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -195,7 +194,7 @@
 %---------------------------------------------------------------------------%
 
 compute_dep_graphs_gendep(ProgressStream, Globals, ModuleName, DepsMap,
-        DepGraphs, BurdenedModules, !Specs, !IO) :-
+        DepGraphs, BurdenedModules, ErrSpecs, WarnSpecs, !IO) :-
     % Compute the interface and implementation deps graphs from the deps map.
     map.values(DepsMap, DepsList),
     digraph.init(IntDepsGraph0),
@@ -222,7 +221,7 @@ compute_dep_graphs_gendep(ProgressStream, Globals, ModuleName, DepsMap,
 
     compute_opt_trans_opt_deps_graph(ProgressStream, Globals, ModuleName,
         ImpDepsGraph, IndirectOptDepsGraph,
-        TransOptDepsGraph, TransOptDepsOrdering, !Specs, !IO),
+        TransOptDepsGraph, TransOptDepsOrdering, ErrSpecs, WarnSpecs, !IO),
 
     % Compute the indirect dependencies: they are equal to the composition
     % of the implementation dependencies with the transitive closure of the
diff --git a/compiler/decide_type_repn.m b/compiler/decide_type_repn.m
index ad96dfcdc..17027b678 100644
--- a/compiler/decide_type_repn.m
+++ b/compiler/decide_type_repn.m
@@ -155,7 +155,7 @@
     type_ctor_checked_map::in,
     map(module_name, direct_int3_spec)::in,
     map(module_name, indirect_int3_spec)::in,
-    type_ctor_repn_map::out, list(diag_spec)::out) is det.
+    type_ctor_repn_map::out, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -772,7 +772,7 @@ record_type_repn_in_parse_tree_int3(ModuleName, TypeCtor0, ItemTypeRepnInfo,
     set_tree234(type_ctor)::in, simple_du_map::in,
     type_ctor::in, type_ctor_checked_defn::in,
     type_ctor_repn_map::in, type_ctor_repn_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 decide_all_type_repns_stage_2(BaseParams, EqvRepnMap, EqvMap, SubtypeMap,
         WordAlignedTypeCtorsC, SimpleDuMap, TypeCtor, CheckedDefn,
@@ -825,7 +825,7 @@ decide_all_type_repns_stage_2(BaseParams, EqvRepnMap, EqvMap, SubtypeMap,
     subtype_repn_map::in, set_tree234(type_ctor)::in, simple_du_map::in,
     type_ctor::in, item_type_defn_info_du::in, c_j_cs_maybe_defn::in,
     type_ctor_repn_map::in, type_ctor_repn_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 decide_type_repns_stage_2_du_gen(BaseParams, EqvMap, SubtypeMap,
         WordAlignedTypeCtorsC, SimpleDuMap, TypeCtor, DuDefn, MaybeDefnCJCs,
@@ -2287,7 +2287,7 @@ is_direct_arg_ctor_for_c(WordAlignedTypeCtorsC, ClassifiedCtor) :-
 :- pred expand_eqv_sub_of_notag_types_in_constructors(type_eqv_map::in,
     subtype_repn_map::in, simple_du_map::in, tvarset::in,
     list(constructor)::in, list(constructor)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 expand_eqv_sub_of_notag_types_in_constructors(_, _, _, _, [], [], !Specs).
 expand_eqv_sub_of_notag_types_in_constructors(EqvMap, SubtypeMap, SimpleDuMap,
@@ -2300,7 +2300,7 @@ expand_eqv_sub_of_notag_types_in_constructors(EqvMap, SubtypeMap, SimpleDuMap,
 :- pred expand_eqv_sub_of_notag_types_in_constructor(type_eqv_map::in,
     subtype_repn_map::in, simple_du_map::in, tvarset::in,
     constructor::in, constructor::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 expand_eqv_sub_of_notag_types_in_constructor(EqvMap, SubtypeMap, SimpleDuMap,
         TVarSet, Ctor0, Ctor, !Specs) :-
@@ -2321,7 +2321,7 @@ expand_eqv_sub_of_notag_types_in_constructor(EqvMap, SubtypeMap, SimpleDuMap,
     subtype_repn_map::in, simple_du_map::in, tvarset::in,
     list(constructor_arg)::in, list(constructor_arg)::out,
     maybe_changed::in, maybe_changed::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 expand_eqv_sub_of_notag_types_in_constructor_args(_, _, _, _, [], [],
         !Changed, !Specs).
@@ -2347,7 +2347,7 @@ expand_eqv_sub_of_notag_types_in_constructor_args(TypeEqvMap, SubtypeMap,
 :- pred expand_eqv_sub_of_notag_type_fixpoint(type_eqv_map::in,
     subtype_repn_map::in, simple_du_map::in, tvarset::in, prog_context::in,
     int::in, mer_type::in, mer_type::out, maybe_changed::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 expand_eqv_sub_of_notag_type_fixpoint(TypeEqvMap, SubtypeMap, SimpleDuMap,
         TVarSet0, Context, IterationsLeft, Type0, Type, Changed, !Specs) :-
diff --git a/compiler/deps_map.m b/compiler/deps_map.m
index 138c2882f..01784c881 100644
--- a/compiler/deps_map.m
+++ b/compiler/deps_map.m
@@ -51,7 +51,8 @@
 
 :- pred generate_deps_map(io.text_output_stream::in, globals::in,
     maybe_search::in, file_or_module::in, module_name::out,
-    deps_map::out, list(diag_spec)::out, io::di, io::uo) is det.
+    deps_map::out, list(err_spec)::out, list(warn_spec)::out,
+    io::di, io::uo) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -75,15 +76,16 @@
 %---------------------------------------------------------------------------%
 
 generate_deps_map(ProgressStream, Globals, Search, FileOrModule, ModuleName,
-        !:DepsMap, !:Specs, !IO) :-
+        !:DepsMap, !:ErrSpecs, !:WarnSpecs, !IO) :-
     (
         FileOrModule = fm_module(ModuleName),
         map.init(!:DepsMap),
-        !:Specs = []
+        !:ErrSpecs = [],
+        !:WarnSpecs = []
     ;
         FileOrModule = fm_file(FileName),
         build_initial_deps_map_for_file(ProgressStream, Globals,
-            FileName, ModuleName, !:DepsMap, !:Specs, !IO)
+            FileName, ModuleName, !:DepsMap, !:ErrSpecs, !:WarnSpecs, !IO)
     ),
     CmdLineModuleName = ModuleName,
     SeenModules0 = set_tree234.init,
@@ -93,7 +95,7 @@ generate_deps_map(ProgressStream, Globals, Search, FileOrModule, ModuleName,
     generate_deps_map_loop(ProgressStream, Globals, Search, CmdLineModuleName,
         SeenModules0, ModuleExpectationContexts0,
         ReadModules0, ReadModules, UnreadModules0, UnreadModules1,
-        !DepsMap, !Specs, !IO),
+        !DepsMap, !ErrSpecs, !WarnSpecs, !IO),
     % When module mod_a.mod_b is nested inside mod_a.m, the source file
     % containing module mod_a, then it is possible for an attempt to read
     % mod_a.mod_b.m to fail (since module mod_a.mod_b is not there),
@@ -119,16 +121,16 @@ generate_deps_map(ProgressStream, Globals, Search, FileOrModule, ModuleName,
         io.write_line(ProgressStream, UnreadStrs, !TIO)
     ),
     warn_about_any_unread_modules_with_read_ancestors(ReadModules,
-        UnreadModules, !Specs).
+        UnreadModules, !WarnSpecs).
 
 %---------------------------------------------------------------------------%
 
 :- pred build_initial_deps_map_for_file(io.text_output_stream::in, globals::in,
-    file_name::in, module_name::out, deps_map::out, list(diag_spec)::out,
-    io::di, io::uo) is det.
+    file_name::in, module_name::out, deps_map::out,
+    list(err_spec)::out, list(warn_spec)::out, io::di, io::uo) is det.
 
 build_initial_deps_map_for_file(ProgressStream, Globals, FileName, ModuleName,
-        DepsMap, Specs, !IO) :-
+        DepsMap, ErrSpecs, WarnSpecs, !IO) :-
     % Read in the top-level file (to figure out its module name).
     FileNameDotM = FileName ++ ".m",
     read_module_src_from_file(ProgressStream, Globals, FileName, FileNameDotM,
@@ -140,13 +142,13 @@ build_initial_deps_map_for_file(ProgressStream, Globals, FileName, ModuleName,
         ParseTreeSrc = parse_tree_src(ModuleName, _, _),
         parse_tree_src_to_burdened_module_list(Globals, FileNameDotM,
             ReadModuleErrors, MaybeTimestamp, ParseTreeSrc,
-            Specs, BurdenedModules)
+            ErrSpecs, WarnSpecs, BurdenedModules)
     ;
         HaveReadModuleSrc = have_not_read_module(_, ReadModuleErrors),
         get_default_module_name_for_file(FileName, FileNameDotM,
             ModuleName, !IO),
         % XXX Caller should not need this info.
-        Specs = get_read_module_specs(ReadModuleErrors),
+        get_read_module_specs(ReadModuleErrors, ErrSpecs, WarnSpecs),
         BurdenedModules = []
     ),
     map.init(DepsMap0),
@@ -168,20 +170,22 @@ build_initial_deps_map_for_file(ProgressStream, Globals, FileName, ModuleName,
     expectation_contexts_map::in,
     set_tree234(module_name)::in, set_tree234(module_name)::out,
     set_tree234(module_name)::in, set_tree234(module_name)::out,
-    deps_map::in, deps_map::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    deps_map::in, deps_map::out, list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out, io::di, io::uo) is det.
 
 generate_deps_map_loop(ProgressStream, Globals, Search, CmdLineModuleName,
-        !.SeenModules, !.ModuleExpCs, !ReadModules, !UnreadModules,
-        !DepsMap, !Specs, !IO) :-
+        !.SeenModules, !.ModuleExpCs, !ReadModules, !UnreadModules, !DepsMap,
+        !ErrSpecs, !WarnSpecs, !IO) :-
     ( if map.remove_smallest(Module, ExpectationContexts, !ModuleExpCs) then
         set_tree234.insert(Module, !SeenModules),
         generate_deps_map_step(ProgressStream, Globals, Search,
             CmdLineModuleName, Module, ExpectationContexts, !.SeenModules,
-            !ModuleExpCs, !ReadModules, !UnreadModules, !DepsMap, !Specs, !IO),
+            !ModuleExpCs, !ReadModules, !UnreadModules, !DepsMap,
+            !ErrSpecs, !WarnSpecs, !IO),
         generate_deps_map_loop(ProgressStream, Globals, Search,
             CmdLineModuleName, !.SeenModules, !.ModuleExpCs,
-            !ReadModules, !UnreadModules, !DepsMap, !Specs, !IO)
+            !ReadModules, !UnreadModules, !DepsMap, !ErrSpecs,
+            !WarnSpecs, !IO)
     else
         % If we can't remove the smallest, then the set of modules to be
         % processed is empty.
@@ -215,17 +219,17 @@ generate_deps_map_loop(ProgressStream, Globals, Search, CmdLineModuleName,
     expectation_contexts_map::in, expectation_contexts_map::out,
     set_tree234(module_name)::in, set_tree234(module_name)::out,
     set_tree234(module_name)::in, set_tree234(module_name)::out,
-    deps_map::in, deps_map::out, list(diag_spec)::in, list(diag_spec)::out,
-    io::di, io::uo) is det.
+    deps_map::in, deps_map::out, list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out, io::di, io::uo) is det.
 
 generate_deps_map_step(ProgressStream, Globals, Search, CmdLineModuleName,
         Module, ExpectationContexts, SeenModules0, !ModuleExpCs,
-        !ReadModules, !UnreadModules, !DepsMap, !Specs, !IO) :-
+        !ReadModules, !UnreadModules, !DepsMap, !ErrSpecs, !WarnSpecs, !IO) :-
     % Look up the module's dependencies, and determine whether
     % it has been processed yet.
     lookup_or_find_dependency_info_for_module(ProgressStream, Globals, Search,
         CmdLineModuleName, Module, ExpectationContexts, MaybeDeps0,
-        NewBurdenedModules, !DepsMap, !Specs, !IO),
+        NewBurdenedModules, !DepsMap, !ErrSpecs, !WarnSpecs, !IO),
     update_read_unread_modules(ProgressStream, Module,
         MaybeDeps0, NewBurdenedModules, !ReadModules, !UnreadModules),
 
@@ -391,19 +395,20 @@ add_module_name_and_context(SeenModules0, Context, ModuleName, !ModuleExpCs) :-
 :- pred lookup_or_find_dependency_info_for_module(io.text_output_stream::in,
     globals::in, maybe_search::in, module_name::in, module_name::in,
     expectation_contexts::in, maybe(deps)::out, list(burdened_module)::out,
-    deps_map::in, deps_map::out, list(diag_spec)::in, list(diag_spec)::out,
-    io::di, io::uo) is det.
+    deps_map::in, deps_map::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out, io::di, io::uo) is det.
 
 lookup_or_find_dependency_info_for_module(ProgressStream, Globals, Search,
         CmdLineModuleName, ModuleName, ExpectationContexts, MaybeDeps,
-        NewBurdenedModules, !DepsMap, !Specs, !IO) :-
+        NewBurdenedModules, !DepsMap, !ErrSpecs, !WarnSpecs, !IO) :-
     ( if map.search(!.DepsMap, ModuleName, Deps) then
         MaybeDeps = yes(Deps),
         NewBurdenedModules = []
     else
         read_module_src_file_for_dependency_info(ProgressStream, Globals,
             Search, CmdLineModuleName, ModuleName, ExpectationContexts,
-            NewBurdenedModules, !Specs, !IO),
+            NewBurdenedModules, !ErrSpecs, !WarnSpecs, !IO),
         (
             NewBurdenedModules = [_ | _],
             list.foldl(insert_into_deps_map, NewBurdenedModules, !DepsMap),
@@ -462,11 +467,12 @@ insert_into_deps_map(BurdenedModule, !DepsMap) :-
 :- pred read_module_src_file_for_dependency_info(io.text_output_stream::in,
     globals::in, maybe_search::in, module_name::in, module_name::in,
     expectation_contexts::in, list(burdened_module)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out, io::di, io::uo) is det.
 
 read_module_src_file_for_dependency_info(ProgressStream, Globals, Search,
         CmdLineModuleName, ModuleName, ExpectationContexts,
-        BurdenedModules, !Specs, !IO) :-
+        BurdenedModules, !ErrSpecs, !WarnSpecs, !IO) :-
     % XXX If HaveReadModuleSrc contains error messages, any parse tree
     % it may also contain may not be complete, and the rest of this predicate
     % may work on incorrect data.
@@ -478,8 +484,9 @@ read_module_src_file_for_dependency_info(ProgressStream, Globals, Search,
         Source = was_read(MaybeTimestamp, ReadModuleErrors),
         parse_tree_src_to_burdened_module_list(Globals, SourceFileName,
             ReadModuleErrors, MaybeTimestamp, ParseTreeSrc,
-            Specs, BurdenedModules),
-        !:Specs = Specs ++ !.Specs
+            BmErrSpecs, BmWarnSpecs, BurdenedModules),
+        !:ErrSpecs = BmErrSpecs ++ !.ErrSpecs,
+        !:WarnSpecs = BmWarnSpecs ++ !.WarnSpecs
     ;
         HaveReadModuleSrc = have_not_read_module(_SourceFileName,
             ReadModuleErrors),
@@ -488,8 +495,9 @@ read_module_src_file_for_dependency_info(ProgressStream, Globals, Search,
             % The module we cannot read is named on the command line.
             % The user will definitely be interested in the fact that
             % we cannot read it.
-            Specs = get_read_module_specs(ReadModuleErrors),
-            !:Specs = Specs ++ !.Specs
+            get_read_module_specs(ReadModuleErrors, RmErrSpecs, RmWarnSpecs),
+            !:ErrSpecs = RmErrSpecs ++ !.ErrSpecs,
+            !:WarnSpecs = RmWarnSpecs ++ !.WarnSpecs
         else
             % The module is NOT named on the command line, but merely
             % imported directly or (more likely) indirectly by it.
diff --git a/compiler/det_check_proc.m b/compiler/det_check_proc.m
index d39a5a360..4a5f7272b 100644
--- a/compiler/det_check_proc.m
+++ b/compiler/det_check_proc.m
@@ -251,7 +251,7 @@ check_for_too_tight_or_loose_declared_determinism(PredProcId,
                 report_determinism_problem(!.ModuleInfo, PredProcId,
                     "Warning", "could be tighter", [],
                     DeclaredDetism, InferredDetism, ReportMsg),
-                ReportSpec = diag_spec($pred,
+                ReportSpec = gen_spec($pred,
                     severity_warning(warn_det_decls_too_lax),
                     phase_detism_check, [ReportMsg]),
                 !:Specs = [ReportSpec | !.Specs]
@@ -287,7 +287,7 @@ check_for_too_tight_or_loose_declared_determinism(PredProcId,
             report_determinism_problem(!.ModuleInfo, PredProcId,
                 "Error", "is not satisfied", ReasonPieces,
                 DeclaredDetism, InferredDetism, ReportMsg),
-            ReportSpec = diag_spec($pred, severity_error, phase_detism_check,
+            ReportSpec = gen_spec($pred, severity_error, phase_detism_check,
                 [ReportMsg | start_each_msg_with_blank_line(DetailMsgs)]),
             !:Specs = [ReportSpec | !.Specs]
         )
@@ -453,7 +453,7 @@ check_determinism_for_eval_method(ProcInfo, !Specs) :-
             [words("This pragma is valid only for the following"),
             words(choose_number(Detisms, "determinism", "determinisms")),
             suffix(":") | DetismPieces] ++ [nl],
-        ValidSpec = diag_spec($pred, severity_error, phase_detism_check,
+        ValidSpec = gen_spec($pred, severity_error, phase_detism_check,
             [simple_msg(Context,
                 [always(MainPieces),
                 verbose_only(verbose_always, VerbosePieces)])]),
@@ -698,7 +698,7 @@ report_multisoln_func(ModuleInfo, PredProcId, ProcInfo, InferredDetism)
         color_as_incorrect([quote((InferredDetismStr)), suffix(".")]) ++
         [nl],
     VerbosePieces = func_primary_mode_det_msg,
-    Spec = diag_spec($pred, severity_error, phase_detism_check,
+    Spec = gen_spec($pred, severity_error, phase_detism_check,
         [simple_msg(Context,
             [always(MainPieces),
             verbose_only(verbose_once, VerbosePieces)])]).
diff --git a/compiler/det_check_switch.m b/compiler/det_check_switch.m
index 1333a2786..0b68330df 100644
--- a/compiler/det_check_switch.m
+++ b/compiler/det_check_switch.m
@@ -499,7 +499,7 @@ generate_incomplete_switch_spec(Why, MaybeLimit, InstMap0, SwitchContexts,
     (
         MaybeSeverityComponents = yes({Severity, SpecComponents}),
         Msg = simple_msg(Context, SpecComponents),
-        Spec = diag_spec($pred, Severity, phase_detism_check, [Msg]),
+        Spec = gen_spec($pred, Severity, phase_detism_check, [Msg]),
         det_info_add_diag_spec(Spec, !DetInfo)
     ;
         MaybeSeverityComponents = no
@@ -761,7 +761,7 @@ reqscope_check_goal_detism(RequiredDetism, Goal, CheckKind, InstMap0,
         Msg = msg(Context, Pieces),
         det_diagnose_goal_get_msgs(InstMap0, RequiredDetism, Goal,
             SubMsgs, !DetInfo),
-        Spec = diag_spec($pred, severity_error, phase_detism_check,
+        Spec = gen_spec($pred, severity_error, phase_detism_check,
             [Msg | SubMsgs]),
         det_info_add_diag_spec(Spec, !DetInfo)
     ).
diff --git a/compiler/det_infer_goal.m b/compiler/det_infer_goal.m
index 8cf77d0cc..63701c6ac 100644
--- a/compiler/det_infer_goal.m
+++ b/compiler/det_infer_goal.m
@@ -618,7 +618,7 @@ det_check_lambda(DeclaredDetism, InferredDetism, Goal, GoalInfo, InstMap0,
             [words("inferred")] ++ InferredPieces ++ [nl],
         det_diagnose_goal_get_msgs(InstMap0, DeclaredDetism, Goal,
             GoalMsgs, !DetInfo),
-        Spec = diag_spec($pred, severity_error, phase_detism_check,
+        Spec = gen_spec($pred, severity_error, phase_detism_check,
             [msg(Context, Pieces) | GoalMsgs]),
         det_info_add_diag_spec(Spec, !DetInfo)
     ;
@@ -681,7 +681,7 @@ det_infer_call(SolnContext, GoalInfo, PredId, ArgVars,
                 [nl],
             ContextMsgs = failing_contexts_description(ModuleInfo, VarTable,
                 RightFailingContexts),
-            Spec = diag_spec($pred, severity_error, phase_detism_check,
+            Spec = gen_spec($pred, severity_error, phase_detism_check,
                 [msg(GoalContext, FirstPieces) | ContextMsgs]),
             det_info_add_diag_spec(Spec, !DetInfo),
 
@@ -766,7 +766,7 @@ det_infer_generic_call(SolnContext, GoalInfo, GenericCall, CallDetism, Detism,
         det_info_get_module_info(!.DetInfo, ModuleInfo),
         ContextMsgs = failing_contexts_description(ModuleInfo, VarTable,
             RightFailingContexts),
-        Spec = diag_spec($pred, severity_error, phase_detism_check,
+        Spec = gen_spec($pred, severity_error, phase_detism_check,
             [msg(Context, FirstPieces) | ContextMsgs]),
         det_info_add_diag_spec(Spec, !DetInfo),
 
@@ -846,7 +846,7 @@ det_infer_foreign_proc(Attributes, PredId, ProcId, _PragmaCode,
                 [nl],
             ContextMsgs = failing_contexts_description(ModuleInfo, VarTable,
                 RightFailingContexts),
-            Spec = diag_spec($pred, severity_error, phase_detism_check,
+            Spec = gen_spec($pred, severity_error, phase_detism_check,
                 [msg(GoalContext, WrongContextFirstPieces) | ContextMsgs]),
             det_info_add_diag_spec(Spec, !DetInfo),
             NumSolns = at_most_many
@@ -986,7 +986,7 @@ det_infer_par_conj(InstMap0, SolnContext, MaybePromiseEqvSolutionSets,
             GoalMsgGroups, !DetInfo),
         sort_diag_msg_groups(GoalMsgGroups, SortedGoalMsgGroups),
         SortedGoalMsgs = flatten_diag_msg_groups(SortedGoalMsgGroups),
-        Spec = diag_spec($pred, severity_error, phase_detism_check,
+        Spec = gen_spec($pred, severity_error, phase_detism_check,
             [msg(Context, Pieces)] ++ SortedGoalMsgs),
         det_info_add_diag_spec(Spec, !DetInfo)
     ).
@@ -1359,7 +1359,7 @@ det_infer_scope(InstMap0, SolnContext, MaybePromiseEqvSolutionSets0,
                     quote("promise_equivalent_solution_sets"),
                     words("scope."), nl],
                 NestedSeverity = severity_warning(warn_dodgy_simple_code),
-                NestedSpec = diag_spec($pred,
+                NestedSpec = gen_spec($pred,
                     NestedSeverity, phase_detism_check,
                     [msg(Context, NestedPieces),
                     msg(OuterContext, NestedOuterPieces)]),
@@ -1414,7 +1414,7 @@ det_infer_scope(InstMap0, SolnContext, MaybePromiseEqvSolutionSets0,
                     OverlapPromisePieces = [words("This is the outer"),
                         quote("promise_equivalent_solution_sets"),
                         words("scope."), nl],
-                    OverlapSpec = diag_spec($pred, severity_error,
+                    OverlapSpec = gen_spec($pred, severity_error,
                         phase_detism_check,
                         [msg(Context, OverlapPieces),
                         msg(PromiseContext, OverlapPromisePieces)]),
@@ -1771,7 +1771,7 @@ det_check_for_noncanonical_type(Var, ExaminesRepresentation, CanFail,
                 words("Figuring out whether there is a solution"),
                 words("to this unification")] ++
                 noncanon_unify_verbose_would_require,
-            Spec = diag_spec($pred, severity_error, phase_detism_check,
+            Spec = gen_spec($pred, severity_error, phase_detism_check,
                 [simple_msg(Context,
                     [always(Pieces0 ++ Pieces1),
                     verbose_only(verbose_once, VerbosePieces)])]),
@@ -1808,7 +1808,7 @@ det_check_for_noncanonical_type(Var, ExaminesRepresentation, CanFail,
                 det_info_get_module_info(!.DetInfo, ModuleInfo),
                 ContextMsgs = failing_contexts_description(ModuleInfo,
                     VarTable, FailingContextsA ++ FailingContextsB),
-                Spec = diag_spec($pred, severity_error, phase_detism_check,
+                Spec = gen_spec($pred, severity_error, phase_detism_check,
                     [simple_msg(Context,
                         [always(Pieces0 ++ Pieces1),
                         verbose_only(verbose_once, VerbosePieces)])]
diff --git a/compiler/du_type_layout.m b/compiler/du_type_layout.m
index 1448281bf..79144b62f 100644
--- a/compiler/du_type_layout.m
+++ b/compiler/du_type_layout.m
@@ -102,7 +102,7 @@
 :- import_module list.
 
 :- pred decide_type_repns(module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::out, list(info_spec)::out, io::di, io::uo) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -150,7 +150,7 @@
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
 
-decide_type_repns(!ModuleInfo, !Specs, !IO) :-
+decide_type_repns(!ModuleInfo, !:ErrSpecs, !:InfoSpecs, !IO) :-
     module_info_get_type_repn_dec(!.ModuleInfo, TypeRepnDec),
     TypeRepnDec = type_repn_decision_data(_TypeRepns, _DirectArgMap,
         _ForeignEnums, ForeignExportEnums),
@@ -158,24 +158,28 @@ decide_type_repns(!ModuleInfo, !Specs, !IO) :-
     module_info_get_type_table(!.ModuleInfo, TypeTable0),
     get_all_type_ctor_defns(TypeTable0, TypeCtorsTypeDefns0),
 
+    !:ErrSpecs = [],
+    !:InfoSpecs = [],
     module_info_get_globals(!.ModuleInfo, Globals),
     globals.lookup_bool_option(Globals, experiment2, Experiment2),
     (
         Experiment2 = no,
         decide_type_repns_old(!.ModuleInfo, TypeRepnDec, TypeTable0,
-            TypeCtorsTypeDefns0, TypeCtorsTypeDefns, NoTagTypeMap, !Specs),
+            TypeCtorsTypeDefns0, TypeCtorsTypeDefns, NoTagTypeMap,
+            !ErrSpecs, !InfoSpecs),
         set_all_type_ctor_defns(TypeCtorsTypeDefns,
             SortedTypeCtorsTypeDefns, TypeTable)
     ;
         Experiment2 = yes,
         decide_type_repns_old(!.ModuleInfo, TypeRepnDec, TypeTable0,
-            TypeCtorsTypeDefns0, TypeCtorsTypeDefns, NoTagTypeMap, !Specs),
+            TypeCtorsTypeDefns0, TypeCtorsTypeDefns, NoTagTypeMap,
+            !ErrSpecs, !InfoSpecs),
         set_all_type_ctor_defns(TypeCtorsTypeDefns,
             SortedTypeCtorsTypeDefns, TypeTable),
         module_info_get_name(!.ModuleInfo, ModuleName),
         decide_type_repns_new(Globals, ModuleName, TypeRepnDec,
             TypeCtorsTypeDefns0, TypeCtorsTypeDefnsB,
-            NoTagTypeMapB, UnRepnTypeCtors, BadRepnTypeCtors, !Specs),
+            NoTagTypeMapB, UnRepnTypeCtors, BadRepnTypeCtors, !ErrSpecs),
         set_all_type_ctor_defns(TypeCtorsTypeDefnsB,
             SortedTypeCtorsTypeDefnsB, _TypeTableB),
         get_debug_output_stream(!.ModuleInfo, DebugStream, !IO),
@@ -191,7 +195,7 @@ decide_type_repns(!ModuleInfo, !Specs, !IO) :-
         SortedTypeCtorsTypeDefns, !ModuleInfo),
 
     list.foldl2(add_pragma_foreign_export_enum, ForeignExportEnums,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
 
     maybe_show_type_repns(!.ModuleInfo, SortedTypeCtorsTypeDefns, !IO).
 
@@ -219,7 +223,7 @@ decide_type_repns(!ModuleInfo, !Specs, !IO) :-
     assoc_list(type_ctor, hlds_type_defn)::in,
     assoc_list(type_ctor, hlds_type_defn)::out,
     no_tag_type_table::out, set(type_ctor)::out, set(type_ctor)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 decide_type_repns_new(Globals, ModuleName, TypeRepnDec, !TypeCtorsTypeDefns,
         NoTagTypeMap, UnRepnTypeCtors, BadRepnTypeCtors, !Specs) :-
@@ -260,7 +264,7 @@ decide_type_repns_new(Globals, ModuleName, TypeRepnDec, !TypeCtorsTypeDefns,
     no_tag_type_table::in, no_tag_type_table::out,
     set(type_ctor)::in, set(type_ctor)::out,
     set(type_ctor)::in, set(type_ctor)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 fill_in_non_sub_type_repn(Globals, ModuleName, RepnTarget, TypeCtorRepnMap,
         TypeCtorTypeDefn0, TypeCtorTypeDefn,
@@ -441,7 +445,7 @@ fill_in_non_sub_type_repn(Globals, ModuleName, RepnTarget, TypeCtorRepnMap,
 :- type maybe_du_type_repn
     --->    have_du_type_repn(du_type_repn)
     ;       have_foreign_type_repn(foreign_type_body)
-    ;       have_errors(list(diag_spec)).
+    ;       have_errors(list(err_spec)).
 
 %---------------------%
 
@@ -907,7 +911,7 @@ check_and_record_non_sub_du_more_functors(RepnTarget, TypeCtor, Context,
 
 :- pred check_non_sub_gen_du_functor(type_ctor::in,
     pair(constructor, gen_du_functor_repn)::in, uint32::in, uint32::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_non_sub_gen_du_functor(TypeCtor, Ctor - GenDuFunctorRepn,
         !ExpectedOrdinal, !Specs) :-
@@ -924,7 +928,7 @@ check_non_sub_gen_du_functor(TypeCtor, Ctor - GenDuFunctorRepn,
     !:ExpectedOrdinal = !.ExpectedOrdinal + 1u32.
 
 :- pred check_non_sub_du_functor(type_ctor::in, constructor::in, string::in,
-    int::in, uint32::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    int::in, uint32::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 check_non_sub_du_functor(TypeCtor, Ctor, RepnCtorName, RepnCtorArity,
         ExpectedOrdinal, !Specs) :-
@@ -1722,10 +1726,12 @@ compare_old_new_notag_type_ctor(Stream, OldNoTagTypeTable, NewNoTagTypeTable,
     type_repn_decision_data::in, type_table::in,
     assoc_list(type_ctor, hlds_type_defn)::in,
     assoc_list(type_ctor, hlds_type_defn)::out, no_tag_type_table::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(info_spec)::in, list(info_spec)::out) is det.
 
 decide_type_repns_old(ModuleInfo, TypeRepnDec, TypeTable0,
-        TypeCtorsTypeDefns0, TypeCtorsTypeDefns, NoTagTypeMap, !Specs) :-
+        TypeCtorsTypeDefns0, TypeCtorsTypeDefns, NoTagTypeMap,
+        !ErrSpecs, !InfoSpecs) :-
     TypeRepnDec = type_repn_decision_data(_TypeRepns, DirectArgMap,
         ForeignEnums, _ForeignExportEnums),
     module_info_get_globals(ModuleInfo, Globals),
@@ -1733,7 +1739,7 @@ decide_type_repns_old(ModuleInfo, TypeRepnDec, TypeTable0,
     setup_decide_du_params(Globals, ModuleName, DirectArgMap, Params),
 
     list.foldl2(add_pragma_foreign_enum(ModuleInfo), ForeignEnums,
-        map.init, TypeCtorToForeignEnumMap, !Specs),
+        map.init, TypeCtorToForeignEnumMap, !ErrSpecs),
 
     % Pass 1.
     map.init(ComponentTypeMap0),
@@ -1745,7 +1751,7 @@ decide_type_repns_old(ModuleInfo, TypeRepnDec, TypeTable0,
         [], NonSubTypeCtorsTypeDefns1,
         [], SubTypeCtorsTypeDefns1,
         ComponentTypeMap0, ComponentTypeMap1,
-        NoTagTypeMap0, NoTagTypeMap1, !Specs),
+        NoTagTypeMap0, NoTagTypeMap1, !ErrSpecs),
 
     % Pass 1b.
     list.foldl2(decide_if_subtype_of_simple_du_type(TypeTable0),
@@ -1754,10 +1760,11 @@ decide_type_repns_old(ModuleInfo, TypeRepnDec, TypeTable0,
         NoTagTypeMap1, NoTagTypeMap),
 
     % Pass 2.
-    list.map_foldl(
+    list.map_foldl2(
         decide_if_complex_non_sub_du_type(ModuleInfo, Params,
             ComponentTypeMap),
-        NonSubTypeCtorsTypeDefns1, NonSubTypeCtorsTypeDefns2, !Specs),
+        NonSubTypeCtorsTypeDefns1, NonSubTypeCtorsTypeDefns2,
+        !ErrSpecs, !InfoSpecs),
 
     % Pass 2b.
     list.map(decide_if_subtype(TypeTable0, NonSubTypeCtorsTypeDefns2),
@@ -1813,7 +1820,7 @@ add_special_pred_decl_defns_for_types_maybe_lazily(
     assoc_list(type_ctor, hlds_type_defn)::out,
     component_type_map::in, component_type_map::out,
     no_tag_type_table::in, no_tag_type_table::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 decide_if_simple_du_type(ModuleInfo, Params, TypeCtorToForeignEnumMap,
         TypeCtorTypeDefn0, !NonSubTypeCtorTypeDefns, !SubTypeCtorsTypeDefns,
@@ -1937,7 +1944,7 @@ decide_if_simple_du_type(ModuleInfo, Params, TypeCtorToForeignEnumMap,
     type_ctor::in, hlds_type_defn::in, type_body_du::in,
     one_or_more(constructor)::in, {du_ctor_to_tag_map, foreign_language}::in,
     pair(type_ctor, hlds_type_defn)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 decide_simple_type_foreign_enum(_ModuleInfo, Params, TypeCtor, TypeDefn0,
         BodyDu0, OoMCtors, ForeignEnums, TypeCtorTypeDefn, !Specs) :-
@@ -2013,7 +2020,7 @@ add_dummy_repn_to_foreign_enum_ctor_arg(ConsArg) = ConsArgRepn :-
     type_body_du::in, one_or_more(constructor)::in,
     pair(type_ctor, hlds_type_defn)::out,
     component_type_map::in, component_type_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 decide_simple_type_dummy_or_mercury_enum(_ModuleInfo, Params,
         TypeCtor, TypeDefn0, BodyDu0, OoMCtors, TypeCtorTypeDefn,
@@ -2087,7 +2094,7 @@ assign_tags_to_enum_constants([Ctor | Ctors], [CtorRepn | CtorRepns],
     sym_name::in, constructor_arg::in, prog_context::in,
     pair(type_ctor, hlds_type_defn)::out,
     no_tag_type_table::in, no_tag_type_table::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 decide_simple_type_non_sub_notag(_ModuleInfo, Params,
         TypeCtor, TypeDefn0, BodyDu0,
@@ -2201,7 +2208,7 @@ add_du_if_single_ctor_is_word_aligned_ptr(Params, TypeCtor, TypeDefn,
     type_ctor::in, foreign_type_body::in,
     maybe_require_foreign_type_for_target::in,
     component_type_map::in, component_type_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_foreign_if_word_aligned_ptr(ModuleInfo, Params, TypeCtor,
         ForeignType, MaybeRequireForTarget, !ComponentTypeMap, !Specs) :-
@@ -2403,10 +2410,11 @@ maybe_copy_no_tag_type_from_base(BaseTypeCtor, TypeCtor, TypeParams0,
 :- pred decide_if_complex_non_sub_du_type(module_info::in,
     decide_du_params::in, component_type_map::in,
     pair(type_ctor, hlds_type_defn)::in, pair(type_ctor, hlds_type_defn)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(info_spec)::in, list(info_spec)::out) is det.
 
 decide_if_complex_non_sub_du_type(ModuleInfo, Params, ComponentTypeMap,
-        TypeCtorTypeDefn0, TypeCtorTypeDefn, !Specs) :-
+        TypeCtorTypeDefn0, TypeCtorTypeDefn, !ErrSpecs, !InfoSpecs) :-
     TypeCtorTypeDefn0 = TypeCtor - TypeDefn0,
     get_type_defn_body(TypeDefn0, Body0),
     (
@@ -2424,7 +2432,7 @@ decide_if_complex_non_sub_du_type(ModuleInfo, Params, ComponentTypeMap,
             MaybeRepn0 = no,
             decide_complex_non_sub_du_type(ModuleInfo, Params,
                 ComponentTypeMap, TypeCtor, TypeDefn0,
-                one_or_more_to_list(Ctors), Repn, !Specs),
+                one_or_more_to_list(Ctors), Repn, !ErrSpecs, !InfoSpecs),
             BodyDu = BodyDu0 ^ du_type_repn := yes(Repn),
             Body = hlds_du_type(BodyDu),
             set_type_defn_body(Body, TypeDefn0, TypeDefn),
@@ -2443,17 +2451,19 @@ decide_if_complex_non_sub_du_type(ModuleInfo, Params, ComponentTypeMap,
 :- pred decide_complex_non_sub_du_type(module_info::in, decide_du_params::in,
     component_type_map::in, type_ctor::in, hlds_type_defn::in,
     list(constructor)::in, du_type_repn::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(info_spec)::in, list(info_spec)::out) is det.
 
 decide_complex_non_sub_du_type(ModuleInfo, Params, ComponentTypeMap, TypeCtor,
-        TypeDefn0, Ctors, Repn, !Specs) :-
+        TypeDefn0, Ctors, Repn, !ErrSpecs, !InfoSpecs) :-
     get_type_defn_status(TypeDefn0, TypeStatus),
     ( if Ctors = [SingleCtor] then
         decide_complex_non_sub_du_type_single_ctor(ModuleInfo, Params,
-            ComponentTypeMap, TypeStatus, SingleCtor, Repn, !Specs)
+            ComponentTypeMap, TypeStatus, SingleCtor, Repn, !InfoSpecs)
     else
         decide_complex_non_sub_du_type_general(ModuleInfo, Params,
-            ComponentTypeMap, TypeCtor, TypeStatus, Ctors, Repn, !Specs)
+            ComponentTypeMap, TypeCtor, TypeStatus, Ctors, Repn,
+            !ErrSpecs, !InfoSpecs)
     ).
 
 %---------------------------------------------------------------------------%
@@ -2461,10 +2471,10 @@ decide_complex_non_sub_du_type(ModuleInfo, Params, ComponentTypeMap, TypeCtor,
 :- pred decide_complex_non_sub_du_type_single_ctor(module_info::in,
     decide_du_params::in, component_type_map::in,
     type_status::in, constructor::in, du_type_repn::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(info_spec)::in, list(info_spec)::out) is det.
 
 decide_complex_non_sub_du_type_single_ctor(ModuleInfo, Params,
-        ComponentTypeMap, TypeStatus, SingleCtor, Repn, !Specs) :-
+        ComponentTypeMap, TypeStatus, SingleCtor, Repn, !InfoSpecs) :-
     SingleCtor = ctor(Ordinal, MaybeExistConstraints, SingleCtorSymName,
         SingleCtorArgs, SingleCtorArity, SingleCtorContext),
     % Check whether we could pack SingleCtorArgs into a single word
@@ -2494,7 +2504,7 @@ decide_complex_non_sub_du_type_single_ctor(ModuleInfo, Params,
         decide_complex_non_sub_du_ctor_remote_args(ModuleInfo, Params,
             ComponentTypeMap, TypeStatus, NumRemoteSectagBits, SingleCtorTag,
             MaybeExistConstraints, SingleCtorSymName, SingleCtorContext,
-            SingleCtorArgs, SingleCtorArgRepns, _MaybeTagwordArgs, !Specs)
+            SingleCtorArgs, SingleCtorArgRepns, _MaybeTagwordArgs, !InfoSpecs)
     ),
     SingleCtorRepn = ctor_repn(Ordinal, MaybeExistConstraints,
         SingleCtorSymName, SingleCtorTag,
@@ -2512,10 +2522,11 @@ decide_complex_non_sub_du_type_single_ctor(ModuleInfo, Params,
 :- pred decide_complex_non_sub_du_type_general(module_info::in,
     decide_du_params::in, component_type_map::in, type_ctor::in,
     type_status::in, list(constructor)::in, du_type_repn::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(info_spec)::in, list(info_spec)::out) is det.
 
 decide_complex_non_sub_du_type_general(ModuleInfo, Params, ComponentTypeMap,
-        TypeCtor, TypeStatus, Ctors, Repn, !Specs) :-
+        TypeCtor, TypeStatus, Ctors, Repn, !ErrSpecs, !InfoSpecs) :-
     Target = Params ^ ddp_target,
     UsesConstructors = target_uses_constructors(Target),
     MaybePrimaryTags = Params ^ ddp_maybe_primary_tags,
@@ -2557,7 +2568,7 @@ decide_complex_non_sub_du_type_general(ModuleInfo, Params, ComponentTypeMap,
                     AssertedDirectArgFunctors),
                 Functors, DirectArgFunctors, NonDirectArgFunctors),
             check_direct_arg_assertions(AssertedDirectArgFunctors,
-                NonDirectArgFunctors, !Specs),
+                NonDirectArgFunctors, !ErrSpecs),
             DirectArgFunctorNames =
                 list.map(constructor_to_sym_name_arity, DirectArgFunctors)
         ;
@@ -2612,7 +2623,7 @@ decide_complex_non_sub_du_type_general(ModuleInfo, Params, ComponentTypeMap,
         decide_complex_non_sub_du_type_ctor(ModuleInfo, Params,
             ComponentTypeMap, TypeCtor, TypeStatus, CtorTagMap,
             NumRemoteSectagBitsInt),
-        Ctors, CtorRepns0, no_tagword_args, MaybeTagwordArgs, !Specs),
+        Ctors, CtorRepns0, no_tagword_args, MaybeTagwordArgs, !InfoSpecs),
     (
         MaybeTagwordArgs = no_tagword_args,
         CtorRepns = CtorRepns0
@@ -2702,11 +2713,11 @@ set_remote_args_sectag_size(SectagSize,
     decide_du_params::in, component_type_map::in, type_ctor::in,
     type_status::in, du_ctor_to_tag_map::in, int::in, constructor::in,
     constructor_repn::out, maybe_tagword_args::in, maybe_tagword_args::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(info_spec)::in, list(info_spec)::out) is det.
 
 decide_complex_non_sub_du_type_ctor(ModuleInfo, Params, ComponentTypeMap,
         TypeCtor, TypeStatus, CtorTagMap, NumRemoteSectagBits,
-        Ctor, CtorRepn, !MaybeTagwordArgs, !Specs) :-
+        Ctor, CtorRepn, !MaybeTagwordArgs, !InfoSpecs) :-
     Ctor = ctor(Ordinal, MaybeExistConstraints, CtorSymName,
         CtorArgs, CtorArity, CtorContext),
     DuCtor = du_ctor(CtorSymName, CtorArity, TypeCtor),
@@ -2726,7 +2737,7 @@ decide_complex_non_sub_du_type_ctor(ModuleInfo, Params, ComponentTypeMap,
         decide_complex_non_sub_du_ctor_remote_args(ModuleInfo, Params,
             ComponentTypeMap, TypeStatus, NumRemoteSectagBits, CtorTag,
             MaybeExistConstraints, CtorSymName, CtorContext,
-            CtorArgs, CtorArgRepns, CtorMaybeTagwordArgs, !Specs),
+            CtorArgs, CtorArgRepns, CtorMaybeTagwordArgs, !InfoSpecs),
         (
             CtorMaybeTagwordArgs = no_tagword_args
         ;
@@ -2793,12 +2804,12 @@ decide_complex_non_sub_du_type_ctor(ModuleInfo, Params, ComponentTypeMap,
     maybe_cons_exist_constraints::in, sym_name::in, prog_context::in,
     list(constructor_arg)::in, list(constructor_arg_repn)::out,
     maybe_tagword_args::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(info_spec)::in, list(info_spec)::out) is det.
 
 decide_complex_non_sub_du_ctor_remote_args(ModuleInfo, Params,
         ComponentTypeMap, TypeStatus, NumRemoteSectagBits, CtorTag,
         MaybeExistConstraints, CtorSymName, CtorContext, CtorArgs,
-        CtorArgRepns, MaybeTagwordArgs, !Specs) :-
+        CtorArgRepns, MaybeTagwordArgs, !InfoSpecs) :-
     maybe_exist_constraints_num_extra_words(MaybeExistConstraints,
         NumExtraArgWords),
 
@@ -2900,7 +2911,7 @@ decide_complex_non_sub_du_ctor_remote_args(ModuleInfo, Params,
             MaybeSectagAsPseudoArg = yes(NumRemoteSectagBits)
         ),
         inform_about_any_suboptimal_packing(Params, CtorSymName, CtorContext,
-            MaybeSectagAsPseudoArg, CtorArgRepns, !Specs)
+            MaybeSectagAsPseudoArg, CtorArgRepns, !InfoSpecs)
     else
         true
     ).
@@ -4140,7 +4151,7 @@ is_foreign_type_body_for_target(ForeignType, Target, Assertions) :-
     % for it.
     %
 :- pred check_direct_arg_assertions(list(sym_name_arity)::in,
-    list(constructor)::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(constructor)::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 check_direct_arg_assertions(_AssertedDirectArgCtors, [], !Specs).
 check_direct_arg_assertions(AssertedDirectArgCtors, [Ctor | Ctors], !Specs) :-
@@ -4207,10 +4218,10 @@ compute_cheaper_tag_test(TypeCtor, CtorRepns, CheaperTagTest) :-
 :- pred inform_about_any_suboptimal_packing(decide_du_params::in,
     sym_name::in, prog_context::in,
     maybe(int)::in, list(constructor_arg_repn)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(info_spec)::in, list(info_spec)::out) is det.
 
 inform_about_any_suboptimal_packing(Params, CtorSymName, CtorContext,
-        MaybeSectagAsPseudoArg, CtorArgRepns, !Specs) :-
+        MaybeSectagAsPseudoArg, CtorArgRepns, !InfoSpecs) :-
     % Find the number of words we would need to store all the sub-word-sized
     % arguments in CtorArgRepns using the first-fit-decreasing algorithm
     % (see the wikipedia page on "Bin_packing_problem"). If this number,
@@ -4260,7 +4271,7 @@ inform_about_any_suboptimal_packing(Params, CtorSymName, CtorContext,
             ++ EndPieces,
         Spec = spec($pred, severity_informational(inform_suboptimal_packing),
             phase_type_check, CtorContext, Pieces),
-        !:Specs = [Spec | !.Specs]
+        !:InfoSpecs = [Spec | !.InfoSpecs]
     else
         true
     ).
diff --git a/compiler/equiv_type.m b/compiler/equiv_type.m
index e51c5fc02..d34cede0f 100644
--- a/compiler/equiv_type.m
+++ b/compiler/equiv_type.m
@@ -108,7 +108,7 @@
     %
 :- pred replace_in_type_report_circular_eqvs(type_eqv_map::in, tvarset::in,
     prog_context::in, mer_type::in, mer_type::out, maybe_changed::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
     % Replace equivalence types in a given type.
     % The bool output is `yes' if anything changed.
@@ -538,7 +538,7 @@ replace_in_inst_location(InstEqvMap, MaybeRecord,
 %---------------------------------------------------------------------------%
 
 :- func report_contains_circular_eqv_type(tvarset, mer_type, prog_context,
-    type_ctor, list(type_ctor)) = diag_spec.
+    type_ctor, list(type_ctor)) = err_spec.
 
 report_contains_circular_eqv_type(TVarSet, Type, Context,
         HeadTypeCtor, TailTypeCtors) = Spec :-
diff --git a/compiler/equiv_type_parse_tree.m b/compiler/equiv_type_parse_tree.m
index 8243df38d..db536458c 100644
--- a/compiler/equiv_type_parse_tree.m
+++ b/compiler/equiv_type_parse_tree.m
@@ -105,7 +105,7 @@
     event_spec_map::in, event_spec_map::out,
     type_eqv_map::out, used_eqv_modules::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-    list(diag_spec)::out) is det.
+    list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -118,7 +118,7 @@
     %
 :- pred replace_in_type_repn_eqv(type_eqv_map::in,
     item_type_repn_info_eqv::in, item_type_repn_info_eqv::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -216,7 +216,7 @@ expand_eqv_types_insts(AugCompUnit0, AugCompUnit, EventSpecMap0, EventSpecMap,
     parse_tree_module_src::in, parse_tree_module_src::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_parse_tree_module_src(Params,
         ParseTreeModuleSrc0, ParseTreeModuleSrc,
@@ -229,7 +229,7 @@ replace_in_parse_tree_module_src(Params,
         IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,
 
         TypeCtorCheckedMap0, InstCtorCheckedMap0, ModeCtorCheckedMap0,
-        TypeSpecs, InstModeSpecs,
+        TypeErrSpecs, TypeWarnSpecs, InstModeErrSpecs, InstModeWarnSpecs,
 
         IntTypeClasses0, IntInstances0, IntPredDecls0, IntModeDecls0,
         IntDeclPragmas0, IntDeclMarkers, IntPromises, IntBadPreds,
@@ -292,7 +292,7 @@ replace_in_parse_tree_module_src(Params,
         IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,
 
         TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
-        TypeSpecs, InstModeSpecs,
+        TypeErrSpecs, TypeWarnSpecs, InstModeErrSpecs, InstModeWarnSpecs,
 
         IntTypeClasses, IntInstances, IntPredDecls, IntModeDecls,
         IntDeclPragmas, IntDeclMarkers, IntPromises, IntBadPreds,
@@ -306,7 +306,7 @@ replace_in_parse_tree_module_src(Params,
     ancestor_int_spec::in, ancestor_int_spec::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_ancestor_int_spec(Params, AncestorIntSpec0, AncestorIntSpec,
         !RecompInfo, !UsedModules, !Specs) :-
@@ -319,7 +319,7 @@ replace_in_ancestor_int_spec(Params, AncestorIntSpec0, AncestorIntSpec,
     direct_int1_spec::in, direct_int1_spec::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_direct_int1_spec(Params, DirectIntSpec0, DirectIntSpec,
         !RecompInfo, !UsedModules, !Specs) :-
@@ -332,7 +332,7 @@ replace_in_direct_int1_spec(Params, DirectIntSpec0, DirectIntSpec,
     indirect_int2_spec::in, indirect_int2_spec::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_indirect_int2_spec(Params, IndirectIntSpec0, IndirectIntSpec,
         !RecompInfo, !UsedModules, !Specs) :-
@@ -345,7 +345,7 @@ replace_in_indirect_int2_spec(Params, IndirectIntSpec0, IndirectIntSpec,
     int_for_opt_spec::in, int_for_opt_spec::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_int_for_opt_spec(Params, IntForOptSpec0, IntForOptSpec,
         !RecompInfo, !UsedModules, !Specs) :-
@@ -372,7 +372,7 @@ replace_in_int_for_opt_spec(Params, IntForOptSpec0, IntForOptSpec,
     parse_tree_int0::in, parse_tree_int0::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_parse_tree_int0(Params, OrigParseTreeInt0, ParseTreeInt0,
         !RecompInfo, !UsedModules, !Specs) :-
@@ -439,7 +439,7 @@ replace_in_parse_tree_int0(Params, OrigParseTreeInt0, ParseTreeInt0,
     parse_tree_int1::in, parse_tree_int1::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_parse_tree_int1(Params, OrigParseTreeInt1, ParseTreeInt1,
         !RecompInfo, !UsedModules, !Specs) :-
@@ -496,7 +496,7 @@ replace_in_parse_tree_int1(Params, OrigParseTreeInt1, ParseTreeInt1,
     parse_tree_int2::in, parse_tree_int2::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_parse_tree_int2(Params, OrigParseTreeInt2, ParseTreeInt2,
         !RecompInfo, !UsedModules, !Specs) :-
@@ -536,7 +536,7 @@ replace_in_parse_tree_int2(Params, OrigParseTreeInt2, ParseTreeInt2,
     parse_tree_plain_opt::in, parse_tree_plain_opt::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_parse_tree_plain_opt(Params,
         OrigParseTreePlainOpt, ParseTreePlainOpt,
@@ -585,7 +585,7 @@ replace_in_parse_tree_plain_opt(Params,
     parse_tree_trans_opt::in, parse_tree_trans_opt::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_parse_tree_trans_opt(_Params, ParseTreeTransOpt, ParseTreeTransOpt,
         RecompInfo, RecompInfo, UsedModules, UsedModules, Specs, Specs).
@@ -600,7 +600,7 @@ replace_in_parse_tree_trans_opt(_Params, ParseTreeTransOpt, ParseTreeTransOpt,
     type_ctor_checked_defn::in, type_ctor_checked_defn::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_type_ctor_checked_defn(Params, MaybeRecordInt, MaybeRecordImp,
         CheckedDefn0, CheckedDefn, !RecompInfo, !UsedModules, !Specs) :-
@@ -692,13 +692,13 @@ replace_in_type_ctor_checked_defn(Params, MaybeRecordInt, MaybeRecordImp,
 :- pred replace_in_type_defn_info_general(
     pred(equiv_params, maybe_record_sym_name_use, type_ctor, prog_context,
         T, T, tvarset, tvarset, item_recomp_deps, item_recomp_deps,
-        used_eqv_modules, used_eqv_modules, list(diag_spec))
+        used_eqv_modules, used_eqv_modules, list(err_spec))
     :: in(pred(in, in, in, in, in, out, in, out, in, out, in, out, out)
         is det),
     equiv_params::in, maybe_record_sym_name_use::in,
     item_type_defn_info_general(T)::in, item_type_defn_info_general(T)::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_type_defn_info_general(ReplaceInTypeDefn, Params, MaybeRecord,
         TypeDefnInfo0, TypeDefnInfo, !RecompInfo, !UsedModules, Specs) :-
@@ -724,7 +724,7 @@ replace_in_type_defn_info_general(ReplaceInTypeDefn, Params, MaybeRecord,
     type_ctor::in, prog_context::in,
     type_defn::in, type_defn::out,
     tvarset::in, tvarset::out, item_recomp_deps::in, item_recomp_deps::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_type_defn(Params, MaybeRecord, TypeCtor, Context,
         TypeDefn0, TypeDefn, !TVarSet, !ItemRecompDeps, !UsedModules, Specs) :-
@@ -766,7 +766,7 @@ replace_in_type_defn(Params, MaybeRecord, TypeCtor, Context,
     maybe_record_sym_name_use::in, type_ctor::in, prog_context::in,
     type_details_eqv::in, type_details_eqv::out,
     tvarset::in, tvarset::out, item_recomp_deps::in, item_recomp_deps::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_type_defn_eqv(Params, MaybeRecord, TypeCtor, Context,
         DetailsEqv0, DetailsEqv,
@@ -791,7 +791,7 @@ replace_in_type_defn_eqv(Params, MaybeRecord, TypeCtor, Context,
     maybe_record_sym_name_use::in, type_ctor::in, prog_context::in,
     type_details_du::in, type_details_du::out,
     tvarset::in, tvarset::out, item_recomp_deps::in, item_recomp_deps::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_type_defn_du(Params, MaybeRecord, _TypeCtor, _Context,
         DetailsDu0, DetailsDu,
@@ -807,7 +807,7 @@ replace_in_type_defn_du(Params, MaybeRecord, _TypeCtor, _Context,
     maybe_record_sym_name_use::in, type_ctor::in, prog_context::in,
     type_details_sub::in, type_details_sub::out,
     tvarset::in, tvarset::out, item_recomp_deps::in, item_recomp_deps::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_type_defn_sub(Params, MaybeRecord, _TypeCtor, _Context,
         DetailsSub0, DetailsSub,
@@ -827,7 +827,7 @@ replace_in_type_defn_sub(Params, MaybeRecord, _TypeCtor, _Context,
     maybe_record_sym_name_use::in, type_ctor::in, prog_context::in,
     type_details_solver::in, type_details_solver::out,
     tvarset::in, tvarset::out, item_recomp_deps::in, item_recomp_deps::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_type_defn_solver(Params, MaybeRecord, TypeCtor, Context,
         DetailsSolver0, DetailsSolver,
@@ -888,7 +888,7 @@ replace_in_constraint_store(Params, MaybeRecord,
     item_type_repn_info::in, item_type_repn_info::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_type_repn_info(Params, MaybeRecord, TypeRepnInfo0, TypeRepnInfo,
         !RecompInfo, !UsedModules, !Specs) :-
@@ -977,7 +977,7 @@ replace_in_type_repn_eqv(TypeEqvMap, TypeRepnInfo0, TypeRepnInfo, !Specs) :-
     maybe_record_sym_name_use::in,
     item_pred_decl_info::in, item_pred_decl_info::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_pred_decl_info(Params, MaybeRecord,
         PredDeclInfo0, PredDeclInfo, !RecompInfo, !UsedModules, Specs) :-
@@ -1015,7 +1015,7 @@ replace_in_pred_decl_info(Params, MaybeRecord,
     maybe_record_sym_name_use::in,
     item_mode_decl_info::in, item_mode_decl_info::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_mode_decl_info(Params, MaybeRecord,
         Info0, Info, !RecompInfo, !UsedModules, Specs) :-
@@ -1071,7 +1071,7 @@ replace_in_mode_decl_info(Params, MaybeRecord,
     maybe_record_sym_name_use::in,
     item_typeclass_info::in, item_typeclass_info::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_typeclass_info(Params, MaybeRecord, TypeClassInfo0, TypeClassInfo,
         !RecompInfo, !UsedModules, Specs) :-
@@ -1106,7 +1106,7 @@ replace_in_typeclass_info(Params, MaybeRecord, TypeClassInfo0, TypeClassInfo,
     maybe_record_sym_name_use::in,
     item_abstract_typeclass_info::in, item_abstract_typeclass_info::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_abstract_typeclass_info(Params, MaybeRecord,
         TypeClassInfo0, TypeClassInfo, !RecompInfo, !UsedModules, Specs) :-
@@ -1134,7 +1134,7 @@ replace_in_abstract_typeclass_info(Params, MaybeRecord,
     list(class_decl)::in, list(class_decl)::out,
     item_recomp_deps::in, item_recomp_deps::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_class_interface(Params, MaybeRecord,
         ClassInterface0, ClassInterface, !ItemRecompDeps, !UsedModules,
@@ -1147,7 +1147,7 @@ replace_in_class_interface(Params, MaybeRecord,
     class_decl::in, class_decl::out,
     item_recomp_deps::in, item_recomp_deps::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_class_decl(Params, MaybeRecord, Decl0, Decl,
         !ItemRecompDeps, !UsedModules, !Specs) :-
@@ -1204,7 +1204,7 @@ replace_in_class_decl(Params, MaybeRecord, Decl0, Decl,
     maybe_record_sym_name_use::in,
     item_instance_info::in, item_instance_info::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_instance_info(Params, MaybeRecord, InstanceInfo0, InstanceInfo,
         !RecompInfo, !UsedModules, []) :-
@@ -1255,7 +1255,7 @@ replace_in_instance_info(Params, MaybeRecord, InstanceInfo0, InstanceInfo,
     maybe_record_sym_name_use::in,
     item_abstract_instance_info::in, item_abstract_instance_info::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_abstract_instance_info(Params, MaybeRecord,
         InstanceInfo0, InstanceInfo, !RecompInfo, !UsedModules, []) :-
@@ -1297,7 +1297,7 @@ replace_in_abstract_instance_info(Params, MaybeRecord,
 %   maybe_record_sym_name_use::in,
 %   instance_method::in, instance_method::out,
 %   maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-%   used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+%   used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 % replace_in_instance_method(Params, MaybeRecord,
 %       InstanceMethod0, InstanceMethod, !RecompInfo, !UsedModules, Specs) :-
@@ -1318,7 +1318,7 @@ replace_in_abstract_instance_info(Params, MaybeRecord,
     maybe_record_sym_name_use::in,
     item_decl_pragma_info::in, item_decl_pragma_info::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_decl_pragma_info(Params, MaybeRecord, DeclPragma0, DeclPragma,
         !RecompInfo, !UsedModules, Specs) :-
@@ -1350,7 +1350,7 @@ replace_in_decl_pragma_info(Params, MaybeRecord, DeclPragma0, DeclPragma,
     maybe_record_sym_name_use::in,
     decl_pragma_type_spec_constr_info::in,
         decl_pragma_type_spec_constr_info::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_decl_pragma_type_spec_constr(Params, MaybeRecord,
         TypeSpecInfoConstr0, TypeSpecInfoConstr, !UsedModules, []) :-
@@ -1399,7 +1399,7 @@ replace_in_decl_pragma_type_spec_constr(Params, MaybeRecord,
     maybe_record_sym_name_use::in,
     decl_pragma_type_spec_info::in, decl_pragma_type_spec_info::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_decl_pragma_type_spec(Params, MaybeRecord,
         TypeSpecInfo0, TypeSpecInfo,
@@ -1527,7 +1527,7 @@ replace_in_var_or_ground_type_location(TypeEqvMap, MaybeRecord,
     maybe_record_sym_name_use::in,
     item_foreign_proc_info::in, item_foreign_proc_info::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_foreign_proc(Params, MaybeRecord, FPInfo0, FPInfo,
         !RecompInfo, !UsedModules, []) :-
@@ -1632,7 +1632,7 @@ replace_in_unit_selector(TypeEqvMap, MaybeRecord, TVarSet, Sel0, Sel,
     maybe_record_sym_name_use::in,
     item_mutable_info::in, item_mutable_info::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_mutable_info(Params, MaybeRecord,
         MutableInfo0, MutableInfo, !RecompInfo, !UsedModules, []) :-
@@ -1741,7 +1741,7 @@ replace_in_event_attr(TypeEqvMap, Attr0, Attr, !UsedModules) :-
     maybe(mer_inst)::in, maybe(mer_inst)::out,
     maybe(determinism)::in, maybe(determinism)::out,
     item_recomp_deps::in, item_recomp_deps::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_pred_types_and_maybe_modes(Params, MaybeRecord,
         PredSymName, PredOrFunc, Context, ClassContext0, ClassContext,
@@ -1800,7 +1800,7 @@ replace_in_pred_types_and_maybe_modes(Params, MaybeRecord,
 :- pred check_and_maybe_add_extra_types_and_modes(pred_or_func::in,
     sym_name::in, prog_context::in, list(mer_type)::in, list(mer_mode)::in,
     types_and_maybe_modes::in, types_and_maybe_modes::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_and_maybe_add_extra_types_and_modes(PredOrFunc, PredSymName, Context,
         ExtraTypes, ExtraModes, TypesAndMaybeModes1, TypesAndMaybeModes,
@@ -1952,7 +1952,7 @@ pair_extra_types_and_modes([Type | Types], [Mode | Modes],
     pred_or_func::in, sym_name::in, prog_context::in,
     maybe(mer_type)::in, list(mer_type)::out,
     tvarset::in, tvarset::out, item_recomp_deps::in, item_recomp_deps::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_with_type(TypeEqvMap, MaybeRecord, PredOrFunc, PredSymName,
         Context, MaybeWithType0, ExtraTypes,
@@ -2007,7 +2007,7 @@ replace_in_with_type(TypeEqvMap, MaybeRecord, PredOrFunc, PredSymName,
     maybe(mer_inst)::in, maybe(mer_inst)::out, list(mer_mode)::out,
     maybe(determinism)::in, maybe(determinism)::out,
     item_recomp_deps::in, item_recomp_deps::out,
-    used_eqv_modules::in, used_eqv_modules::out, list(diag_spec)::out) is det.
+    used_eqv_modules::in, used_eqv_modules::out, list(err_spec)::out) is det.
 
 replace_in_with_inst(Params, MaybeRecord, PredSymName, PredFormArity, Context,
         DeclType, MaybePredOrFunc0, MaybePredOrFunc,
@@ -2125,12 +2125,12 @@ replace_in_type_and_mode(TypeEqvMap, MaybeRecord, TypeAndMode0, TypeAndMode,
 :- pred replace_in_maybe(equiv_params::in, maybe_record_sym_name_use::in,
     pred(equiv_params, maybe_record_sym_name_use,
         T, T, maybe(recompilation_info), maybe(recompilation_info),
-        used_eqv_modules, used_eqv_modules, list(diag_spec))
+        used_eqv_modules, used_eqv_modules, list(err_spec))
     :: in(pred(in, in, in, out, in, out, in, out, out) is det),
     maybe(T)::in, maybe(T)::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_maybe(Params, MaybeRecord, ReplaceInItem, MaybeItem0, MaybeItem,
         !RecompInfo, !UsedModules, !Specs) :-
@@ -2156,12 +2156,12 @@ replace_in_maybe(Params, MaybeRecord, ReplaceInItem, MaybeItem0, MaybeItem,
 :- pred replace_in_list(equiv_params::in, maybe_record_sym_name_use::in,
     pred(equiv_params, maybe_record_sym_name_use,
         T, T, maybe(recompilation_info), maybe(recompilation_info),
-        used_eqv_modules, used_eqv_modules, list(diag_spec))
+        used_eqv_modules, used_eqv_modules, list(err_spec))
     :: in(pred(in, in, in, out, in, out, in, out, out) is det),
     list(T)::in, list(T)::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_list(Params, MaybeRecord, ReplaceInItem,
         Items0, Items, !RecompInfo, !UsedModules, !Specs) :-
@@ -2172,12 +2172,12 @@ replace_in_list(Params, MaybeRecord, ReplaceInItem,
 :- pred replace_in_list_loop(equiv_params::in, maybe_record_sym_name_use::in,
     pred(equiv_params, maybe_record_sym_name_use,
         T, T, maybe(recompilation_info), maybe(recompilation_info),
-        used_eqv_modules, used_eqv_modules, list(diag_spec))
+        used_eqv_modules, used_eqv_modules, list(err_spec))
     :: in(pred(in, in, in, out, in, out, in, out, out) is det),
     list(T)::in, list(T)::in, list(T)::out,
     maybe(recompilation_info)::in, maybe(recompilation_info)::out,
     used_eqv_modules::in, used_eqv_modules::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 replace_in_list_loop(_Params, _MaybeRecord, _ReplaceInItem,
         [], !RevItems, !RecompInfo, !UsedModules, !Specs).
@@ -2198,7 +2198,7 @@ replace_in_list_loop(Params, MaybeRecord, ReplaceInItem,
 
 %---------------------------------------------------------------------------%
 
-:- func report_circular_eqv_type(type_ctor, prog_context) = diag_spec.
+:- func report_circular_eqv_type(type_ctor, prog_context) = err_spec.
 
 report_circular_eqv_type(TypeCtor, Context) = Spec :-
     Pieces = [words("Error: equivalence type")] ++
diff --git a/compiler/error_sort.m b/compiler/error_sort.m
index 3ea6f3233..0a9e71058 100644
--- a/compiler/error_sort.m
+++ b/compiler/error_sort.m
@@ -86,7 +86,7 @@ standardize_diag_specs(Specs, StdSpecs) :-
 
 standardize_diag_spec(Spec0, StdSpec) :-
     (
-        Spec0 = diag_spec(Id, Severity, Phase, Msgs0),
+        Spec0 = gen_spec(Id, Severity, Phase, Msgs0),
         list.map(standardize_diag_msg, Msgs0, StdMsgs)
     ;
         Spec0 = spec(Id, Severity, Phase, Context0, Pieces0),
@@ -102,7 +102,7 @@ standardize_diag_spec(Spec0, StdSpec) :-
         unexpected($pred, "StdMsgs = []")
     ;
         StdMsgs = [_ | _],
-        StdSpec = diag_spec(Id, Severity, Phase, StdMsgs)
+        StdSpec = gen_spec(Id, Severity, Phase, StdMsgs)
     ).
 
 :- pred standardize_diag_msg(diag_msg::in, std_diag_msg::out) is det.
@@ -177,8 +177,8 @@ sort_std_diag_specs_opt_table(OptionTable, StdSpecs, SortedStdSpecs) :-
     std_diag_spec::in, std_diag_spec::in, comparison_result::out) is det.
 
 compare_std_diag_specs(ReverseErrorOrder, SpecA, SpecB, Result) :-
-    SpecA = diag_spec(_, _, _, MsgsA),
-    SpecB = diag_spec(_, _, _, MsgsB),
+    SpecA = gen_spec(_, _, _, MsgsA),
+    SpecB = gen_spec(_, _, _, MsgsB),
     compare_std_diag_msg_lists(ReverseErrorOrder, MsgsA, MsgsB, MsgsResult),
     (
         MsgsResult = (=),
diff --git a/compiler/error_spec.m b/compiler/error_spec.m
index bf3d2d3e0..50cd978b7 100644
--- a/compiler/error_spec.m
+++ b/compiler/error_spec.m
@@ -32,6 +32,7 @@
 :- import_module edit_seq.
 :- import_module list.
 :- import_module maybe.
+:- import_module one_or_more.
 :- import_module set.
 :- import_module term.
 :- import_module varset.
@@ -39,7 +40,7 @@
 %---------------------------------------------------------------------------%
 
 % Every distinct problem should generate a single error specification,
-% whose general form is diag_spec(Id, Severity, Phase, Msgs).
+% whose general form is gen_spec(Id, Severity, Phase, Msgs).
 % The second, third and fourth fields of this term state respectively
 %
 % - the severity of the problem (so that we can update the exit status
@@ -57,11 +58,11 @@
 % message giving the original declaration's context.
 %
 % spec(Id, Severity, Phase, Context, Pieces) is a shorthand for
-% (and equivalent in every respect to) diag_spec(Id, Severity, Phase,
+% (and equivalent in every respect to) gen_spec(Id, Severity, Phase,
 % [simple_msg(Context, always(Pieces)])]).
 %
 % no_ctxt_spec(Id, Severity, Phase, Pieces) is shorthand for
-% (and equivalent in every respect to) diag_spec(Id, Severity, Phase,
+% (and equivalent in every respect to) gen_spec(Id, Severity, Phase,
 % error_msg(maybe.no, treat_based_on_posn, 0, [always(Pieces)])).
 %
 % The Id field, which is present in all these alternatives, is totally
@@ -97,24 +98,89 @@
                 ncs_spec_phase          :: spec_phase,
                 ncs_spec_pieces         :: list(format_piece)
             )
-    ;       diag_spec(
-                ds_id                   :: string,
-                ds_severity             :: spec_severity,
-                ds_phase                :: spec_phase,
-                ds_msgs                 :: list(diag_msg)
+    ;       gen_spec(
+                gs_id                   :: string,
+                gs_severity             :: spec_severity,
+                gs_phase                :: spec_phase,
+                gs_msgs                 :: list(diag_msg)
             ).
 
-    % An diag_spec that is *intended* to contain a warning,
-    % XXX We can now enforce that intention using subtypes.
-    %
-:- type warning_spec == diag_spec.
+:- type err_spec =< diag_spec
+    --->    spec(
+                s_id                    :: string,
+                s_spec_severity         :: spec_severity_err,
+                s_spec_phase            :: spec_phase,
+                s_spec_context          :: prog_context,
+                s_spec_pieces           :: list(format_piece)
+            )
+    ;       no_ctxt_spec(
+                ncs_id                  :: string,
+                ncs_spec_severity       :: spec_severity_err,
+                ncs_spec_phase          :: spec_phase,
+                ncs_spec_pieces         :: list(format_piece)
+            )
+    ;       gen_spec(
+                gs_id                   :: string,
+                gs_severity             :: spec_severity_err,
+                gs_phase                :: spec_phase,
+                gs_msgs                 :: list(diag_msg)
+            ).
+
+:- type warn_spec =< diag_spec
+    --->    spec(
+                s_id                    :: string,
+                s_spec_severity         :: spec_severity_warn,
+                s_spec_phase            :: spec_phase,
+                s_spec_context          :: prog_context,
+                s_spec_pieces           :: list(format_piece)
+            )
+    ;       no_ctxt_spec(
+                ncs_id                  :: string,
+                ncs_spec_severity       :: spec_severity_warn,
+                ncs_spec_phase          :: spec_phase,
+                ncs_spec_pieces         :: list(format_piece)
+            )
+    ;       gen_spec(
+                gs_id                   :: string,
+                gs_severity             :: spec_severity_warn,
+                gs_phase                :: spec_phase,
+                gs_msgs                 :: list(diag_msg)
+            ).
+
+:- type info_spec =< diag_spec
+    --->    spec(
+                s_id                    :: string,
+                s_spec_severity         :: spec_severity_info,
+                s_spec_phase            :: spec_phase,
+                s_spec_context          :: prog_context,
+                s_spec_pieces           :: list(format_piece)
+            )
+    ;       no_ctxt_spec(
+                ncs_id                  :: string,
+                ncs_spec_severity       :: spec_severity_info,
+                ncs_spec_phase          :: spec_phase,
+                ncs_spec_pieces         :: list(format_piece)
+            )
+    ;       gen_spec(
+                gs_id                   :: string,
+                gs_severity             :: spec_severity_info,
+                gs_phase                :: spec_phase,
+                gs_msgs                 :: list(diag_msg)
+            ).
+
+:- type errs_warns
+    --->    errs_warns(list(err_spec), list(warn_spec)).
+
+:- pred record_err_spec(err_spec::in, errs_warns::in, errs_warns::out) is det.
+:- pred record_warn_spec(warn_spec::in, errs_warns::in, errs_warns::out)
+    is det.
 
 :- type std_diag_spec =< diag_spec
-    --->    diag_spec(
-                ds_id                   :: string,
-                ds_severity             :: spec_severity,
-                ds_phase                :: spec_phase,
-                ds_msgs                 :: list(std_diag_msg)
+    --->    gen_spec(
+                gs_id                   :: string,
+                gs_severity             :: spec_severity,
+                gs_phase                :: spec_phase,
+                gs_msgs                 :: list(std_diag_msg)
             ).
 
     % Many operations in the compiler may either succeed or fail.
@@ -127,6 +193,8 @@
 %   --->    ok_no_spec(T)
 %   ;       diag_specs(diag_spec, list(diag_spec)).
 
+:- func oom_err_to_oom_diag(one_or_more(err_spec)) = one_or_more(diag_spec).
+
 %---------------------------------------------------------------------------%
 
 :- type spec_severity
@@ -142,6 +210,13 @@
     ;       severity_informational(option).
             % Don't set the exit status to indicate an error.
 
+:- type spec_severity_err =< spec_severity
+    --->    severity_error.
+:- type spec_severity_warn =< spec_severity
+    --->    severity_warning(option).
+:- type spec_severity_info =< spec_severity
+    --->    severity_informational(option).
+
 :- type actual_severity
     --->    actual_severity_error
     ;       actual_severity_warning
@@ -814,6 +889,24 @@
 
 %---------------------------------------------------------------------------%
 
+record_err_spec(Err, ErrsWarns0, ErrsWarns) :-
+    ErrsWarns0 = errs_warns(Errs0, Warns0),
+    Errs = [Err | Errs0],
+    ErrsWarns  = errs_warns(Errs, Warns0).
+
+record_warn_spec(Warn, ErrsWarns0, ErrsWarns) :-
+    ErrsWarns0 = errs_warns(Errs0, Warns0),
+    Warns = [Warn | Warns0],
+    ErrsWarns  = errs_warns(Errs0, Warns).
+
+%---------------------------------------------------------------------------%
+
+oom_err_to_oom_diag(OoMErrSpecs) = OoMDiagSpecs :-
+    OoMErrSpecs = one_or_more(HeadErrSpec, TailErrSpecs),
+    OoMDiagSpecs = one_or_more(coerce(HeadErrSpec), coerce(TailErrSpecs)).
+
+%---------------------------------------------------------------------------%
+
 string_to_words_piece(Str) = words(Str).
 
 var_to_quote_piece(VarSet, Var) =
@@ -998,7 +1091,7 @@ extract_spec_phase(Spec, Phase) :-
     ;
         Spec = no_ctxt_spec(_, _, Phase, _)
     ;
-        Spec = diag_spec(_, _, Phase, _)
+        Spec = gen_spec(_, _, Phase, _)
     ).
 
 extract_spec_severity(Spec, Severity) :-
@@ -1007,7 +1100,7 @@ extract_spec_severity(Spec, Severity) :-
     ;
         Spec = no_ctxt_spec(_, Severity, _, _)
     ;
-        Spec = diag_spec(_, Severity, _, _)
+        Spec = gen_spec(_, Severity, _, _)
     ).
 
 accumulate_contexts(Spec, !Contexts) :-
@@ -1017,7 +1110,7 @@ accumulate_contexts(Spec, !Contexts) :-
     ;
         Spec = no_ctxt_spec(_, _, _, _)
     ;
-        Spec = diag_spec(_, _, _, Msgs),
+        Spec = gen_spec(_, _, _, Msgs),
         list.foldl(accumulate_contexts_in_msg, Msgs, !Contexts)
     ).
 
@@ -1043,7 +1136,7 @@ extract_spec_msgs_and_id(Spec, Msgs, Id) :-
         Spec = no_ctxt_spec(Id, _Severity, _Phase, Pieces),
         Msgs = [no_ctxt_msg(Pieces)]
     ;
-        Spec = diag_spec(Id, _Severity, _Phase, Msgs)
+        Spec = gen_spec(Id, _Severity, _Phase, Msgs)
     ).
 
 %---------------------------------------------------------------------------%
diff --git a/compiler/error_util.m b/compiler/error_util.m
index e21c0f1cf..4de206986 100644
--- a/compiler/error_util.m
+++ b/compiler/error_util.m
@@ -116,6 +116,12 @@
 
 :- pred add_to_be_written_specs(list(diag_spec)::in,
     maybe_written_specs::in, maybe_written_specs::out) is det.
+:- pred add_to_be_written_err_specs(list(err_spec)::in,
+    maybe_written_specs::in, maybe_written_specs::out) is det.
+:- pred add_to_be_written_warn_specs(list(warn_spec)::in,
+    maybe_written_specs::in, maybe_written_specs::out) is det.
+:- pred add_to_be_written_info_specs(list(info_spec)::in,
+    maybe_written_specs::in, maybe_written_specs::out) is det.
 
 :- func maybe_written_specs_to_specs(maybe_written_specs) = list(diag_spec).
 
@@ -193,7 +199,7 @@ does_spec_print_anything_2(Spec) = Prints :-
         ),
         Prints = yes
     ;
-        Spec = diag_spec(_, _, _, Msgs),
+        Spec = gen_spec(_, _, _, Msgs),
         PrintsList = list.map(does_msg_print_anything, Msgs),
         bool.or_list(PrintsList, Prints)
     ).
@@ -250,7 +256,7 @@ actual_spec_severity(Globals, Spec) = MaybeSeverity :-
     MaybeSeverity = actual_spec_severity_opt_table(OptionTable, Spec).
 
 actual_spec_severity_opt_table(OptionTable, Spec) = MaybeActualSeverity :-
-    ( Spec = diag_spec(_, Severity, _, _)
+    ( Spec = gen_spec(_, Severity, _, _)
     ; Spec = spec(_, Severity, _, _, _)
     ; Spec = no_ctxt_spec(_, Severity, _, _)
     ),
@@ -438,6 +444,21 @@ add_to_be_written_specs(Specs, !MaybeWrittenSpecs) :-
     ToBeWritten = Specs ++ ToBeWritten0,
     !:MaybeWrittenSpecs = maybe_written_specs(ToBeWritten, AlreadyWritten).
 
+add_to_be_written_err_specs(Specs, !MaybeWrittenSpecs) :-
+    !.MaybeWrittenSpecs = maybe_written_specs(ToBeWritten0, AlreadyWritten),
+    ToBeWritten = coerce(Specs) ++ ToBeWritten0,
+    !:MaybeWrittenSpecs = maybe_written_specs(ToBeWritten, AlreadyWritten).
+
+add_to_be_written_warn_specs(Specs, !MaybeWrittenSpecs) :-
+    !.MaybeWrittenSpecs = maybe_written_specs(ToBeWritten0, AlreadyWritten),
+    ToBeWritten = coerce(Specs) ++ ToBeWritten0,
+    !:MaybeWrittenSpecs = maybe_written_specs(ToBeWritten, AlreadyWritten).
+
+add_to_be_written_info_specs(Specs, !MaybeWrittenSpecs) :-
+    !.MaybeWrittenSpecs = maybe_written_specs(ToBeWritten0, AlreadyWritten),
+    ToBeWritten = coerce(Specs) ++ ToBeWritten0,
+    !:MaybeWrittenSpecs = maybe_written_specs(ToBeWritten, AlreadyWritten).
+
 maybe_written_specs_to_specs(MaybeWrittenSpecs) = Specs :-
     MaybeWrittenSpecs = maybe_written_specs(ToBeWritten, AlreadyWritten),
     Specs = ToBeWritten ++ AlreadyWritten.
@@ -525,7 +546,7 @@ accumulate_diag_specs_for_proc(ProcSpecs, !MaybeSpecs) :-
 
 project_spec_phase(Spec) = Phase :-
     (
-        Spec = diag_spec(_, _, Phase, _)
+        Spec = gen_spec(_, _, Phase, _)
     ;
         Spec = spec(_, _, Phase, _, _)
     ;
diff --git a/compiler/fact_table_gen.m b/compiler/fact_table_gen.m
index 59ffe747c..49bb1e3d1 100644
--- a/compiler/fact_table_gen.m
+++ b/compiler/fact_table_gen.m
@@ -69,7 +69,7 @@
 
 :- type fact_table_arg_check_result
     --->    fact_table_args_ok(fact_table_gen_info)
-    ;       fact_table_args_not_ok(list(diag_spec)).
+    ;       fact_table_args_not_ok(list(err_spec)).
 
 :- type fact_table_gen_info.
 
@@ -96,7 +96,7 @@
 :- pred fact_table_compile_facts(io.text_output_stream::in, module_info::in,
     string::in, prog_context::in, fact_table_gen_info::in, string::out,
     proc_id::out, pred_info::in, pred_info::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
     % fact_table_generate_c_code_for_proc(ModuleInfo, PredName,
     %   ProcId, PrimaryProcId, ProcInfo, GenInfo, VarSet, PragmaVars,
@@ -401,7 +401,7 @@ fact_table_check_args(ModuleInfo, PragmaContext, PredId, PredInfo, Result) :-
     fact_table_proc_map::in, fact_table_proc_map::out,
     list(proc_id)::in, list(proc_id)::out,
     list(proc_id)::in, list(proc_id)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 fact_table_check_proc_modes(_, _, _, [],
         !FactArgInfos, !FactTableProcMap,
@@ -455,7 +455,7 @@ fact_table_check_proc_modes(ModuleInfo, PredId, PredInfo, [ProcId | ProcIds],
     %
 :- pred init_fact_arg_infos(pred_info::in, list(mer_type)::in,
     list(fact_arg_info)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 init_fact_arg_infos(_, [], [], !Specs).
 init_fact_arg_infos(PredInfo, [Type | Types], [Info | Infos], !Specs) :-
@@ -498,7 +498,7 @@ init_fact_arg_infos(PredInfo, [Type | Types], [Info | Infos], !Specs) :-
 :- pred check_proc_arg_modes(module_info::in, pred_proc_id::in, proc_info::in,
     int::in, list(mer_type)::in, list(mer_mode)::in, list(fact_table_var)::out,
     prog_varset::in, prog_varset::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_proc_arg_modes(_, _, _, _, [], [], [], !VarSet, !Specs).
 check_proc_arg_modes(_, _, _, _, [], [_ | _], _, !VarSet, !Specs) :-
@@ -539,7 +539,7 @@ check_proc_arg_modes(ModuleInfo, PredProcId, ProcInfo,
         % so generating an error message here for the user would be redundant.
         % However, we *did* find an error that prevents us from generating
         % fact table code for this procedure, and we have to signal this
-        % by an diag_spec. So we generate and return an empty diag_spec.
+        % by an err_spec. So we generate and return an empty err_spec.
         proc_info_get_context(ProcInfo, Context),
         Spec = spec($pred, severity_error, phase_fact_table_check,
             Context, []),
@@ -647,7 +647,7 @@ fact_table_compile_facts(ProgressStream, ModuleInfo, FactTableFileName,
     int::in, module_info::in, sym_name::in, fact_table_gen_info::in,
     string::out, proc_id::out, maybe(string)::out,
     pred_info::in, pred_info::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 compile_fact_table_in_file(MaybeProgressStream, FileStream, FileName,
         OutputStream, FactTableSize, ModuleInfo, PredSymName, GenInfo,
@@ -873,7 +873,7 @@ infer_procs_determinism_pass_1(GenInfo, [ProcId | ProcIds],
     maybe(io.text_output_stream)::in, int::in, pred_info::in,
     int::in, list(fact_arg_info)::in, list(proc_stream)::in,
     maybe(pair(io.text_output_stream, string))::in, int::in, int::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 read_in_and_compile_facts(FileStream, FileName, MaybeProgressStream,
         FactTableSize, PredInfo, NumFactArgInfos, FactArgInfos,
@@ -920,7 +920,7 @@ read_in_and_compile_facts(FileStream, FileName, MaybeProgressStream,
     maybe(io.text_output_stream)::in, int::in, pred_info::in,
     int::in, list(fact_arg_info)::in, int::in, prog_varset::in, prog_term::in,
     list(proc_stream)::in, maybe(pair(io.text_output_stream, string))::in,
-    list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::out, io::di, io::uo) is det.
 
 check_fact_term(FileStream, FileName, MaybeProgressStream, FactTableSize,
         PredInfo, NumFactArgInfos, FactArgInfos, FactNum,
@@ -976,7 +976,7 @@ check_fact_term(FileStream, FileName, MaybeProgressStream, FactTableSize,
     pred_info::in, int::in, list(fact_arg_info)::in,
     int::in, prog_varset::in, list(prog_term)::in, prog_context::in,
     list(proc_stream)::in, maybe(pair(io.text_output_stream, string))::in,
-    list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::out, io::di, io::uo) is det.
 
 check_fact_term_args(MaybeProgressStream, FactTableSize, PredInfo,
         NumFactArgInfos, FactArgInfos, FactNum, VarSet, ArgTerms, Context,
@@ -1021,7 +1021,7 @@ check_fact_term_args(MaybeProgressStream, FactTableSize, PredInfo,
     %
 :- pred check_fact_type_and_mode(pred_or_func::in, prog_varset::in,
     list(fact_arg_info)::in, list(prog_term)::in, int::in, list(fact_arg)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_fact_type_and_mode(_, _, [], [], _, [], !Specs).
 check_fact_type_and_mode(_, _, [_ | _], [], _, _, !Specs) :-
@@ -1078,7 +1078,7 @@ check_fact_type_and_mode(PredOrFunc, VarSet,
 
 :- pred report_arg_error(pred_or_func::in, prog_varset::in, int::in,
     prog_term::in, list(prog_term)::in, string::in, string::in, string::in,
-    fact_arg::out, list(diag_spec)::in, list(diag_spec)::out) is det.
+    fact_arg::out, list(err_spec)::in, list(err_spec)::out) is det.
 
 report_arg_error(PredOrFunc, VarSet, ArgNum, ArgTerm, RemainingArgTerms,
         TypeOrMode, AAn, Expected, DummyFactArg, !Specs) :-
@@ -1259,7 +1259,7 @@ struct MR_fact_table_hash_entry_i {
     %
 :- pred open_sort_files(fact_table_proc_map::in,
     list(proc_id)::in, list(proc_stream)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 open_sort_files(_, [], [], !Specs, !IO).
 open_sort_files(ProcMap, [HeadProcId | TailProcIds], ProcStreams,
@@ -1436,7 +1436,7 @@ key_from_chars_loop([Char | Chars], !EscapedCharsCord) :-
 :- pred infer_determinism_pass_2(maybe(io.text_output_stream)::in,
     fact_table_gen_info::in, assoc_list(proc_id, string)::in,
     proc_table::in, proc_table::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 infer_determinism_pass_2(_, _, [], !ProcTable, !Specs, !IO).
 infer_determinism_pass_2(MaybeProgressStream, GenInfo,
@@ -1532,7 +1532,7 @@ infer_determinism_pass_2(MaybeProgressStream, GenInfo,
     fact_table_proc_map::in, string::in, int::in, list(fact_arg_info)::in,
     maybe_write_hash_tables::in, maybe_write_data_table::in,
     string::out, proc_id::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 write_fact_table_arrays(MaybeProgressStream, OutputStream, FactTableSize,
         ModuleInfo, ProcFiles, DataFileName, FactTableProcMap,
@@ -1667,7 +1667,7 @@ write_fact_args(OutputStream, [FactArg | FactArgs], !IO) :-
     % end of the main output file and then delete it.
     %
 :- pred append_data_table(maybe(io.text_output_stream)::in,
-    string::in, string::in, list(diag_spec)::in, list(diag_spec)::out,
+    string::in, string::in, list(err_spec)::in, list(err_spec)::out,
     io::di, io::uo) is det.
 
 append_data_table(MaybeProgressStream, OutputFileName, DataFileName,
@@ -1715,7 +1715,7 @@ append_data_table(MaybeProgressStream, OutputFileName, DataFileName,
     string::in, string::in, string::in, list(fact_arg_info)::in,
     maybe_write_data_table::in, int::in, maybe_create_fact_map::in,
     fact_result::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 write_primary_hash_table(MaybeProgressStream, OutputStream, FactTableSize,
         ModuleInfo, FactTableProcMap, ProcId, FileName, DataFileName,
@@ -1799,7 +1799,7 @@ write_primary_hash_table(MaybeProgressStream, OutputStream, FactTableSize,
     list(fact_arg_info)::in, map(int, int)::in,
     assoc_list(proc_id, string)::in,
     string::in, string::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 write_secondary_hash_tables(_, _, _, _, _, _, _, _, [],
         !HeaderCode, !Specs, !IO).
@@ -1849,7 +1849,7 @@ write_secondary_hash_tables(MaybeProgressStream, OutputStream, FactTableSize,
 :- pred read_sort_file_line(io.text_input_stream::in, string::in,
     list(fact_arg_info)::in, list(fact_table_mode)::in,
     maybe(sort_file_line)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 read_sort_file_line(InputStream, InputFileName,
         FactArgInfos, Modes, MaybeSortFileLine, !Specs, !IO) :-
@@ -2059,7 +2059,7 @@ remove_sort_file_escapes([C0 | Cs0], !RevChars) :-
     list(fact_arg_info)::in, list(fact_table_mode)::in,
     int::in, string::in, int::in, sort_file_line::in, int::in,
     maybe_create_fact_map::in, map(int, int)::in, map(int, int)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 build_hash_table(MaybeProgressStream, InputStream, InputFileName, OutputStream,
         MaybeDataStream, FactTableSize, ModuleInfo, IsPrimaryTable,
@@ -2085,7 +2085,7 @@ build_hash_table(MaybeProgressStream, InputStream, InputFileName, OutputStream,
     int::in, string::in, int::in, sort_file_line::in, int::in,
     maybe_create_fact_map::in, map(int, int)::in, map(int, int)::out,
     list(hash_entry)::in, list(hash_entry)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 build_hash_table_loop(MaybeProgressStream, InputStream, InputFileName,
         OutputStream, MaybeDataStream, FactTableSize, ModuleInfo,
@@ -2240,7 +2240,7 @@ do_build_hash_table(OutputStream, Globals, IsPrimaryTable, FactMap,
 :- pred top_level_collect_matching_facts(io.text_input_stream::in, string::in,
     list(fact_arg_info)::in, list(fact_table_mode)::in,
     sort_file_line::in, list(sort_file_line)::out, maybe(sort_file_line)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 top_level_collect_matching_facts(InputStream, InputFileName,
         Infos, Modes, Fact, MatchingFacts, MaybeNextFact, !Specs, !IO) :-
@@ -2253,7 +2253,7 @@ top_level_collect_matching_facts(InputStream, InputFileName,
     string::in, list(fact_arg_info)::in, list(fact_table_mode)::in,
     sort_file_line::in, list(sort_file_line)::in, list(sort_file_line)::out,
     maybe(sort_file_line)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 top_level_collect_matching_facts_loop(InputStream, InputFileName,
         Infos, Modes, Fact, !RevMatchingFacts, MaybeNextFact, !Specs, !IO) :-
@@ -3854,7 +3854,7 @@ fact_table_size(Globals, FactTableSize) :-
     % Delete a file. Report an error message if something goes wrong.
     %
 :- pred delete_temporary_file(string::in,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 delete_temporary_file(FileName, !Specs, !IO) :-
     io.file.remove_file(FileName, Result, !IO),
@@ -3867,7 +3867,7 @@ delete_temporary_file(FileName, !Specs, !IO) :-
         Pieces = [fixed(ProgName), suffix(":"), words("error deleting file"),
             quote(FileName), suffix(":"), nl,
             words(ErrorMsg), suffix("."), nl],
-        Spec = diag_spec($pred, severity_error, phase_fact_table_check,
+        Spec = gen_spec($pred, severity_error, phase_fact_table_check,
             [gen_msg(no, treat_based_on_posn, 0u, [always(Pieces)])]),
         !:Specs = [Spec | !.Specs]
     ).
@@ -3875,7 +3875,7 @@ delete_temporary_file(FileName, !Specs, !IO) :-
 %---------------------------------------------------------------------------%
 
 :- pred add_call_system_error(string::in, io.error::in,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 add_call_system_error(Cmd, ErrorCode, !Specs, !IO) :-
     io.progname_base("mercury_compile", ProgName, !IO),
@@ -3883,14 +3883,14 @@ add_call_system_error(Cmd, ErrorCode, !Specs, !IO) :-
     Pieces = [fixed(ProgName), suffix(":"),
         words("error executing system command"), quote(Cmd), suffix(":"), nl,
         words(ErrorMsg), suffix("."), nl],
-    Spec = diag_spec($pred, severity_error, phase_fact_table_check,
+    Spec = gen_spec($pred, severity_error, phase_fact_table_check,
         [gen_msg(no, treat_based_on_posn, 0u, [always(Pieces)])]),
     !:Specs = [Spec | !.Specs].
 
 %---------------------------------------------------------------------------%
 
 :- pred add_file_open_error(maybe(prog_context)::in, string::in, string::in,
-    io.error::in, list(diag_spec)::in, list(diag_spec)::out,
+    io.error::in, list(err_spec)::in, list(err_spec)::out,
     io::di, io::uo) is det.
 
 add_file_open_error(MaybeContext, FileName, InOrOut, Error, !Specs, !IO) :-
@@ -3900,7 +3900,7 @@ add_file_open_error(MaybeContext, FileName, InOrOut, Error, !Specs, !IO) :-
         words("error opening file"), quote(FileName),
         words("for"), words(InOrOut), suffix(":"), nl,
         words(ErrorMsg), nl],
-    Spec = diag_spec($pred, severity_error, phase_fact_table_check,
+    Spec = gen_spec($pred, severity_error, phase_fact_table_check,
         [gen_msg(MaybeContext, treat_based_on_posn, 0u, [always(Pieces)])]),
     !:Specs = [Spec | !.Specs].
 
@@ -3908,7 +3908,7 @@ add_file_open_error(MaybeContext, FileName, InOrOut, Error, !Specs, !IO) :-
 
 :- pred add_error_context_and_pieces(prog_context::in,
     list(format_piece)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_error_context_and_pieces(Context, Pieces, !Specs) :-
     Spec = spec($pred, severity_error, phase_fact_table_check,
@@ -3916,7 +3916,7 @@ add_error_context_and_pieces(Context, Pieces, !Specs) :-
     !:Specs = [Spec | !.Specs].
 
 :- pred add_error_pieces(list(format_piece)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_error_pieces(Pieces, !Specs) :-
     Spec = no_ctxt_spec($pred, severity_error,
diff --git a/compiler/field_access.m b/compiler/field_access.m
index 60ec3e7e9..171978c01 100644
--- a/compiler/field_access.m
+++ b/compiler/field_access.m
@@ -302,7 +302,7 @@ parse_field_list(Term, VarSet, ContextPieces, MaybeFieldNames) :-
     ).
 
 :- func make_field_list_error(prog_varset, term.context, prog_term,
-    list(format_piece)) = diag_spec.
+    list(format_piece)) = err_spec.
 
 make_field_list_error(VarSet, Context, Term, ContextPieces) = Spec :-
     TermStr = mercury_term_to_string_vs(VarSet, print_name_only, Term),
diff --git a/compiler/file_util.m b/compiler/file_util.m
index cc46bb545..0cecf67d8 100644
--- a/compiler/file_util.m
+++ b/compiler/file_util.m
@@ -126,9 +126,9 @@
     file_name::in, io.error::in, io::di, io::uo) is det.
 
 :- func construct_spec_for_cannot_open_file_for_input(file_name,
-    maybe(module_file_id), io.error) = diag_spec.
+    maybe(module_file_id), io.error) = err_spec.
 :- func construct_spec_for_cannot_open_file_for_output(file_name, io.error)
-    = diag_spec.
+    = err_spec.
 
 %---------------------------------------------------------------------------%
 
diff --git a/compiler/float_regs.m b/compiler/float_regs.m
index 396c6e4fc..723f7a17a 100644
--- a/compiler/float_regs.m
+++ b/compiler/float_regs.m
@@ -1482,7 +1482,7 @@ report_missing_higher_order_inst(PredInfo, VarTable, Var, Context) = Spec :-
         words("of the generated code in this grade.")],
     Msg = simple_msg(Context, [always(InPieces), always(ErrorPieces),
         verbose_only(verbose_always, VerbosePieces)]),
-    Spec = diag_spec($pred, severity_error, phase_code_gen, [Msg]).
+    Spec = gen_spec($pred, severity_error, phase_code_gen, [Msg]).
 
 %---------------------------------------------------------------------------%
 
diff --git a/compiler/get_dependencies.m b/compiler/get_dependencies.m
index d5920e1e4..abc2d460d 100644
--- a/compiler/get_dependencies.m
+++ b/compiler/get_dependencies.m
@@ -352,7 +352,7 @@ acc_implicit_avail_needs_in_parse_tree_module_src(ParseTreeModuleSrc,
         _IntFIMSpecMap, _ImpFIMSpecMap, _IntSelfFIMLangs, _ImpSelfFIMLangs,
 
         TypeCtorCheckedMap, _InstCtorCheckedMap, _ModeCtorCheckedMap,
-        _TypeSpecs, _InstModeSpecs,
+        _TypeErrSpecs, _TypeWarnSpecs, _InstModeErrSpecs, _InstModeWarnSpecs,
 
         _IntTypeClasses, IntInstances, _IntPredDecls, _IntModeDecls,
         _IntDeclPragmas, _IntDeclMarkers, IntPromises, _IntBadPreds,
diff --git a/compiler/goal_expr_to_goal.m b/compiler/goal_expr_to_goal.m
index 53292ba11..c1da7b538 100644
--- a/compiler/goal_expr_to_goal.m
+++ b/compiler/goal_expr_to_goal.m
@@ -427,8 +427,8 @@ transform_dcg_record_syntax(LocKind, Renaming, AccessType, ArgTerms0, Context,
                 Context, HLDSGoal, !SVarState, !UrInfo),
             svar_finish_atomic_goal(LocKind, !SVarState)
         ;
-            MaybeFieldNames = error1(FieldNamesSpecs),
-            add_unravel_oom_specs(FieldNamesSpecs, !UrInfo),
+            MaybeFieldNames = error1(OoMFieldNamesSpecs),
+            add_unravel_oom_errs(OoMFieldNamesSpecs, !UrInfo),
             invalid_goal("^", ArgTerms1, GoalInfo, HLDSGoal,
                 !SVarState, !UrInfo),
             record_unravel_found_syntax_error(!UrInfo)
@@ -474,7 +474,7 @@ transform_dcg_record_syntax(LocKind, Renaming, AccessType, ArgTerms0, Context,
             )
         ),
         Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-        add_unravel_spec(Spec, !UrInfo)
+        add_unravel_err(Spec, !UrInfo)
     ).
 
 :- pred transform_dcg_record_syntax_2(field_access_type::in, field_list::in,
@@ -864,7 +864,7 @@ transform_parse_tree_goal_to_hlds_try(LocKind, Renaming, Goal, HLDSGoal,
                     words("part.")]) ++
                 [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            add_unravel_spec(Spec, !UrInfo),
+            add_unravel_err(Spec, !UrInfo),
             HLDSGoal = true_goal_with_context(Context)
         )
     ).
diff --git a/compiler/grab_modules.m b/compiler/grab_modules.m
index b65725ec7..442c9c946 100644
--- a/compiler/grab_modules.m
+++ b/compiler/grab_modules.m
@@ -128,26 +128,26 @@
     io::di, io::uo) is det.
 
     % grab_plain_opt_and_int_for_opt_files(ProgressStream, Globals,
-    %   BlockingSpecs, !Baggage, !AugCompUnit, !HaveParseTreeMaps, !IO):
+    %   BlockErrSpecs, !Baggage, !AugCompUnit, !HaveParseTreeMaps, !IO):
     %
     % Add the contents of the .opt files of imported modules, as well as
     % the .int files needed to make sense of them, to !AugCompUnit.
     %
 :- pred grab_plain_opt_and_int_for_opt_files(io.text_output_stream::in,
-    globals::in, list(diag_spec)::out,
+    globals::in, list(err_spec)::out,
     module_baggage::in, module_baggage::out,
     aug_compilation_unit::in, aug_compilation_unit::out,
     have_parse_tree_maps::in, have_parse_tree_maps::out,
     io::di, io::uo) is det.
 
     % grab_trans_opt_files(ProgressStream, Globals, Modules,
-    %   BlockingSpecs, !Baggage, !AugCompUnit, !HaveParseTreeMaps, !IO):
+    %   BlockErrSpecs, !Baggage, !AugCompUnit, !HaveParseTreeMaps, !IO):
     %
     % Add the contents of the .trans_opt file of each module in Modules
     % to !AugCompUnit.
     %
 :- pred grab_trans_opt_files(io.text_output_stream::in, globals::in,
-    list(module_name)::in, list(diag_spec)::out,
+    list(module_name)::in, list(err_spec)::out,
     module_baggage::in, module_baggage::out,
     aug_compilation_unit::in, aug_compilation_unit::out,
     have_parse_tree_maps::in, have_parse_tree_maps::out,
@@ -327,7 +327,7 @@ grab_unqual_imported_modules_make_int(ProgressStream, Globals,
             ImportAndOrUseMap1, ImportAndOrUseMap),
         ParseTreeModuleSrc = ParseTreeModuleSrc0
             ^ ptms_import_use_map := ImportAndOrUseMap,
-        !AugMakeIntUnit ^ amiu_delayed_specs := DelayedSpecs,
+        !AugMakeIntUnit ^ amiu_delayed_specs := coerce(DelayedSpecs),
         !AugMakeIntUnit ^ amiu_module_src := ParseTreeModuleSrc
     ).
 
@@ -572,7 +572,7 @@ grab_qual_imported_modules_augment(ProgressStream, Globals, MaybeTimestamp,
 %---------------------------------------------------------------------------%
 
 grab_plain_opt_and_int_for_opt_files(ProgressStream, Globals,
-        !:BlockingSpecs, !Baggage, !AugCompUnit, !HaveParseTreeMaps, !IO) :-
+        !:BlockErrSpecs, !Baggage, !AugCompUnit, !HaveParseTreeMaps, !IO) :-
     % Read in the .opt files for imported and ancestor modules.
     ParseTreeModuleSrc = !.AugCompUnit ^ acu_module_src,
     ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
@@ -594,7 +594,7 @@ grab_plain_opt_and_int_for_opt_files(ProgressStream, Globals,
         set.to_sorted_list(OptModules), DontQueueOptModules,
         cord.empty, ParseTreePlainOptsCord0, set.init, ExplicitDeps,
         cord.empty, ImplicitNeedsCord,
-        [], NonBlockingSpecs0, [], !:BlockingSpecs, !IO),
+        [], !:BlockErrSpecs, [], WarnSpecs0, !IO),
     ParseTreePlainOpts0 = cord.list(ParseTreePlainOptsCord0),
 
     % Get the :- pragma unused_args(...) declarations created when writing
@@ -627,8 +627,7 @@ grab_plain_opt_and_int_for_opt_files(ProgressStream, Globals,
                 OwnParseTreePlainOpt0, OwnParseTreePlainOpt),
             ParseTreePlainOpts = [OwnParseTreePlainOpt | ParseTreePlainOpts0],
             report_any_errors_in_read_opt_file(OwnOptModuleErrors,
-                !BlockingSpecs),
-            NonBlockingSpecs = NonBlockingSpecs0
+                !BlockErrSpecs, WarnSpecs0, WarnSpecs)
         ;
             HaveReadOwnPlainOpt0 =
                 have_not_read_module(OwnOptFileName, OwnOptModuleErrors),
@@ -638,11 +637,11 @@ grab_plain_opt_and_int_for_opt_files(ProgressStream, Globals,
             OwnOptModuleFileId = module_file_id(ModuleName, PlainOptExt),
             report_cannot_read_opt_file(Globals, warn_missing_opt_files,
                 OwnOptFileName, OwnOptModuleFileId, OwnOptModuleErrors,
-                NonBlockingSpecs0, NonBlockingSpecs)
+                WarnSpecs0, WarnSpecs)
         )
     else
         ParseTreePlainOpts = ParseTreePlainOpts0,
-        NonBlockingSpecs = NonBlockingSpecs0
+        WarnSpecs = WarnSpecs0
     ),
 
     list.foldl(aug_compilation_unit_add_plain_opt, ParseTreePlainOpts,
@@ -687,35 +686,35 @@ grab_plain_opt_and_int_for_opt_files(ProgressStream, Globals,
     % Return the diagnostics that describe the things that went wrong
     % in a way that prevents us continuing on to the semantic analysis passes.
     %
-    % Instead of returning a list of diag_specs, we used to return a flag
+    % Instead of returning a list of warn_specs, we used to return a flag
     % meaning "do not continue to semantic analysis". We set this flag to its
     % "do not continue" value not just when ModuleErrors ^ rm_fatal_errors
     % was nonempty, but also when ModuleErrors ^ rm_nonfatal_errors was
     % nonempty. This was a legacy of the time when we stored fatal and
     % nonfatal errors mixed together.
     ModuleErrors = !.Baggage ^ mb_errors,
-    !:BlockingSpecs =
-        ModuleErrors ^ rm_fatal_diag_specs ++
-        % ModuleErrors ^ rm_nonfatal_diag_specs ++     see above
-        !.BlockingSpecs,
+    !:BlockErrSpecs =
+        ModuleErrors ^ rm_fatal_err_specs ++
+        % ModuleErrors ^ rm_nonfatal_err_specs ++     see above
+        !.BlockErrSpecs,
 
-    % This adds NonBlockingSpecs to ModuleErrors ^ rm_nonfatal_diag_specs.
+    % This adds NonBlockingSpecs to ModuleErrors ^ rm_nonfatal_err_specs.
     % If we ever want to go back to the old behavior of considering
-    % ModuleErrors ^ rm_nonfatal_diag_specs being nonempty as grounds for
+    % ModuleErrors ^ rm_nonfatal_err_specs being nonempty as grounds for
     % stopping compiler execution before semantic analysis, then we would
-    % want the computation of !:BlockingSpecs to use the value of that field
+    % want the computation of !:BlockErrSpecs to use the value of that field
     % before this addition.
     %
     % NOTE Another legacy of the time when we stored fatal and nonfatal
     % errors mixed together was that previously, we also added the original
-    % !.BlockingSpecs (i.e. the version from before adding
-    % ModuleErrors ^ rm_fatal_diag_specs) to the baggage as well.
-    module_baggage_add_nonfatal_specs(NonBlockingSpecs, !Baggage).
+    % !.BlockErrSpecs (i.e. the version from before adding
+    % ModuleErrors ^ rm_fatal_warn_specs) to the baggage as well.
+    module_baggage_add_warnings(WarnSpecs, !Baggage).
 
 %---------------------------------------------------------------------------%
 
 grab_trans_opt_files(ProgressStream, Globals, TransOptModuleNames,
-        BlockingSpecs, !Baggage, !AugCompUnit,
+        BlockErrSpecs, !Baggage, !AugCompUnit,
         HaveParseTreeMaps, HaveParseTreeMaps, !IO) :-
     % XXX We should be using !HaveParseTreeMaps.
     globals.lookup_bool_option(Globals, verbose, Verbose),
@@ -725,10 +724,11 @@ grab_trans_opt_files(ProgressStream, Globals, TransOptModuleNames,
 
     read_trans_opt_files(ProgressStream, Globals, TransOptModuleNames,
         cord.init, ParseTreeTransOptsCord,
-        [], NonBlockingSpecs, [], BlockingSpecs, !IO),
+        [], BlockErrSpecs, [], WarnSpecs, !IO),
     list.foldl(aug_compilation_unit_add_trans_opt,
         cord.list(ParseTreeTransOptsCord), !AugCompUnit),
-    module_baggage_add_nonfatal_specs(NonBlockingSpecs, !Baggage),
+    % XXX DIAG_SPECS We used to call module_baggage_add_nonfatal_specs.
+    module_baggage_add_warnings(WarnSpecs, !Baggage),
     % XXX why ignore any existing errors?
     !Baggage ^ mb_errors := init_read_module_errors,
 
@@ -1342,14 +1342,24 @@ module_baggage_add_grabbed_file(ModuleName, FileWhy, !Baggage) :-
     map.set(ModuleName, FileWhy, GrabbedFileMap0, GrabbedFileMap),
     !Baggage ^ mb_grabbed_file_map := GrabbedFileMap.
 
-:- pred module_baggage_add_nonfatal_specs(list(diag_spec)::in,
+:- pred module_baggage_add_nonfatal_specs(list(err_spec)::in,
     module_baggage::in, module_baggage::out) is det.
 
 module_baggage_add_nonfatal_specs(NewSpecs, !Baggage) :-
     Errors0 = !.Baggage ^ mb_errors,
-    NonFatalErrorSpecs0 = Errors0 ^ rm_nonfatal_diag_specs,
+    NonFatalErrorSpecs0 = Errors0 ^ rm_nonfatal_err_specs,
     NonFatalErrorSpecs = NewSpecs ++ NonFatalErrorSpecs0,
-    Errors = Errors0 ^ rm_nonfatal_diag_specs := NonFatalErrorSpecs,
+    Errors = Errors0 ^ rm_nonfatal_err_specs := NonFatalErrorSpecs,
+    !Baggage ^ mb_errors := Errors.
+
+:- pred module_baggage_add_warnings(list(warn_spec)::in,
+    module_baggage::in, module_baggage::out) is det.
+
+module_baggage_add_warnings(NewSpecs, !Baggage) :-
+    Errors0 = !.Baggage ^ mb_errors,
+    WarnSpecs0 = Errors0 ^ rm_warn_specs,
+    WarnSpecs = NewSpecs ++ WarnSpecs0,
+    Errors = Errors0 ^ rm_warn_specs := WarnSpecs,
     !Baggage ^ mb_errors := Errors.
 
 :- pred module_baggage_add_errors(read_module_errors::in,
@@ -1408,17 +1418,15 @@ keep_only_unused_and_reuse_pragmas_in_parse_tree_plain_opt(
     cord(parse_tree_plain_opt)::in, cord(parse_tree_plain_opt)::out,
     set(module_name)::in, set(module_name)::out,
     cord(implicit_avail_needs)::in, cord(implicit_avail_needs)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out, io::di, io::uo) is det.
 
 read_plain_opt_files(_, _, _, _, [], _, !ParseTreePlainOptsCord,
-        !ExplicitDeps, !ImplicitNeeds, !NonBlockingSpecs, !BlockingSpecs, !IO).
+        !ExplicitDeps, !ImplicitNeeds, !BlockErrSpecs, !WarnSpecs, !IO).
 read_plain_opt_files(ProgressStream, Globals, VeryVerbose,
         ReadOptFilesTransitively, [ModuleName | ModuleNames0],
         DontQueueOptModules0, !ParseTreePlainOptsCord,
-        !ExplicitDeps, !ImplicitNeeds,
-        !NonBlockingSpecs, !BlockingSpecs, !IO) :-
+        !ExplicitDeps, !ImplicitNeeds, !BlockErrSpecs, !WarnSpecs, !IO) :-
     read_module_plain_opt(ProgressStream, Globals, ModuleName,
         HaveReadPlainOpt, !IO),
     (
@@ -1426,7 +1434,8 @@ read_plain_opt_files(ProgressStream, Globals, VeryVerbose,
         have_parse_tree_source_get_maybe_timestamp_errors(Source,
             _, ModuleErrors),
         cord.snoc(ParseTreePlainOpt, !ParseTreePlainOptsCord),
-        report_any_errors_in_read_opt_file(ModuleErrors, !BlockingSpecs),
+        report_any_errors_in_read_opt_file(ModuleErrors,
+            !BlockErrSpecs, !WarnSpecs),
 
         get_explicit_and_implicit_avail_needs_in_parse_tree_plain_opt(
             ParseTreePlainOpt, ParseTreeExplicitDeps, ParseTreeImplicitNeeds),
@@ -1452,7 +1461,7 @@ read_plain_opt_files(ProgressStream, Globals, VeryVerbose,
             ext_cur_ngs_gs_max_ngs(ext_cur_ngs_gs_max_ngs_legacy_opt_plain),
         ModuleFileId = module_file_id(ModuleName, PlainOptExt),
         report_cannot_read_opt_file(Globals, warn_missing_opt_files,
-            FileName, ModuleFileId, ModuleErrors, !NonBlockingSpecs),
+            FileName, ModuleFileId, ModuleErrors, !WarnSpecs),
         ModuleNames1 = ModuleNames0,
         DontQueueOptModules1 = DontQueueOptModules0
     ),
@@ -1460,21 +1469,20 @@ read_plain_opt_files(ProgressStream, Globals, VeryVerbose,
     read_plain_opt_files(ProgressStream, Globals, VeryVerbose,
         ReadOptFilesTransitively, ModuleNames1, DontQueueOptModules1,
         !ParseTreePlainOptsCord, !ExplicitDeps, !ImplicitNeeds,
-        !NonBlockingSpecs, !BlockingSpecs, !IO).
+        !BlockErrSpecs, !WarnSpecs, !IO).
 
 %---------------------------------------------------------------------------%
 
 :- pred read_trans_opt_files(io.text_output_stream::in, globals::in,
     list(module_name)::in,
     cord(parse_tree_trans_opt)::in, cord(parse_tree_trans_opt)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out, io::di, io::uo) is det.
 
 read_trans_opt_files(_, _, [], !ParseTreeTransOpts,
-        !NonBlockingSpecs, !BlockingSpecs, !IO).
+        !BlockErrSpecs, !WarnSpecs, !IO).
 read_trans_opt_files(ProgressStream, Globals, [ModuleName | ModuleNames],
-        !ParseTreeTransOptsCord, !NonBlockingSpecs, !BlockingSpecs, !IO) :-
+        !ParseTreeTransOptsCord, !BlockErrSpecs, !WarnSpecs, !IO) :-
     read_module_trans_opt(ProgressStream, Globals, ModuleName,
         HaveReadTransOpt, !IO),
     (
@@ -1482,7 +1490,8 @@ read_trans_opt_files(ProgressStream, Globals, [ModuleName | ModuleNames],
         have_parse_tree_source_get_maybe_timestamp_errors(Source,
             _, ModuleErrors),
         cord.snoc(ParseTreeTransOpt, !ParseTreeTransOptsCord),
-        report_any_errors_in_read_opt_file(ModuleErrors, !BlockingSpecs)
+        report_any_errors_in_read_opt_file(ModuleErrors,
+            !BlockErrSpecs, !WarnSpecs)
     ;
         HaveReadTransOpt = have_not_read_module(FileName, ReadErrors),
         WarnOpt = warn_missing_trans_opt_files,
@@ -1490,10 +1499,10 @@ read_trans_opt_files(ProgressStream, Globals, [ModuleName | ModuleNames],
             ext_cur_ngs_gs_max_ngs(ext_cur_ngs_gs_max_ngs_legacy_opt_trans),
         ModuleFileId = module_file_id(ModuleName, TransOptExt),
         report_cannot_read_opt_file(Globals, WarnOpt, FileName, ModuleFileId,
-            ReadErrors, !NonBlockingSpecs)
+            ReadErrors, !WarnSpecs)
     ),
     read_trans_opt_files(ProgressStream, Globals, ModuleNames,
-        !ParseTreeTransOptsCord, !NonBlockingSpecs, !BlockingSpecs, !IO).
+        !ParseTreeTransOptsCord, !BlockErrSpecs, !WarnSpecs, !IO).
 
 %---------------------------------------------------------------------------%
 
@@ -1513,17 +1522,17 @@ read_trans_opt_files(ProgressStream, Globals, [ModuleName | ModuleNames],
     %
 :- pred report_cannot_read_opt_file(globals::in, option::in,
     file_name::in, module_file_id::in, read_module_errors::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 report_cannot_read_opt_file(Globals, WarnOption, FileName, ModuleFileId,
-        ReadModuleErrors, !NonBlockingSpecs) :-
+        ReadModuleErrors, !WarnSpecs) :-
     % We get here if we couldn't find and/or open the file.
-    % ModuleErrors ^ rm_fatal_diag_specs will already contain
-    % an error_severity diag_spec about that, with more details
+    % ModuleErrors ^ rm_fatal_warn_specs will already contain
+    % an error_severity warn_spec about that, with more details
     % than the message we generate below, but the test case
     % hard_coded/intermod_unused_args insists on there being no error,
     % only a warning with the text below. That is why we do not add
-    % any diag_specs from ModuleErrors to !Specs here.
+    % any warn_specs from ModuleErrors to !Specs here.
     %
     % I (zs) don't know whether we should add a version of ModuleSpecs
     % with downgraded severity to !Specs instead of the Spec we generate
@@ -1541,17 +1550,17 @@ report_cannot_read_opt_file(Globals, WarnOption, FileName, ModuleFileId,
         else
             Phase = phase_read_files
         ),
-        Spec = no_ctxt_spec($pred, severity_warning(WarnOption),
-            Phase, Pieces),
-        !:NonBlockingSpecs = [Spec | !.NonBlockingSpecs]
+        Severity = severity_warning(WarnOption),
+        Spec = no_ctxt_spec($pred, Severity, Phase, Pieces),
+        !:WarnSpecs = [Spec | !.WarnSpecs]
     ).
-    % NOTE: We do NOT update !BlockingSpecs, since a missing optimization
+    % NOTE: We do NOT update !BlockErrSpecs, since a missing optimization
     % interface file is not necessarily an error.
 
-    % report_any_errors_in_read_opt_file(ModuleErrors, !BlockingSpecs):
+    % report_any_errors_in_read_opt_file(ModuleErrors, !BlockErrSpecs):
     %
     % Work out whether any errors have occurred while reading
-    % a .opt or .trans_opt file, and update !BlockingSpecs accordingly.
+    % a .opt or .trans_opt file, and update !BlockErrSpecs accordingly.
     % Note that
     %
     % - we can ignore *not finding* a .opt or .trans_opt file,
@@ -1565,9 +1574,10 @@ report_cannot_read_opt_file(Globals, WarnOption, FileName, ModuleFileId,
     %   - or that the file has been tampered with later.
     %
 :- pred report_any_errors_in_read_opt_file(read_module_errors::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-report_any_errors_in_read_opt_file(ModuleErrors, !BlockingSpecs) :-
+report_any_errors_in_read_opt_file(ModuleErrors, !BlockErrSpecs, !WarnSpecs) :-
     FatalErrors = ModuleErrors ^ rm_fatal_errors,
     NonFatalErrors0 = ModuleErrors ^ rm_nonfatal_errors,
     set.delete(rme_nec, NonFatalErrors0, NonFatalErrors),
@@ -1588,9 +1598,10 @@ report_any_errors_in_read_opt_file(ModuleErrors, !BlockingSpecs) :-
         % Not adding either of those to !Specs preserves old behavior.
         true
     else
-        ModuleSpecs = get_read_module_specs(ModuleErrors),
-        expect_not(unify(ModuleSpecs, []), $pred, "ModuleSpecs = []"),
-        !:BlockingSpecs = ModuleSpecs ++ !.BlockingSpecs
+        get_read_module_specs(ModuleErrors, ModuleErrSpecs, ModuleWarnSpecs),
+        expect_not(unify(ModuleErrSpecs, []), $pred, "ModuleErrSpecs = []"),
+        !:BlockErrSpecs = ModuleErrSpecs ++ !.BlockErrSpecs,
+        !:WarnSpecs = ModuleWarnSpecs ++ !.WarnSpecs
     ).
 
 %---------------------------------------------------------------------------%
diff --git a/compiler/handle_options.m b/compiler/handle_options.m
index 6310b7bd6..4bea027b8 100644
--- a/compiler/handle_options.m
+++ b/compiler/handle_options.m
@@ -2206,7 +2206,7 @@ handle_chosen_stdlib_dir(MaybeEnvOptFileMerStdLibDir, !Globals, !Specs) :-
         ;
             MaybeEnvOptFileMerStdLibDir = error1(EnvOptFileSpecs),
             MaybeChosenStdLibDir = no,
-            !:Specs = EnvOptFileSpecs ++ !.Specs
+            !:Specs = coerce(EnvOptFileSpecs) ++ !.Specs
         )
     ),
     globals.set_option(chosen_stdlib_dir, maybe_string(MaybeChosenStdLibDir),
@@ -3390,7 +3390,7 @@ disable_smart_recompilation(OptionDescr, !Globals, !Specs, !IO) :-
 usage_errors(ProgressStream, Globals, Specs, !IO) :-
     io.progname_base("mercury_compile", ProgName, !IO),
     io.format(ProgressStream, "%s:\n", [s(ProgName)], !IO),
-    write_error_specs(ProgressStream, Globals, Specs, !IO). % usage msg only
+    write_diag_specs(ProgressStream, Globals, Specs, !IO). % usage msg only
 
 %---------------------------------------------------------------------------%
 :- end_module libs.handle_options.
diff --git a/compiler/hlds_clauses.m b/compiler/hlds_clauses.m
index 3ac97d3ab..6706e918e 100644
--- a/compiler/hlds_clauses.m
+++ b/compiler/hlds_clauses.m
@@ -337,7 +337,7 @@
                 clause_body                 :: hlds_goal,
                 clause_lang                 :: implementation_language,
                 clause_context              :: prog_context,
-                clause_statevar_warnings    :: list(diag_spec),
+                clause_statevar_warnings    :: list(warn_spec),
                 clause_unused_svar_arg_map  :: unused_statevar_arg_map,
                 clause_maybe_fact           :: is_clause_a_fact
             ).
diff --git a/compiler/hlds_data.m b/compiler/hlds_data.m
index 30ac4021c..934411564 100644
--- a/compiler/hlds_data.m
+++ b/compiler/hlds_data.m
@@ -742,7 +742,7 @@ map_foldl_over_type_ctor_defns_2(Pred, _Name, !TypeCtorTable, !Acc) :-
     %
 :- type type_defn_prev_errors
     --->    type_defn_no_prev_errors
-    ;       type_defn_prev_errors(diag_spec).
+    ;       type_defn_prev_errors(err_spec).
 
     % An `hlds_type_body' holds the body of a type definition:
     % du = discriminated union, eqv_type = equivalence type (a type defined
diff --git a/compiler/hlds_pred.m b/compiler/hlds_pred.m
index e426ebf1c..169c4b6ce 100644
--- a/compiler/hlds_pred.m
+++ b/compiler/hlds_pred.m
@@ -2008,7 +2008,7 @@ pred_info_get_sym_name(PredInfo, SymName) :-
     eval_method::out, prog_context::out, item_seq_num::out,
     can_process::out, maybe(mode_constraint)::out, detism_decl::out,
     list(prog_context)::out, maybe(untuple_proc_info)::out,
-    map(prog_var, string)::out, list(diag_spec)::out, set(pred_proc_id)::out,
+    map(prog_var, string)::out, list(warn_spec)::out, set(pred_proc_id)::out,
     is_address_taken::out, proc_foreign_exports::out, has_parallel_conj::out,
     has_user_event::out, has_tail_rec_call::out, list(oisu_pred_kind_for)::out,
     maybe(require_tail_recursion)::out, set_of_progvar::out,
@@ -2029,7 +2029,7 @@ pred_info_get_sym_name(PredInfo, SymName) :-
     eval_method::in, prog_context::in, item_seq_num::in, can_process::in,
     maybe(mode_constraint)::in, detism_decl::in,
     list(prog_context)::in, maybe(untuple_proc_info)::in,
-    map(prog_var, string)::in, list(diag_spec)::in, set(pred_proc_id)::in,
+    map(prog_var, string)::in, list(warn_spec)::in, set(pred_proc_id)::in,
     is_address_taken::in, proc_foreign_exports::in, has_parallel_conj::in,
     has_user_event::in, has_tail_rec_call::in, list(oisu_pred_kind_for)::in,
     maybe(require_tail_recursion)::in, set_of_progvar::in,
@@ -2153,7 +2153,7 @@ pred_info_get_sym_name(PredInfo, SymName) :-
 :- pred proc_info_get_var_name_remap(proc_info::in,
     map(prog_var, string)::out) is det.
 :- pred proc_info_get_statevar_warnings(proc_info::in,
-    list(diag_spec)::out) is det.
+    list(warn_spec)::out) is det.
 :- pred proc_info_get_deleted_call_callees(proc_info::in,
     set(pred_proc_id)::out) is det.
 :- pred proc_info_get_is_address_taken(proc_info::in,
@@ -2238,7 +2238,7 @@ pred_info_get_sym_name(PredInfo, SymName) :-
     proc_info::in, proc_info::out) is det.
 :- pred proc_info_set_var_name_remap(map(prog_var, string)::in,
     proc_info::in, proc_info::out) is det.
-:- pred proc_info_set_statevar_warnings(list(diag_spec)::in,
+:- pred proc_info_set_statevar_warnings(list(warn_spec)::in,
     proc_info::in, proc_info::out) is det.
 :- pred proc_info_set_deleted_call_callees(set(pred_proc_id)::in,
     proc_info::in, proc_info::out) is det.
@@ -2455,7 +2455,7 @@ pred_info_get_sym_name(PredInfo, SymName) :-
                 % Any warnings generated by the state variable transformation
                 % that we should print only if we find a mode error that could
                 % be caused by the problem being warned about.
-                psi_statevar_warnings           :: list(diag_spec),
+                psi_statevar_warnings           :: list(warn_spec),
 
                 % The set of procedures that the body of this procedure
                 % *used* to call, but doesn't anymore. This can happen
diff --git a/compiler/instance_method_clauses.m b/compiler/instance_method_clauses.m
index 76d64ac4c..0d89c4f58 100644
--- a/compiler/instance_method_clauses.m
+++ b/compiler/instance_method_clauses.m
@@ -35,7 +35,8 @@
     pred_or_func::in, list(mer_type)::in, pred_markers::in, term.context::in,
     instance_status::in, clauses_info::out, tvarset::in, tvarset::out,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -68,7 +69,7 @@
 
 produce_instance_method_clauses(InstanceProcDefn, PredOrFunc, ArgTypes,
         Markers, Context, InstanceStatus, ClausesInfo,
-        !TVarSet, !ModuleInfo, !QualInfo, !Specs) :-
+        !TVarSet, !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     PredFormArity = arg_list_arity(ArgTypes),
     (
         % Handle the `pred(<MethodName>/<Arity>) is <ImplName>' syntax.
@@ -115,22 +116,23 @@ produce_instance_method_clauses(InstanceProcDefn, PredOrFunc, ArgTypes,
         % XXX CIT_TYPES: should be cit_types(ArgTypes)
         clauses_info_init(PredOrFunc, cit_no_types(PredFormArity),
             init_clause_item_numbers_comp_gen, ClausesInfo0),
-        list.foldl5(
+        list.foldl6(
             produce_instance_method_clause(PredOrFunc, Context,
                 InstanceStatus),
             InstanceClauses, !TVarSet, !ModuleInfo, !QualInfo,
-            ClausesInfo0, ClausesInfo, !Specs)
+            ClausesInfo0, ClausesInfo, !ErrSpecs, !WarnSpecs)
     ).
 
 :- pred produce_instance_method_clause(pred_or_func::in,
     prog_context::in, instance_status::in, item_clause_info::in,
     tvarset::in, tvarset::out, module_info::in, module_info::out,
     qual_info::in, qual_info::out, clauses_info::in, clauses_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 produce_instance_method_clause(PredOrFunc, Context, InstanceStatus,
         InstanceClause, TVarSet0, TVarSet, !ModuleInfo, !QualInfo,
-        !ClausesInfo, !Specs) :-
+        !ClausesInfo, !ErrSpecs, !WarnSpecs) :-
     InstanceClause = item_clause_info(ClausePredOrFunc, PredSymName,
         HeadTerms0, ClauseVarSet, MaybeBodyGoal, _ClauseContext, _SeqNum),
     % XXX Can this ever fail? If yes, we should generate an error message
@@ -143,16 +145,20 @@ produce_instance_method_clause(PredOrFunc, Context, InstanceStatus,
         TVarSet = TVarSet0,
         ResultSpec = report_illegal_func_svar_result_raw(StateVarContext,
             ClauseVarSet, StateVar),
-        !:Specs = [ResultSpec | get_any_errors_warnings2(MaybeBodyGoal)] ++
-            !.Specs
+        get_all_errors_warnings2(MaybeBodyGoal,
+            BodyGoalErrSpecs, BodyGoalWarnSpecs),
+        !:ErrSpecs = [ResultSpec | BodyGoalErrSpecs] ++ !.ErrSpecs,
+        !:WarnSpecs = BodyGoalWarnSpecs ++ !.WarnSpecs
     else
         (
-            MaybeBodyGoal = error2(BodyGoalSpecs),
+            MaybeBodyGoal = error2({OoMBodyGoalErrSpecs, BodyGoalWarnSpecs}),
             TVarSet = TVarSet0,
-            !:Specs = one_or_more_to_list(BodyGoalSpecs) ++ !.Specs
+            !:ErrSpecs =
+                one_or_more_to_list(OoMBodyGoalErrSpecs) ++ !.ErrSpecs,
+            !:WarnSpecs = BodyGoalWarnSpecs ++ !.WarnSpecs
         ;
             MaybeBodyGoal = ok2(BodyGoal, BodyGoalWarningSpecs),
-            !:Specs = BodyGoalWarningSpecs ++ !.Specs,
+            !:WarnSpecs = BodyGoalWarningSpecs ++ !.WarnSpecs,
             expand_bang_state_pairs_in_terms(HeadTerms0, HeadTerms),
             % AllProcIds is only used when the predicate has foreign procs,
             % which the instance method pred should not have, so this
@@ -165,7 +171,7 @@ produce_instance_method_clause(PredOrFunc, Context, InstanceStatus,
                 clause_not_for_promise, PredOrFunc, PredSymName, HeadTerms,
                 Context, item_no_seq_num, BodyGoal, ClauseVarSet,
                 TVarSet0, TVarSet, !ClausesInfo, !ModuleInfo,
-                !QualInfo, !Specs)
+                !QualInfo, !ErrSpecs, !WarnSpecs)
         )
     ).
 
diff --git a/compiler/make.build.m b/compiler/make.build.m
index af6f8e165..bca51945f 100644
--- a/compiler/make.build.m
+++ b/compiler/make.build.m
@@ -209,7 +209,7 @@ setup_for_build_with_module_options(ProgressStream, DefaultOptionTable,
         MaybeModuleOptionArgs),
     (
         MaybeModuleOptionArgs = error1(LookupSpecs),
-        MayBuild = may_not_build(LookupSpecs)
+        MayBuild = may_not_build(oom_err_to_oom_diag(LookupSpecs))
     ;
         MaybeModuleOptionArgs = ok1(ModuleOptionArgs),
         % --invoked-by-mmc-make disables reading DEFAULT_MCFLAGS from the
diff --git a/compiler/make.get_module_dep_info.m b/compiler/make.get_module_dep_info.m
index c75e39c17..ba48bd637 100644
--- a/compiler/make.get_module_dep_info.m
+++ b/compiler/make.get_module_dep_info.m
@@ -556,7 +556,7 @@ try_to_write_module_dep_files_for_top_module(ProgressStream, Globals,
         % warnings from errors, but without some test cases targeting
         % this kind of error, I cannot know for certain that removing
         % the next line does not have any effect.
-        ReadModuleErrors = ReadModuleErrors0 ^ rm_warning_specs := [],
+        ReadModuleErrors = ReadModuleErrors0 ^ rm_warn_specs := [],
         cannot_write_module_dep_files(Globals, ProgressStream,
             ModuleName, ReadModuleErrors, !Info, !IO)
     ).
@@ -579,10 +579,11 @@ report_cannot_read_src_to_generate_module_dep(ProgressStream, SourceFileName,
 
 cannot_write_module_dep_files(Globals, ProgressStream, ModuleName,
         ReadModuleErrors, !Info, !IO) :-
-    Specs0 = get_read_module_specs(ReadModuleErrors),
+    get_read_module_specs(ReadModuleErrors, ErrSpecs0, WarnSpecs0),
+    Specs0 = coerce(ErrSpecs0) ++ coerce(WarnSpecs0),
     % XXX ProgressStream may not be stdout.
     with_locked_stdout(!.Info,
-        write_error_specs(ProgressStream, Globals, Specs0),
+        write_diag_specs(ProgressStream, Globals, Specs0),
         !IO),
 
     ModuleDepMap0 = make_info_get_maybe_module_dep_info_map(!.Info),
@@ -602,7 +603,7 @@ write_module_dep_files_for_source_file(Globals, ProgressStream,
         MaybeTimestamp, ParseTreeSrc, !Info, !IO) :-
     parse_tree_src_to_burdened_module_list(Globals, SourceFileName,
         ReadModuleErrors, MaybeTimestamp, ParseTreeSrc,
-        Specs, BurdenedModules),
+        ErrSpecs, WarnSpecs, BurdenedModules),
     ParseTreeModuleSrcs = list.map((func(burdened_module(_, PTMS)) = PTMS),
         BurdenedModules),
     SubModuleNames = list.map(parse_tree_module_src_project_name,
@@ -610,7 +611,8 @@ write_module_dep_files_for_source_file(Globals, ProgressStream,
 
     % XXX Why are we ignoring all previously reported errors?
     io.set_exit_status(0, !IO),
-    write_error_specs(ErrorStream, Globals, Specs, !IO),
+    Specs = coerce(ErrSpecs) ++ coerce(WarnSpecs),
+    write_diag_specs(ErrorStream, Globals, Specs, !IO),
 
     list.foldl(make_info_add_burdened_module_as_dep, BurdenedModules, !Info),
 
@@ -694,7 +696,7 @@ make_int3_files(ProgressStream, ErrorStream, Globals,
             do_not_add_new_to_hptm),
         BurdenedModules, Succeededs, SpecsList,
         init_have_parse_tree_maps, _HaveParseTreeMaps, !IO),
-    list.foldl(write_error_specs(ErrorStream, Globals), SpecsList, !IO),
+    list.foldl(write_diag_specs(ErrorStream, Globals), SpecsList, !IO),
     Succeeded = and_list(Succeededs).
 
 :- pred cleanup_int3_files(io.text_output_stream::in, globals::in,
diff --git a/compiler/make.library_install.m b/compiler/make.library_install.m
index c4305becf..77e525f4c 100644
--- a/compiler/make.library_install.m
+++ b/compiler/make.library_install.m
@@ -613,7 +613,7 @@ setup_make_and_install_grade_specific_files_for_grade(ProgressStream, Globals,
             OptionsSpecs, LibGlobals, !IO)
     ;
         MaybeMCFlags = error1(LookupSpecs),
-        write_oom_diag_specs(ProgressStream, Globals, LookupSpecs, !IO),
+        write_oom_error_specs(ProgressStream, Globals, LookupSpecs, !IO),
         % Errors should have been caught before.
         unexpected($pred, "bad DEFAULT_MCFLAGS")
     ),
@@ -699,7 +699,7 @@ make_and_install_grade_specific_files_for_grades(ProgressStream, Globals,
         LibSucceeded = did_not_succeed,
         % XXX MAKE_STREAM
         io.output_stream(ErrorStream, !IO),
-        write_error_specs(ErrorStream, Globals, Specs, !IO),
+        write_diag_specs(ErrorStream, Globals, Specs, !IO),
         Succeeded = did_not_succeed
     ).
 
diff --git a/compiler/make.module_target.m b/compiler/make.module_target.m
index 957cb6020..9bf748e90 100644
--- a/compiler/make.module_target.m
+++ b/compiler/make.module_target.m
@@ -520,7 +520,7 @@ build_object_code(ProgressStream, ErrorStream, Globals, Target, PIC,
         % XXX MAKE This predicate, build_object_code, is invoked only as the
         % top call in a newly-spawned-off process. We cannot return Specs
         % to our caller, because our caller is in a separate process.
-        write_error_specs(ErrorStream, Globals, Specs, !IO)
+        write_diag_specs(ErrorStream, Globals, Specs, !IO)
     ).
 
 :- pred compile_foreign_code_file(globals::in, io.text_output_stream::in,
diff --git a/compiler/make.program_target.m b/compiler/make.program_target.m
index 33532fbd4..2c2280d41 100644
--- a/compiler/make.program_target.m
+++ b/compiler/make.program_target.m
@@ -134,7 +134,7 @@ make_linked_target(ProgressStream, Globals, LinkedTargetFile,
                 LinkedTargetSucceeded, !Info, !Specs, !IO)
         ;
             LibgradeCheckSpecs = [_ | _],
-            !:Specs = LibgradeCheckSpecs ++ !.Specs,
+            !:Specs = coerce(LibgradeCheckSpecs) ++ !.Specs,
             LinkedTargetSucceeded = did_not_succeed
         )
     ).
@@ -654,7 +654,7 @@ link_and_write_error_specs(Globals, ProgressStream,
         Globals, LinkTargetType, ModuleName, ObjectsList,
         Specs, Succeeded, !IO),
     % The errors we can get here are not specific to any Mercury module.
-    write_error_specs(ProgressStream, Globals, Specs, !IO).
+    write_diag_specs(ProgressStream, Globals, Specs, !IO).
 
 %---------------------------------------------------------------------------%
 
diff --git a/compiler/make.top_level.m b/compiler/make.top_level.m
index e7e1a54fe..f42edf76b 100644
--- a/compiler/make.top_level.m
+++ b/compiler/make.top_level.m
@@ -92,7 +92,7 @@ make_process_compiler_args(ProgressStream, Globals, ArgPack, !IO) :-
     (
         MaybeTargets = error1(Specs),
         io.stderr_stream(StdErr, !IO),
-        write_oom_diag_specs(StdErr, Globals, Specs, !IO)
+        write_oom_error_specs(StdErr, Globals, Specs, !IO)
     ;
         MaybeTargets = ok1(Targets),
         globals.lookup_bool_option(Globals, keep_going, KeepGoingBool),
@@ -205,7 +205,7 @@ report_any_absolute_targets(ProgName, MaybeTargets0, MaybeTargets) :-
         )
     ).
 
-:- func report_target_with_dir_component(string, string) = diag_spec.
+:- func report_target_with_dir_component(string, string) = err_spec.
 
 report_target_with_dir_component(ProgName, Target) = Spec :-
     Pieces = [fixed(ProgName), suffix(":"),
@@ -260,12 +260,12 @@ make_top_target(ProgressStream, Globals, Target, Succeeded, !Info, !IO) :-
                 linked_target_file(ModuleName, LinkedTargetType),
             make_linked_target(ProgressStream, Globals, LinkedTargetFile,
                 Succeeded, !Info, [], Specs, !IO),
-            write_error_specs(ErrorStream, Globals, Specs, !IO)
+            write_diag_specs(ErrorStream, Globals, Specs, !IO)
         ;
             TargetType = misc_target(MiscTargetType),
             make_misc_target(ProgressStream, Globals,
                 ModuleName - MiscTargetType, Succeeded, !Info, [], Specs, !IO),
-            write_error_specs(ErrorStream, Globals, Specs, !IO)
+            write_diag_specs(ErrorStream, Globals, Specs, !IO)
         )
     ;
         TrackFlagsSucceeded = did_not_succeed,
diff --git a/compiler/make.track_flags.m b/compiler/make.track_flags.m
index cb60eef14..3772a7a34 100644
--- a/compiler/make.track_flags.m
+++ b/compiler/make.track_flags.m
@@ -171,7 +171,7 @@ make_track_flags_files_for_module(ErrorStream, ProgressStream, Globals, Info,
         % I also don't think we have a good basis for deciding the answer
         % to that question until we have practical experience with
         % compiler invocations that lead execution to this spot.
-        write_oom_diag_specs(ErrorStream, Globals, LookupSpecs, !IO),
+        write_oom_error_specs(ErrorStream, Globals, LookupSpecs, !IO),
         Succeeded = did_not_succeed
     ).
 
diff --git a/compiler/make_hlds_error.m b/compiler/make_hlds_error.m
index 9d95d4592..1c7314845 100644
--- a/compiler/make_hlds_error.m
+++ b/compiler/make_hlds_error.m
@@ -46,7 +46,7 @@
     %
 :- pred report_multiply_defined(string::in, sym_name::in, user_arity::in,
     prog_context::in, prog_context::in, list(format_piece)::in,
-    diag_spec::out) is det.
+    err_spec::out) is det.
 
     % report_undefined_pred_or_func_error(MaybePorF, SymName,
     %    UserArity, OtherUserArities, Context, DeclPieces, !Specs):
@@ -60,23 +60,22 @@
     %
 :- pred report_undefined_pred_or_func_error(maybe(pred_or_func)::in,
     sym_name::in, user_arity::in, list(user_arity)::in, prog_context::in,
-    list(format_piece)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(format_piece)::in, err_spec::out) is det.
 
 :- pred report_undeclared_mode_error(module_info::in,
     pred_id::in, pred_info::in, prog_varset::in, list(mer_mode)::in,
-    list(format_piece)::in, prog_context::in, diag_spec::out) is det.
+    list(format_piece)::in, prog_context::in, err_spec::out) is det.
 
 :- pred maybe_report_undefined_pred_error(module_info::in,
     pred_or_func::in, sym_name::in, pred_form_arity::in, pred_status::in,
     maybe_class_method::in, prog_context::in, list(format_piece)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
 :- pred maybe_warn_about_pfumm_unknown(module_info::in, string::in,
     pred_func_or_unknown_maybe_modes::in, sym_name::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::out) is det.
 
 :- type does_pragma_allow_modes
     --->    pragma_does_not_allow_modes
@@ -84,7 +83,7 @@
 
 :- pred warn_about_pfu_unknown(module_info::in, string::in,
     does_pragma_allow_modes::in, sym_name::in, user_arity::in,
-    prog_context::in, list(diag_spec)::out) is det.
+    prog_context::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -149,11 +148,11 @@ report_multiply_defined(EntityKind, SymName, UserArity, Context, OrigContext,
         ExtraPieces = [_ | _],
         ExtraMsgs = [msg(SecondContext, ExtraPieces)]
     ),
-    Spec = diag_spec($pred, severity_error, phase_pt2h,
+    Spec = gen_spec($pred, severity_error, phase_pt2h,
         [SecondDeclMsg, FirstDeclMsg | ExtraMsgs]).
 
 report_undefined_pred_or_func_error(MaybePorF, SymName,
-        UserArity, OtherUserArities, Context, DeclPieces, !Specs) :-
+        UserArity, OtherUserArities, Context, DeclPieces, Spec) :-
     (
         MaybePorF = no,
         SNAPrefixPieces = [],
@@ -193,8 +192,7 @@ report_undefined_pred_or_func_error(MaybePorF, SymName,
             [nl]
     ),
     Pieces = MainPieces ++ OtherArityPieces,
-    Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-    !:Specs = [Spec | !.Specs].
+    Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces).
 
 %---------------------------------------------------------------------------%
 
@@ -243,7 +241,7 @@ report_undeclared_mode_error(ModuleInfo, PredId, PredInfo, VarSet, ArgModes,
     ),
     Msg = simple_msg(Context,
         [always(MainPieces), verbose_only(verbose_always, VerbosePieces)]),
-    Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg]).
+    Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg]).
 
 :- func mode_decl_for_pred_info_to_pieces(pred_info, proc_id)
     = list(format_piece).
@@ -320,7 +318,7 @@ maybe_report_undefined_pred_error(ModuleInfo, PredOrFunc, SymName,
                 InferMsg = simple_msg(Context,
                     [always(MainPieces),
                     verbose_only(verbose_once, VerbosePieces)]),
-                Spec = diag_spec($pred, severity_error, phase_pt2h,
+                Spec = gen_spec($pred, severity_error, phase_pt2h,
                     [InferMsg])
             ;
                 InferTypes = yes,
@@ -351,7 +349,7 @@ maybe_report_undefined_pred_error(ModuleInfo, PredOrFunc, SymName,
                     [nl]
             ),
             OtherAritiesMsg = msg(Context, OtherAritiesPieces),
-            Spec = diag_spec($pred, severity_error, phase_pt2h,
+            Spec = gen_spec($pred, severity_error, phase_pt2h,
                 [MainMsg, OtherAritiesMsg])
         ),
         !:Specs = [Spec | !.Specs]
@@ -395,16 +393,16 @@ pred_form_arity_to_int_fixed(PredOrFunc, PredFormArity) = Component :-
 %---------------------------------------------------------------------------%
 
 maybe_warn_about_pfumm_unknown(ModuleInfo, PragmaName, PFUMM, SymName, Context,
-        !Specs) :-
+        Specs) :-
     (
         ( PFUMM = pfumm_predicate(_)
         ; PFUMM = pfumm_function(_)
-        )
+        ),
+        Specs = []
     ;
         PFUMM = pfumm_unknown(UserArity),
         warn_about_pfu_unknown(ModuleInfo, PragmaName, pragma_allows_modes,
-            SymName, UserArity, Context, WarnSpecs),
-        !:Specs = WarnSpecs ++ !.Specs
+            SymName, UserArity, Context, Specs)
     ).
 
 warn_about_pfu_unknown(ModuleInfo, PragmaName, PragmaAllowsModes,
diff --git a/compiler/make_hlds_passes.m b/compiler/make_hlds_passes.m
index bee01e019..67bc39850 100644
--- a/compiler/make_hlds_passes.m
+++ b/compiler/make_hlds_passes.m
@@ -37,8 +37,9 @@
 
     % parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals,
     %   DumpBaseFileName, MQInfo0, TypeEqvMap,
-    %   UsedEqvModules, UnusedInterfaceImports,
-    %   QualInfo, HLDS, InvalidTypeSpecs, InvalidInstModeSpecs, Specs):
+    %   UsedEqvModules, UnusedInterfaceImports, QualInfo, HLDS,
+    %   InvalidTypeSpecs, InvalidInstModeSpecs,
+    %   ErrSpecs, WarnSpecs, InfoSpecs):
     %
     % Given MQInfo (returned by module_qual.m) and TypeEqvMap and UsedModules
     % (both returned by equiv_type.m), convert AugCompUnit to HLDS.
@@ -53,8 +54,8 @@
     globals::in, string::in, mq_info::in, type_eqv_map::in,
     used_eqv_modules::in, set_tree234(module_name)::in,
     qual_info::out, module_info::out,
-    list(diag_spec)::out, list(diag_spec)::out,
-    list(diag_spec)::out) is det.
+    list(err_spec)::out, list(err_spec)::out, list(err_spec)::out,
+    list(warn_spec)::out, list(info_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -122,9 +123,10 @@
 parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
         MQInfo0, TypeEqvMap, UsedEqvModules, UnusedInterfaceImports,
         !:QualInfo, !:ModuleInfo, !:InvalidTypeSpecs, !:InvalidInstModeSpecs,
-        !:Specs) :-
+        !:ErrSpecs, !:WarnSpecs, !:InfoSpecs) :-
     ParseTreeModuleSrc = AugCompUnit ^ acu_module_src,
-    maybe_warn_include_and_non_include(Globals, ParseTreeModuleSrc, InclSpecs),
+    maybe_warn_include_and_non_include(Globals, ParseTreeModuleSrc,
+        !:WarnSpecs),
     ModuleName = ParseTreeModuleSrc ^ ptms_module_name,
     ModuleNameContext = ParseTreeModuleSrc ^ ptms_module_name_context,
     get_implicit_avail_needs_in_aug_compilation_unit(Globals, AugCompUnit,
@@ -157,22 +159,26 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
         )
     ),
 
-    TypeSpecs = ParseTreeModuleSrc ^ ptms_type_specs,
-    InstModeSpecs = ParseTreeModuleSrc ^ ptms_inst_mode_specs,
-    !:Specs = InclSpecs ++ TypeSpecs ++ InstModeSpecs,
+    TypeErrSpecs =      ParseTreeModuleSrc ^ ptms_type_err_specs,
+    TypeWarnSpecs =     ParseTreeModuleSrc ^ ptms_type_warn_specs,
+    InstModeErrSpecs =  ParseTreeModuleSrc ^ ptms_inst_mode_err_specs,
+    InstModeWarnSpecs = ParseTreeModuleSrc ^ ptms_inst_mode_warn_specs,
+    !:ErrSpecs = TypeErrSpecs ++ InstModeErrSpecs,
+    !:WarnSpecs = TypeWarnSpecs ++ InstModeWarnSpecs ++ !.WarnSpecs,
 
     IsInvalidTypeSpec =
         ( pred(Spec::in) is semidet :-
-            extract_spec_phase(Spec, Phase),
+            extract_spec_phase(coerce(Spec), Phase),
             Phase = phase_tim_check_invalid_type
         ),
     IsInvalidInstModeSpec =
         ( pred(Spec::in) is semidet :-
-            extract_spec_phase(Spec, Phase),
+            extract_spec_phase(coerce(Spec), Phase),
             Phase = phase_tim_check_invalid_inst_mode
         ),
-    list.filter(IsInvalidTypeSpec, TypeSpecs, !:InvalidTypeSpecs),
-    list.filter(IsInvalidInstModeSpec, InstModeSpecs, !:InvalidInstModeSpecs),
+    list.filter(IsInvalidTypeSpec, TypeErrSpecs, !:InvalidTypeSpecs),
+    list.filter(IsInvalidInstModeSpec, InstModeErrSpecs,
+        !:InvalidInstModeSpecs),
 
     % We used to add items to the HLDS in three passes.
     % Roughly,
@@ -256,14 +262,14 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
         % while usually returning abstract types, sometimes returns Mercury
         % types.
         add_type_defns(TypeDefnsAbstract,
-            !ModuleInfo, !InvalidTypeSpecs, !Specs, !SolverPredDeclCord,
-            !SolverForeignProcCord, !SolverMutableCord),
+            !ModuleInfo, !SolverPredDeclCord, !SolverForeignProcCord,
+            !SolverMutableCord, !InvalidTypeSpecs, !ErrSpecs, !WarnSpecs),
         add_type_defns(TypeDefnsMercury,
-            !ModuleInfo, !InvalidTypeSpecs, !Specs, !SolverPredDeclCord,
-            !SolverForeignProcCord, !SolverMutableCord),
+            !ModuleInfo, !SolverPredDeclCord, !SolverForeignProcCord,
+            !SolverMutableCord, !InvalidTypeSpecs, !ErrSpecs, !WarnSpecs),
         add_type_defns(TypeDefnsForeign,
-            !ModuleInfo, !InvalidTypeSpecs, !Specs, !SolverPredDeclCord,
-            !SolverForeignProcCord, !SolverMutableCord),
+            !ModuleInfo, !SolverPredDeclCord, !SolverForeignProcCord,
+            !SolverMutableCord, !InvalidTypeSpecs, !ErrSpecs, !WarnSpecs),
         % We use cords to record new predicate declarations, foreign_procs
         % and mutables. This preserves order without quadratic behavior.
         % Preserving order can be important, because if e.g. a pred decl
@@ -305,7 +311,7 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
     % that do not check for infinite recursion. Any circularity we miss here
     % is thus very likely to cause a later pass to enter an infinite loop.
     add_inst_defns(InstDefns,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs, !WarnSpecs),
     check_inst_defns(!.ModuleInfo, InstDefns,
         !InvalidInstModeSpecs),
 
@@ -313,7 +319,7 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
     % seen all inst definitions, we could check whether the newly defined
     % mode refers to an undefined inst, but we do not (yet) do so.
     add_mode_defns(ModeDefns,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
     check_mode_defns(!.ModuleInfo, ModeDefns,
         !InvalidInstModeSpecs),
 
@@ -354,7 +360,8 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
     % (Currently, we discover any such errors when we type and mode check
     % the automatically created unify and compare predicates, whose bodies
     % call the user-specified predicate names.)
-    InvalidTypesSoFar = contains_errors(Globals, !.InvalidTypeSpecs),
+    % XXX DIAG_SPECS
+    InvalidTypesSoFar = contains_errors(Globals, coerce(!.InvalidTypeSpecs)),
     (
         InvalidTypesSoFar = no,
         % Add constructors for du types to the HLDS, check subtype definitions,
@@ -368,7 +375,7 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
         module_info_get_type_table(!.ModuleInfo, TypeTable0),
         foldl3_over_type_ctor_defns(
             add_du_ctors_check_subtype_check_foreign_type(TypeTable0),
-            TypeTable0, !ModuleInfo, !InvalidTypeSpecs, !Specs)
+            TypeTable0, !ModuleInfo, !InvalidTypeSpecs, !WarnSpecs)
     ;
         InvalidTypesSoFar = yes
     ),
@@ -379,9 +386,9 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
     % defined predicate refers to an undefined type, inst, or mode, but
     % we do not (yet) do so.
     add_pred_decls(PredDecls,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
     add_pred_decls(SolverPredDecls,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
 
     % We need to process the mode declaration of a predicate
     % after we have seen the (type) declaration of the predicate.
@@ -392,7 +399,7 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
     % Note that mode declarations embedded in predmode declarations
     % have already been added to the HLDS by add_pred_decl.
     add_mode_decls(ModeDecls,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
 
     % Every mutable has its own set of access predicates. Declare them
     % (using predmode declarations, which specify their types, modes and
@@ -411,15 +418,15 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
     implement_mutables_if_local(!.ModuleInfo, MQUndefInsts0, AllMutables,
         MutablePredDecls, MutableClauses, MutableForeignProcs,
         MutableForeignDeclCodes, MutableForeignBodyCodes, FPEInfosCord1,
-        InitPredTargetNames0, InitPredTargetNames1, !Specs),
+        InitPredTargetNames0, InitPredTargetNames1, !ErrSpecs),
     add_pred_decls(MutablePredDecls,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
 
     % Record the definitions of typeclasses.
     % This will add the pred and mode declarations of the methods inside them
     % to the HLDS.
     add_typeclass_defns(Typeclasses,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
 
     % The old pass 2.
 
@@ -436,7 +443,7 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
 
     % Record instance definitions.
     add_instance_defns(Instances,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
 
     % Implement several kinds of pragmas, the ones in the subtype
     % defined by the pragma_pass_2 inst.
@@ -466,14 +473,14 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
 
     % Add clauses to their predicates.
     add_clauses(ProgressStream, Clauses,
-        !ModuleInfo, !QualInfo, !Specs),
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs),
     % Add clauses that define the auxiliary predicates
     % that implement some of the auxiliary predicates of mutables.
     add_clauses(ProgressStream, MutableClauses,
-        !ModuleInfo, !QualInfo, !Specs),
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs),
     % Add clauses that record promises.
     add_promises(ProgressStream, Promises,
-        !ModuleInfo, !QualInfo, !Specs),
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs),
 
     % Remember attempts to define predicates in the interface.
     module_info_set_int_bad_clauses(IntBadClauses, !ModuleInfo),
@@ -488,9 +495,9 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
     % may for part of the specification that the actual implementation
     % can be compared against.
     add_decl_markers(DeclMarkers,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs, !WarnSpecs),
     add_impl_markers(ImplMarkers,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs, !WarnSpecs),
 
     % Add foreign proc definitions from the program, as well as
     % - for the auxiliary predicates that implement solver types, and
@@ -503,11 +510,11 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
     % a predicate/function that is local for one backend and external
     % for the other.
     add_foreign_procs(ProgressStream, ForeignProcs,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs, !WarnSpecs),
     add_foreign_procs(ProgressStream, SolverForeignProcs,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs, !WarnSpecs),
     add_foreign_procs(ProgressStream, MutableForeignProcs,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs, !WarnSpecs),
 
     % Check that the predicates listed in `:- initialise' and `:- finalise'
     % declarations exist and have the correct signature, construct
@@ -521,10 +528,10 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
         FinalPredTargetNames1),
     add_initialises(!.ModuleInfo, Initialises,
         FPEInfosCord1, FPEInfosCord2,
-        InitPredTargetNames1, InitPredTargetNames, !Specs),
+        InitPredTargetNames1, InitPredTargetNames, !ErrSpecs),
     add_finalises(!.ModuleInfo, Finalises,
         FPEInfosCord2, FPEInfosCord,
-        FinalPredTargetNames1, FinalPredTargetNames, !Specs),
+        FinalPredTargetNames1, FinalPredTargetNames, !ErrSpecs),
     module_info_set_user_init_pred_target_names(InitPredTargetNames,
         !ModuleInfo),
     module_info_set_user_final_pred_target_names(FinalPredTargetNames,
@@ -557,20 +564,21 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
     % This times does have to be after we have processed all predicate
     % and mode declarations, since several pragmas do refer to predicates
     % or to modes of predicates.
+    !:InfoSpecs = [],
     add_decl_pragmas(ProgressStream, DeclPragmas,
-        !ModuleInfo, !QualInfo, !Specs),
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs, !InfoSpecs),
     add_decl_pragmas_type_spec_constr(ProgressStream, DeclTypeSpecConstr,
-        !ModuleInfo, !QualInfo, !Specs),
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs, !InfoSpecs),
     add_decl_pragmas_type_spec(DeclTypeSpec,
-        !ModuleInfo, !QualInfo, !Specs),
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs),
     add_decl_pragmas_termination(DeclTermination,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
     add_decl_pragmas_termination2(DeclTermination2,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
     add_decl_pragmas_sharing(DeclSharing,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
     add_decl_pragmas_reuse(DeclReuse,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
 
     % Tabling pragmas are not compatible with some other pragmas.
     % We used to delay their processing until after other impl pragmas
@@ -585,14 +593,14 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
     % pred_infos don't have a marker to say "defined using a fact table".
     % and without this, we cannot know when to generate such a warning.
     add_impl_pragmas(ProgressStream, ImplPragmas, cord.init, PragmaTabledCord,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs, !WarnSpecs),
     PragmasTabled = cord.list(PragmaTabledCord),
     add_impl_pragmas_tabled(ProgressStream, PragmasTabled,
-        !ModuleInfo, !QualInfo, !Specs),
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs),
 
     FPEInfos = cord.list(FPEInfosCord),
     list.foldl2(add_pragma_foreign_proc_export, FPEInfos,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
 
     list.foldl(module_add_foreign_decl_code_aux, MutableForeignDeclCodes,
         !ModuleInfo),
@@ -600,43 +608,44 @@ parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
         !ModuleInfo),
 
     list.foldl2(add_gen_pragma_unused_args, GenUnusedArgs,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
     list.foldl2(add_gen_pragma_exceptions, GenExceptions,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
     list.foldl2(add_gen_pragma_trailing, GenTrailing,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
     list.foldl2(add_gen_pragma_mm_tabling, GenMMTabling,
-        !ModuleInfo, !Specs),
+        !ModuleInfo, !ErrSpecs),
 
     % Check that the declarations for field extraction and update functions
     % are sensible, and generate error messages for the ones that aren't.
     % We can do this only after we have processed every predicate declaration,
     % as well as everything that affects either the type table or the
     % constructor table.
-    check_preds_if_field_access_function(!.ModuleInfo, PredDecls, !Specs),
+    check_preds_if_field_access_function(!.ModuleInfo, PredDecls, !ErrSpecs),
 
     ModuleItemVersionNumbers = AugCompUnit ^ acu_item_version_map,
     map.foldl(add_module_item_version_numbers, ModuleItemVersionNumbers,
         !QualInfo),
 
     qual_info_get_mq_info(!.QualInfo, MQInfo),
-    get_diag_specs_in_mq_info(MQInfo,
+    get_err_specs_in_mq_info(MQInfo,
         MQInvalidTypeSpecs, MQInvalidInstModeSpecs, MQNonBlockingUndefSpecs),
     !:InvalidTypeSpecs = MQInvalidTypeSpecs ++ !.InvalidTypeSpecs,
     !:InvalidInstModeSpecs = MQInvalidInstModeSpecs ++ !.InvalidInstModeSpecs,
-    !:Specs = MQNonBlockingUndefSpecs ++ !.Specs.
+    !:ErrSpecs = MQNonBlockingUndefSpecs ++ !.ErrSpecs.
 
 %---------------------------------------------------------------------------%
 
 :- pred maybe_warn_include_and_non_include(globals::in,
-    parse_tree_module_src::in, list(diag_spec)::out) is det.
+    parse_tree_module_src::in, list(warn_spec)::out) is det.
 
 maybe_warn_include_and_non_include(Globals, ParseTreeModuleSrc, Specs) :-
     globals.lookup_bool_option(Globals, warn_include_and_non_include,
         WarnIncludeAndNonInclude),
     ParseTreeModuleSrc = parse_tree_module_src(ModuleName, _MNC, InclMap,
         ImportUseMap, IntFIMs, ImpFIMs, IntSelfFIMLangs, ImpSelfFIMLangs,
-        TypeDefnMap, InstDefnMap, ModeDefnMap, _TypeSpecs, _InstModeSpecs,
+        TypeDefnMap, InstDefnMap, ModeDefnMap,
+        _TypeErrSpecs, _TypeWarnSpecs, _InstModeErrSpecs, _InstModeWarnSpecs,
         IntTypeClasses, IntInstances, IntPredDecls, IntModeDecls,
         IntDeclPragmas, IntDeclMarkers, IntPromises, IntBadClauses,
         ImpTypeClasses, ImpInstances, ImpPredDecls, ImpModeDecls,
@@ -698,7 +707,9 @@ maybe_warn_include_and_non_include(Globals, ParseTreeModuleSrc, Specs) :-
             words("Moving those entities to other modules can reduce"),
             words("the number of modules needing to be recompiled"),
             words("after a change."), nl],
-        Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
+        % XXX DIAG_SPECS The severity used to be error.
+        Severity = severity_warning(warn_include_and_non_include),
+        Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),
         Specs = [Spec]
     else
         Specs = []
@@ -825,38 +836,42 @@ add_item_avail(ItemMercuryStatus, Avail, !ModuleInfo) :-
 
 :- pred add_type_defns(sec_list(item_type_defn_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
     sec_cord(item_pred_decl_info)::in, sec_cord(item_pred_decl_info)::out,
     ims_cord(item_foreign_proc_info)::in,
         ims_cord(item_foreign_proc_info)::out,
-    sec_cord(item_mutable_info)::in, sec_cord(item_mutable_info)::out) is det.
+    sec_cord(item_mutable_info)::in, sec_cord(item_mutable_info)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-add_type_defns([], !ModuleInfo, !InvalidTypeSpecs, !Specs,
-        !PredDeclCord, !ForeignProcCord, !MutableCord).
-add_type_defns([SecList | SecLists], !ModuleInfo, !InvalidTypeSpecs, !Specs,
-        !PredDeclCord, !ForeignProcCord, !MutableCord) :-
+add_type_defns([], !ModuleInfo, !PredDeclCord, !ForeignProcCord, !MutableCord,
+        !InvalidTypeSpecs, !ErrSpecs, !WarnSpecs).
+add_type_defns([SecList | SecLists], !ModuleInfo,
+        !PredDeclCord, !ForeignProcCord, !MutableCord,
+        !InvalidTypeSpecs, !ErrSpecs, !WarnSpecs) :-
     SecList = sec_sub_list(SectionInfo, TypeDefns),
     SectionInfo = sec_info(ItemMercuryStatus, _NeedQual),
     item_mercury_status_to_type_status(ItemMercuryStatus, TypeStatus),
-    list.foldl6(add_type_defn(SectionInfo, TypeStatus), TypeDefns,
-        !ModuleInfo, !InvalidTypeSpecs, !Specs,
-        !PredDeclCord, !ForeignProcCord, !MutableCord),
-    add_type_defns(SecLists, !ModuleInfo, !InvalidTypeSpecs, !Specs,
-        !PredDeclCord, !ForeignProcCord, !MutableCord).
+    list.foldl7(add_type_defn(SectionInfo, TypeStatus), TypeDefns,
+        !ModuleInfo, !PredDeclCord, !ForeignProcCord, !MutableCord,
+        !InvalidTypeSpecs, !ErrSpecs, !WarnSpecs),
+    add_type_defns(SecLists, !ModuleInfo,
+        !PredDeclCord, !ForeignProcCord, !MutableCord,
+        !InvalidTypeSpecs, !ErrSpecs, !WarnSpecs).
 
 :- pred add_type_defn(sec_info::in, type_status::in, item_type_defn_info::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
     sec_cord(item_pred_decl_info)::in, sec_cord(item_pred_decl_info)::out,
     ims_cord(item_foreign_proc_info)::in,
         ims_cord(item_foreign_proc_info)::out,
-    sec_cord(item_mutable_info)::in, sec_cord(item_mutable_info)::out) is det.
+    sec_cord(item_mutable_info)::in, sec_cord(item_mutable_info)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 add_type_defn(SectionInfo, TypeStatus, TypeDefnInfo,
-        !ModuleInfo, !InvalidTypeSpecs, !Specs,
-        !PredDeclCord, !ForeignProcCord, !MutableCord) :-
+        !ModuleInfo, !PredDeclCord, !ForeignProcCord, !MutableCord,
+        !InvalidTypeSpecs, !ErrSpecs, !WarnSpecs) :-
     SectionInfo = sec_info(ItemMercuryStatus, NeedQual),
     TypeDefnInfo = item_type_defn_info(SymName, TypeParams, TypeDefn,
         TypeVarSet, Context, _SeqNum),
@@ -904,67 +919,69 @@ add_type_defn(SectionInfo, TypeStatus, TypeDefnInfo,
         )
     ),
     module_add_type_defn(TypeStatus, NeedQual, TypeDefnInfo,
-        !ModuleInfo, !InvalidTypeSpecs, !Specs).
+        !ModuleInfo, !InvalidTypeSpecs, !ErrSpecs, !WarnSpecs).
 
 %---------------------------------------------------------------------------%
 
 :- pred add_inst_defns(ims_list(item_inst_defn_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-add_inst_defns([], !ModuleInfo, !Specs).
-add_inst_defns([ImsSubList | ImsSubLists], !ModuleInfo, !Specs) :-
+add_inst_defns([], !ModuleInfo, !ErrSpecs, !WarnSpecs).
+add_inst_defns([ImsSubList | ImsSubLists],
+        !ModuleInfo, !ErrSpecs, !WarnSpecs) :-
     ImsSubList = ims_sub_list(ItemMercuryStatus, InstDefns),
     item_mercury_status_to_inst_status(ItemMercuryStatus, InstStatus),
-    list.foldl2(module_add_inst_defn(InstStatus), InstDefns,
-        !ModuleInfo, !Specs),
-    add_inst_defns(ImsSubLists, !ModuleInfo, !Specs).
+    list.foldl3(module_add_inst_defn(InstStatus), InstDefns,
+        !ModuleInfo, !ErrSpecs, !WarnSpecs),
+    add_inst_defns(ImsSubLists, !ModuleInfo, !ErrSpecs, !WarnSpecs).
 
 %---------------------------------------------------------------------------%
 
 :- pred add_mode_defns(ims_list(item_mode_defn_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-add_mode_defns([], !ModuleInfo, !Specs).
-add_mode_defns([ImsSubList | ImsSubLists], !ModuleInfo, !Specs) :-
+add_mode_defns([], !ModuleInfo, !ErrSpecs).
+add_mode_defns([ImsSubList | ImsSubLists], !ModuleInfo, !ErrSpecs) :-
     ImsSubList = ims_sub_list(ItemMercuryStatus, ModeDefns),
     item_mercury_status_to_mode_status(ItemMercuryStatus, ModeStatus),
     list.foldl2(module_add_mode_defn(ModeStatus), ModeDefns,
-        !ModuleInfo, !Specs),
-    add_mode_defns(ImsSubLists, !ModuleInfo, !Specs).
+        !ModuleInfo, !ErrSpecs),
+    add_mode_defns(ImsSubLists, !ModuleInfo, !ErrSpecs).
 
 %---------------------------------------------------------------------------%
 
 :- pred add_pred_decls(sec_list(item_pred_decl_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-add_pred_decls([], !ModuleInfo, !Specs).
-add_pred_decls([SecSubList | SecSubLists], !ModuleInfo, !Specs) :-
+add_pred_decls([], !ModuleInfo, !ErrSpecs).
+add_pred_decls([SecSubList | SecSubLists], !ModuleInfo, !ErrSpecs) :-
     SecSubList = sec_sub_list(SectionInfo, PredDecls),
     SectionInfo = sec_info(ItemMercuryStatus, NeedQual),
     item_mercury_status_to_pred_status(ItemMercuryStatus, PredStatus),
     list.map_foldl2(
         module_add_pred_decl(ItemMercuryStatus, PredStatus, NeedQual),
-        PredDecls, _MaybePredProcIds, !ModuleInfo, !Specs),
-    add_pred_decls(SecSubLists, !ModuleInfo, !Specs).
+        PredDecls, _MaybePredProcIds, !ModuleInfo, !ErrSpecs),
+    add_pred_decls(SecSubLists, !ModuleInfo, !ErrSpecs).
 
 %---------------------------------------------------------------------------%
 
 :- pred add_mode_decls(ims_list(item_mode_decl_info)::in,
     module_info::in, module_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
-add_mode_decls([], !ModuleInfo, !Specs).
-add_mode_decls([SecSubList | SecSubLists], !ModuleInfo, !Specs) :-
+add_mode_decls([], !ModuleInfo, !ErrSpecs).
+add_mode_decls([SecSubList | SecSubLists], !ModuleInfo, !ErrSpecs) :-
     SecSubList = ims_sub_list(ItemMercuryStatus, ModeDecls),
     item_mercury_status_to_pred_status(ItemMercuryStatus, PredStatus),
     list.map_foldl2(
         module_add_mode_decl(not_part_of_predmode, is_not_a_class_method,
             ItemMercuryStatus, PredStatus),
-        ModeDecls, _PredProcIds, !ModuleInfo, !Specs),
-    add_mode_decls(SecSubLists, !ModuleInfo, !Specs).
+        ModeDecls, _PredProcIds, !ModuleInfo, !ErrSpecs),
+    add_mode_decls(SecSubLists, !ModuleInfo, !ErrSpecs).
 
 %---------------------------------------------------------------------------%
 
@@ -1019,42 +1036,47 @@ maybe_add_default_mode(PredDecl, !ModuleInfo) :-
 
 :- pred add_clauses(io.text_output_stream::in, ims_list(item_clause_info)::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-add_clauses(_, [], !ModuleInfo, !QualInfo, !Specs).
+add_clauses(_, [], !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs).
 add_clauses(ProgressStream, [ImsList | ImsLists],
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     ImsList = ims_sub_list(ItemMercuryStatus, Items),
     ClauseType = clause_not_for_promise,
     item_mercury_status_to_pred_status(ItemMercuryStatus, PredStatus),
-    list.foldl3(
+    list.foldl4(
         module_add_clause(ProgressStream, PredStatus, ClauseType), Items,
-        !ModuleInfo, !QualInfo, !Specs),
-    add_clauses(ProgressStream, ImsLists, !ModuleInfo, !QualInfo, !Specs).
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs),
+    add_clauses(ProgressStream, ImsLists, !ModuleInfo, !QualInfo,
+        !ErrSpecs, !WarnSpecs).
 
 %---------------------------------------------------------------------------%
 
 :- pred add_promises(io.text_output_stream::in,
     ims_list(item_promise_info)::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
-add_promises(_, [], !ModuleInfo, !QualInfo, !Specs).
+add_promises(_, [], !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs).
 add_promises(ProgressStream, [ImsList | ImsLists],
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     ImsList = ims_sub_list(ItemMercuryStatus, Items),
     item_mercury_status_to_pred_status(ItemMercuryStatus, PredStatus),
-    list.foldl3(add_promise(ProgressStream, PredStatus), Items,
-        !ModuleInfo, !QualInfo, !Specs),
-    add_promises(ProgressStream, ImsLists, !ModuleInfo, !QualInfo, !Specs).
+    list.foldl4(add_promise(ProgressStream, PredStatus), Items,
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs),
+    add_promises(ProgressStream, ImsLists, !ModuleInfo, !QualInfo,
+        !ErrSpecs, !WarnSpecs).
 
 :- pred add_promise(io.text_output_stream::in,
     pred_status::in, item_promise_info::in,
     module_info::in, module_info::out, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 add_promise(ProgressStream, PredStatus, PromiseInfo,
-        !ModuleInfo, !QualInfo, !Specs) :-
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs) :-
     PromiseInfo = item_promise_info(PromiseType, Goal, VarSet, UnivVars,
         Context, SeqNum),
     % Promise declarations are recorded as a predicate with a goal_type
@@ -1083,7 +1105,7 @@ add_promise(ProgressStream, PredStatus, PromiseInfo,
         ; PromiseType = promise_type_exclusive_exhaustive
         ),
         % Extra error checking for promise ex declarations.
-        check_promise_ex_decl(UnivVars, PromiseType, Goal, Context, !Specs)
+        check_promise_ex_decl(UnivVars, PromiseType, Goal, Context, !ErrSpecs)
     ;
         PromiseType = promise_type_true
     ),
@@ -1114,7 +1136,7 @@ add_promise(ProgressStream, PredStatus, PromiseInfo,
     ClauseInfo = item_clause_info(pf_predicate, PromisePredSymName,
         HeadVarTerms, VarSet, ok2(Goal, []), Context, SeqNum),
     module_add_clause(ProgressStream, PredStatus, ClauseType, ClauseInfo,
-        !ModuleInfo, !QualInfo, !Specs).
+        !ModuleInfo, !QualInfo, !ErrSpecs, !WarnSpecs).
 
 %---------------------------------------------------------------------------%
 
@@ -1122,7 +1144,7 @@ add_promise(ProgressStream, PredStatus, PromiseInfo,
     cord(impl_pragma_fproc_export_info)::in,
     cord(impl_pragma_fproc_export_info)::out,
     pred_target_names::in, pred_target_names::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_initialises(_, [], !PragmaFPEInfoCord, !PredTargetNames, !Specs).
 add_initialises(ModuleInfo, [ImsList | ImsLists],
@@ -1138,7 +1160,7 @@ add_initialises(ModuleInfo, [ImsList | ImsLists],
     cord(impl_pragma_fproc_export_info)::in,
     cord(impl_pragma_fproc_export_info)::out,
     pred_target_names::in, pred_target_names::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_initialise(ModuleInfo, ItemMercuryStatus, Initialise,
         !PragmaFPEInfoCord, !PredTargetNames, !Specs) :-
@@ -1165,7 +1187,7 @@ add_initialise(ModuleInfo, ItemMercuryStatus, Initialise,
     cord(impl_pragma_fproc_export_info)::in,
     cord(impl_pragma_fproc_export_info)::out,
     pred_target_names::in, pred_target_names::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_finalises(_, [], !PragmaFPEInfoCord, !PredTargetNames, !Specs).
 add_finalises(ModuleInfo, [ImsList | ImsLists],
@@ -1181,7 +1203,7 @@ add_finalises(ModuleInfo, [ImsList | ImsLists],
     cord(impl_pragma_fproc_export_info)::in,
     cord(impl_pragma_fproc_export_info)::out,
     pred_target_names::in, pred_target_names::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_finalise(ModuleInfo, ItemMercuryStatus, FinaliseInfo,
         !PragmaFPEInfoCord, !PredTargetNames, !Specs) :-
@@ -1215,7 +1237,7 @@ add_finalise(ModuleInfo, ItemMercuryStatus, FinaliseInfo,
     cord(impl_pragma_fproc_export_info)::in,
     cord(impl_pragma_fproc_export_info)::out,
     pred_target_names::in, pred_target_names::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 implement_initialise_finalise(ModuleInfo, InitOrFinal, SymName, UserArity,
         Context, SeqNum, !PragmaFPEInfoCord, !PredTargetNames, !Specs) :-
diff --git a/compiler/make_hlds_separate_items.m b/compiler/make_hlds_separate_items.m
index aba024c4a..aa405e392 100644
--- a/compiler/make_hlds_separate_items.m
+++ b/compiler/make_hlds_separate_items.m
@@ -412,7 +412,7 @@ acc_parse_tree_module_src(ParseTreeModuleSrc, !Acc) :-
         IntFIMSpecMap, ImpFIMSpecMap, _IntSelfFIMLangs, _ImpSelfFIMLangs,
 
         TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
-        _TypeSpecs, _InstModeSpecs,
+        _TypeErrSpecs, _TypeWarnSpecs, _InstModeErrSpecs, _InstModeWarnSpecs,
 
         IntTypeClasses, IntInstances, IntPredDecls, IntModeDecls,
         IntDeclPragmas, IntDeclMarkers, IntPromises, _IntBadPreds,
diff --git a/compiler/make_hlds_warn.m b/compiler/make_hlds_warn.m
index cd307ec96..eed384010 100644
--- a/compiler/make_hlds_warn.m
+++ b/compiler/make_hlds_warn.m
@@ -35,7 +35,7 @@
     %
 :- pred add_quant_warnings(module_info::in, pf_sym_name_arity::in,
     prog_varset::in, list(quant_warning)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -54,7 +54,7 @@
     %
 :- pred warn_singletons_in_clause_body(module_info::in, pf_sym_name_arity::in,
     prog_varset::in, hlds_goal::in, maybe_seen_quant::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -68,7 +68,7 @@
     %   disjunction has at most one call, and otherwise has only unifications.
     %
 :- pred check_promise_ex_decl(list(prog_var)::in, promise_type::in, goal::in,
-    prog_context::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    prog_context::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -78,7 +78,7 @@
     %
 :- pred warn_suspicious_foreign_code(foreign_language::in,
     foreign_literal_or_include::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -124,7 +124,7 @@ add_quant_warnings(ModuleInfo, PfSymNameArity, VarSet, Warnings, !Specs) :-
     ).
 
 :- func quant_warning_to_spec(pf_sym_name_arity, prog_varset, quant_warning)
-    = diag_spec.
+    = warn_spec.
 
 quant_warning_to_spec(PfSymNameArity, VarSet, Warning) = Spec :-
     Warning = warn_overlap(Vars, Context),
@@ -275,7 +275,7 @@ warn_singletons_in_clause_body(ModuleInfo, PfSymNameArity, VarSet, BodyGoal,
                 % All these fields are writeable.
 
                 % The warnings we have generated while checking.
-                wi_specs                :: list(diag_spec),
+                wi_specs                :: list(warn_spec),
 
                 % The set of variables that occur singleton in the clause head.
                 wi_singleton_headvars   :: set_of_progvar,
@@ -290,7 +290,7 @@ warn_singletons_in_clause_body(ModuleInfo, PfSymNameArity, VarSet, BodyGoal,
                 %
                 % It is possible for the clause head to occupy more than one
                 % line, and thus for different parts of it to have different
-                % contexts. Since we want to generate only a single diag_spec,
+                % contexts. Since we want to generate only a single warn_spec,
                 % we arbitrarily pick the context of one of those variables.
                 wi_head_context         :: prog_context,
 
@@ -628,7 +628,7 @@ warn_singletons_in_scope(Params, Reason, SubGoal, GoalInfo,
 
 %---------------------------------------------------------------------------%
 
-:- pred add_warn_specs(list(diag_spec)::in,
+:- pred add_warn_specs(list(warn_spec)::in,
     warn_info::in, warn_info::out) is det.
 
 add_warn_specs(NewSpecs, !Info) :-
@@ -642,7 +642,7 @@ add_warn_specs(NewSpecs, !Info) :-
 
 :- pred generate_variable_warning(warn_params::in, prog_context::in,
     single_or_multi::in, pf_sym_name_arity::in,
-    prog_var::in, list(prog_var)::in, list(diag_spec)::out) is det.
+    prog_var::in, list(prog_var)::in, list(warn_spec)::out) is det.
 
 generate_variable_warning(Params, Context, SingleMulti, PfSymNameArity,
         Var0, Vars0, Specs) :-
@@ -707,19 +707,19 @@ separate_state_var_names([Name | Names], !PlainVarNames, !BangVarNames) :-
 
     % For each singleton variable that is close enough to another variable
     % name that a "did you mean" replacement suggestion is worthwhile,
-    % generate an diag_spec including that suggestions. Return
+    % generate an warn_spec including that suggestions. Return
     %
-    % - the list of such singleton-var-specific diag_specs, and
+    % - the list of such singleton-var-specific warn_specs, and
     % - the list of singleton vars for which we have no "did you mean"
     %   suggestion.
     %
-    % Our caller will then generate a single diag_spec that mentions
+    % Our caller will then generate a single warn_spec that mentions
     % *all* of the variables without their own "did you mean" suggestions.
     %
 :- pred generate_singleton_variable_warning_dyms(prog_varset::in,
     prog_context::in, list(format_piece)::in, option::in,
     set(string)::in, set(string)::in, list(prog_var)::in, list(string)::in,
-    list(string)::out, list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(string)::out, list(warn_spec)::in, list(warn_spec)::out) is det.
 
 generate_singleton_variable_warning_dyms(_, _, _, _, _, _,
         [], !NoDymVarNames, !Specs).
@@ -787,7 +787,7 @@ generate_singleton_variable_warning_dyms(VarSet, Context, PreamblePieces,
 
 :- pred generate_variable_warning_no_dym(prog_context::in,
     list(format_piece)::in, option::in, string::in, list(string)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 generate_variable_warning_no_dym(Context, PreamblePieces, WarnOption,
         OnlyMoreThanOnce, VarNames0, !Specs) :-
@@ -814,7 +814,7 @@ generate_variable_warning_no_dym(Context, PreamblePieces, WarnOption,
 
 :- pred generate_singleton_variable_warning_dym(prog_context::in,
     list(format_piece)::in, option::in, string::in, list(format_piece)::in,
-    diag_spec::out) is det.
+    warn_spec::out) is det.
 
 generate_singleton_variable_warning_dym(Context, PreamblePieces, WarnOption,
         VarName, DymPieces, Spec) :-
@@ -881,7 +881,8 @@ check_promise_ex_decl(UnivVars, PromiseType, Goal, Context, !Specs) :-
     (
         UnivVars = [],
         promise_ex_error(PromiseType, Context,
-            "declaration has no universally quantified variables", !Specs)
+            "declaration has no universally quantified variables", ErrSpec),
+        !:Specs = [ErrSpec | !.Specs]
     ;
         UnivVars = [_ | _]
     ),
@@ -891,7 +892,7 @@ check_promise_ex_decl(UnivVars, PromiseType, Goal, Context, !Specs) :-
     % disjunction, flatten it out into list form and perform further checks.
     %
 :- pred check_promise_ex_goal(promise_type::in, goal::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_promise_ex_goal(PromiseType, Goal, !Specs) :-
     ( if
@@ -910,11 +911,13 @@ check_promise_ex_goal(PromiseType, Goal, !Specs) :-
     then
         promise_ex_error(PromiseType, Context,
             "universal quantification should come before " ++
-            "the declaration name", !Specs),
+            "the declaration name", ErrSpec),
+        !:Specs = [ErrSpec | !.Specs],
         check_promise_ex_goal(PromiseType, SubGoal, !Specs)
     else
         promise_ex_error(PromiseType, get_goal_context(Goal),
-            "goal in declaration is not a disjunction", !Specs)
+            "goal in declaration is not a disjunction", ErrSpec),
+        !:Specs = [ErrSpec | !.Specs]
     ).
 
     % Takes a goal representing an arm of a disjunction and turns it into
@@ -934,7 +937,7 @@ flatten_to_conj_list(Goal, GoalList) :-
     % Taking a list of arms of the disjunction, check each arm individually.
     %
 :- pred check_promise_ex_disjunction(promise_type::in, list(list(goal))::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_promise_ex_disjunction(PromiseType, DisjConjList, !Specs) :-
     (
@@ -949,7 +952,7 @@ check_promise_ex_disjunction(PromiseType, DisjConjList, !Specs) :-
     % unifications.
     %
 :- pred check_promise_ex_disj_arm(promise_type::in, list(goal)::in, bool::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_promise_ex_disj_arm(PromiseType, Goals, CallUsed, !Specs) :-
     (
@@ -964,7 +967,7 @@ check_promise_ex_disj_arm(PromiseType, Goals, CallUsed, !Specs) :-
         else if
             HeadGoal = quant_expr(quant_some, quant_ordinary_vars, _, _,
                 HeadSubGoal)
-            then
+        then
             check_promise_ex_disj_arm(PromiseType, [HeadSubGoal | TailGoals],
                 CallUsed, !Specs)
         else if
@@ -975,12 +978,14 @@ check_promise_ex_disj_arm(PromiseType, Goals, CallUsed, !Specs) :-
             ;
                 CallUsed = yes,
                 promise_ex_error(PromiseType, Context,
-                    "disjunct contains more than one call", !Specs)
+                    "disjunct contains more than one call", ErrSpec),
+                !:Specs = [ErrSpec | !.Specs]
             ),
             check_promise_ex_disj_arm(PromiseType, TailGoals, yes, !Specs)
         else
             promise_ex_error(PromiseType, get_goal_context(HeadGoal),
-                "disjunct is not a call or unification", !Specs),
+                "disjunct is not a call or unification", ErrSpec),
+            !:Specs = [ErrSpec | !.Specs],
             check_promise_ex_disj_arm(PromiseType, TailGoals, CallUsed, !Specs)
         )
     ).
@@ -988,15 +993,14 @@ check_promise_ex_disj_arm(PromiseType, Goals, CallUsed, !Specs) :-
     % Called for any error in the above checks.
     %
 :- pred promise_ex_error(promise_type::in, prog_context::in, string::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    err_spec::out) is det.
 
-promise_ex_error(PromiseType, Context, Message, !Specs) :-
+promise_ex_error(PromiseType, Context, Message, Spec) :-
     Pieces = [words("In"),
         quote(parse_tree_out_misc.promise_to_string(PromiseType)),
         words("declaration:"), nl,
         words("error:"), words(Message), nl],
-    Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-    !:Specs = [Spec | !.Specs].
+    Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces).
 
 %---------------------------------------------------------------------------%
 
diff --git a/compiler/mark_tail_calls.m b/compiler/mark_tail_calls.m
index a1c955029..4c51873fe 100644
--- a/compiler/mark_tail_calls.m
+++ b/compiler/mark_tail_calls.m
@@ -1246,7 +1246,7 @@ add_message_for_nontail_self_recursive_call(CallerPFSNA, MaybeCallerProcId,
         words("this")] ++ color_as_subject([words("self-recursive call")]) ++
         ReasonPieces,
     MainMsg = msg(Context, MainPieces),
-    Spec = diag_spec($pred, Severity, phase_code_gen,
+    Spec = gen_spec($pred, Severity, phase_code_gen,
         [MainMsg | VerboseMsgs]),
     !:Specs = [Spec | !.Specs].
 
@@ -1280,7 +1280,7 @@ add_message_for_nontail_mutual_recursive_call(CallerPFSNA, MaybeCallerProcId,
         [words("to"), unqual_pf_sym_name_pred_form_arity(CalleePFSNA)] ++
         ReasonPieces,
     MainMsg = msg(Context, MainPieces),
-    Spec = diag_spec($pred, Severity, phase_code_gen,
+    Spec = gen_spec($pred, Severity, phase_code_gen,
         [MainMsg | VerboseMsgs]),
     !:Specs = [Spec | !.Specs].
 
diff --git a/compiler/mark_trace_goals.m b/compiler/mark_trace_goals.m
index f273a9199..b5b61c669 100644
--- a/compiler/mark_trace_goals.m
+++ b/compiler/mark_trace_goals.m
@@ -158,7 +158,7 @@ set_goal_contains_trace_features_in_goal(Goal0, Goal, ContainsTrace,
                 TraceMsg = msg(Context, TracePieces),
                 LastMsg = msg(context(FileName, LastLineNumber), LastPieces),
                 Severity = severity_warning(warn_moved_trace_goal),
-                Spec = diag_spec($pred, Severity, Phase, [TraceMsg, LastMsg]),
+                Spec = gen_spec($pred, Severity, Phase, [TraceMsg, LastMsg]),
                 !:Specs = [Spec | !.Specs]
             else
                 true
diff --git a/compiler/maybe_error.m b/compiler/maybe_error.m
index 540e72d35..f62eb3f76 100644
--- a/compiler/maybe_error.m
+++ b/compiler/maybe_error.m
@@ -53,30 +53,35 @@
     ;       ok6(T1, T2, T3, T4, T5, T6).
 
 :- type maybe1(T1) ==
-    maybe1(T1, one_or_more(diag_spec)).
+    maybe1(T1, one_or_more(err_spec)).
 :- type maybe2(T1, T2) ==
-    maybe2(T1, T2, one_or_more(diag_spec)).
+    maybe2(T1, T2, one_or_more(err_spec)).
 :- type maybe3(T1, T2, T3) ==
-    maybe3(T1, T2, T3, one_or_more(diag_spec)).
+    maybe3(T1, T2, T3, one_or_more(err_spec)).
 :- type maybe4(T1, T2, T3, T4) ==
-    maybe4(T1, T2, T3, T4, one_or_more(diag_spec)).
+    maybe4(T1, T2, T3, T4, one_or_more(err_spec)).
 :- type maybe5(T1, T2, T3, T4, T5) ==
-    maybe5(T1, T2, T3, T4, T5, one_or_more(diag_spec)).
+    maybe5(T1, T2, T3, T4, T5, one_or_more(err_spec)).
 :- type maybe6(T1, T2, T3, T4, T5, T6) ==
-    maybe6(T1, T2, T3, T4, T5, T6, one_or_more(diag_spec)).
+    maybe6(T1, T2, T3, T4, T5, T6, one_or_more(err_spec)).
 
 :- type maybe1el(T1) ==
-    maybe1(T1, list(diag_spec)).
+    maybe1(T1, list(err_spec)).
 :- type maybe2el(T1, T2) ==
-    maybe2(T1, T2, list(diag_spec)).
+    maybe2(T1, T2, list(err_spec)).
 :- type maybe3el(T1, T2, T3) ==
-    maybe3(T1, T2, T3, list(diag_spec)).
+    maybe3(T1, T2, T3, list(err_spec)).
 :- type maybe4el(T1, T2, T3, T4) ==
+    maybe4(T1, T2, T3, T4, list(err_spec)).
+
+:- type maybe1eld(T1) ==
+    maybe1(T1, list(diag_spec)).
+:- type maybe2eld(T1, T2) ==
+    maybe2(T1, T2, list(diag_spec)).
+:- type maybe3eld(T1, T2, T3) ==
+    maybe3(T1, T2, T3, list(diag_spec)).
+:- type maybe4eld(T1, T2, T3, T4) ==
     maybe4(T1, T2, T3, T4, list(diag_spec)).
-:- type maybe5el(T1, T2, T3, T4, T5) ==
-    maybe5(T1, T2, T3, T4, T5, list(diag_spec)).
-:- type maybe6el(T1, T2, T3, T4, T5, T6) ==
-    maybe6(T1, T2, T3, T4, T5, T6, list(diag_spec)).
 
 %---------------------%
 
@@ -106,36 +111,79 @@
 
 %---------------------%
 
-:- func get_any_errors1(maybe1(T1)) = list(diag_spec).
-:- func get_any_errors2(maybe2(T1, T2)) = list(diag_spec).
-:- func get_any_errors3(maybe3(T1, T2, T3)) = list(diag_spec).
-:- func get_any_errors4(maybe4(T1, T2, T3, T4)) = list(diag_spec).
-:- func get_any_errors5(maybe5(T1, T2, T3, T4, T5)) = list(diag_spec).
-:- func get_any_errors6(maybe6(T1, T2, T3, T4, T5, T6)) = list(diag_spec).
+    % This type, which is used mostly by code that parses goals,
+    % allows us to record both
+    % - the presence of at least one error, and
+    % - the presence of zero or more warnings.
+    % The reason why we use tuples is that any readable function symbol
+    % we could use would make the lines that construct errors too long.
+:- type err_warn_error == {one_or_more(err_spec), list(warn_spec)}.
 
-:- func get_any_errors1el(maybe1el(T1)) = list(diag_spec).
-:- func get_any_errors2el(maybe2el(T1, T2)) = list(diag_spec).
-:- func get_any_errors3el(maybe3el(T1, T2, T3)) = list(diag_spec).
-:- func get_any_errors4el(maybe4el(T1, T2, T3, T4)) = list(diag_spec).
-:- func get_any_errors5el(maybe5el(T1, T2, T3, T4, T5)) = list(diag_spec).
-:- func get_any_errors6el(maybe6el(T1, T2, T3, T4, T5, T6)) = list(diag_spec).
+% XXX DIAG_SPECS
+% The numbers in these names mirror the number of arguments of the okN
+% function symbol, but they do not match the type constructor's arity,
+% due to the warn_specs being implicit. Which is more important?
+:- type parse_result2(T) ==
+    maybe2(T, list(warn_spec), err_warn_error).
+:- type parse_result3(T1, T2) ==
+    maybe3(T1, T2, list(warn_spec), err_warn_error).
+:- type parse_result4(T1, T2, T3) ==
+    maybe4(T1, T2, T3, list(warn_spec), err_warn_error).
 
-:- func get_any_errors_warnings2(maybe2(T1, list(warning_spec))) =
+%---------------------%
+
+:- func get_any_errors1(maybe1(T1)) = list(err_spec).
+:- func get_any_errors2(maybe2(T1, T2)) = list(err_spec).
+:- func get_any_errors3(maybe3(T1, T2, T3)) = list(err_spec).
+:- func get_any_errors4(maybe4(T1, T2, T3, T4)) = list(err_spec).
+:- func get_any_errors5(maybe5(T1, T2, T3, T4, T5)) = list(err_spec).
+:- func get_any_errors6(maybe6(T1, T2, T3, T4, T5, T6)) = list(err_spec).
+
+:- func get_any_errors1el(maybe1el(T1)) = list(err_spec).
+:- func get_any_errors2el(maybe2el(T1, T2)) = list(err_spec).
+:- func get_any_errors3el(maybe3el(T1, T2, T3)) = list(err_spec).
+:- func get_any_errors4el(maybe4el(T1, T2, T3, T4)) = list(err_spec).
+
+:- func get_any_errors1eld(maybe1eld(T1)) = list(diag_spec).
+:- func get_any_errors2eld(maybe2eld(T1, T2)) = list(diag_spec).
+:- func get_any_errors3eld(maybe3eld(T1, T2, T3)) = list(diag_spec).
+:- func get_any_errors4eld(maybe4eld(T1, T2, T3, T4)) = list(diag_spec).
+
+%---------------------------------------------------------------------------%
+
+:- func get_any_errors_warnings2(maybe2(T1, list(warn_spec))) =
     list(diag_spec).
-:- func get_any_errors_warnings3(maybe3(T1, T2, list(warning_spec))) =
+:- func get_any_errors_warnings3(maybe3(T1, T2, list(warn_spec))) =
     list(diag_spec).
-:- func get_any_errors_warnings4(maybe4(T1, T2, T3, list(warning_spec))) =
+:- func get_any_errors_warnings4(maybe4(T1, T2, T3, list(warn_spec))) =
     list(diag_spec).
-:- func get_any_errors_warnings5(maybe5(T1, T2, T3, T4, list(warning_spec))) =
-    list(diag_spec).
-:- func get_any_errors_warnings6(maybe6(T1, T2, T3, T4, T5,
-    list(warning_spec))) = list(diag_spec).
+
+:- pred get_all_errors_warnings1(
+    maybe1(T1, err_warn_error)::in,
+    list(err_spec)::out, list(warn_spec)::out) is det.
+
+:- pred get_all_errors_warnings2(
+    maybe2(T1, list(warn_spec), err_warn_error)::in,
+    list(err_spec)::out, list(warn_spec)::out) is det.
+:- pred get_all_errors_warnings3(
+    maybe3(T1, T2, list(warn_spec), err_warn_error)::in,
+    list(err_spec)::out, list(warn_spec)::out) is det.
+:- pred get_all_errors_warnings4(
+    maybe4(T1, T2, T3, list(warn_spec), err_warn_error)::in,
+    list(err_spec)::out, list(warn_spec)::out) is det.
+
+%---------------------------------------------------------------------------%
+
+:- pred add_warns_to_err_warn_error(err_warn_error::in, list(warn_spec)::in,
+    err_warn_error::out) is det.
+
+%---------------------------------------------------------------------------%
 
 :- pred project_ok1(maybe1(T1)::in, T1::out) is semidet.
 :- pred det_project_ok1(maybe1(T1)::in, T1::out) is det.
 
 :- pred separate_ok1_error1(list(maybe1(T1))::in,
-    list(T1)::out, list(diag_spec)::out) is det.
+    list(T1)::out, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -182,28 +230,63 @@ get_any_errors3el(error3(Specs)) = Specs.
 get_any_errors4el(ok4(_, _, _, _)) = [].
 get_any_errors4el(error4(Specs)) = Specs.
 
-get_any_errors5el(ok5(_, _, _, _, _)) = [].
-get_any_errors5el(error5(Specs)) = Specs.
+%---------------------%
 
-get_any_errors6el(ok6(_, _, _, _, _, _)) = [].
-get_any_errors6el(error6(Specs)) = Specs.
+get_any_errors1eld(ok1(_)) = [].
+get_any_errors1eld(error1(Specs)) = Specs.
+
+get_any_errors2eld(ok2(_, _)) = [].
+get_any_errors2eld(error2(Specs)) = Specs.
+
+get_any_errors3eld(ok3(_, _, _)) = [].
+get_any_errors3eld(error3(Specs)) = Specs.
+
+get_any_errors4eld(ok4(_, _, _, _)) = [].
+get_any_errors4eld(error4(Specs)) = Specs.
 
 %---------------------%
 
-get_any_errors_warnings2(ok2(_, Specs)) = Specs.
-get_any_errors_warnings2(error2(OoMSpecs)) = one_or_more_to_list(OoMSpecs).
+get_any_errors_warnings2(ok2(_, WarnSpecs)) = coerce(WarnSpecs).
+get_any_errors_warnings2(error2(OoMErrSpecs)) =
+    coerce(one_or_more_to_list(OoMErrSpecs)).
 
-get_any_errors_warnings3(ok3(_, _, Specs)) = Specs.
-get_any_errors_warnings3(error3(OoMSpecs)) = one_or_more_to_list(OoMSpecs).
+get_any_errors_warnings3(ok3(_, _, WarnSpecs)) = coerce(WarnSpecs).
+get_any_errors_warnings3(error3(OoMErrSpecs)) =
+    coerce(one_or_more_to_list(OoMErrSpecs)).
 
-get_any_errors_warnings4(ok4(_, _, _, Specs)) = Specs.
-get_any_errors_warnings4(error4(OoMSpecs)) = one_or_more_to_list(OoMSpecs).
+get_any_errors_warnings4(ok4(_, _, _, WarnSpecs)) = coerce(WarnSpecs).
+get_any_errors_warnings4(error4(OoMErrSpecs)) =
+    coerce(one_or_more_to_list(OoMErrSpecs)).
 
-get_any_errors_warnings5(ok5(_, _, _, _, Specs)) = Specs.
-get_any_errors_warnings5(error5(OoMSpecs)) = one_or_more_to_list(OoMSpecs).
+%---------------------%
 
-get_any_errors_warnings6(ok6(_, _, _, _, _, Specs)) = Specs.
-get_any_errors_warnings6(error6(OoMSpecs)) = one_or_more_to_list(OoMSpecs).
+get_all_errors_warnings1(ok1(_), [], []).
+get_all_errors_warnings1(error1({OoMErrSpecs, WarnSpecs}),
+        ErrSpecs, WarnSpecs) :-
+    ErrSpecs = one_or_more_to_list(OoMErrSpecs).
+
+%---------------------%
+
+get_all_errors_warnings2(ok2(_, WarnSpecs), [], WarnSpecs).
+get_all_errors_warnings2(error2({OoMErrSpecs, WarnSpecs}),
+        ErrSpecs, WarnSpecs) :-
+    ErrSpecs = one_or_more_to_list(OoMErrSpecs).
+
+get_all_errors_warnings3(ok3(_, _, WarnSpecs), [], WarnSpecs).
+get_all_errors_warnings3(error3({OoMErrSpecs, WarnSpecs}),
+        ErrSpecs, WarnSpecs) :-
+    ErrSpecs = one_or_more_to_list(OoMErrSpecs).
+
+get_all_errors_warnings4(ok4(_, _, _, WarnSpecs), [], WarnSpecs).
+get_all_errors_warnings4(error4({OoMErrSpecs, WarnSpecs}),
+        ErrSpecs, WarnSpecs) :-
+    ErrSpecs = one_or_more_to_list(OoMErrSpecs).
+
+%---------------------%
+
+add_warns_to_err_warn_error(ErrWarnError0, NewWarnSpecs, ErrWarnError) :-
+    ErrWarnError0 = {OoMErrSpecs0, WarnSpecs0},
+    ErrWarnError = {OoMErrSpecs0, NewWarnSpecs ++ WarnSpecs0}.
 
 %---------------------%
 
@@ -230,7 +313,7 @@ separate_ok1_error1(Maybes, OKs, Specs) :-
     list.reverse(RevOKs, OKs).
 
 :- pred separate_ok1_error1_loop(list(maybe1(T1))::in,
-    list(T1)::in, list(T1)::out, list(diag_spec)::in, list(diag_spec)::out)
+    list(T1)::in, list(T1)::out, list(err_spec)::in, list(err_spec)::out)
     is det.
 
 separate_ok1_error1_loop([], !RevOKs, !Specs).
diff --git a/compiler/mercury_compile_args.m b/compiler/mercury_compile_args.m
index 8e53f54f1..a3c0bd2f6 100644
--- a/compiler/mercury_compile_args.m
+++ b/compiler/mercury_compile_args.m
@@ -81,10 +81,11 @@ setup_all_args(ProgressStream, CmdLineArgs, ArgResult, !IO) :-
 
     % Replace all @file arguments with the contents of the file.
     expand_at_file_arguments_loop(CmdLineArgs,
-        cord.init, ExpandedCmdLineArgsCord, [], ExpandSpecs, !IO),
+        cord.init, ExpandedCmdLineArgsCord, [], ExpandSpecs0, !IO),
+    ExpandSpecs = coerce(ExpandSpecs0),
     % NOTE: We need the DefaultOptionTable both
     % - on all the success paths, to help build the Globals structure, and
-    % - on all the failure paths, to print the diag_specs.
+    % - on all the failure paths, to print the err_specs.
     get_option_default_table(DefaultOptionTable),
     (
         ExpandSpecs = [],
@@ -136,7 +137,7 @@ setup_all_args(ProgressStream, CmdLineArgs, ArgResult, !IO) :-
 
             % Now that we have constructed a globals, print out any errors
             % and/or warnings generated by the predicates in options_file.m.
-            write_error_specs(ProgressStream, Globals, OptionSpecs, !IO),
+            write_diag_specs(ProgressStream, Globals, OptionSpecs, !IO),
 
             % When computing the option arguments to pass to `--make',
             % only include the command-line arguments, not the contents of
@@ -153,7 +154,10 @@ setup_all_args(ProgressStream, CmdLineArgs, ArgResult, !IO) :-
                 ArgResult = apr_success(Globals, ArgPack)
             )
         ;
-            OptResult = opr_failure(OptionSpecs),
+            OptResult = opr_failure(OoMOptionErrSpecs, OptionWarnSpecs),
+            OoMOptionSpecs = oom_err_to_oom_diag(OoMOptionErrSpecs),
+            append_one_or_more_list(OoMOptionSpecs, OptionWarnSpecs,
+                OptionSpecs),
             % Usually, these OptionSpecs were generated in options_file.m.
             ArgResult = apr_failure(DefaultOptionTable, OptionSpecs)
         )
@@ -172,7 +176,7 @@ setup_all_args(ProgressStream, CmdLineArgs, ArgResult, !IO) :-
     %
 :- pred expand_at_file_arguments_loop(list(string)::in,
     cord(string)::in, cord(string)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 expand_at_file_arguments_loop([], !ExpandedArgs, !Specs, !IO).
 expand_at_file_arguments_loop([Arg | Args], !ExpandedArgs, !Specs, !IO) :-
@@ -199,10 +203,8 @@ expand_at_file_arguments_loop([Arg | Args], !ExpandedArgs, !Specs, !IO) :-
 
 :- type option_processing_result
     --->    opr_failure(
-                % This field should really contain one_or_more(diag_spec),
-                % but some of the predicates that find errors date from
-                % before the introduction of the one_or_more type.
-                oprf_fatal_errors           :: one_or_more(diag_spec)
+                oprf_fatal_error_specs      :: one_or_more(err_spec),
+                oprf_warn_specs             :: list(diag_spec)
             )
     ;       opr_success(
                 oprs_env_optfile_variables  :: env_optfile_variables,
@@ -226,13 +228,13 @@ process_options_arg_file(ProgressStream, DefaultOptionTable, ArgFile,
     % of command lines on Windows.) The environment is ignored, unlike
     % with @file syntax.
     read_args_file(ProgressStream, ArgFile, MaybeArgs1,
-        ArgsNonUndefSpecs, ArgsUndefSpecs, !IO),
+        ArgsNonUndefErrSpecs, ArgsUndefWarnSpecs, !IO),
     % Since the args file is supposed to be generated by the parent
     % `mmc --make' process, there shouldn't be any references to
     % undefined make variables in it. If there are, that process has
     % screwed up. We can't fix that bug unless the bug is reported,
     % which requires printing the error messages that it yields.
-    Specs = ArgsNonUndefSpecs ++ ArgsUndefSpecs,
+    Specs = coerce(ArgsNonUndefErrSpecs) ++ coerce(ArgsUndefWarnSpecs),
     EnvOptFileVariables = env_optfile_variables_init(EnvVarMap),
     (
         MaybeArgs1 = yes(Args1),
@@ -244,9 +246,9 @@ process_options_arg_file(ProgressStream, DefaultOptionTable, ArgFile,
             OptionArgs, NonOptionArgs),
         (
             Errors = [_ | _],
-            OptionSpecs = list.map(option_error_to_diag_spec, Errors),
+            OptionSpecs = list.map(option_error_to_err_spec, Errors),
             det_list_to_one_or_more(OptionSpecs, OoMOptionSpecs),
-            Result = opr_failure(OoMOptionSpecs)
+            Result = opr_failure(OoMOptionSpecs, [])
         ;
             Errors = [],
             Result = opr_success(EnvOptFileVariables, [],
@@ -260,9 +262,9 @@ process_options_arg_file(ProgressStream, DefaultOptionTable, ArgFile,
             OptionArgs, NonOptionArgs, Specs)
     ).
 
-:- func option_error_to_diag_spec(option_error(option)) = diag_spec.
+:- func option_error_to_err_spec(option_error(option)) = err_spec.
 
-option_error_to_diag_spec(OptionError) = Spec :-
+option_error_to_err_spec(OptionError) = Spec :-
     OptionErrorStr = option_error_to_string(OptionError),
     Pieces = [words(OptionErrorStr), suffix("."), nl],
     Spec = no_ctxt_spec($pred, severity_error, phase_options, Pieces).
@@ -286,34 +288,37 @@ process_options_std(ProgressStream, DefaultOptionTable, CmdLineArgs,
         DefaultOptionTable, ArgsOptionTable, cord.init, _UserData, !IO),
     (
         MaybeError = yes(OptionError),
-        Specs = report_option_error(OptionError),
-        Result = opr_failure(Specs)
+        OoMErrSpecs = report_option_error(OptionError),
+        Result = opr_failure(OoMErrSpecs, [])
     ;
         MaybeError = no,
         read_options_files_named_in_options_file_option(ProgressStream,
             ArgsOptionTable, EnvOptFileVariables0,
-            OptFileNonUndefSpecs, OptFileUndefSpecs, !IO),
+            OptFileErrSpecs, OptFileUndefWarnSpecs0, !IO),
         getopt.lookup_bool_option(ArgsOptionTable,
             warn_undefined_options_variables, WarnUndef),
         (
             WarnUndef = no,
-            OptFileSpecs = OptFileNonUndefSpecs
+            OptFileUndefWarnSpecs = []
         ;
             WarnUndef = yes,
-            OptFileSpecs = OptFileNonUndefSpecs ++ OptFileUndefSpecs
+            OptFileUndefWarnSpecs = OptFileUndefWarnSpecs0
         ),
         io.environment.get_environment_var_map(EnvVarMap, !IO),
+        % XXX DIAG_SPEC we used to include OptFileUndefWarnSpecs in this
         (
-            OptFileSpecs = [HeadSpec | TailSpecs],
-            Result = opr_failure(one_or_more(HeadSpec, TailSpecs))
+            OptFileErrSpecs = [HeadSpec | TailSpecs],
+            OoMOptFileErrSpecs = one_or_more(HeadSpec, TailSpecs),
+            Result = opr_failure(OoMOptFileErrSpecs,
+                coerce(OptFileUndefWarnSpecs))
         ;
-            OptFileSpecs = [],
+            OptFileErrSpecs = [],
             maybe_dump_options_file(ProgressStream, ArgsOptionTable,
                 EnvOptFileVariables0, !IO),
             lookup_mmc_options(EnvOptFileVariables0, MaybeMCFlags0),
             (
-                MaybeMCFlags0 = error1(Specs),
-                Result = opr_failure(Specs)
+                MaybeMCFlags0 = error1(OoMErrSpecs),
+                Result = opr_failure(OoMErrSpecs, [])
             ;
                 MaybeMCFlags0 = ok1(MCFlags0),
                 trace [
@@ -336,19 +341,18 @@ process_options_std(ProgressStream, DefaultOptionTable, CmdLineArgs,
                     cord.init, _UserDataMC, !IO),
                 (
                     MaybeErrorMC = yes(OptionError),
-                    Specs = report_option_error(OptionError),
-                    Result = opr_failure(Specs)
+                    OoMErrSpecs = report_option_error(OptionError),
+                    Result = opr_failure(OoMErrSpecs, [])
                 ;
                     MaybeErrorMC = no,
                     process_options_std_config_file(ProgressStream,
                         FlagsArgsOptionTable, EnvVarMap, WarnUndef,
                         EnvOptFileVariables0, EnvOptFileVariables,
                         MaybeMCFlags, OtherConfigSpecs, !IO),
-                    Specs = OptFileSpecs ++ OtherConfigSpecs,
+                    Specs = OtherConfigSpecs ++ coerce(OptFileUndefWarnSpecs),
                     (
                         MaybeMCFlags = error1(OoMFlagSpecs),
-                        append_one_or_more_list(OoMFlagSpecs, Specs, OoMSpecs),
-                        Result = opr_failure(OoMSpecs)
+                        Result = opr_failure(OoMFlagSpecs, Specs)
                     ;
                         MaybeMCFlags = ok1(MCFlags),
                         Result = opr_success(EnvOptFileVariables, MCFlags,
@@ -410,7 +414,7 @@ process_options_std_config_file(ProgressStream, FlagsArgsOptionTable,
             ConfigUndefSpecs = []
         ;
             WarnUndef = yes,
-            ConfigUndefSpecs = ConfigUndefSpecs0
+            ConfigUndefSpecs = coerce(ConfigUndefSpecs0)
         ),
         (
             ConfigNonUndefSpecs = [],
@@ -426,7 +430,7 @@ process_options_std_config_file(ProgressStream, FlagsArgsOptionTable,
             lookup_mercury_stdlib_dir(EnvOptFileVariables,
                 MaybeConfigMerStdLibDir),
             OtherSpecs = ConfigUndefSpecs ++
-                get_any_errors1(MaybeConfigMerStdLibDir)
+                coerce(get_any_errors1(MaybeConfigMerStdLibDir))
         ;
             ConfigNonUndefSpecs = [HeadSpec | TailSpecs],
             MaybeMCFlags = error1(one_or_more(HeadSpec, TailSpecs)),
@@ -441,7 +445,7 @@ process_options_std_config_file(ProgressStream, FlagsArgsOptionTable,
 
 %---------------------------------------------------------------------------%
 
-:- func report_option_error(option_error(option)) = one_or_more(diag_spec).
+:- func report_option_error(option_error(option)) = one_or_more(err_spec).
 
 report_option_error(OptionError) = Specs :-
     OptionErrorStr = option_error_to_string(OptionError),
@@ -479,7 +483,7 @@ report_option_error(OptionError) = Specs :-
     else
         Msgs = [MainMsg]
     ),
-    Spec = diag_spec($pred, severity_error, phase_options, Msgs),
+    Spec = gen_spec($pred, severity_error, phase_options, Msgs),
     Specs = one_or_more(Spec, []).
 
 %---------------------------------------------------------------------------%
diff --git a/compiler/mercury_compile_augment.m b/compiler/mercury_compile_augment.m
index 85bde34c9..17fbea3ef 100644
--- a/compiler/mercury_compile_augment.m
+++ b/compiler/mercury_compile_augment.m
@@ -102,8 +102,9 @@ augment_and_process_source_file(ProgressStream, ErrorStream, Globals,
     ModuleName = ParseTreeSrc ^ pts_module_name,
     parse_tree_src_to_burdened_module_list(Globals, SourceFileName,
         ReadModuleErrors, MaybeTimestamp, ParseTreeSrc,
-        SplitSpecs, BurdenedModules0),
-    add_to_be_written_specs(SplitSpecs, !MaybeWrittenSpecs),
+        SplitErrSpecs, SplitWarnSpecs, BurdenedModules0),
+    add_to_be_written_err_specs(SplitErrSpecs, !MaybeWrittenSpecs),
+    add_to_be_written_warn_specs(SplitWarnSpecs, !MaybeWrittenSpecs),
     (
         MaybeModulesToRecompile = some_file_components(ModulesToRecompile),
         ToRecompile =
@@ -200,16 +201,17 @@ augment_and_process_module(ProgressStream, ErrorStream, Globals,
         !HaveParseTreeMaps, !MaybeWrittenSpecs, !IO) :-
     BurdenedModule = burdened_module(Baggage0, ParseTreeModuleSrc),
     check_module_interface_for_no_exports(Globals, ParseTreeModuleSrc,
-        NoExportSpecs),
-    add_to_be_written_specs(NoExportSpecs, !MaybeWrittenSpecs),
+        NoExportWarnSpecs),
+    add_to_be_written_warn_specs(NoExportWarnSpecs, !MaybeWrittenSpecs),
     % XXX STREAM We could switch from a general progress stream
     % to a module-specific progress stream.
     grab_qual_imported_modules_augment(ProgressStream, Globals,
         MaybeTimestamp, ParseTreeModuleSrc, AugCompUnit,
         Baggage0, Baggage, !HaveParseTreeMaps, !IO),
     BaggageErrors = Baggage ^ mb_errors,
-    BaggageSpecs = get_read_module_specs(BaggageErrors),
-    add_to_be_written_specs(BaggageSpecs, !MaybeWrittenSpecs),
+    get_read_module_specs(BaggageErrors, BaggageErrSpecs, BaggageWarnSpecs),
+    add_to_be_written_err_specs(BaggageErrSpecs, !MaybeWrittenSpecs),
+    add_to_be_written_warn_specs(BaggageWarnSpecs, !MaybeWrittenSpecs),
     ( if set.is_empty(BaggageErrors ^ rm_fatal_errors) then
         process_augmented_module(ProgressStream, ErrorStream, Globals,
             OpModeAugment, InvokedByMmcMake, Baggage, AugCompUnit,
@@ -257,7 +259,7 @@ process_augmented_module(ProgressStream, ErrorStream, Globals,
         BlockingTypeSpecs = [],
         SpecsSoFar = maybe_written_specs_to_specs(!.MaybeWrittenSpecs),
         SemanticErrors = contains_errors(Globals, SpecsSoFar),
-        OptBlockingErrors = contains_errors(Globals, OptBlockingSpecs),
+        OptBlockingErrors = contains_errors(Globals, coerce(OptBlockingSpecs)),
         bool.or(SemanticErrors, OptBlockingErrors, PreHLDSErrors),
         frontend_pass(ProgressStream, ErrorStream, OpModeAugment, QualInfo,
             InvalidInstModeSpecs, PreHLDSErrors, FrontEndErrors,
diff --git a/compiler/mercury_compile_front_end.m b/compiler/mercury_compile_front_end.m
index 45a1e5bd4..822ba4b56 100644
--- a/compiler/mercury_compile_front_end.m
+++ b/compiler/mercury_compile_front_end.m
@@ -40,7 +40,7 @@
 %---------------------------------------------------------------------------%
 
 :- pred frontend_pass(io.text_output_stream::in, io.text_output_stream::in,
-    op_mode_augment::in, qual_info::in, list(diag_spec)::in,
+    op_mode_augment::in, qual_info::in, list(err_spec)::in,
     bool::in, bool::out, module_info::in, module_info::out,
     dump_info::in, dump_info::out,
     maybe_written_specs::in, maybe_written_specs::out, io::di, io::uo) is det.
@@ -207,7 +207,7 @@ frontend_pass(ProgressStream, ErrorStream, OpModeAugment, QualInfo0,
 
 :- pred frontend_pass_after_typeclass_check(io.text_output_stream::in,
     io.text_output_stream::in, op_mode_augment::in,
-    list(diag_spec)::in, bool::in, bool::out,
+    list(err_spec)::in, bool::in, bool::out,
     module_info::in, module_info::out, dump_info::in, dump_info::out,
     maybe_written_specs::in, maybe_written_specs::out, io::di, io::uo) is det.
 
@@ -413,7 +413,7 @@ do_typecheck(ProgressStream, ErrorStream, Verbose, Stats, Globals,
 
 :- pred frontend_pass_after_typecheck(io.text_output_stream::in,
     io.text_output_stream::in, op_mode_augment::in, globals::in,
-    bool::in, bool::in, list(diag_spec)::in, bool::in, bool::out,
+    bool::in, bool::in, list(err_spec)::in, bool::in, bool::out,
     module_info::in, module_info::out, dump_info::in, dump_info::out,
     maybe_written_specs::in, maybe_written_specs::out, io::di, io::uo) is det.
 
@@ -895,8 +895,9 @@ decide_type_repns_pass(ProgressStream, ErrorStream, Verbose, Stats,
         !MaybeWrittenSpecs, !IO),
     maybe_write_string(ProgressStream, Verbose,
         "% Deciding type representations...\n", !IO),
-    decide_type_repns(!HLDS, [], RepnSpecs, !IO),
-    add_to_be_written_specs(RepnSpecs, !MaybeWrittenSpecs),
+    decide_type_repns(!HLDS, RepnErrSpecs, RepnInfoSpecs, !IO),
+    add_to_be_written_err_specs(RepnErrSpecs, !MaybeWrittenSpecs),
+    add_to_be_written_info_specs(RepnInfoSpecs, !MaybeWrittenSpecs),
     maybe_write_string(ProgressStream, Verbose, "% done.\n", !IO),
     maybe_report_stats(ProgressStream, Stats, !IO).
 
diff --git a/compiler/mercury_compile_main.m b/compiler/mercury_compile_main.m
index 55fa04d1f..00c64c011 100644
--- a/compiler/mercury_compile_main.m
+++ b/compiler/mercury_compile_main.m
@@ -132,7 +132,7 @@ real_main(!IO) :-
         ArgResult = apr_failure(OptionTable, OoMArgSpecs),
         ArgSpecs = one_or_more_to_list(OoMArgSpecs),
         io.write_string(ProgressStream, "mmc:\n", !IO),
-        write_error_specs_opt_table(ProgressStream, OptionTable,
+        write_diag_specs_opt_table(ProgressStream, OptionTable,
             ArgSpecs, !IO),
         % In most cases, ArgSpecs should contain errors, so the above
         % should have set the exit status to 1. However, in cases such as
@@ -230,8 +230,8 @@ do_op_mode(ProgressStream, ErrorStream, Globals, OpMode, ArgPack,
     ;
         OpMode = opm_top_generate_source_file_mapping,
         ArgPack = compiler_arg_pack(_, _, _, Args),
-        source_file_map.write_source_file_map(Args, FileMapSpecs, !IO),
-        add_to_be_written_specs(FileMapSpecs, !MaybeWrittenSpecs)
+        write_source_file_map(Args, FileMapErrSpecs, !IO),
+        add_to_be_written_err_specs(FileMapErrSpecs, !MaybeWrittenSpecs)
     ;
         OpMode = opm_top_generate_standalone_interface(StandaloneIntBasename),
         do_op_mode_standalone_interface(ProgressStream, Globals,
@@ -409,10 +409,10 @@ do_op_mode_args(ProgressStream, ErrorStream, Globals, OpModeArgs,
         OptionArgs, Args),
     Params = compiler_params(EnvOptFileVariables, EnvVarArgs,
         OptionArgs),
-    maybe_check_libraries_are_installed(Globals, LibgradeCheckSpecs, !IO),
+    maybe_check_libraries_are_installed(Globals, LibgradeCheckErrSpecs, !IO),
     io.stderr_stream(StdErr, !IO),
     (
-        LibgradeCheckSpecs = [],
+        LibgradeCheckErrSpecs = [],
         (
             FileNamesFromStdin = yes,
             % Mmc --make does not set --filenames-from-stdin.
@@ -497,7 +497,7 @@ do_op_mode_args(ProgressStream, ErrorStream, Globals, OpModeArgs,
             true
         )
     ;
-        LibgradeCheckSpecs = [_ | _],
+        LibgradeCheckErrSpecs = [_ | _],
         % Print all remaining module-specific diag_specs.
         write_not_yet_written_specs(ErrorStream, Globals,
             !MaybeWrittenSpecs, !IO),
@@ -505,7 +505,7 @@ do_op_mode_args(ProgressStream, ErrorStream, Globals, OpModeArgs,
 
         % Print the diag_specs from the library check, which are
         % not specific to any module.
-        add_to_be_written_specs(LibgradeCheckSpecs, !MaybeWrittenSpecs),
+        add_to_be_written_err_specs(LibgradeCheckErrSpecs, !MaybeWrittenSpecs),
         write_not_yet_written_specs(StdErr, Globals,
             !MaybeWrittenSpecs, !IO)
     ),
@@ -841,11 +841,13 @@ do_process_compiler_arg(ProgressStream, ErrorStream, Globals0,
     (
         OpModeArgs = opma_generate_dependencies(MaybeMakeInts),
         generate_and_write_dep_file_gendep(ProgressStream, Globals0,
-            FileOrModule, DepsMap, DepSpecs, !IO),
-        add_to_be_written_specs(DepSpecs, !MaybeWrittenSpecs),
+            FileOrModule, DepsMap, DepErrSpecs, DepWarnSpecs, !IO),
+        add_to_be_written_err_specs(DepErrSpecs, !MaybeWrittenSpecs),
+        add_to_be_written_warn_specs(DepWarnSpecs, !MaybeWrittenSpecs),
         ( if
             MaybeMakeInts = do_make_ints,
-            contains_errors(Globals0, DepSpecs) = no
+            % XXX DIAG_SPEC
+            contains_errors(Globals0, coerce(DepErrSpecs)) = no
         then
             deps_make_ints(ProgressStream, Globals0, DepsMap,
                 !HaveParseTreeMaps, !MaybeWrittenSpecs, !IO)
@@ -857,8 +859,9 @@ do_process_compiler_arg(ProgressStream, ErrorStream, Globals0,
     ;
         OpModeArgs = opma_generate_dependency_file,
         generate_and_write_d_file_gendep(ProgressStream, Globals0,
-            FileOrModule, _DepsMap, DepSpecs, !IO),
-        add_to_be_written_specs(DepSpecs, !MaybeWrittenSpecs),
+            FileOrModule, _DepsMap, DepErrSpecs, DepWarnSpecs, !IO),
+        add_to_be_written_err_specs(DepErrSpecs, !MaybeWrittenSpecs),
+        add_to_be_written_warn_specs(DepWarnSpecs, !MaybeWrittenSpecs),
         ModulesToLink = [],
         ExtraObjFiles = []
     ;
@@ -881,8 +884,9 @@ do_process_compiler_arg(ProgressStream, ErrorStream, Globals0,
                     ParseTreeSrc, _Succeeded, !IO)
             )
         ),
-        Specs = get_read_module_specs(Errors),
-        add_to_be_written_specs(Specs, !MaybeWrittenSpecs),
+        get_read_module_specs(Errors, ErrSpecs, WarnSpecs),
+        add_to_be_written_err_specs(ErrSpecs, !MaybeWrittenSpecs),
+        add_to_be_written_warn_specs(WarnSpecs, !MaybeWrittenSpecs),
         ModulesToLink = [],
         ExtraObjFiles = []
     ;
@@ -1128,25 +1132,28 @@ do_process_compiler_arg_make_interface(ProgressStream, Globals0,
         ReturnTimestamp, HaveReadSrc, !HaveParseTreeMaps, !IO),
     (
         HaveReadSrc = have_not_read_module(_FileName, ReadErrors),
-        ReadSpecs = get_read_module_specs(ReadErrors),
-        add_to_be_written_specs(ReadSpecs, !MaybeWrittenSpecs)
+        get_read_module_specs(ReadErrors, ReadErrSpecs, ReadWarnSpecs),
+        add_to_be_written_err_specs(ReadErrSpecs, !MaybeWrittenSpecs),
+        add_to_be_written_warn_specs(ReadWarnSpecs, !MaybeWrittenSpecs)
     ;
         HaveReadSrc = have_module(FileName, ParseTreeSrc, Source),
         have_parse_tree_source_get_maybe_timestamp_errors(Source,
             MaybeTimestamp, ReadErrors),
-        ReadSpecs = get_read_module_specs(ReadErrors),
         ( if halt_at_module_error(Globals, ReadErrors) then
-            add_to_be_written_specs(ReadSpecs, !MaybeWrittenSpecs)
+            get_read_module_specs(ReadErrors, ReadErrSpecs, ReadWarnSpecs),
+            add_to_be_written_err_specs(ReadErrSpecs, !MaybeWrittenSpecs),
+            add_to_be_written_warn_specs(ReadWarnSpecs, !MaybeWrittenSpecs)
         else
             parse_tree_src_to_burdened_module_list(Globals, FileName,
                 ReadErrors, MaybeTimestamp, ParseTreeSrc,
-                SplitSpecs, BurdenedModules),
+                SplitErrSpecs, SplitWarnSpecs, BurdenedModules),
+            SplitSpecs = coerce(SplitErrSpecs) ++ coerce(SplitWarnSpecs),
             % parse_tree_src_to_burdened_module_list includes in SplitSpecs
             % the errors it gets from ReadErrors.
             % ZZZ
             ReadSplitSpecs0 = SplitSpecs,
-            filter_interface_generation_specs(Globals, ReadSplitSpecs0,
-                ReadSplitSpecs),
+            filter_interface_generation_specs(Globals,
+                ReadSplitSpecs0, ReadSplitSpecs),
             add_to_be_written_specs(ReadSplitSpecs, !MaybeWrittenSpecs),
             (
                 InterfaceFile = omif_int0,
@@ -1270,9 +1277,10 @@ read_augment_and_process_module(ProgressStream, ErrorStream, Globals0,
     read_module_or_file(ProgressStream, Globals0, Globals, FileOrModule,
         do_return_timestamp, HaveReadSrc, !HaveParseTreeMaps, !IO),
     (
-        HaveReadSrc = have_not_read_module(_, Errors),
-        Specs = get_read_module_specs(Errors),
-        add_to_be_written_specs(Specs, !MaybeWrittenSpecs),
+        HaveReadSrc = have_not_read_module(_, ReadModuleErrors),
+        get_read_module_specs(ReadModuleErrors, ErrSpecs, WarnSpecs),
+        add_to_be_written_err_specs(ErrSpecs, !MaybeWrittenSpecs),
+        add_to_be_written_warn_specs(WarnSpecs, !MaybeWrittenSpecs),
         ModulesToLink = [],
         ExtraObjFiles = []
     ;
@@ -1280,8 +1288,9 @@ read_augment_and_process_module(ProgressStream, ErrorStream, Globals0,
         have_parse_tree_source_get_maybe_timestamp_errors(Source,
             MaybeTimestamp, ReadModuleErrors),
         ( if halt_at_module_error(Globals, ReadModuleErrors) then
-            Specs = get_read_module_specs(ReadModuleErrors),
-            add_to_be_written_specs(Specs, !MaybeWrittenSpecs),
+            get_read_module_specs(ReadModuleErrors, ErrSpecs, WarnSpecs),
+            add_to_be_written_err_specs(ErrSpecs, !MaybeWrittenSpecs),
+            add_to_be_written_warn_specs(WarnSpecs, !MaybeWrittenSpecs),
             ModulesToLink = [],
             ExtraObjFiles = []
         else
diff --git a/compiler/mercury_compile_make_hlds.m b/compiler/mercury_compile_make_hlds.m
index 9c99c3632..983baf770 100644
--- a/compiler/mercury_compile_make_hlds.m
+++ b/compiler/mercury_compile_make_hlds.m
@@ -39,11 +39,11 @@
 
 :- type make_hlds_result
     --->    make_hlds_result(
-                mhr_invalid_types       :: list(diag_spec),
-                mhr_invalid_insts_modes :: list(diag_spec),
-                mhr_opt_blocking        :: list(diag_spec),
-                mhr_expansion           :: list(diag_spec),
-                mhr_event_set           :: list(diag_spec)
+                mhr_invalid_types       :: list(err_spec),
+                mhr_invalid_insts_modes :: list(err_spec),
+                mhr_opt_blocking        :: list(err_spec),
+                mhr_expansion           :: list(err_spec),
+                mhr_event_set           :: list(err_spec)
             ).
 
     % make_hlds_pass(ProgressStream, ErrorStream, Globals,
@@ -124,11 +124,13 @@ make_hlds_pass(ProgressStream, ErrorStream, Globals,
         OpModeAugment, Verbose, MaybeDFileTransOptDeps, OptBlockingSpecs,
         Baggage0, Baggage1, AugCompUnit0, AugCompUnit1,
         !HaveReadModuleMaps, !MaybeWrittenSpecs, !IO),
-    add_to_be_written_specs(OptBlockingSpecs, !MaybeWrittenSpecs),
+    add_to_be_written_err_specs(OptBlockingSpecs, !MaybeWrittenSpecs),
     MaybeTimestampMap = Baggage1 ^ mb_maybe_timestamp_map,
 
-    BaggageSpecs = get_read_module_specs(Baggage1 ^ mb_errors),
-    add_to_be_written_specs(BaggageSpecs, !MaybeWrittenSpecs),
+    get_read_module_specs(Baggage1 ^ mb_errors,
+        BaggageErrSpecs, BaggageWarnSpecs),
+    add_to_be_written_err_specs(BaggageErrSpecs, !MaybeWrittenSpecs),
+    add_to_be_written_warn_specs(BaggageWarnSpecs, !MaybeWrittenSpecs),
 
     % We must read in EventSpecMap0 before
     % - the call to module_qualify_aug_comp_unit, since that call
@@ -139,7 +141,7 @@ make_hlds_pass(ProgressStream, ErrorStream, Globals,
         EventSetFileName),
     maybe_read_event_set(Globals, EventSetFileName,
         EventSetName, EventSpecMap0, EventSetSpecs, !IO),
-    add_to_be_written_specs(EventSetSpecs, !MaybeWrittenSpecs),
+    add_to_be_written_err_specs(EventSetSpecs, !MaybeWrittenSpecs),
 
     maybe_write_not_yet_written_specs(ErrorStream, Globals, Verbose,
         !MaybeWrittenSpecs, !IO),
@@ -150,7 +152,7 @@ make_hlds_pass(ProgressStream, ErrorStream, Globals,
         EventSpecMap0, EventSpecMap1, EventSetFileName,
         MQInfo0, UnusedImports, UnusedImportsSpecsMap),
     map.values(UnusedImportsSpecsMap, UnusedImportsSpecs),
-    add_to_be_written_specs(UnusedImportsSpecs, !MaybeWrittenSpecs),
+    add_to_be_written_warn_specs(UnusedImportsSpecs, !MaybeWrittenSpecs),
     maybe_write_not_yet_written_specs(ErrorStream, Globals, Verbose,
         !MaybeWrittenSpecs, !IO),
     maybe_write_string(ProgressStream, Verbose, "% done.\n", !IO),
@@ -163,7 +165,7 @@ make_hlds_pass(ProgressStream, ErrorStream, Globals,
     expand_eqv_types_insts(AugCompUnit2, AugCompUnit,
         EventSpecMap1, EventSpecMap, TypeEqvMap, UsedEqvModules,
         RecompInfo0, RecompInfo, ExpandSpecs),
-    add_to_be_written_specs(ExpandSpecs, !MaybeWrittenSpecs),
+    add_to_be_written_err_specs(ExpandSpecs, !MaybeWrittenSpecs),
     maybe_write_not_yet_written_specs(ErrorStream, Globals, Verbose,
         !MaybeWrittenSpecs, !IO),
     maybe_write_string(ProgressStream, Verbose, "% done.\n", !IO),
@@ -178,10 +180,13 @@ make_hlds_pass(ProgressStream, ErrorStream, Globals,
         ModuleName, DumpBaseFileName),
     parse_tree_to_hlds(ProgressStream, AugCompUnit, Globals, DumpBaseFileName,
         MQInfo, TypeEqvMap, UsedEqvModules, UnusedImports, QualInfo, !:HLDS,
-        InvalidTypeSpecs, InvalidInstModeSpecs, MakeSpecs),
-    add_to_be_written_specs(InvalidTypeSpecs, !MaybeWrittenSpecs),
-    add_to_be_written_specs(InvalidInstModeSpecs, !MaybeWrittenSpecs),
-    add_to_be_written_specs(MakeSpecs, !MaybeWrittenSpecs),
+        InvalidTypeSpecs, InvalidInstModeSpecs,
+        MakeErrSpecs, MakeWarnSpecs, MakeInfoSpecs),
+    add_to_be_written_err_specs(InvalidTypeSpecs, !MaybeWrittenSpecs),
+    add_to_be_written_err_specs(InvalidInstModeSpecs, !MaybeWrittenSpecs),
+    add_to_be_written_err_specs(MakeErrSpecs, !MaybeWrittenSpecs),
+    add_to_be_written_warn_specs(MakeWarnSpecs, !MaybeWrittenSpecs),
+    add_to_be_written_info_specs(MakeInfoSpecs, !MaybeWrittenSpecs),
 
     % Now that we have both EventSpecMap and an initial HLDS,
     % we can put the former into the latter.
@@ -299,7 +304,7 @@ maybe_mention_undoc(DocUndoc, Pieces0, Pieces) :-
 %---------------------%
 
 :- pred maybe_read_event_set(globals::in, string::in,
-    string::out, event_spec_map::out, list(diag_spec)::out,
+    string::out, event_spec_map::out, list(err_spec)::out,
     io::di, io::uo) is det.
 
 maybe_read_event_set(Globals, EventSetFileName, EventSetName, EventSpecMap,
@@ -311,7 +316,8 @@ maybe_read_event_set(Globals, EventSetFileName, EventSetName, EventSpecMap,
     else
         read_event_set(EventSetFileName, EventSetName0, EventSpecMap0,
             EventSetSpecs, !IO),
-        Errors = contains_errors(Globals, EventSetSpecs),
+        % XXX DIAG_SPEC
+        Errors = contains_errors(Globals, coerce(EventSetSpecs)),
         (
             Errors = no,
             EventSetName = EventSetName0,
@@ -446,7 +452,7 @@ read_d_file_get_modules(InStream, TransOptDeps, !IO) :-
 
 :- pred maybe_grab_plain_and_trans_opt_files(io.text_output_stream::in,
     globals::in, op_mode_augment::in,
-    bool::in, maybe(list(module_name))::in, list(diag_spec)::out,
+    bool::in, maybe(list(module_name))::in, list(err_spec)::out,
     module_baggage::in, module_baggage::out,
     aug_compilation_unit::in, aug_compilation_unit::out,
     have_parse_tree_maps::in, have_parse_tree_maps::out,
diff --git a/compiler/mode_errors.m b/compiler/mode_errors.m
index 90180760c..147e5608f 100644
--- a/compiler/mode_errors.m
+++ b/compiler/mode_errors.m
@@ -692,7 +692,7 @@ mode_error_unify_var_poly_to_spec(ModeInfo, Var, VarInst) = Spec :-
         words("Unifications of polymorphically-typed variables with"),
         words("partially instantiated modes are not allowed.")],
     Phase = phase_mode_check(report_in_any_mode),
-    Spec = diag_spec($pred, severity_error, Phase,
+    Spec = gen_spec($pred, severity_error, Phase,
         [simple_msg(Context,
             [always(Preamble ++ MainPieces),
             verbose_only(verbose_once, VerbosePieces)])]).
@@ -921,7 +921,7 @@ mode_error_higher_order_unify_to_spec(ModeInfo, LHSVar, RHS, Type, PredOrFunc)
         quote("all [X] call(PredA, X) <=> call(PredB, X)"), suffix(","),
         words("instead of"), quote("PredA = PredB"), suffix("."), nl],
     Phase = phase_mode_check(report_in_any_mode),
-    Spec = diag_spec($pred, severity_error, Phase,
+    Spec = gen_spec($pred, severity_error, Phase,
         [simple_msg(Context,
             [always(Preamble ++ MainPieces),
             verbose_only(verbose_once, VerbosePieces)])]).
@@ -983,7 +983,7 @@ mode_error_var_is_not_sufficiently_instantiated_to_spec(ModeInfo, Var,
         MultiModeMsgs = ConnectMsgs ++ SubMsgs
     ),
     AllMsgs = MainMsgs ++ UniqMsgs ++ MultiModeMsgs,
-    Spec = diag_spec($pred, severity_error, Phase, AllMsgs).
+    Spec = gen_spec($pred, severity_error, Phase, AllMsgs).
 
 :- pred inst_has_uniqueness(mer_inst::in, uniqueness::in) is semidet.
 
@@ -1667,7 +1667,7 @@ mode_error_unschedulable_conjuncts_to_spec(ModeInfo, OoMErrors, Culprit)
             msg(ImpureGoalContext, Pieces2)]
     ),
     Phase = phase_mode_check(report_in_any_mode),
-    Spec = diag_spec($pred, severity_error, Phase, Msgs1 ++ Msgs2).
+    Spec = gen_spec($pred, severity_error, Phase, Msgs1 ++ Msgs2).
 
 :- func prefix_with_blank_line(prog_context, list(diag_msg)) = list(diag_msg).
 
@@ -1771,7 +1771,7 @@ mode_error_merge_par_conj_to_spec(ModeInfo, MergeErrors) = Spec :-
         one_or_more_to_list(MergeErrors)),
     list.condense(MergeMsgLists, MergeMsgs),
     Phase = phase_mode_check(report_in_any_mode),
-    Spec = diag_spec($pred, severity_error, Phase,
+    Spec = gen_spec($pred, severity_error, Phase,
         [msg(Context, Preamble ++ MainPieces) | MergeMsgs]).
 
 %---------------------------------------------------------------------------%
@@ -1791,7 +1791,7 @@ mode_error_merge_disj_to_spec(ModeInfo, MergeContext, MergeErrors) = Spec :-
         one_or_more_to_list(MergeErrors)),
     list.condense(MergeMsgLists, MergeMsgs),
     Phase = phase_mode_check(report_in_any_mode),
-    Spec = diag_spec($pred, severity_error, Phase,
+    Spec = gen_spec($pred, severity_error, Phase,
         [msg(Context, Preamble ++ MainPieces) | MergeMsgs]).
 
 :- func merge_context_to_string(merge_context) = string.
@@ -2120,7 +2120,7 @@ mode_error_bind_locked_var_to_spec(ModeInfo, Reason, Var, VarInst, Inst)
             [nl]
     ),
     Phase = phase_mode_check(report_in_any_mode),
-    Spec = diag_spec($pred, severity_error, Phase,
+    Spec = gen_spec($pred, severity_error, Phase,
         [simple_msg(Context,
             [always(Preamble ++ MainPieces),
             verbose_only(verbose_always, VerbosePieces)])]).
@@ -2281,7 +2281,7 @@ mode_error_in_callee_to_spec(!.ModeInfo, Vars, Insts,
             LaterMsgs = start_each_msg_with_blank_line([LaterHead | LaterTail])
         ),
         Phase = phase_mode_check(report_in_any_mode),
-        Spec = diag_spec($pred, severity_error, Phase, [InitMsg | LaterMsgs])
+        Spec = gen_spec($pred, severity_error, Phase, [InitMsg | LaterMsgs])
     ;
         CalleeModeErrors = [],
         unexpected($pred, "no error")
@@ -2321,7 +2321,7 @@ mode_error_cannot_create_implied_mode_to_spec(ModeInfo, Reason, Var, VarInst,
                 NonImpliedInitialInst),
         Spec = spec($pred, severity_error, Phase, Context, Preamble ++ Pieces)
     else
-        Spec = diag_spec($pred, severity_informational(report_noop), Phase,
+        Spec = gen_spec($pred, severity_informational(report_noop), Phase,
             [simple_msg(Context, [])])
     ).
 
@@ -2391,7 +2391,7 @@ purity_error_lambda_should_be_any_to_spec(ModeInfo, OoMVars) = Spec :-
         words("can be written"),
         quote("any_func(Args) = Result is det :- ..."), suffix("."), nl]),
     Phase = phase_mode_check(report_in_any_mode),
-    Spec = diag_spec($pred, severity_error, Phase,
+    Spec = gen_spec($pred, severity_error, Phase,
         [simple_msg(Context, [Always, VerboseOnly])]).
 
 %---------------------------------------------------------------------------%
diff --git a/compiler/mode_info.m b/compiler/mode_info.m
index b6e1f3719..41e4a38ae 100644
--- a/compiler/mode_info.m
+++ b/compiler/mode_info.m
@@ -1305,7 +1305,7 @@ mode_info_add_error(ModeErrorInfo, !ModeInfo) :-
             Spec = mode_error_info_to_spec(!.ModeInfo, ModeErrorInfo),
             globals.set_option(print_error_spec_id, bool(yes),
                 Globals0, Globals),
-            write_error_spec(DebugStream, Globals, Spec, !IO), % debug msg
+            write_diag_spec(DebugStream, Globals, Spec, !IO),
             io.flush_output(DebugStream, !IO)
         )
     ).
diff --git a/compiler/modes.m b/compiler/modes.m
index 5a235f890..41b4a921b 100644
--- a/compiler/modes.m
+++ b/compiler/modes.m
@@ -506,7 +506,7 @@ modecheck_to_fixpoint(ProgressStream, WhatToCheck, MayChangeCalledProc,
                             DebugStream, !IO),
                         io.write_string(DebugStream,
                             "Inferences by current iteration:\n", !IO),
-                        write_error_specs(DebugStream, Globals,
+                        write_diag_specs(DebugStream, Globals,
                             InferenceSpecs, !IO),
                         io.write_string(DebugStream,
                             "End of inferences.\n", !IO)
@@ -772,7 +772,7 @@ maybe_report_error_no_modes(ModuleInfo, PredId, PredInfo) = Specs :-
                     verbose_only(verbose_once, VerbosePieces)])],
             pred_info_get_context(PredInfo, Context),
             Phase = phase_mode_check(report_in_any_mode),
-            Spec = diag_spec($pred, severity_error, Phase, Msgs),
+            Spec = gen_spec($pred, severity_error, Phase, Msgs),
             Specs = [Spec]
         )
     else
@@ -1016,7 +1016,7 @@ do_modecheck_proc(WhatToCheck, MayChangeCalledProc,
                 WarningSpecs = list.map(mode_warning_info_to_spec(!.ModeInfo),
                     ModeWarnings),
                 ErrorAndWarningSpecs = ErrorSpecs ++ WarningSpecs ++
-                    StateVarWarningSpecs
+                    coerce(StateVarWarningSpecs)
             )
         ),
 
@@ -1838,7 +1838,7 @@ report_eval_method_requires_ground_args(ProcInfo, TabledMethod) = Spec :-
     Msg = simple_msg(Context,
         [always(MainPieces), verbose_only(verbose_once, VerbosePieces)]),
     Phase = phase_mode_check(report_in_any_mode),
-    Spec = diag_spec($pred, severity_error, Phase, [Msg]).
+    Spec = gen_spec($pred, severity_error, Phase, [Msg]).
 
 :- func report_eval_method_destroys_uniqueness(proc_info, tabled_eval_method)
     = diag_spec.
@@ -1859,7 +1859,7 @@ report_eval_method_destroys_uniqueness(ProcInfo, TabledMethod) = Spec :-
     Msg = simple_msg(Context,
         [always(MainPieces), verbose_only(verbose_once, VerbosePieces)]),
     Phase = phase_mode_check(report_in_any_mode),
-    Spec = diag_spec($pred, severity_error, Phase, [Msg]).
+    Spec = gen_spec($pred, severity_error, Phase, [Msg]).
 
 :- func report_wrong_mode_for_main(proc_info) = diag_spec.
 
diff --git a/compiler/module_baggage.m b/compiler/module_baggage.m
index ae221ac21..d502741fb 100644
--- a/compiler/module_baggage.m
+++ b/compiler/module_baggage.m
@@ -244,7 +244,8 @@
     %
 :- pred parse_tree_src_to_burdened_module_list(globals::in, file_name::in,
     read_module_errors::in, maybe(timestamp)::in, parse_tree_src::in,
-    list(diag_spec)::out, list(burdened_module)::out) is det.
+    list(err_spec)::out, list(warn_spec)::out, list(burdened_module)::out)
+    is det.
 
 %---------------------------------------------------------------------------%
 %
@@ -292,10 +293,10 @@ get_nested_children_list_of_top_module(MaybeTopModule) = Modules :-
 
 parse_tree_src_to_burdened_module_list(Globals, SourceFileName,
         ReadModuleErrors, MaybeTimestamp, ParseTreeSrc,
-        !:Specs, BurdenedModules) :-
-    !:Specs = get_read_module_specs(ReadModuleErrors),
+        !:ErrSpecs, !:WarnSpecs, BurdenedModules) :-
+    get_read_module_specs(ReadModuleErrors, !:ErrSpecs, !:WarnSpecs),
     split_into_component_modules_perform_checks(Globals, ParseTreeSrc,
-        ParseTreeModuleSrcs, !Specs),
+        ParseTreeModuleSrcs, !ErrSpecs, !WarnSpecs),
     ParseTreeSrc = parse_tree_src(TopModuleName, _, _),
     AllModuleNames = set.list_to_set(
         list.map(parse_tree_module_src_project_name, ParseTreeModuleSrcs)),
diff --git a/compiler/module_qual.collect_mq_info.m b/compiler/module_qual.collect_mq_info.m
index 075be800d..674f1eef6 100644
--- a/compiler/module_qual.collect_mq_info.m
+++ b/compiler/module_qual.collect_mq_info.m
@@ -75,7 +75,7 @@ collect_mq_info_in_parse_tree_module_src(ParseTreeModuleSrc, !Info) :-
         _IntFIMSpecMap, _ImpFIMSpecMap, _IntSelfFIMLangs, _ImpSelfFIMLangs,
 
         TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
-        _TypeSpecs, _InstModeSpecs,
+        _TypeErrSpecs, _TypeWarnSpecs, _InstModeErrSpecs, _InstModeWarnSpecs,
 
         IntTypeClasses, IntInstances, _IntPredDecls, _IntModeDecls,
         _IntDeclPragmas, _IntDeclMarkers, IntPromises, _IntBadPreds,
diff --git a/compiler/module_qual.id_set.m b/compiler/module_qual.id_set.m
index 44defa9c3..80202b832 100644
--- a/compiler/module_qual.id_set.m
+++ b/compiler/module_qual.id_set.m
@@ -358,7 +358,7 @@ find_unique_match(InInt, ErrorContext, IdSet, IdType, Id0, SymName, !Info) :-
             record_used_item(UsedItemType, ItemName0, ItemName), !Info)
     ).
 
-:- pred mq_info_record_undef_mq_id(qual_id_kind::in, mq_id::in, diag_spec::in,
+:- pred mq_info_record_undef_mq_id(qual_id_kind::in, mq_id::in, err_spec::in,
     mq_info::in, mq_info::out) is det.
 
 mq_info_record_undef_mq_id(IdType, Id, Spec, !Info) :-
diff --git a/compiler/module_qual.mq_info.m b/compiler/module_qual.mq_info.m
index acf87b0ca..dc632a1ab 100644
--- a/compiler/module_qual.mq_info.m
+++ b/compiler/module_qual.mq_info.m
@@ -42,7 +42,7 @@
     --->    undef_is_blocking
     ;       undef_is_not_blocking.
 
-:- type undef_specs(T) == one_or_more_map(T, diag_spec).
+:- type undef_specs(T) == one_or_more_map(T, err_spec).
 
 %---------------------------------------------------------------------------%
 
@@ -80,7 +80,7 @@
 :- pred mq_info_get_is_undef_blocking(mq_info::in,
     is_undef_blocking::out) is det.
 :- pred mq_info_get_nonblocking_undef_specs(mq_info::in,
-    list(diag_spec)::out) is det.
+    list(err_spec)::out) is det.
 :- pred mq_info_get_should_report_errors(mq_info::in,
     maybe_should_report_errors::out) is det.
 
@@ -115,7 +115,7 @@
     mq_info::in, mq_info::out) is det.
 :- pred mq_info_set_is_undef_blocking(is_undef_blocking::in,
     mq_info::in, mq_info::out) is det.
-:- pred mq_info_set_nonblocking_undef_specs(list(diag_spec)::in,
+:- pred mq_info_set_nonblocking_undef_specs(list(err_spec)::in,
     mq_info::in, mq_info::out) is det.
 
 %---------------------------------------------------------------------------%
@@ -170,12 +170,11 @@
 
 %---------------------------------------------------------------------------%
 
-    % get_diag_specs_in_mq_info(Info,
+    % get_err_specs_in_mq_info(Info,
     %   InvalidTypeSpecs, InvalidInstModeSpecs, NonBlockingUndefSpecs)
     %
-:- pred get_diag_specs_in_mq_info(mq_info::in,
-    list(diag_spec)::out, list(diag_spec)::out, list(diag_spec)::out)
-    is det.
+:- pred get_err_specs_in_mq_info(mq_info::in,
+    list(err_spec)::out, list(err_spec)::out, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -243,12 +242,12 @@
                 mqsi_undef_typeclasses          :: undef_specs(sym_name_arity),
 
                 % When we find undefined type, inst, mode or typeclass,
-                % do we want to record is blocking (meaning we record it
+                % do we want to record it as blocking (meaning we record it
                 % in one of the four fields above, where its presence will
-                % prevent the compiler to proceeding to some passes),
+                % prevent the compiler from proceeding to some passes),
                 % or as nonblocking (meaning we record it in the field below).
                 mqsi_is_undef_blocking          :: is_undef_blocking,
-                mqsi_nonblocking_undef_specs    :: list(diag_spec),
+                mqsi_nonblocking_undef_specs    :: list(err_spec),
 
                 % Do we want to report errors.
                 mqsi_should_report_errors       :: maybe_should_report_errors,
@@ -458,7 +457,7 @@ mq_info_set_module_used(InInt, ModuleName, !Info) :-
 
 %---------------------------------------------------------------------------%
 
-get_diag_specs_in_mq_info(Info,
+get_err_specs_in_mq_info(Info,
         InvalidTypeSpecs, InvalidInstModeSpecs, NonBlockingUndefSpecs) :-
     mq_info_get_undef_types(Info, UndefTypesMap),
     mq_info_get_undef_insts(Info, UndefInstsMap),
diff --git a/compiler/module_qual.qual_errors.m b/compiler/module_qual.qual_errors.m
index bfa947a3e..c62322ec1 100644
--- a/compiler/module_qual.qual_errors.m
+++ b/compiler/module_qual.qual_errors.m
@@ -183,7 +183,7 @@
 :- pred report_undefined_mq_id(mq_info::in, mq_error_context::in,
     mq_id::in, qual_id_kind::in, module_name::in,
     list(module_name)::in, list(module_name)::in, set(int)::in,
-    diag_spec::out) is det.
+    err_spec::out) is det.
 
     % report_ambiguous_match(ErrorContext, Id, IdType,
     %   UsableModuleNames, UnusableModuleNames, !Specs):
@@ -193,18 +193,18 @@
     %
 :- pred report_ambiguous_match(mq_error_context::in, mq_id::in,
     qual_id_kind::in,
-    list(module_name)::in, list(module_name)::in, diag_spec::out) is det.
+    list(module_name)::in, list(module_name)::in, err_spec::out) is det.
 
     % Output an error message about an ill-formed user_inst.
     %
 :- pred report_invalid_user_inst(sym_name::in, list(mer_inst)::in,
-    mq_error_context::in, diag_spec::out) is det.
+    mq_error_context::in, err_spec::out) is det.
 
     % Warn about a module imported in the interface that is not used
     % in the interface.
     %
 :- pred warn_unused_interface_import(module_name::in,
-    module_name::in, one_or_more(prog_context)::in, diag_spec::out) is det.
+    module_name::in, one_or_more(prog_context)::in, warn_spec::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -445,7 +445,7 @@ report_ambiguous_match(ErrorContext, Id, IdType,
     Msg = simple_msg(Context,
         [always(MainPieces), always(UnusablePieces),
         verbose_only(verbose_always, VerbosePieces)]),
-    Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg]).
+    Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg]).
 
 %---------------------------------------------------------------------------%
 
diff --git a/compiler/module_qual.qualify_items.m b/compiler/module_qual.qualify_items.m
index 692261819..64e0c5c2c 100644
--- a/compiler/module_qual.qualify_items.m
+++ b/compiler/module_qual.qualify_items.m
@@ -46,11 +46,12 @@
 :- pred module_qualify_aug_comp_unit(globals::in,
     aug_compilation_unit::in, aug_compilation_unit::out,
     event_spec_map::in, event_spec_map::out, string::in, mq_info::out,
-    set_tree234(module_name)::out, map(module_name, diag_spec)::out) is det.
+    set_tree234(module_name)::out, map(module_name, warn_spec)::out) is det.
 
 :- pred module_qualify_aug_make_int_unit(globals::in,
     aug_make_int_unit::in, aug_make_int_unit::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
     % module_qualify_parse_tree_int3(Globals, OrigParseTreeInt3, ParseTreeInt3,
     %   !Specs):
@@ -60,7 +61,7 @@
     %
 :- pred module_qualify_parse_tree_int3(globals::in,
     parse_tree_int3::in, parse_tree_int3::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -175,7 +176,7 @@ module_qualify_aug_comp_unit(Globals, AugCompUnit0, AugCompUnit,
 %---------------------%
 
 module_qualify_aug_make_int_unit(Globals, AugMakeIntUnit0, AugMakeIntUnit,
-        !Specs) :-
+        !ErrSpecs, !WarnSpecs) :-
     AugMakeIntUnit0 = aug_make_int_unit(ParseTreeModuleSrc0, DelayedSpecs0,
         AncestorInt0s, DirectInt3Specs, IndirectInt3Specs,
         ModuleVersionNumbers),
@@ -193,10 +194,10 @@ module_qualify_aug_make_int_unit(Globals, AugMakeIntUnit0, AugMakeIntUnit,
         AugMakeIntUnit = aug_make_int_unit(ParseTreeModuleSrc, DelayedSpecs0,
             AncestorInt0s, DirectInt3Specs, IndirectInt3Specs,
             ModuleVersionNumbers),
-        get_diag_specs_in_mq_info(!.Info,
+        get_err_specs_in_mq_info(!.Info,
             InvalidTypeSpecs, InvalidInstModeSpecs, NonBlockingUndefSpecs),
-        !:Specs = InvalidTypeSpecs ++ InvalidInstModeSpecs ++
-            NonBlockingUndefSpecs ++ !.Specs,
+        !:ErrSpecs = InvalidTypeSpecs ++ InvalidInstModeSpecs ++
+            NonBlockingUndefSpecs ++ !.ErrSpecs,
 
         globals.lookup_bool_option(Globals, warn_unused_interface_imports,
             WarnInterfaceImports),
@@ -208,7 +209,7 @@ module_qualify_aug_make_int_unit(Globals, AugMakeIntUnit0, AugMakeIntUnit,
             map.map_values(warn_unused_interface_import(ModuleName),
                 UnusedImportsContextsMap, UnusedImportsSpecsMap),
             map.values(UnusedImportsSpecsMap, UnusedImportsSpecs),
-            !:Specs = UnusedImportsSpecs ++ !.Specs
+            !:WarnSpecs = UnusedImportsSpecs ++ !.WarnSpecs
         )
     ).
 
@@ -259,17 +260,17 @@ get_unused_imports_map(Info, UnusedImportsMap) :-
 %---------------------%
 
 module_qualify_parse_tree_int3(Globals, OrigParseTreeInt3, ParseTreeInt3,
-        !Specs) :-
+        !ErrSpecs) :-
     ModuleName = OrigParseTreeInt3 ^ pti3_module_name,
     init_mq_info(Globals, ModuleName, should_not_report_errors, Info0),
     collect_mq_info_in_parse_tree_int3(int3_as_src, OrigParseTreeInt3,
         Info0, Info1),
     qualify_parse_tree_int3(OrigParseTreeInt3, ParseTreeInt3,
         Info1, Info),
-    get_diag_specs_in_mq_info(Info,
+    get_err_specs_in_mq_info(Info,
         InvalidTypeSpecs, InvalidInstModeSpecs, NonBlockingUndefSpecs),
-    !:Specs = InvalidTypeSpecs ++ InvalidInstModeSpecs ++
-        NonBlockingUndefSpecs ++ !.Specs.
+    !:ErrSpecs = InvalidTypeSpecs ++ InvalidInstModeSpecs ++
+        NonBlockingUndefSpecs ++ !.ErrSpecs.
 
 %---------------------------------------------------------------------------%
 
@@ -286,7 +287,7 @@ qualify_parse_tree_module_src(ParseTreeModuleSrc0, ParseTreeModuleSrc,
         IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,
 
         TypeCtorCheckedMap0, InstCtorCheckedMap0, ModeCtorCheckedMap0,
-        TypeSpecs, InstModeSpecs,
+        TypeErrSpecs, TypeWarnSpecs, InstModeErrSpecs, InstModeWarnSpecs,
 
         IntTypeClasses0, IntInstances0, IntPredDecls0, IntModeDecls0,
         IntDeclPragmas0, IntDeclMarkers0, IntPromises0, IntBadPreds,
@@ -348,7 +349,7 @@ qualify_parse_tree_module_src(ParseTreeModuleSrc0, ParseTreeModuleSrc,
         IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,
 
         TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
-        TypeSpecs, InstModeSpecs,
+        TypeErrSpecs, TypeWarnSpecs, InstModeErrSpecs, InstModeWarnSpecs,
 
         IntTypeClasses, IntInstances, IntPredDecls, IntModeDecls,
         IntDeclPragmas, IntDeclMarkers0, IntPromises, IntBadPreds,
diff --git a/compiler/old_type_constraints.m b/compiler/old_type_constraints.m
index 8a9831bfc..4b586d8f3 100644
--- a/compiler/old_type_constraints.m
+++ b/compiler/old_type_constraints.m
@@ -2212,7 +2212,7 @@ next_min_unsat(Constraint, C, !D, !P, !MinUnsats) :-
     type_constraint_info::out) is det.
 
 add_message_to_spec(ErrMsg, !TCInfo) :-
-    Spec = diag_spec($pred, severity_error, phase_type_check, [ErrMsg]),
+    Spec = gen_spec($pred, severity_error, phase_type_check, [ErrMsg]),
     !TCInfo ^ tconstr_diag_specs := [Spec | !.TCInfo ^ tconstr_diag_specs].
 
 :- pred bracket_context_to_string(prog_context::in, string::out) is det.
diff --git a/compiler/opt_deps_spec.m b/compiler/opt_deps_spec.m
index 09696a72d..ccaac3e23 100644
--- a/compiler/opt_deps_spec.m
+++ b/compiler/opt_deps_spec.m
@@ -28,13 +28,13 @@
 
     % compute_opt_trans_opt_deps_graph(ProgressStream, Globals, ModuleName,
     %   ImpDepsGraph, IndirectOptDepsGraph, TransOptDepsGraph,
-    %   TransOptDepsOrdering, !Specs, !IO)
+    %   TransOptDepsOrdering, ErrSpecs, WarnSpecs, !IO)
     %
 :- pred compute_opt_trans_opt_deps_graph(io.text_output_stream::in,
     globals::in, module_name::in, digraph(module_name)::in,
     digraph(module_name)::out, digraph(module_name)::out,
     list(module_name)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::out, list(warn_spec)::out, io::di, io::uo) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -71,7 +71,7 @@
 
 compute_opt_trans_opt_deps_graph(ProgressStream, Globals, ModuleName,
         ImpDepsGraph, IndirectOptDepsGraph, TransOptDepsGraph,
-        TransOptDepsOrdering, !Specs, !IO) :-
+        TransOptDepsOrdering, ErrSpecs, WarnSpecs, !IO) :-
     globals.lookup_bool_option(Globals, also_output_module_order, OutputOrder),
     (
         OutputOrder = yes,
@@ -138,18 +138,22 @@ compute_opt_trans_opt_deps_graph(ProgressStream, Globals, ModuleName,
             MaybeEdgesToRemove = ok1(EdgesToRemove),
             report_unknown_module_names_in_deps_spec(ImpDepsGraph,
                 EdgesToRemove, UnknownModuleSpecs),
-            !:Specs = UnknownModuleSpecs ++ !.Specs,
+            ErrSpecs = [],
+            WarnSpecs = UnknownModuleSpecs,
             apply_trans_opt_deps_spec(EdgesToRemove,
                 ImpDepsGraph, TrimmedImpDepsGraph),
             TransOptDepsGraph = digraph.transitive_closure(TrimmedImpDepsGraph)
         ;
             MaybeEdgesToRemove = error1(EdgeSpecs),
-            !:Specs = one_or_more_to_list(EdgeSpecs) ++ !.Specs,
-            TransOptDepsGraph = IndirectOptDepsGraph
+            TransOptDepsGraph = IndirectOptDepsGraph,
+            ErrSpecs = one_or_more_to_list(EdgeSpecs),
+            WarnSpecs = []
         )
     ;
         MaybeSpecFileName = no,
-        TransOptDepsGraph = IndirectOptDepsGraph
+        TransOptDepsGraph = IndirectOptDepsGraph,
+        ErrSpecs = [],
+        WarnSpecs = []
     ),
     TransOptDepsOrdering0 =
         digraph.return_sccs_in_from_to_order(TransOptDepsGraph),
@@ -228,7 +232,7 @@ read_trans_opt_deps_spec_file(FileName, Result, !IO) :-
             Result = ok1(EdgesToRemove)
         ;
             FileSpecs0 = [_ | _],
-            list.foldl(accumulate_contexts, FileSpecs0,
+            list.foldl(accumulate_contexts, coerce(FileSpecs0),
                 set.init, FileSpecContextsSet),
             set.to_sorted_list(FileSpecContextsSet, FileSpecContexts),
             list.reverse(FileSpecContexts, RevFileSpecContexts),
@@ -258,7 +262,7 @@ read_trans_opt_deps_spec_file(FileName, Result, !IO) :-
 
 :- pred parse_trans_opt_deps_spec_file(string::in, string::in, int::in,
     posn::in, posn::out, trans_opt_deps_spec::in, trans_opt_deps_spec::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 parse_trans_opt_deps_spec_file(FileName, Contents, ContentsLen,
         !Pos, !EdgesToRemove, !Specs) :-
@@ -280,7 +284,7 @@ parse_trans_opt_deps_spec_file(FileName, Contents, ContentsLen,
 
 :- pred parse_trans_opt_deps_spec_term(varset::in, term::in,
     trans_opt_deps_spec::in, trans_opt_deps_spec::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 parse_trans_opt_deps_spec_term(VarSet, Term, !EdgesToRemove, !Specs) :-
     ( if
@@ -333,7 +337,7 @@ parse_trans_opt_deps_spec_term(VarSet, Term, !EdgesToRemove, !Specs) :-
                 Pieces2 = [words("The original entry is here."), nl],
                 Msg1 = msg(LeftTermContext, Pieces1),
                 Msg2 = msg(OldContext, Pieces2),
-                Spec = diag_spec($pred, severity_error, phase_read_files,
+                Spec = gen_spec($pred, severity_error, phase_read_files,
                     [Msg1, Msg2]),
                 !:Specs = [Spec | !.Specs]
             )
@@ -360,7 +364,7 @@ parse_trans_opt_deps_spec_term(VarSet, Term, !EdgesToRemove, !Specs) :-
 :- pred parse_trans_opt_deps_spec_module_list(varset::in, term::in,
     cord(pair(term_context, module_name))::in,
     cord(pair(term_context, module_name))::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 parse_trans_opt_deps_spec_module_list(VarSet, Term, !ModuleNameCord, !Specs) :-
     ( if list_term_to_term_list(Term, TermList) then
@@ -378,7 +382,7 @@ parse_trans_opt_deps_spec_module_list(VarSet, Term, !ModuleNameCord, !Specs) :-
 :- pred parse_trans_opt_deps_spec_module_names(varset::in, list(term)::in,
     cord(pair(term_context, module_name))::in,
     cord(pair(term_context, module_name))::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 parse_trans_opt_deps_spec_module_names(_VarSet, [], !ModuleNameCord, !Specs).
 parse_trans_opt_deps_spec_module_names(VarSet, [Term | Terms],
@@ -399,7 +403,7 @@ parse_trans_opt_deps_spec_module_names(VarSet, [Term | Terms],
 %---------------------------------------------------------------------------%
 
 :- pred report_unknown_module_names_in_deps_spec(digraph(module_name)::in,
-    trans_opt_deps_spec::in, list(diag_spec)::out) is det.
+    trans_opt_deps_spec::in, list(warn_spec)::out) is det.
 
 report_unknown_module_names_in_deps_spec(Graph, DepsSpec, Specs) :-
     digraph.vertices(Graph, KnownModules),
@@ -408,7 +412,7 @@ report_unknown_module_names_in_deps_spec(Graph, DepsSpec, Specs) :-
 
 :- pred report_unknown_module_names_in_allow_disallow(set(module_name)::in,
     module_name::in, allow_or_disallow_trans_opt_deps::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 report_unknown_module_names_in_allow_disallow(KnownModules,
         Module, AllowOrDisallow, !Specs) :-
@@ -434,7 +438,7 @@ report_unknown_module_names_in_allow_disallow(KnownModules,
 :- pred report_unknown_module_names_in_module_names(set(module_name)::in,
     string::in, int::in, assoc_list(term_context, module_name)::in,
     map(module_name, int)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 report_unknown_module_names_in_module_names(_, _, _, [], _OrdMap, !Specs).
 report_unknown_module_names_in_module_names(KnownModules, AoD, N,
diff --git a/compiler/opt_format_call.m b/compiler/opt_format_call.m
index 57b626986..6cdd49ed2 100644
--- a/compiler/opt_format_call.m
+++ b/compiler/opt_format_call.m
@@ -718,8 +718,8 @@ check_format_call_site(ModuleInfo, PredInfo, ProcInfo, ImplicitStreamWarnings,
             check_fmt_str_val_vars(ModuleInfo, PredInfo, ProcInfo,
                 ConjMaps, PredMap, FormatCallSite),
             TailFmtStrVals, TailCheckResults),
-        HeadCheckSpecs = get_any_errors3el(HeadCheckResult),
-        TailCheckSpecLists = list.map(get_any_errors3el, TailCheckResults),
+        HeadCheckSpecs = get_any_errors3eld(HeadCheckResult),
+        TailCheckSpecLists = list.map(get_any_errors3eld, TailCheckResults),
         CheckSpecs = HeadCheckSpecs ++ list.condense(TailCheckSpecLists),
         !:Specs = CheckSpecs ++ !.Specs
     ).
@@ -727,7 +727,7 @@ check_format_call_site(ModuleInfo, PredInfo, ProcInfo, ImplicitStreamWarnings,
 :- pred check_fmt_str_val_vars(module_info::in, pred_info::in, proc_info::in,
     conj_maps::in, conj_pred_map::in, format_call_site::in,
     fmt_str_val_vars::in,
-    maybe3el(list(compiler_format_spec), list(prog_var), list(goal_id))::out)
+    maybe3eld(list(compiler_format_spec), list(prog_var), list(goal_id))::out)
     is det.
 
 check_fmt_str_val_vars(ModuleInfo, PredInfo, ProcInfo, ConjMaps, PredMap,
@@ -766,8 +766,8 @@ check_fmt_str_val_vars(ModuleInfo, PredInfo, ProcInfo, ConjMaps, PredMap,
             Specs = []
         else
             Specs =
-                get_any_errors3el(FormatStringResult) ++
-                get_any_errors2el(ValuesResult)
+                get_any_errors3eld(FormatStringResult) ++
+                get_any_errors2eld(ValuesResult)
         ),
         Result = error3(Specs)
     ).
@@ -782,7 +782,7 @@ project_all_yes([yes(Value) | TailMaybes], [Value | Tail]) :-
 
 :- pred follow_format_string_handle_unknown(module_info::in,
     conj_maps::in, conj_pred_map::in, format_call_site::in, prog_var::in,
-    maybe3el(string, list(prog_var), list(goal_id))::out) is det.
+    maybe3eld(string, list(prog_var), list(goal_id))::out) is det.
 
 follow_format_string_handle_unknown(ModuleInfo, ConjMaps, PredMap,
         FormatCallSite, StringVar, Result) :-
@@ -899,7 +899,7 @@ project_all_follow_string_results([HeadResult | TailResults],
 
 :- pred follow_values_handle_unknown(module_info::in, conj_maps::in,
     conj_pred_map::in, format_call_site::in, prog_var::in,
-    maybe2el(list(abstract_poly_type), list(prog_var))::out) is det.
+    maybe2eld(list(abstract_poly_type), list(prog_var))::out) is det.
 
 follow_values_handle_unknown(ModuleInfo, ConjMaps, PredMap, FormatCallSite,
         ValuesVar, Result) :-
diff --git a/compiler/options_file.m b/compiler/options_file.m
index 2857f22a6..aa0328034 100644
--- a/compiler/options_file.m
+++ b/compiler/options_file.m
@@ -87,7 +87,7 @@
     %
 :- pred read_options_files_named_in_options_file_option(
     io.text_output_stream::in, option_table::in, env_optfile_variables::out,
-    list(diag_spec)::out, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::out, list(warn_spec)::out, io::di, io::uo) is det.
 
     % read_named_options_file(ProgressStream, OptionsPathName,
     %   !Variables, Specs, UndefSpecs, !IO) :-
@@ -103,7 +103,7 @@
     %
 :- pred read_named_options_file(io.text_output_stream::in,
     file_name::in, env_optfile_variables::in, env_optfile_variables::out,
-    list(diag_spec)::out, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::out, list(warn_spec)::out, io::di, io::uo) is det.
 
     % read_args_file(ProgressStream, OptionsFile, MaybeMCFlags,
     %   Specs, UndefSpecs, !IO):
@@ -126,13 +126,13 @@
     %
 :- pred read_args_file(io.text_output_stream::in, file_name::in,
     maybe(list(string))::out,
-    list(diag_spec)::out, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::out, list(warn_spec)::out, io::di, io::uo) is det.
 
 %---------------------------------------------------------------------------%
 %
 % If any of the following predicates return error1(Specs), Specs will
 % contain only errors, not warnings. (There is only one piece of code
-% in this module that generates an diag_spec with severity_warning,
+% in this module that generates an err_spec with severity_warning,
 % and the only exported operations whose call tree includes that code
 % are ones listed *above*.)
 %
@@ -266,9 +266,9 @@ read_options_files_named_in_options_file_option(ProgressStream, OptionTable,
 :- pred read_options_file_set_params(io.text_output_stream::in,
     option_table::in, string::in,
     env_optfile_variables::in, env_optfile_variables::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out, io::di, io::uo) is det.
 
 read_options_file_set_params(ProgressStream, OptionTable, OptionsFile,
         !Variables, !IOSpecs, !ParseSpecs, !UndefSpecs, !IO) :-
@@ -378,9 +378,9 @@ read_args_file(ProgressStream, OptionsFile, MaybeMCFlags,
 :- pred read_options_file_params(search_info::in,
     pre_incl_stack::in, is_options_file_optional::in, string::in,
     env_optfile_variables::in, env_optfile_variables::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out, io::di, io::uo) is det.
 
 read_options_file_params(SearchInfo, PreStack0, IsOptionsFileOptional,
         OptionsPathName, !Variables,
@@ -522,7 +522,7 @@ read_options_file_params(SearchInfo, PreStack0, IsOptionsFileOptional,
 
 :- type include_check_result
     --->    include_ok(incl_stack)
-    ;       include_error(diag_spec).
+    ;       include_error(err_spec).
 
 :- pred check_include_for_infinite_recursion(pre_incl_stack::in,
     file_name::in, include_check_result::out) is det.
@@ -545,7 +545,7 @@ check_include_for_infinite_recursion(PreStack0, PathName, Result) :-
     ).
 
 :- pred pathname_occurs_in_incl_stack(incl_stack::in, file_name::in,
-    term_context::in, diag_spec::out) is semidet.
+    term_context::in, err_spec::out) is semidet.
 
 pathname_occurs_in_incl_stack(InclStack0, PathName, Context, Spec) :-
     (
@@ -577,7 +577,7 @@ pathname_occurs_in_incl_stack(InclStack0, PathName, Context, Spec) :-
                 MainMsg = msg(TopContext, MainPieces),
                 InclMsgs = list.map(include_context_msg, TopDownIncludes),
                 LastMsg = include_context_msg(PathName - Context),
-                Spec = diag_spec($pred, severity_error, phase_read_files,
+                Spec = gen_spec($pred, severity_error, phase_read_files,
                     [MainMsg | InclMsgs] ++ [LastMsg])
             else
                 fail
@@ -620,7 +620,7 @@ include_context_msg(FileName - Context) = Msg :-
 :- type parse_result(T)
     --->    pr_ok(T)
     ;       pr_eof
-    ;       pr_error(diag_spec).
+    ;       pr_error(err_spec).
 
 %---------------------------------------------------------------------------%
 
@@ -632,9 +632,9 @@ include_context_msg(FileName - Context) = Msg :-
 :- pred read_options_lines(search_info::in, incl_stack::in,
     io.text_input_stream::in, file_name::in, int::in,
     env_optfile_variables::in, env_optfile_variables::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out, io::di, io::uo) is det.
 
 read_options_lines(SearchInfo, InclStack0, InStream, FileName, LineNumber0,
         !Variables, !IOSpecs, !ParseSpecs, !UndefSpecs, !IO) :-
@@ -795,7 +795,7 @@ read_options_line_loop(InStream, FileName, !LineNumber, !.RevChars,
         Result = pr_error(Spec)
     ).
 
-:- func io_error_to_parse_error(file_name, int, io.error) = diag_spec.
+:- func io_error_to_parse_error(file_name, int, io.error) = err_spec.
 
 io_error_to_parse_error(FileName, LineNumber, Error) = Spec :-
     Context = term_context.context(FileName, LineNumber),
@@ -804,7 +804,7 @@ io_error_to_parse_error(FileName, LineNumber, Error) = Spec :-
     Spec = spec($pred, severity_error, phase_read_files,
         Context, Pieces).
 
-:- func report_split_error(file_name, int, string) = diag_spec.
+:- func report_split_error(file_name, int, string) = err_spec.
 
 report_split_error(FileName, LineNumber, Msg) = Spec :-
     Context = term_context.context_init(FileName, LineNumber),
@@ -837,7 +837,7 @@ skip_comment_line(InStream, Result, !IO) :-
 
 :- type maybe_options_file_line
     --->    ofl_ok(options_file_line)
-    ;       ofl_error(diag_spec).
+    ;       ofl_error(err_spec).
 
 :- type options_file_line
     --->    ofl_var_defn(
@@ -910,7 +910,7 @@ parse_options_line(FileName, LineNumber, Line0, MaybeOptionsFileLine) :-
 
 :- type opt_var_or_spec
     --->    ovos_var_name(env_optfile_var)
-    ;       ovos_spec(diag_spec).
+    ;       ovos_spec(err_spec).
 
 :- pred parse_variable_name(file_name::in, int::in,
     list(char)::in, list(char)::out, opt_var_or_spec::out) is det.
@@ -1100,8 +1100,8 @@ get_string_acc([Char | Chars0], Chars, RevString0, RevString, MaybeError) :-
 :- pred update_variable(file_name::in, int::in,
     set_or_add::in, env_optfile_var::in, list(char)::in,
     env_optfile_variables::in, env_optfile_variables::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out, io::di, io::uo) is det.
 
 update_variable(FileName, LineNumber, SetOrAdd, VarName, NewChars0,
         !Variables, !ParseSpecs, !UndefSpecs, !IO) :-
@@ -1144,7 +1144,7 @@ update_variable(FileName, LineNumber, SetOrAdd, VarName, NewChars0,
                 SplitResult = ok(_)
             ;
                 SplitResult = error(Msg),
-                Spec = split_error_msg_to_diag_spec(VarName, Msg),
+                Spec = split_error_msg_to_err_spec(VarName, Msg),
                 !:ParseSpecs = [Spec | !.ParseSpecs]
             )
         else
@@ -1177,8 +1177,8 @@ update_variable(FileName, LineNumber, SetOrAdd, VarName, NewChars0,
 
 :- pred expand_any_var_references(env_optfile_variables::in,
     file_name::in, int::in, list(char)::in, list(char)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out, io::di, io::uo) is det.
 
 expand_any_var_references(Variables, FileName, LineNumber, Chars0, Chars,
         !ParseSpecs, !UndefSpecs, !IO) :-
@@ -1190,7 +1190,7 @@ expand_any_var_references(Variables, FileName, LineNumber, Chars0, Chars,
 
 :- pred expand_any_var_references_loop(env_optfile_variables::in,
     file_name::in, int::in, list(char)::in, list(char)::in, list(char)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
     set(string)::in, set(string)::out, io::di, io::uo) is det.
 
 expand_any_var_references_loop(_, _, _,
@@ -1266,7 +1266,7 @@ expand_any_var_references_loop(Variables, FileName, LineNumber,
     ).
 
 :- func report_unterminated_variable_reference(file_name, int, list(char))
-    = diag_spec.
+    = err_spec.
 
 report_unterminated_variable_reference(FileName, LineNumber, RevChars)
         = Spec :-
@@ -1276,7 +1276,7 @@ report_unterminated_variable_reference(FileName, LineNumber, RevChars)
     Spec = spec($pred, severity_error, phase_read_files, Context, Pieces).
 
 :- pred report_any_undefined_variables(file_name::in, int::in,
-    set(string)::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    set(string)::in, list(warn_spec)::in, list(warn_spec)::out) is det.
 
 report_any_undefined_variables(FileName, LineNumber, UndefVarNamesSet,
         !UndefSpecs) :-
@@ -1352,9 +1352,9 @@ lookup_mmc_maybe_module_options(Variables, EnvOptFileVarClass, Result) :-
         Result = ok1(MmcOptions)
     ;
         Specs = [HeadSpec | TailSpecs],
-        % Returning error1 here is correct because all diag_specs in Specs
+        % Returning error1 here is correct because all err_specs in Specs
         % will have severity_error. There is (as of 2022 jan 23) exactly
-        % one place in this module that generates an diag_spec whose
+        % one place in this module that generates an err_spec whose
         % severity is NOT severity_error, but it is not reachable from
         % lookup_env_optfile_var.
         Result = error1(one_or_more(HeadSpec, TailSpecs))
@@ -1365,12 +1365,12 @@ lookup_mmc_maybe_module_options(Variables, EnvOptFileVarClass, Result) :-
 :- type variable_result(T)
     --->    var_result_set(T)
     ;       var_result_unset
-    ;       var_result_error(one_or_more(diag_spec)).
+    ;       var_result_error(one_or_more(err_spec)).
 
 :- pred lookup_env_optfile_var(env_optfile_variables::in,
     env_optfile_var_class::in, env_optfile_var_id::in,
     list(string)::in, list(string)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 lookup_env_optfile_var(Variables, EnvOptFileVarClass, FlagsVarId,
         !AllMmcOptions, !Specs) :-
@@ -1452,7 +1452,7 @@ lookup_env_optfile_var(Variables, EnvOptFileVarClass, FlagsVarId,
     ).
 
 :- pred check_ml_libs_values(list(string)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_ml_libs_values(VarValues, !Specs) :-
     NotLibLPrefix =
@@ -1690,7 +1690,7 @@ lookup_variable_words(Variables, VarName, Result) :-
             Result = var_result_set(EnvWords)
         ;
             SplitResult = error(Msg),
-            Spec = split_error_msg_to_diag_spec(VarName, Msg),
+            Spec = split_error_msg_to_err_spec(VarName, Msg),
             Result = var_result_error(one_or_more(Spec, []))
         )
     else if map.search(OptsMap, VarName, OptsEntry) then
@@ -1714,9 +1714,9 @@ lookup_variable_value(Variables, VarName, ValueChars, !UndefVarNames) :-
         set.insert(VarName, !UndefVarNames)
     ).
 
-:- func split_error_msg_to_diag_spec(string, string) = diag_spec.
+:- func split_error_msg_to_err_spec(string, string) = err_spec.
 
-split_error_msg_to_diag_spec(VarName, Msg) = Spec :-
+split_error_msg_to_err_spec(VarName, Msg) = Spec :-
     Pieces = [words("Error: in environment variable"),
         quote(VarName), suffix(":"), words(Msg), nl],
     Spec = no_ctxt_spec($pred, severity_error, phase_read_files, Pieces).
diff --git a/compiler/parse_class.m b/compiler/parse_class.m
index dea9490de..65f3a493f 100644
--- a/compiler/parse_class.m
+++ b/compiler/parse_class.m
@@ -33,12 +33,14 @@
     % Parse a typeclass declaration.
     %
 :- pred parse_typeclass_item(module_name::in, varset::in, list(term)::in,
-    prog_context::in, item_seq_num::in, maybe1(item_or_marker)::out) is det.
+    prog_context::in, item_seq_num::in,
+    maybe1(item_or_marker, err_warn_error)::out) is det.
 
     % Parse an instance declaration.
     %
 :- pred parse_instance_item(module_name::in, varset::in, list(term)::in,
-    prog_context::in, item_seq_num::in, maybe1(item_or_marker)::out) is det.
+    prog_context::in, item_seq_num::in,
+    maybe1(item_or_marker, err_warn_error)::out) is det.
 
     % Parse constraints on a pred or func declaration, or on an existentially
     % quantified type definition. Currently all such constraints must be
@@ -94,17 +96,24 @@ parse_typeclass_item(ModuleName, VarSet, ArgTerms, Context, SeqNum,
                 [NameTerm, MethodsTerm], _)
         then
             parse_non_empty_class(ModuleName, VarSet, NameTerm, MethodsTerm,
-                Context, SeqNum, MaybeItemTypeClassInfo)
+                Context, SeqNum, MaybeItemTypeClassInfo),
+            (
+                MaybeItemTypeClassInfo = ok1(ItemTypeClassInfo),
+                MaybeIOM = ok1(iom_item(item_typeclass(ItemTypeClassInfo)))
+            ;
+                MaybeItemTypeClassInfo = error1(ErrWarnError),
+                MaybeIOM = error1(ErrWarnError)
+            )
         else
             parse_class_head(ModuleName, VarSet, ArgTerm, Context, SeqNum,
-                MaybeItemTypeClassInfo)
-        ),
-        (
-            MaybeItemTypeClassInfo = ok1(ItemTypeClassInfo),
-            MaybeIOM = ok1(iom_item(item_typeclass(ItemTypeClassInfo)))
-        ;
-            MaybeItemTypeClassInfo = error1(Specs),
-            MaybeIOM = error1(Specs)
+                MaybeItemTypeClassInfo),
+            (
+                MaybeItemTypeClassInfo = ok1(ItemTypeClassInfo),
+                MaybeIOM = ok1(iom_item(item_typeclass(ItemTypeClassInfo)))
+            ;
+                MaybeItemTypeClassInfo = error1(OoMErrSpecs),
+                MaybeIOM = error1({OoMErrSpecs, []})
+            )
         )
     else
         Pieces =
@@ -119,12 +128,12 @@ parse_typeclass_item(ModuleName, VarSet, ArgTerms, Context, SeqNum,
                 suffix(".")]) ++
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeIOM = error1(one_or_more(Spec, []))
+        MaybeIOM = error1({one_or_more(Spec, []), []})
     ).
 
 :- pred parse_non_empty_class(module_name::in, varset::in, term::in, term::in,
-    prog_context::in, item_seq_num::in, maybe1(item_typeclass_info)::out)
-    is det.
+    prog_context::in, item_seq_num::in,
+    maybe1(item_typeclass_info, err_warn_error)::out) is det.
 
 parse_non_empty_class(ModuleName, VarSet, NameTerm, MethodsTerm,
         Context, SeqNum, MaybeItemTypeClassInfo) :-
@@ -141,10 +150,11 @@ parse_non_empty_class(ModuleName, VarSet, NameTerm, MethodsTerm,
             ^ tc_varset := TVarSet),
         MaybeItemTypeClassInfo = ok1(ItemTypeClassInfo)
     else
-        Specs = get_any_errors1(MaybeItemTypeClassInfo0) ++
-            get_any_errors1(MaybeClassDecls),
-        det_list_to_one_or_more(Specs, OoMSpecs),
-        MaybeItemTypeClassInfo = error1(OoMSpecs)
+        InfoErrSpecs = get_any_errors1(MaybeItemTypeClassInfo0),
+        get_all_errors_warnings1(MaybeClassDecls,
+            DeclErrSpecs, DeclWarnSpecs),
+        det_list_to_one_or_more(InfoErrSpecs ++ DeclErrSpecs, OoMErrSpecs),
+        MaybeItemTypeClassInfo = error1({OoMErrSpecs, DeclWarnSpecs})
     ).
 
 :- pred parse_class_head(module_name::in, varset::in, term::in,
@@ -326,7 +336,7 @@ parse_superclass_constraints(_ModuleName, VarSet, ConstraintsTerm, Result) :-
 :- pred collect_superclass_constraints(varset::in,
     list(arbitrary_constraint)::in,
     list(prog_constraint)::out, list(prog_fundep)::out,
-    list(diag_spec)::out) is det.
+    list(err_spec)::out) is det.
 
 collect_superclass_constraints(_, [], [], [], []).
 collect_superclass_constraints(VarSet, [Constraint | Constraints],
@@ -433,12 +443,12 @@ parse_unconstrained_class(ModuleName, TVarSet, NameTerm, Context, SeqNum,
     ).
 
 :- pred parse_class_decls(module_name::in, varset::in, term::in,
-    maybe1(list(class_decl))::out) is det.
+    maybe1(list(class_decl), err_warn_error)::out) is det.
 
 parse_class_decls(ModuleName, VarSet, DeclsTerm, MaybeClassDecls) :-
     ( if list_term_to_term_list(DeclsTerm, DeclTerms) then
         list.map(parse_class_decl(ModuleName, VarSet), DeclTerms, MaybeDecls),
-        find_errors(MaybeDecls, MaybeClassDecls)
+        find_errors_pr2(MaybeDecls, MaybeClassDecls)
     else
         DeclsTermStr = describe_error_term(VarSet, DeclsTerm),
         Pieces = [words("Error: expected a")] ++
@@ -448,37 +458,7 @@ parse_class_decls(ModuleName, VarSet, DeclsTerm, MaybeClassDecls) :-
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt,
             get_term_context(DeclsTerm), Pieces),
-        MaybeClassDecls = error1(one_or_more(Spec, []))
-    ).
-
-    % From a list of maybe1s, search them for errors.
-    % If some errors are found, return error1(their union).
-    % If no error is found, return ok1(the original elements).
-    %
-:- pred find_errors(list(maybe1(T))::in, maybe1(list(T))::out) is det.
-
-find_errors(Xs, Result) :-
-    find_errors_loop(Xs, [], Results, [], Specs),
-    (
-        Specs = [],
-        Result = ok1(Results)
-    ;
-        Specs = [HeadSpec | TailSpec],
-        Result = error1(one_or_more(HeadSpec, TailSpec))
-    ).
-
-:- pred find_errors_loop(list(maybe1(T))::in, list(T)::in, list(T)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
-
-find_errors_loop([], !Results, !Specs).
-find_errors_loop([X | Xs], !Results, !Specs) :-
-    find_errors_loop(Xs, !Results, !Specs),
-    (
-        X = ok1(CurResult),
-        !:Results = [CurResult | !.Results]
-    ;
-        X = error1(CurSpecs),
-        !:Specs = one_or_more_to_list(CurSpecs) ++ !.Specs
+        MaybeClassDecls = error1({one_or_more(Spec, []), []})
     ).
 
 %---------------------------------------------------------------------------%
@@ -492,17 +472,24 @@ parse_instance_item(ModuleName, VarSet, ArgTerms, Context, SeqNum,
                 [NameTerm, MethodsTerm], _)
         then
             parse_non_empty_instance(ModuleName, VarSet, TVarSet,
-                NameTerm, MethodsTerm, Context, SeqNum, MaybeItemInstanceInfo)
+                NameTerm, MethodsTerm, Context, SeqNum, MaybeItemInstanceInfo),
+            (
+                MaybeItemInstanceInfo = ok1(ItemInstanceInfo),
+                MaybeIOM = ok1(iom_item(item_instance(ItemInstanceInfo)))
+            ;
+                MaybeItemInstanceInfo = error1(ErrWarnError),
+                MaybeIOM = error1(ErrWarnError)
+            )
         else
             parse_instance_name(ModuleName, TVarSet, ArgTerm,
-                Context, SeqNum, MaybeItemInstanceInfo)
-        ),
-        (
-            MaybeItemInstanceInfo = ok1(ItemInstanceInfo),
-            MaybeIOM = ok1(iom_item(item_instance(ItemInstanceInfo)))
-        ;
-            MaybeItemInstanceInfo = error1(Specs),
-            MaybeIOM = error1(Specs)
+                Context, SeqNum, MaybeItemInstanceInfo),
+            (
+                MaybeItemInstanceInfo = ok1(ItemInstanceInfo),
+                MaybeIOM = ok1(iom_item(item_instance(ItemInstanceInfo)))
+            ;
+                MaybeItemInstanceInfo = error1(OoMErrSpecs),
+                MaybeIOM = error1({OoMErrSpecs, []})
+            )
         )
     else
         Pieces =
@@ -519,7 +506,7 @@ parse_instance_item(ModuleName, VarSet, ArgTerms, Context, SeqNum,
                 suffix(".")]) ++
             [nl_indent_delta(-1)],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeIOM = error1(one_or_more(Spec, []))
+        MaybeIOM = error1({one_or_more(Spec, []), []})
     ).
 
 :- pred parse_instance_name(module_name::in, tvarset::in, term::in,
@@ -609,7 +596,7 @@ parse_underived_instance(ModuleName, TVarSet, NameTerm, Context, SeqNum,
 
 :- pred parse_non_empty_instance(module_name::in, varset::in, tvarset::in,
     term::in, term::in, prog_context::in, item_seq_num::in,
-    maybe1(item_instance_info)::out) is det.
+    maybe1(item_instance_info, err_warn_error)::out) is det.
 
 parse_non_empty_instance(ModuleName, VarSet, TVarSet, NameTerm, MethodsTerm,
         Context, SeqNum, MaybeItemInstanceInfo) :-
@@ -628,20 +615,21 @@ parse_non_empty_instance(ModuleName, VarSet, TVarSet, NameTerm, MethodsTerm,
             MaybeCheckSpec),
         (
             MaybeCheckSpec = yes(Spec),
-            MaybeItemInstanceInfo = error1(one_or_more(Spec, []))
+            MaybeItemInstanceInfo = error1({one_or_more(Spec, []), []})
         ;
             MaybeCheckSpec = no,
             MaybeItemInstanceInfo = ok1(ItemInstanceInfo)
         )
     else
-        Specs = get_any_errors1(MaybeItemInstanceInfo0) ++
-            get_any_errors1(MaybeInstanceMethods),
-        det_list_to_one_or_more(Specs, OoMSpecs),
-        MaybeItemInstanceInfo = error1(OoMSpecs)
+        InfoErrSpecs = get_any_errors1(MaybeItemInstanceInfo0),
+        get_all_errors_warnings1(MaybeInstanceMethods,
+            MethodsErrSpecs, MethodsWarnSpecs),
+        det_list_to_one_or_more(InfoErrSpecs ++ MethodsErrSpecs, OoMErrSpecs),
+        MaybeItemInstanceInfo = error1({OoMErrSpecs, MethodsWarnSpecs})
     ).
 
 :- pred check_tvars_in_instance_constraint(item_instance_info::in,
-    term::in, maybe(diag_spec)::out) is det.
+    term::in, maybe(err_spec)::out) is det.
 
 check_tvars_in_instance_constraint(ItemInstanceInfo, NameTerm, MaybeSpec) :-
     ItemInstanceInfo = item_instance_info(_Name, Types, _OriginalTypes,
@@ -676,13 +664,13 @@ check_tvars_in_instance_constraint(ItemInstanceInfo, NameTerm, MaybeSpec) :-
     ).
 
 :- pred parse_instance_methods(module_name::in, varset::in, term::in,
-    maybe1(list(instance_method))::out) is det.
+    maybe1(list(instance_method), err_warn_error)::out) is det.
 
 parse_instance_methods(ModuleName, VarSet, MethodsTerm, Result) :-
     ( if list_term_to_term_list(MethodsTerm, MethodList) then
         list.map(term_to_instance_method(ModuleName, VarSet),
             MethodList, Interface),
-        find_errors(Interface, Result)
+        find_errors_m1(Interface, Result)
     else
         MethodsTermStr = describe_error_term(VarSet, MethodsTerm),
         Pieces = [words("Error: expected a")] ++
@@ -692,13 +680,13 @@ parse_instance_methods(ModuleName, VarSet, MethodsTerm, Result) :-
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt,
             get_term_context(MethodsTerm), Pieces),
-        Result = error1(one_or_more(Spec, []))
+        Result = error1({one_or_more(Spec, []), []})
     ).
 
     % Turn the term into a method instance.
     %
 :- pred term_to_instance_method(module_name::in, varset::in, term::in,
-    maybe1(instance_method)::out) is det.
+    maybe1(instance_method, err_warn_error)::out) is det.
 
 term_to_instance_method(_ModuleName, VarSet, MethodTerm,
         MaybeInstanceMethod) :-
@@ -740,7 +728,7 @@ term_to_instance_method(_ModuleName, VarSet, MethodTerm,
                     [nl_indent_delta(-1)],
                 Spec = spec($pred, severity_error, phase_t2pt,
                     get_term_context(MethodTerm), Pieces),
-                MaybeInstanceMethod = error1(one_or_more(Spec, []))
+                MaybeInstanceMethod = error1({one_or_more(Spec, []), []})
             )
         else if
             ClassMethodTerm = term.functor(term.atom("func"), [SlashTerm], _),
@@ -773,7 +761,7 @@ term_to_instance_method(_ModuleName, VarSet, MethodTerm,
                     [nl_indent_delta(-1)],
                 Spec = spec($pred, severity_error, phase_t2pt,
                     get_term_context(MethodTerm), Pieces),
-                MaybeInstanceMethod = error1(one_or_more(Spec, []))
+                MaybeInstanceMethod = error1({one_or_more(Spec, []), []})
             )
         else
             MethodTermStr = describe_error_term(VarSet, MethodTerm),
@@ -794,12 +782,12 @@ term_to_instance_method(_ModuleName, VarSet, MethodTerm,
                 [nl_indent_delta(-1)],
             Spec = spec($pred, severity_error, phase_t2pt,
                 get_term_context(MethodTerm), Pieces),
-            MaybeInstanceMethod = error1(one_or_more(Spec, []))
+            MaybeInstanceMethod = error1({one_or_more(Spec, []), []})
         )
     else
         ( if MethodTerm = term.functor(term.atom(":-"), [_], _) then
             Spec = report_unexpected_method_term(VarSet, MethodTerm),
-            MaybeInstanceMethod = error1(one_or_more(Spec, []))
+            MaybeInstanceMethod = error1({one_or_more(Spec, []), []})
         else
             % For the clauses in an instance declaration, the default
             % module name for the clause heads is the module name of the class
@@ -827,13 +815,13 @@ term_to_instance_method(_ModuleName, VarSet, MethodTerm,
                 InstanceMethod = instance_method(MethodName, ProcDef, Context),
                 MaybeInstanceMethod = ok1(InstanceMethod)
             ;
-                MaybeClause = error1(Specs),
-                MaybeInstanceMethod = error1(Specs)
+                MaybeClause = error1(ErrWarnError),
+                MaybeInstanceMethod = error1(ErrWarnError)
             )
         )
     ).
 
-:- func report_unexpected_method_term(varset, term) = diag_spec.
+:- func report_unexpected_method_term(varset, term) = err_spec.
 
 report_unexpected_method_term(VarSet, MethodTerm) = Spec :-
     MethodTermStr = describe_error_term(VarSet, MethodTerm),
@@ -1160,6 +1148,84 @@ classify_types_as_var_ground_or_neither(TVarSet, [Type0 | Types0],
         !:NonVarNonGroundTypes = [Type | !.NonVarNonGroundTypes]
     ).
 
+%---------------------------------------------------------------------------%
+
+    % From a list of parse_result2s, search them for errors.
+    % If some errors are found, return error1 wrapped around
+    % all the errors and warnings.
+    % If no error is found, return ok1 wrapped around the original elements.
+    %
+:- pred find_errors_pr2(list(parse_result2(T))::in,
+    maybe1(list(T), err_warn_error)::out) is det.
+
+find_errors_pr2(Xs, Result) :-
+    find_errors_pr2_loop(Xs, [], Results, [], ErrSpecs, [], WarnSpecs),
+    (
+        ErrSpecs = [],
+        % We add to WarnSpecs *only* when we add at least one ErrSpec.
+        expect(unify(WarnSpecs, []), $pred, "WarnSpecs != []"),
+        Result = ok1(Results)
+    ;
+        ErrSpecs = [HeadErrSpec | TailErrSpec],
+        Result = error1({one_or_more(HeadErrSpec, TailErrSpec), WarnSpecs})
+    ).
+
+:- pred find_errors_pr2_loop(list(parse_result2(T))::in,
+    list(T)::in, list(T)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
+
+find_errors_pr2_loop([], !Results, !ErrSpecs, !WarnSpecs).
+find_errors_pr2_loop([X | Xs], !Results, !ErrSpecs, !WarnSpecs) :-
+    find_errors_pr2_loop(Xs, !Results, !ErrSpecs, !WarnSpecs),
+    (
+        X = ok2(CurResult, CurWarnSpecs),
+        !:Results = [CurResult | !.Results]
+    ;
+        X = error2({CurErrSpecs, CurWarnSpecs}),
+        !:ErrSpecs = one_or_more_to_list(CurErrSpecs) ++ !.ErrSpecs
+    ),
+    !:WarnSpecs = CurWarnSpecs ++ !.WarnSpecs.
+
+%---------------------------------------------------------------------------%
+
+    % From a list of maybe1s, search them for errors.
+    % If some errors are found, return error1 wrapped around
+    % all the errors and warnings.
+    % If no error is found, return ok1 wrapped around the original elements.
+    %
+:- pred find_errors_m1(list(maybe1(T, err_warn_error))::in,
+    maybe1(list(T), err_warn_error)::out) is det.
+
+find_errors_m1(Xs, Result) :-
+    find_errors_m1_loop(Xs, [], Results, [], ErrSpecs, [], WarnSpecs),
+    (
+        ErrSpecs = [],
+        % We add to WarnSpecs *only* when we add at least one ErrSpec.
+        expect(unify(WarnSpecs, []), $pred, "WarnSpecs != []"),
+        Result = ok1(Results)
+    ;
+        ErrSpecs = [HeadErrSpec | TailErrSpec],
+        Result = error1({one_or_more(HeadErrSpec, TailErrSpec), WarnSpecs})
+    ).
+
+:- pred find_errors_m1_loop(list(maybe1(T, err_warn_error))::in,
+    list(T)::in, list(T)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
+
+find_errors_m1_loop([], !Results, !ErrSpecs, !WarnSpecs).
+find_errors_m1_loop([X | Xs], !Results, !ErrSpecs, !WarnSpecs) :-
+    find_errors_m1_loop(Xs, !Results, !ErrSpecs, !WarnSpecs),
+    (
+        X = ok1(CurResult),
+        !:Results = [CurResult | !.Results]
+    ;
+        X = error1({CurErrSpecs, CurWarnSpecs}),
+        !:ErrSpecs = one_or_more_to_list(CurErrSpecs) ++ !.ErrSpecs,
+        !:WarnSpecs = CurWarnSpecs ++ !.WarnSpecs
+    ).
+
 %---------------------------------------------------------------------------%
 :- end_module parse_tree.parse_class.
 %---------------------------------------------------------------------------%
diff --git a/compiler/parse_dcg_goal.m b/compiler/parse_dcg_goal.m
index 70e3d7ed4..87e769306 100644
--- a/compiler/parse_dcg_goal.m
+++ b/compiler/parse_dcg_goal.m
@@ -32,7 +32,6 @@
 :- import_module parse_tree.prog_item.
 
 :- import_module cord.
-:- import_module list.
 :- import_module maybe.
 :- import_module term.
 :- import_module varset.
@@ -41,7 +40,7 @@
 
 :- pred parse_dcg_clause(maybe(module_name)::in, varset::in,
     term::in, term::in, prog_context::in, item_seq_num::in,
-    maybe1(item_clause_info)::out) is det.
+    maybe1(item_clause_info, err_warn_error)::out) is det.
 
     % parse_dcg_pred_goal(GoalTerm, MaybeGoal, DCGVar0, DCGVar, !VarSet):
     %
@@ -49,7 +48,7 @@
     % `DCGVar0' is the initial DCG variable, and `DCGVar' is the final one.
     %
 :- pred parse_dcg_pred_goal(term::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out, prog_var::out, prog_var::out,
+    parse_result2(goal)::out, prog_var::out, prog_var::out,
     prog_varset::in, prog_varset::out) is det.
 
 :- implementation.
@@ -65,6 +64,7 @@
 
 :- import_module assoc_list.
 :- import_module counter.
+:- import_module list.
 :- import_module one_or_more.
 :- import_module pair.
 :- import_module require.
@@ -102,10 +102,12 @@ parse_dcg_clause(MaybeModuleName, VarSet0, DCG_HeadTerm, DCG_BodyTerm,
             ProgVarSet, MaybeBodyGoal, Context, SeqNum),
         MaybeClause = ok1(ItemClause)
     ;
-        MaybeFunctor = error2(OoMFunctorSpecs),
-        append_one_or_more_list(OoMFunctorSpecs,
-            get_any_errors_warnings2(MaybeBodyGoal), OoMSpecs),
-        MaybeClause = error1(OoMSpecs)
+        MaybeFunctor = error2(OoMFunctorErrSpecs),
+        get_all_errors_warnings2(MaybeBodyGoal,
+            BodyGoalErrSpecs, BodyGoalWarnSpecs),
+        append_one_or_more_list(OoMFunctorErrSpecs, BodyGoalErrSpecs,
+            OoMErrSpecs),
+        MaybeClause = error1({OoMErrSpecs, BodyGoalWarnSpecs})
     ).
 
 %---------------------------------------------------------------------------%
@@ -121,7 +123,7 @@ parse_dcg_pred_goal(GoalTerm, ContextPieces, MaybeGoal,
     % Expand a DCG goal.
     %
 :- pred parse_dcg_goal(term::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 
@@ -251,7 +253,7 @@ string_dcg_goal_kind(Functor, GoalKind) :-
     %
 :- pred parse_non_call_dcg_goal(dcg_goal_kind::in, list(term)::in,
     prog_context::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 
@@ -345,7 +347,7 @@ parse_non_call_dcg_goal(GoalKind, Args, Context, ContextPieces, MaybeGoal,
 
 :- pred parse_dcg_goal_impure_semipure(dcg_goal_kind::in(dcg_goal_kind_purity),
     list(term)::in, prog_context::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 :- pragma inline(pred(parse_dcg_goal_impure_semipure/11)).
@@ -363,7 +365,7 @@ parse_dcg_goal_impure_semipure(GoalKind, ArgTerms, Context, ContextPieces,
     else
         string_dcg_goal_kind(Functor, GoalKind),
         Spec = should_have_one_goal_prefix(ContextPieces, Context, Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -371,7 +373,7 @@ parse_dcg_goal_impure_semipure(GoalKind, ArgTerms, Context, ContextPieces,
 :- pred parse_dcg_goal_promise_purity(
     dcg_goal_kind::in(dcg_goal_kind_promise_purity),
     list(term)::in, prog_context::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 :- pragma inline(pred(parse_dcg_goal_promise_purity/11)).
@@ -386,9 +388,9 @@ parse_dcg_goal_promise_purity(GoalKind, ArgTerms, Context, ContextPieces,
         parse_dcg_goal(SubGoalTerm, ContextPieces, MaybeGoal0,
             !VarSet, !Counter, !DCGVar),
         (
-            MaybeGoal0 = ok2(Goal0, GoalWarningSpecs),
+            MaybeGoal0 = ok2(Goal0, GoalWarnSpecs),
             Goal = promise_purity_expr(Context, PromisedPurity, Goal0),
-            MaybeGoal = ok2(Goal, GoalWarningSpecs)
+            MaybeGoal = ok2(Goal, GoalWarnSpecs)
         ;
             MaybeGoal0 = error2(Specs),
             MaybeGoal = error2(Specs)
@@ -396,14 +398,14 @@ parse_dcg_goal_promise_purity(GoalKind, ArgTerms, Context, ContextPieces,
     else
         string_dcg_goal_kind(Functor, GoalKind),
         Spec = should_have_one_goal_prefix(ContextPieces, Context, Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
 
 :- pred parse_dcg_goal_not(dcg_goal_kind::in(dcg_goal_kind_not),
     list(term)::in, prog_context::in, cord(format_piece)::in, prog_var::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out) is det.
 :- pragma inline(pred(parse_dcg_goal_not/10)).
 
@@ -413,9 +415,9 @@ parse_dcg_goal_not(GoalKind, ArgTerms, Context, ContextPieces, DCGVar,
         parse_dcg_goal(SubGoalTerm, ContextPieces, MaybeSubGoal,
             !VarSet, !Counter, DCGVar, _),
         (
-            MaybeSubGoal = ok2(SubGoal, GoalWarningSpecs),
+            MaybeSubGoal = ok2(SubGoal, GoalWarnSpecs),
             Goal = not_expr(Context, SubGoal),
-            MaybeGoal = ok2(Goal, GoalWarningSpecs)
+            MaybeGoal = ok2(Goal, GoalWarnSpecs)
         ;
             MaybeSubGoal = error2(_),
             MaybeGoal = MaybeSubGoal
@@ -423,7 +425,7 @@ parse_dcg_goal_not(GoalKind, ArgTerms, Context, ContextPieces, DCGVar,
     else
         string_dcg_goal_kind(Functor, GoalKind),
         Spec = should_have_one_goal_prefix(ContextPieces, Context, Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -435,7 +437,7 @@ parse_dcg_goal_not(GoalKind, ArgTerms, Context, ContextPieces, DCGVar,
 :- pred parse_dcg_goal_some_all(dcg_goal_kind::in(dcg_goal_kind_some_all),
     list(term)::in,
     prog_context::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 :- pragma inline(pred(parse_dcg_goal_some_all/11)).
@@ -463,7 +465,7 @@ parse_dcg_goal_some_all(GoalKind, ArgTerms, Context, ContextPieces,
             !VarSet, !Counter, !DCGVar),
         ( if
             MaybeVars = ok1(plain_state_vars(Vars0, StateVars0)),
-            MaybeSubGoal = ok2(SubGoal, SubGoalWarningSpecs)
+            MaybeSubGoal = ok2(SubGoal, SubGoalWarnSpecs)
         then
             list.map(term.coerce_var, StateVars0, StateVars),
             list.map(term.coerce_var, Vars0, Vars),
@@ -483,18 +485,20 @@ parse_dcg_goal_some_all(GoalKind, ArgTerms, Context, ContextPieces,
                 Goal = quant_expr(QuantType, quant_ordinary_vars, Context,
                     Vars, Goal1)
             ),
-            MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+            MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
         else
-            Specs = get_any_errors1(MaybeVars) ++
-                get_any_errors_warnings2(MaybeSubGoal),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoal = error2(OoMSpecs)
+            VarErrSpecs = get_any_errors1(MaybeVars),
+            get_all_errors_warnings2(MaybeSubGoal,
+                SubGoalErrSpecs, SubGoalWarnSpecs),
+            ErrSpecs = VarErrSpecs ++ SubGoalErrSpecs,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            MaybeGoal = error2({OoMErrSpecs, SubGoalWarnSpecs})
         )
     else
         string_dcg_goal_kind(Functor, GoalKind),
         Spec = should_have_one_x_one_goal_prefix(ContextPieces, Context,
             "a list of variables", Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -505,7 +509,7 @@ parse_dcg_goal_some_all(GoalKind, ArgTerms, Context, ContextPieces,
     % to warrant a small amount of code target language code duplication.
     %
 :- pred parse_dcg_goal_conj(dcg_goal_kind, list(term),
-    prog_context, cord(format_piece), maybe2(goal, list(warning_spec)),
+    prog_context, cord(format_piece), parse_result2(goal),
     prog_varset, prog_varset, counter, counter, prog_var, prog_var).
 :- mode parse_dcg_goal_conj(in(dcg_goal_kind_conj), in, in, in, out,
     in, out, in, out, in, out) is det.
@@ -518,10 +522,13 @@ parse_dcg_goal_conj(GoalKind, ArgTerms, Context, ContextPieces,
     string_dcg_goal_kind(Functor, GoalKind),
     ( if ArgTerms = [TermA, TermB] then
         parse_dcg_goal_conjunction(Functor, TermA, TermB, Context,
-            ContextPieces, cord.init, ConjunctsCord, [], Warnings, [], Errors,
-            !VarSet, !Counter, !DCGVar),
+            ContextPieces, cord.init, ConjunctsCord,
+            [], ErrSpecs, [], WarnSpecs, !VarSet, !Counter, !DCGVar),
         (
-            Errors = [],
+            ErrSpecs = [],
+            % XXX DIAG_SPEC In the past, we used to get here only if
+            % parse_dcg_goal_conjunction returned no diag_specs of
+            % *any* severity.
             Conjuncts = cord.list(ConjunctsCord),
             (
                 Conjuncts = [],
@@ -536,62 +543,62 @@ parse_dcg_goal_conj(GoalKind, ArgTerms, Context, ContextPieces,
                 GoalKind = dgk_par_conj,
                 Goal = par_conj_expr(Context, ConjunctA, ConjunctsB)
             ),
-            MaybeGoal = ok2(Goal, Warnings)
+            MaybeGoal = ok2(Goal, WarnSpecs)
         ;
-            Errors = [HeadSpec | TailSpecs],
-            MaybeGoal = error2(one_or_more(HeadSpec, TailSpecs))
+            ErrSpecs = [HeadSpec | TailSpecs],
+            MaybeGoal = error2({one_or_more(HeadSpec, TailSpecs), WarnSpecs})
         )
     else
         Spec = should_have_two_goals_infix(ContextPieces, Context, Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 :- pred parse_dcg_goal_conjunction(string::in, term::in, term::in,
     prog_context::in, cord(format_piece)::in,
     cord(goal)::in, cord(goal)::out,
-    list(warning_spec)::in, list(warning_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 
 parse_dcg_goal_conjunction(Functor, TermA, TermB, Context,
-        ContextPieces, !ConjunctsCord, !Warnings, !Errors,
+        ContextPieces, !ConjunctsCord, !ErrSpecs, !WarnSpecs,
         !VarSet, !Counter, !DCGVar) :-
     parse_dcg_goal(TermA, ContextPieces, MaybeGoalA,
         !VarSet, !Counter, !DCGVar),
     (
-        MaybeGoalA = ok2(GoalA, WarningsA),
-        cord.snoc(GoalA, !ConjunctsCord),
-        !:Warnings = WarningsA ++ !.Warnings
+        MaybeGoalA = ok2(GoalA, WarnSpecsA),
+        cord.snoc(GoalA, !ConjunctsCord)
     ;
-        MaybeGoalA = error2(SpecsA),
-        !:Errors = one_or_more_to_list(SpecsA) ++ !.Errors
+        MaybeGoalA = error2({OoMErrSpecsA, WarnSpecsA}),
+        !:ErrSpecs = one_or_more_to_list(OoMErrSpecsA) ++ !.ErrSpecs
     ),
+    !:WarnSpecs = WarnSpecsA ++ !.WarnSpecs,
     ( if
         TermB = term.functor(term.atom(Functor), ArgTermsB, Context),
         ArgTermsB = [TermBA, TermBB]
     then
         parse_dcg_goal_conjunction(Functor, TermBA, TermBB, Context,
-            ContextPieces, !ConjunctsCord, !Warnings, !Errors,
+            ContextPieces, !ConjunctsCord, !ErrSpecs, !WarnSpecs,
             !VarSet, !Counter, !DCGVar)
     else
         parse_dcg_goal(TermB, ContextPieces, MaybeGoalB,
             !VarSet, !Counter, !DCGVar),
         (
-            MaybeGoalB = ok2(GoalB, WarningsB),
-            cord.snoc(GoalB, !ConjunctsCord),
-            !:Warnings = WarningsB ++ !.Warnings
+            MaybeGoalB = ok2(GoalB, WarnSpecsB),
+            cord.snoc(GoalB, !ConjunctsCord)
         ;
-            MaybeGoalB = error2(SpecsB),
-            !:Errors = one_or_more_to_list(SpecsB) ++ !.Errors
-        )
+            MaybeGoalB = error2({OoMErrSpecsB, WarnSpecsB}),
+            !:ErrSpecs = one_or_more_to_list(OoMErrSpecsB) ++ !.ErrSpecs
+        ),
+        !:WarnSpecs = WarnSpecsB ++ !.WarnSpecs
     ).
 
 %---------------------%
 
 :- pred parse_dcg_goal_semicolon(list(term)::in,
     prog_context::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 :- pragma inline(pred(parse_dcg_goal_semicolon/10)).
@@ -611,10 +618,13 @@ parse_dcg_goal_semicolon(ArgTerms, Context, ContextPieces,
             InitDCGVar = !.DCGVar,
             parse_dcg_goal_disjunction(InitDCGVar, ContextPieces,
                 SubGoalTermA, SubGoalTermB, no, MaybeFirstDiffDCGVar,
-                cord.init, DisjunctsDCGVarsCord, [], Warnings, [], ErrorSpecs,
-                !VarSet, !Counter),
+                cord.init, DisjunctsDCGVarsCord,
+                [], ErrSpecs, [], WarnSpecs, !VarSet, !Counter),
             (
-                ErrorSpecs = [],
+                ErrSpecs = [],
+                % XXX DIAG_SPEC In the past, we used to get here only if
+                % parse_dcg_goal_disjunction returned no diag_specs of
+                % *any* severity.
                 DisjunctsDCGVars = cord.list(DisjunctsDCGVarsCord),
                 (
                     MaybeFirstDiffDCGVar = no,
@@ -638,11 +648,12 @@ parse_dcg_goal_semicolon(ArgTerms, Context, ContextPieces,
                 ),
                 Goal = disj_expr(Context, Disjunct1, Disjunct2,
                     Disjuncts3plus),
-                MaybeGoal = ok2(Goal, Warnings)
+                MaybeGoal = ok2(Goal, WarnSpecs)
             ;
-                ErrorSpecs = [HeadSpec | TailSpecs],
+                ErrSpecs = [HeadSpec | TailSpecs],
                 % The final value of !DCGVar shouldn't matter.
-                MaybeGoal = error2(one_or_more(HeadSpec, TailSpecs))
+                MaybeGoal =
+                    error2({one_or_more(HeadSpec, TailSpecs), WarnSpecs})
             )
         )
     else
@@ -653,33 +664,32 @@ parse_dcg_goal_semicolon(ArgTerms, Context, ContextPieces,
         % potentially more confusing than helpful.
         % We do the same for ";" in parse_non_call_goal.
         Spec = should_have_two_goals_infix(ContextPieces, Context, ";"),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 :- pred parse_dcg_goal_disjunction(prog_var::in, cord(format_piece)::in,
     term::in, term::in, maybe(prog_var)::in, maybe(prog_var)::out,
     cord(pair(goal, prog_var))::in, cord(pair(goal, prog_var))::out,
-    list(warning_spec)::in, list(warning_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out) is det.
 
 parse_dcg_goal_disjunction(DCGVar0, ContextPieces, TermA, TermB,
-        !MaybeFirstDiffDCGVar, !DisjunctsDCGVarsCord, !Warnings, !Specs,
+        !MaybeFirstDiffDCGVar, !DisjunctsDCGVarsCord, !ErrSpecs, !WarnSpecs,
         !VarSet, !Counter) :-
     parse_dcg_goal(TermA, ContextPieces, MaybeGoalA,
         !VarSet, !Counter, DCGVar0, DCGVarA),
     (
-        MaybeGoalA = ok2(DisjunctA, WarningsA),
+        MaybeGoalA = ok2(DisjunctA, WarnSpecsA),
         maybe_record_non_initial_dcg_var(DCGVar0, DCGVarA,
             !MaybeFirstDiffDCGVar),
         append_disjunct_dcg_var_to_cord(DCGVarA, DisjunctA,
-            !DisjunctsDCGVarsCord),
-        % The order of the warnings does not matter.
-        !:Warnings = WarningsA ++ !.Warnings
+            !DisjunctsDCGVarsCord)
     ;
-        MaybeGoalA = error2(SpecsA),
-        !:Specs = !.Specs ++ one_or_more_to_list(SpecsA)
+        MaybeGoalA = error2({OoMErrSpecsA, WarnSpecsA}),
+        !:ErrSpecs = one_or_more_to_list(OoMErrSpecsA) ++ !.ErrSpecs
     ),
+    !:WarnSpecs = WarnSpecsA ++ !.WarnSpecs,
     ( if
         TermB = term.functor(term.atom(";"), ArgTermsB, _Context),
         ArgTermsB = [TermBA, TermBB],
@@ -688,22 +698,22 @@ parse_dcg_goal_disjunction(DCGVar0, ContextPieces, TermA, TermB,
         )
     then
         parse_dcg_goal_disjunction(DCGVar0, ContextPieces, TermBA, TermBB,
-            !MaybeFirstDiffDCGVar, !DisjunctsDCGVarsCord, !Warnings, !Specs,
-            !VarSet, !Counter)
+            !MaybeFirstDiffDCGVar, !DisjunctsDCGVarsCord,
+            !ErrSpecs, !WarnSpecs, !VarSet, !Counter)
     else
         parse_dcg_goal(TermB, ContextPieces, MaybeGoalB,
             !VarSet, !Counter, DCGVar0, DCGVarB),
         (
-            MaybeGoalB = ok2(DisjunctB, WarningsB),
+            MaybeGoalB = ok2(DisjunctB, WarnSpecsB),
             maybe_record_non_initial_dcg_var(DCGVar0, DCGVarB,
                 !MaybeFirstDiffDCGVar),
             append_disjunct_dcg_var_to_cord(DCGVarB, DisjunctB,
-                !DisjunctsDCGVarsCord),
-            !:Warnings = !.Warnings ++ WarningsB
+                !DisjunctsDCGVarsCord)
         ;
-            MaybeGoalB = error2(SpecsB),
-            !:Specs = !.Specs ++ one_or_more_to_list(SpecsB)
-        )
+            MaybeGoalB = error2({OoMErrSpecsB, WarnSpecsB}),
+            !:ErrSpecs = one_or_more_to_list(OoMErrSpecsB) ++ !.ErrSpecs
+        ),
+        !:WarnSpecs = WarnSpecsB ++ !.WarnSpecs
     ).
 
     % maybe_record_non_initial_dcg_var(DCGVar0, DCGVarEndBranch,
@@ -786,7 +796,7 @@ bring_disjunct_up_to(InitDCGVar, FinalDCGVar, Context,
 
 :- pred parse_dcg_goal_else(list(term)::in,
     prog_context::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 :- pragma inline(pred(parse_dcg_goal_else/10)).
@@ -816,14 +826,14 @@ parse_dcg_goal_else(ArgTerms, Context, ContextPieces,
             color_as_incorrect([quote(ErrorTermStr), suffix(",")]) ++
             [words("does not match that pattern."), nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
 
 :- pred parse_dcg_goal_if(list(term)::in,
     prog_context::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 :- pragma inline(pred(parse_dcg_goal_if/10)).
@@ -840,10 +850,10 @@ parse_dcg_goal_if(ArgTerms, Context, ContextPieces,
         OutVar = !.DCGVar,
         ( if
             MaybeVarsCondGoal =
-                ok4(Vars, StateVars, CondGoal, CondWarningSpecs),
-            MaybeThenGoal = ok2(ThenGoal, ThenWarningSpecs)
+                ok4(Vars, StateVars, CondGoal, CondWarnSpecs),
+            MaybeThenGoal = ok2(ThenGoal, ThenWarnSpecs)
         then
-            WarningSpecs = CondWarningSpecs ++ ThenWarningSpecs,
+            WarnSpecs = CondWarnSpecs ++ ThenWarnSpecs,
             % There is no else part in the source code, so any context
             % we use for it will be misleading. Using Context here is
             % also misleading, but any other context from the source code
@@ -880,12 +890,15 @@ parse_dcg_goal_if(ArgTerms, Context, ContextPieces,
             ),
             Goal = if_then_else_expr(Context, Vars, StateVars,
                 CondGoal, ThenGoal, ElseGoal),
-            MaybeGoal = ok2(Goal, WarningSpecs)
+            MaybeGoal = ok2(Goal, WarnSpecs)
         else
-            Specs = get_any_errors_warnings4(MaybeVarsCondGoal) ++
-                get_any_errors_warnings2(MaybeThenGoal),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoal = error2(OoMSpecs)
+            get_all_errors_warnings4(MaybeVarsCondGoal,
+                CondErrSpecs, CondWarnSpecs),
+            get_all_errors_warnings2(MaybeThenGoal,
+                ThenErrSpecs, ThenWarnSpecs),
+            det_list_to_one_or_more(CondErrSpecs ++ ThenErrSpecs, OoMErrSpecs),
+            WarnSpecs = CondWarnSpecs ++ ThenWarnSpecs,
+            MaybeGoal = error2({OoMErrSpecs, WarnSpecs})
         )
     else
         varset.coerce(!.VarSet, ErrorVarSet),
@@ -906,14 +919,14 @@ parse_dcg_goal_if(ArgTerms, Context, ContextPieces,
             color_as_incorrect([quote(ErrorTermStr), suffix(",")]) ++
             [words("does not match either pattern."), nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
 
 :- pred parse_dcg_goal_braces(list(term)::in,
     prog_context::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out) is det.
 :- pragma inline(pred(parse_dcg_goal_braces/6)).
 
@@ -926,7 +939,7 @@ parse_dcg_goal_braces(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
             color_as_incorrect([words("none"), suffix(".")]) ++
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ;
         ArgTerms = [HeadTerm | TailTerm],
         % Ordinary goal inside { curly braces }.
@@ -941,7 +954,7 @@ parse_dcg_goal_braces(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
 
 :- pred parse_dcg_goal_nil(list(term)::in,
     prog_context::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 :- pragma inline(pred(parse_dcg_goal_nil/10)).
@@ -968,14 +981,14 @@ parse_dcg_goal_nil(ArgTerms, Context, _ContextPieces,
                 words("with arity 0.")]) ++
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
 
 :- pred parse_dcg_goal_cons(list(term)::in,
     prog_context::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 :- pragma inline(pred(parse_dcg_goal_cons/10)).
@@ -1001,7 +1014,7 @@ parse_dcg_goal_cons(ArgTerms, Context, _ContextPieces,
             Pieces = [words("Error: there is no"),
                 quote("[]"), words("at the end of the list."), nl],
             Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-            MaybeGoal = error2(one_or_more(Spec, []))
+            MaybeGoal = error2({one_or_more(Spec, []), []})
         )
     else
         Pieces = [words("Error: in DCG clauses, the")] ++
@@ -1012,14 +1025,14 @@ parse_dcg_goal_cons(ArgTerms, Context, _ContextPieces,
                 words("with arity 2.")]) ++
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
 
 :- pred parse_dcg_goal_equal(list(term)::in,
     prog_context::in, cord(format_piece)::in, prog_var::in,
-    maybe2(goal, list(warning_spec))::out) is det.
+    parse_result2(goal)::out) is det.
 :- pragma inline(pred(parse_dcg_goal_equal/5)).
 
 parse_dcg_goal_equal(ArgTerms, Context, ContextPieces, DCGVar, MaybeGoal) :-
@@ -1031,14 +1044,14 @@ parse_dcg_goal_equal(ArgTerms, Context, ContextPieces, DCGVar, MaybeGoal) :-
         MaybeGoal = ok2(Goal, [])
     else
         Spec = should_have_two_terms_infix(ContextPieces, Context, "="),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
 
 :- pred parse_dcg_goal_colon_equal(list(term)::in,
     prog_context::in, cord(format_piece)::in,
-    maybe2(goal, list(warning_spec))::out,
+    parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 :- pragma inline(pred(parse_dcg_goal_colon_equal/10)).
@@ -1073,7 +1086,7 @@ parse_dcg_goal_colon_equal(ArgTerms, Context, _ContextPieces,
 %---------------------------------------------------------------------------%
 
 :- pred parse_some_vars_dcg_goal(term::in, cord(format_piece)::in,
-    maybe4(list(prog_var), list(prog_var), goal, list(warning_spec))::out,
+    parse_result4(list(prog_var), list(prog_var), goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 
@@ -1101,16 +1114,16 @@ parse_some_vars_dcg_goal(Term, ContextPieces, MaybeVarsGoal,
         !DCGVar),
     ( if
         MaybeVars = ok1(plain_state_vars(Vars0, StateVars0)),
-        MaybeGoal = ok2(Goal, GoalWarningSpecs)
+        MaybeGoal = ok2(Goal, GoalWarnSpecs)
     then
         list.map(term.coerce_var, Vars0, Vars),
         list.map(term.coerce_var, StateVars0, StateVars),
-        MaybeVarsGoal = ok4(Vars, StateVars, Goal, GoalWarningSpecs)
+        MaybeVarsGoal = ok4(Vars, StateVars, Goal, GoalWarnSpecs)
     else
-        Specs = get_any_errors1(MaybeVars) ++
-            get_any_errors_warnings2(MaybeGoal),
-        det_list_to_one_or_more(Specs, OoMSpecs),
-        MaybeVarsGoal = error4(OoMSpecs)
+        VarErrSpecs = get_any_errors1(MaybeVars),
+        get_all_errors_warnings2(MaybeGoal, GoalErrSpecs, GoalWarnSpecs),
+        det_list_to_one_or_more(VarErrSpecs ++ GoalErrSpecs, OoMErrSpecs),
+        MaybeVarsGoal = error4({OoMErrSpecs, GoalWarnSpecs})
     ).
 
     % Parse the "if" and the "then" part of an if-then or an if-then-else.
@@ -1137,8 +1150,8 @@ parse_some_vars_dcg_goal(Term, ContextPieces, MaybeVarsGoal,
     % so that the implicit quantification of DCG_2 is correct.
     %
 :- pred parse_dcg_if_then(term::in, term::in, cord(format_piece)::in,
-    maybe4(list(prog_var), list(prog_var), goal, list(warning_spec))::out,
-    maybe2(goal, list(warning_spec))::out, prog_varset::in, prog_varset::out,
+    parse_result4(list(prog_var), list(prog_var), goal)::out,
+    parse_result2(goal)::out, prog_varset::in, prog_varset::out,
     counter::in, counter::out, prog_var::in, prog_var::out) is det.
 
 parse_dcg_if_then(CondGoalTerm, ThenGoalTerm, ContextPieces,
@@ -1152,7 +1165,7 @@ parse_dcg_if_then(CondGoalTerm, ThenGoalTerm, ContextPieces,
         Var1 = Var2
     then
         (
-            MaybeThen1 = ok2(ThenGoal1, ThenWarningSpecs),
+            MaybeThen1 = ok2(ThenGoal1, ThenWarnSpecs),
             ThenContext = get_goal_context(ThenGoal1),
             new_dcg_var(!VarSet, !Counter, Var),
             UnifyGoal = unify_expr(ThenContext,
@@ -1160,7 +1173,7 @@ parse_dcg_if_then(CondGoalTerm, ThenGoalTerm, ContextPieces,
                 term.variable(Var2, ThenContext),
                 purity_pure),
             ThenGoal = conj_expr(ThenContext, ThenGoal1, [UnifyGoal]),
-            MaybeThen = ok2(ThenGoal, ThenWarningSpecs)
+            MaybeThen = ok2(ThenGoal, ThenWarnSpecs)
         ;
             MaybeThen1 = error2(_),
             MaybeThen = MaybeThen1,
@@ -1172,7 +1185,7 @@ parse_dcg_if_then(CondGoalTerm, ThenGoalTerm, ContextPieces,
     ).
 
 :- pred parse_dcg_if_then_else(term::in, term::in, term::in, prog_context::in,
-    cord(format_piece)::in, maybe2(goal, list(warning_spec))::out,
+    cord(format_piece)::in, parse_result2(goal)::out,
     prog_varset::in, prog_varset::out, counter::in, counter::out,
     prog_var::in, prog_var::out) is det.
 
@@ -1183,12 +1196,11 @@ parse_dcg_if_then_else(CondGoalTerm, ThenGoalTerm, ElseGoalTerm,
     parse_dcg_goal(ElseGoalTerm, ContextPieces, MaybeElse1,
         !VarSet, !Counter, Var0, VarElse),
     ( if
-        MaybeVarsCond = ok4(Vars, StateVars, CondGoal, CondWarningSpecs),
-        MaybeThen1 = ok2(ThenGoal1, ThenWarningSpecs),
-        MaybeElse1 = ok2(ElseGoal1, ElseWarningSpecs)
+        MaybeVarsCond = ok4(Vars, StateVars, CondGoal, CondWarnSpecs),
+        MaybeThen1 = ok2(ThenGoal1, ThenWarnSpecs),
+        MaybeElse1 = ok2(ElseGoal1, ElseWarnSpecs)
     then
-        WarningSpecs = CondWarningSpecs ++
-            ThenWarningSpecs ++ ElseWarningSpecs,
+        WarnSpecs = CondWarnSpecs ++ ThenWarnSpecs ++ ElseWarnSpecs,
         ( if VarThen = Var0, VarElse = Var0 then
             Var = Var0,
             ThenGoal = ThenGoal1,
@@ -1227,13 +1239,15 @@ parse_dcg_if_then_else(CondGoalTerm, ThenGoalTerm, ElseGoalTerm,
         ),
         Goal = if_then_else_expr(CondContext, Vars, StateVars,
             CondGoal, ThenGoal, ElseGoal),
-        MaybeGoal = ok2(Goal, WarningSpecs)
+        MaybeGoal = ok2(Goal, WarnSpecs)
     else
-        Specs = get_any_errors_warnings4(MaybeVarsCond) ++
-            get_any_errors_warnings2(MaybeThen1) ++
-            get_any_errors_warnings2(MaybeElse1),
-        det_list_to_one_or_more(Specs, OoMSpecs),
-        MaybeGoal = error2(OoMSpecs),
+        get_all_errors_warnings4(MaybeVarsCond, CondErrSpecs, CondWarnSpecs),
+        get_all_errors_warnings2(MaybeThen1, ThenErrSpecs, ThenWarnSpecs),
+        get_all_errors_warnings2(MaybeElse1, ElseErrSpecs, ElseWarnSpecs),
+        ErrSpecs = CondErrSpecs ++ ThenErrSpecs ++ ElseErrSpecs,
+        WarnSpecs = CondWarnSpecs ++ ThenWarnSpecs ++ ElseWarnSpecs,
+        det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+        MaybeGoal = error2({OoMErrSpecs, WarnSpecs}),
         Var = Var0              % Dummy; the value shouldn't matter.
     ).
 
diff --git a/compiler/parse_error.m b/compiler/parse_error.m
index 613f126f8..3b08e09e0 100644
--- a/compiler/parse_error.m
+++ b/compiler/parse_error.m
@@ -129,18 +129,15 @@
 :- type read_module_errors
     --->    read_module_errors(
                 % The fatal errors we have encountered, and their messages.
-                % All these diag_specs should have severity_error.
                 rm_fatal_errors         :: set(fatal_read_module_error),
-                rm_fatal_diag_specs    :: list(diag_spec),
+                rm_fatal_err_specs      :: list(err_spec),
 
                 % The nonfatal errors we have encountered, and their messages.
-                % All these diag_specs should have severity_error.
                 rm_nonfatal_errors      :: set(nonfatal_read_module_error),
-                rm_nonfatal_diag_specs :: list(diag_spec),
+                rm_nonfatal_err_specs   :: list(err_spec),
 
-                % The warnings we have encountered. All these should have
-                % severity levels *below* severity_error.
-                rm_warning_specs        :: list(diag_spec)
+                % The warnings we have encountered.
+                rm_warn_specs           :: list(warn_spec)
             ).
 
 %---------------------%
@@ -153,27 +150,29 @@
 
     % Add a fatal error, and its message.
     %
-:- pred add_fatal_error(fatal_read_module_error::in, list(diag_spec)::in,
+:- pred add_fatal_error(fatal_read_module_error::in, list(err_spec)::in,
     read_module_errors::in, read_module_errors::out) is det.
 
     % Add nonfatal errors, and their messages.
     %
 :- pred add_nonfatal_error(nonfatal_read_module_error::in,
-    diag_spec::in,
+    err_spec::in,
     read_module_errors::in, read_module_errors::out) is det.
 :- pred add_nonfatal_errors(nonfatal_read_module_error::in,
-    one_or_more(diag_spec)::in,
+    one_or_more(err_spec)::in,
     read_module_errors::in, read_module_errors::out) is det.
 
     % If there are any diag_specs in the input list,
     % record them as representing a not-elsewhere-classified nonfatal error.
     %
-:- pred add_any_nec_errors(list(diag_spec)::in,
+:- pred add_any_nec_errors(list(err_spec)::in,
     read_module_errors::in, read_module_errors::out) is det.
 
     % Add some warning messages.
     %
-:- pred add_warning(list(diag_spec)::in,
+:- pred add_warning(warn_spec::in,
+    read_module_errors::in, read_module_errors::out) is det.
+:- pred add_warnings(list(warn_spec)::in,
     read_module_errors::in, read_module_errors::out) is det.
 
 %---------------------%
@@ -189,13 +188,14 @@
 
 %---------------------%
 
-    % Return all the diag_specs in the argument, regardless of severity.
+    % Return all the err_specs and warn_specs in the input argument.
     %
-:- func get_read_module_specs(read_module_errors) = list(diag_spec).
+:- pred get_read_module_specs(read_module_errors::in,
+    list(err_spec)::out, list(warn_spec)::out) is det.
 
 %---------------------%
 
-:- pred io_error_to_diag_spec(spec_phase::in, string::in, diag_spec::out,
+:- pred io_error_to_err_spec(spec_phase::in, string::in, err_spec::out,
     io::di, io::uo) is det.
 
 :- pred io_error_to_read_module_errors(fatal_read_module_error::in,
@@ -237,7 +237,14 @@ add_any_nec_errors(Specs, !Errors) :-
         add_nonfatal_errors(rme_nec, one_or_more(HeadSpec, TailSpecs), !Errors)
     ).
 
-add_warning(Specs, Errors0, Errors) :-
+add_warning(Spec, Errors0, Errors) :-
+    Errors0 = read_module_errors(FatalErrors, FatalSpecs,
+        NonFatalErrors, NonFatalSpecs, WarningSpecs0),
+    WarningSpecs = [Spec | WarningSpecs0],
+    Errors = read_module_errors(FatalErrors, FatalSpecs,
+        NonFatalErrors, NonFatalSpecs, WarningSpecs).
+
+add_warnings(Specs, Errors0, Errors) :-
     Errors0 = read_module_errors(FatalErrors, FatalSpecs,
         NonFatalErrors, NonFatalSpecs, WarningSpecs0),
     WarningSpecs = Specs ++ WarningSpecs0,
@@ -259,20 +266,20 @@ there_are_some_errors(Errors) :-
 
 %---------------------%
 
-get_read_module_specs(Errors) = Specs :-
+get_read_module_specs(Errors, ErrSpecs, WarnSpecs) :-
     Errors = read_module_errors(_FatalErrors, FatalSpecs,
-        _NonFatalErrors, NonFatalSpecs, WarningSpecs),
-    Specs = FatalSpecs ++ NonFatalSpecs ++ WarningSpecs.
+        _NonFatalErrors, NonFatalSpecs, WarnSpecs),
+    ErrSpecs = FatalSpecs ++ NonFatalSpecs.
 
 %---------------------%
 
-io_error_to_diag_spec(Phase, ErrorMsg, Spec, !IO) :-
+io_error_to_err_spec(Phase, ErrorMsg, Spec, !IO) :-
     io.progname_base("mercury_compile", ProgName, !IO),
     Pieces = [fixed(ProgName), suffix(":"), words(ErrorMsg), nl],
     Spec = no_ctxt_spec($pred, severity_error, Phase, Pieces).
 
 io_error_to_read_module_errors(FatalError, Phase, ErrorMsg, Errors, !IO) :-
-    io_error_to_diag_spec(Phase, ErrorMsg, Spec, !IO),
+    io_error_to_err_spec(Phase, ErrorMsg, Spec, !IO),
     Errors0 = init_read_module_errors,
     add_fatal_error(FatalError, [Spec], Errors0, Errors).
 
diff --git a/compiler/parse_goal.m b/compiler/parse_goal.m
index c40c607a7..5f84f9ddf 100644
--- a/compiler/parse_goal.m
+++ b/compiler/parse_goal.m
@@ -19,6 +19,7 @@
 
 :- import_module parse_tree.error_spec.
 :- import_module parse_tree.maybe_error.
+:- import_module parse_tree.parse_goal_util.
 :- import_module parse_tree.prog_data.
 :- import_module parse_tree.prog_item.
 
@@ -28,8 +29,6 @@
 
 %---------------------------------------------------------------------------%
 
-:- type goal_result == maybe2(goal, list(warning_spec)).
-
     % Convert a single term into a goal.
     %
 :- pred parse_goal(term::in, cord(format_piece)::in, goal_result::out,
@@ -43,7 +42,7 @@
     % Exported to superhomogeneous.m for parsing if-then-else expressions.
     %
 :- pred parse_some_vars_goal(term::in, cord(format_piece)::in,
-    maybe4(list(prog_var), list(prog_var), goal, list(warning_spec))::out,
+    parse_result4(list(prog_var), list(prog_var), goal)::out,
     prog_varset::in, prog_varset::out) is det.
 
 %---------------------------------------------------------------------------%
@@ -55,7 +54,6 @@
 :- import_module libs.options.
 :- import_module mdbcomp.
 :- import_module mdbcomp.sym_name.
-:- import_module parse_tree.parse_goal_util.
 :- import_module parse_tree.parse_sym_name.
 :- import_module parse_tree.parse_tree_out_misc.
 :- import_module parse_tree.parse_tree_out_term.
@@ -132,16 +130,17 @@ parse_some_vars_goal(Term, ContextPieces, MaybeVarsAndGoal, !VarSet) :-
     parse_goal(GoalTerm, ContextPieces, MaybeGoal, !VarSet),
     ( if
         MaybeVars = ok1(plain_state_vars(Vars0, StateVars0)),
-        MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+        MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
     then
         list.map(term.coerce_var, Vars0, Vars),
         list.map(term.coerce_var, StateVars0, StateVars),
-        MaybeVarsAndGoal = ok4(Vars, StateVars, Goal, SubGoalWarningSpecs)
+        MaybeVarsAndGoal = ok4(Vars, StateVars, Goal, SubGoalWarnSpecs)
     else
-        Specs = get_any_errors1(MaybeVars) ++
-            get_any_errors_warnings2(MaybeGoal),
-        det_list_to_one_or_more(Specs, OoMSpecs),
-        MaybeVarsAndGoal = error4(OoMSpecs)
+        VarErrSpecs = get_any_errors1(MaybeVars),
+        get_all_errors_warnings2(MaybeGoal, GoalErrSpecs, GoalWarnSpecs),
+        ErrSpecs = VarErrSpecs ++ GoalErrSpecs,
+        det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+        MaybeVarsAndGoal = error4({OoMErrSpecs, GoalWarnSpecs})
     ).
 
 %---------------------------------------------------------------------------%
@@ -548,7 +547,7 @@ parse_goal_impure_semipure(GoalKind, ArgTerms, Context, ContextPieces,
     else
         string_goal_kind(Functor, GoalKind),
         Spec = should_have_one_goal_prefix(ContextPieces, Context, Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -567,9 +566,9 @@ parse_goal_promise_purity(GoalKind, ArgTerms, Context, ContextPieces,
     ( if ArgTerms = [SubGoalTerm] then
         parse_goal(SubGoalTerm, ContextPieces, MaybeSubGoal, !VarSet),
         (
-            MaybeSubGoal = ok2(SubGoal, SubGoalWarningSpecs),
+            MaybeSubGoal = ok2(SubGoal, SubGoalWarnSpecs),
             Goal = promise_purity_expr(Context, Purity, SubGoal),
-            MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+            MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
         ;
             MaybeSubGoal = error2(Specs),
             MaybeGoal = error2(Specs)
@@ -577,7 +576,7 @@ parse_goal_promise_purity(GoalKind, ArgTerms, Context, ContextPieces,
     else
         string_goal_kind(Functor, GoalKind),
         Spec = should_have_one_goal_prefix(ContextPieces, Context, Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -596,27 +595,27 @@ parse_goal_disable_warnings(GoalKind, ArgTerms, Context, ContextPieces,
             ContextPieces, 1, MaybeWarnings),
         parse_goal(SubGoalTerm, ContextPieces, MaybeSubGoal, !VarSet),
         ( if
-            MaybeWarnings = ok2(Warnings, WarningsWarningSpecs),
-            MaybeSubGoal = ok2(SubGoal, SubGoalWarningSpecs)
+            MaybeWarnings = ok2(Warnings, WarningsWarnSpecs),
+            MaybeSubGoal = ok2(SubGoal, SubGoalWarnSpecs)
         then
-            WarningSpecs = WarningsWarningSpecs ++ SubGoalWarningSpecs,
+            WarnSpecs = WarningsWarnSpecs ++ SubGoalWarnSpecs,
             WarningsContext = get_term_context(WarningsTerm),
             bag.insert_list(Warnings, bag.init, WarningsBag),
             bag.to_assoc_list(WarningsBag, WarningsCounts),
             generate_warnings_for_duplicate_warnings(WarningsContext,
                 ContextPieces, WarningsCounts,
-                NonDuplicateWarnings, DuplicateSpecs),
+                NonDuplicateWarnings, DuplicateErrSpecs),
             (
-                DuplicateSpecs = [],
+                DuplicateErrSpecs = [],
                 (
                     NonDuplicateWarnings = [HeadWarning | TailWarnings],
                     Goal = disable_warnings_expr(Context,
                         HeadWarning, TailWarnings, SubGoal),
-                    MaybeGoal = ok2(Goal, WarningSpecs)
+                    MaybeGoal = ok2(Goal, WarnSpecs)
                 ;
                     NonDuplicateWarnings = [],
                     (
-                        WarningsWarningSpecs = [],
+                        WarningsWarnSpecs = [],
                         Pieces = cord.list(ContextPieces) ++
                             [lower_case_next_if_not_first,
                             words("Error:"), words("a")] ++
@@ -627,9 +626,9 @@ parse_goal_disable_warnings(GoalKind, ArgTerms, Context, ContextPieces,
                             [nl],
                         Spec = spec($pred, severity_error, phase_t2pt,
                             WarningsContext, Pieces),
-                        MaybeGoal = error2(one_or_more(Spec, WarningSpecs))
+                        MaybeGoal = error2({one_or_more(Spec, []), WarnSpecs})
                     ;
-                        WarningsWarningSpecs = [_ | _],
+                        WarningsWarnSpecs = [_ | _],
                         % We get here if WarningsTerm is a well formed list
                         % but contains only elements that are *not*
                         % warning names. Generating the error message
@@ -639,25 +638,28 @@ parse_goal_disable_warnings(GoalKind, ArgTerms, Context, ContextPieces,
                         % But we don't have any valid warnings for a
                         % disable_warnings scope either. In this case, we just
                         % forgo constructing a scope that would have no effect.
-                        MaybeGoal = ok2(SubGoal, WarningSpecs)
+                        MaybeGoal = ok2(SubGoal, WarnSpecs)
                     )
                 )
             ;
-                DuplicateSpecs = [_ | _],
-                Specs = DuplicateSpecs ++ WarningSpecs,
-                det_list_to_one_or_more(Specs, OoMSpecs),
-                MaybeGoal = error2(OoMSpecs)
+                DuplicateErrSpecs = [DupHeadSpec | DupTailSpecs],
+                OoMErrSpecs = one_or_more(DupHeadSpec, DupTailSpecs),
+                MaybeGoal = error2({OoMErrSpecs, WarnSpecs})
             )
         else
-            Specs = get_any_errors_warnings2(MaybeWarnings) ++
-                get_any_errors_warnings2(MaybeSubGoal),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoal = error2(OoMSpecs)
+            get_all_errors_warnings2(MaybeWarnings,
+                WarningErrSpecs, WarningWarnSpecs),
+            get_all_errors_warnings2(MaybeSubGoal,
+                SubGoalErrSpecs, SubGoalWarnSpecs),
+            ErrSpecs = WarningErrSpecs ++ SubGoalErrSpecs,
+            WarnSpecs = WarningWarnSpecs ++ SubGoalWarnSpecs,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            MaybeGoal = error2({OoMErrSpecs, WarnSpecs})
         )
     else
         Spec = should_have_one_x_one_goal_prefix(ContextPieces, Context,
             "a list of warnings to disable", Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -672,17 +674,17 @@ parse_goal_not(GoalKind, ArgTerms, Context, ContextPieces, MaybeGoal,
     ( if ArgTerms = [SubGoalTerm] then
         parse_goal(SubGoalTerm, ContextPieces, MaybeSubGoal, !VarSet),
         (
-            MaybeSubGoal = ok2(SubGoal, SubGoalWarningSpecs),
+            MaybeSubGoal = ok2(SubGoal, SubGoalWarnSpecs),
             Goal = not_expr(Context, SubGoal),
-            MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+            MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
         ;
-            MaybeSubGoal = error2(Specs),
-            MaybeGoal = error2(Specs)
+            MaybeSubGoal = error2(ErrWarnError),
+            MaybeGoal = error2(ErrWarnError)
         )
     else
         string_goal_kind(Functor, GoalKind),
         Spec = should_have_one_goal_prefix(ContextPieces, Context, Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -715,7 +717,7 @@ parse_goal_some_all(GoalKind, ArgTerms, Context, ContextPieces,
         parse_goal(SubGoalTerm, ContextPieces, MaybeSubGoal, !VarSet),
         ( if
             MaybeVars = ok1(plain_state_vars(Vars0, StateVars0)),
-            MaybeSubGoal = ok2(SubGoal, SubGoalWarningSpecs)
+            MaybeSubGoal = ok2(SubGoal, SubGoalWarnSpecs)
         then
             list.map(term.coerce_var, Vars0, Vars),
             list.map(term.coerce_var, StateVars0, StateVars),
@@ -735,17 +737,19 @@ parse_goal_some_all(GoalKind, ArgTerms, Context, ContextPieces,
                 Goal = quant_expr(QuantType, quant_ordinary_vars, Context,
                     Vars, Goal1)
             ),
-            MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+            MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
         else
-            Specs = get_any_errors1(MaybeVars) ++
-                get_any_errors_warnings2(MaybeSubGoal),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoal = error2(OoMSpecs)
+            VarErrSpecs = get_any_errors1(MaybeVars),
+            get_all_errors_warnings2(MaybeSubGoal,
+                SubGoalErrSpecs, SubGoalWarnSpecs),
+            ErrSpecs = VarErrSpecs ++ SubGoalErrSpecs,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            MaybeGoal = error2({OoMErrSpecs, SubGoalWarnSpecs})
         )
     else
         Spec = should_have_one_x_one_goal_prefix(ContextPieces, Context,
             "a list of variables", Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -768,10 +772,13 @@ parse_goal_conj(GoalKind, ArgTerms, Context, ContextPieces,
     string_goal_kind(Functor, GoalKind),
     ( if ArgTerms = [SubGoalTermA, SubGoalTermB] then
         parse_goal_conjunction(Functor, SubGoalTermA, SubGoalTermB,
-            ContextPieces, cord.init, ConjunctsCord, [], WarningSpecs,
-            [], ErrorSpecs, !VarSet),
+            ContextPieces, cord.init, ConjunctsCord,
+            [], ErrSpecs, [], WarnSpecs, !VarSet),
         (
-            ErrorSpecs = [],
+            ErrSpecs = [],
+            % XXX DIAG_SPEC In the past, we used to get here only if
+            % parse_goal_conjunction returned no diag_specs of
+            % *any* severity.
             Conjuncts = cord.list(ConjunctsCord),
             (
                 Conjuncts = [],
@@ -786,50 +793,50 @@ parse_goal_conj(GoalKind, ArgTerms, Context, ContextPieces,
                 GoalKind = gk_par_conj,
                 Goal = par_conj_expr(Context, Conjunct1, Conjuncts2plus)
             ),
-            MaybeGoal = ok2(Goal, WarningSpecs)
+            MaybeGoal = ok2(Goal, WarnSpecs)
         ;
-            ErrorSpecs = [HeadSpec | TailSpecs],
-            MaybeGoal = error2(one_or_more(HeadSpec, TailSpecs))
+            ErrSpecs = [HeadSpec | TailSpecs],
+            MaybeGoal = error2({one_or_more(HeadSpec, TailSpecs), WarnSpecs})
         )
     else
         Spec = should_have_two_goals_infix(ContextPieces, Context, Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 :- pred parse_goal_conjunction(string::in, term::in, term::in,
     cord(format_piece)::in, cord(goal)::in, cord(goal)::out,
-    list(warning_spec)::in, list(warning_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out,
     prog_varset::in, prog_varset::out) is det.
 % Don't inline this predicate, since it is recursive.
 
 parse_goal_conjunction(Functor, TermA, TermB, ContextPieces, !ConjunctsCord,
-        !Warnings, !Specs, !VarSet) :-
+        !ErrSpecs, !WarnSpecs, !VarSet) :-
     parse_goal(TermA, ContextPieces, MaybeGoalA, !VarSet),
     (
-        MaybeGoalA = ok2(ConjunctA, WarningsA),
-        cord.snoc(ConjunctA, !ConjunctsCord),
-        !:Warnings = WarningsA ++ !.Warnings
+        MaybeGoalA = ok2(ConjunctA, WarnSpecsA),
+        cord.snoc(ConjunctA, !ConjunctsCord)
     ;
-        MaybeGoalA = error2(SpecsA),
-        !:Specs = !.Specs ++ one_or_more_to_list(SpecsA)
+        MaybeGoalA = error2({OoMErrSpecsA, WarnSpecsA}),
+        !:ErrSpecs = one_or_more_to_list(OoMErrSpecsA) ++ !.ErrSpecs
     ),
+    !:WarnSpecs = WarnSpecsA ++ !.WarnSpecs,
     ( if
         TermB = term.functor(term.atom(Functor), ArgTermsB, _Context),
         ArgTermsB = [TermBA, TermBB]
     then
         parse_goal_conjunction(Functor, TermBA, TermBB, ContextPieces,
-            !ConjunctsCord, !Warnings, !Specs, !VarSet)
+            !ConjunctsCord, !ErrSpecs, !WarnSpecs, !VarSet)
     else
         parse_goal(TermB, ContextPieces, MaybeGoalB, !VarSet),
         (
-            MaybeGoalB = ok2(ConjunctB, WarningsB),
-            cord.snoc(ConjunctB, !ConjunctsCord),
-            !:Warnings = !.Warnings ++ WarningsB
+            MaybeGoalB = ok2(ConjunctB, WarnSpecsB),
+            cord.snoc(ConjunctB, !ConjunctsCord)
         ;
-            MaybeGoalB = error2(SpecsB),
-            !:Specs = !.Specs ++ one_or_more_to_list(SpecsB)
-        )
+            MaybeGoalB = error2({OoMErrSpecsB, WarnSpecsB}),
+            !:ErrSpecs = one_or_more_to_list(OoMErrSpecsB) ++ !.ErrSpecs
+        ),
+        !:WarnSpecs = WarnSpecsB ++ !.WarnSpecs
     ).
 
 %---------------------%
@@ -852,28 +859,36 @@ parse_goal_semicolon(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
             parse_goal(ElseGoalTerm, ContextPieces, MaybeElseGoal, !VarSet),
             ( if
                 MaybeCondGoal =
-                    ok4(Vars, StateVars, CondGoal, CondWarningSpecs),
-                MaybeThenGoal = ok2(ThenGoal, ThenWarningSpecs),
-                MaybeElseGoal = ok2(ElseGoal, ElseWarningSpecs)
+                    ok4(Vars, StateVars, CondGoal, CondWarnSpecs),
+                MaybeThenGoal = ok2(ThenGoal, ThenWarnSpecs),
+                MaybeElseGoal = ok2(ElseGoal, ElseWarnSpecs)
             then
                 Goal = if_then_else_expr(Context, Vars, StateVars,
                     CondGoal, ThenGoal, ElseGoal),
-                WarningSpecs = CondWarningSpecs ++
-                    ThenWarningSpecs ++ ElseWarningSpecs,
-                MaybeGoal = ok2(Goal, WarningSpecs)
+                WarnSpecs = CondWarnSpecs ++
+                    ThenWarnSpecs ++ ElseWarnSpecs,
+                MaybeGoal = ok2(Goal, WarnSpecs)
             else
-                Specs = get_any_errors_warnings4(MaybeCondGoal) ++
-                    get_any_errors_warnings2(MaybeThenGoal) ++
-                    get_any_errors_warnings2(MaybeElseGoal),
-                det_list_to_one_or_more(Specs, OoMSpecs),
-                MaybeGoal = error2(OoMSpecs)
+                get_all_errors_warnings4(MaybeCondGoal,
+                    CondErrSpecs, CondWarnSpecs),
+                get_all_errors_warnings2(MaybeThenGoal,
+                    ThenErrSpecs, ThenWarnSpecs),
+                get_all_errors_warnings2(MaybeElseGoal,
+                    ElseErrSpecs, ElseWarnSpecs),
+                ErrSpecs = CondErrSpecs ++ ThenErrSpecs ++ ElseErrSpecs,
+                WarnSpecs = CondWarnSpecs ++ ThenWarnSpecs ++ ElseWarnSpecs,
+                det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+                MaybeGoal = error2({OoMErrSpecs, WarnSpecs})
             )
         else
             parse_goal_disjunction(SubGoalTermA, SubGoalTermB, ContextPieces,
-                cord.init, DisjunctsCord, [], WarningSpecs, [], ErrorSpecs,
+                cord.init, DisjunctsCord, [], ErrSpecs, [], WarnSpecs,
                 !VarSet),
             (
-                ErrorSpecs = [],
+                ErrSpecs = [],
+                % XXX DIAG_SPEC In the past, we used to get here only if
+                % parse_goal_disjunction returned no diag_specs of
+                % *any* severity.
                 Disjuncts = cord.list(DisjunctsCord),
                 (
                     ( Disjuncts = []
@@ -885,10 +900,11 @@ parse_goal_semicolon(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
                 ),
                 Goal = disj_expr(Context, Disjunct1, Disjunct2,
                     Disjuncts3plus),
-                MaybeGoal = ok2(Goal, WarningSpecs)
+                MaybeGoal = ok2(Goal, WarnSpecs)
             ;
-                ErrorSpecs = [HeadSpec | TailSpecs],
-                MaybeGoal = error2(one_or_more(HeadSpec, TailSpecs))
+                ErrSpecs = [HeadSpec | TailSpecs],
+                MaybeGoal =
+                    error2({one_or_more(HeadSpec, TailSpecs), WarnSpecs})
             )
         )
     else
@@ -899,28 +915,27 @@ parse_goal_semicolon(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
         % potentially more confusing than helpful.
         % We do the same for ";" in parse_non_call_dcg_goal.
         Spec = should_have_two_goals_infix(ContextPieces, Context, ";"),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 :- pred parse_goal_disjunction(term::in, term::in, cord(format_piece)::in,
     cord(goal)::in, cord(goal)::out,
-    list(warning_spec)::in, list(warning_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out,
     prog_varset::in, prog_varset::out) is det.
 % Don't inline this predicate, since it is recursive.
 
 parse_goal_disjunction(TermA, TermB, ContextPieces, !DisjunctsCord,
-        !Warnings, !Specs, !VarSet) :-
+        !ErrSpecs, !WarnSpecs, !VarSet) :-
     parse_goal(TermA, ContextPieces, MaybeGoalA, !VarSet),
     (
-        MaybeGoalA = ok2(DisjunctA, WarningsA),
-        append_disjunct_to_cord(DisjunctA, !DisjunctsCord),
-        % The order of the warnings does not matter.
-        !:Warnings = WarningsA ++ !.Warnings
+        MaybeGoalA = ok2(DisjunctA, WarnSpecsA),
+        append_disjunct_to_cord(DisjunctA, !DisjunctsCord)
     ;
-        MaybeGoalA = error2(SpecsA),
-        !:Specs = !.Specs ++ one_or_more_to_list(SpecsA)
+        MaybeGoalA = error2({OoMErrSpecsA, WarnSpecsA}),
+        !:ErrSpecs = one_or_more_to_list(OoMErrSpecsA) ++ !.ErrSpecs
     ),
+    !:WarnSpecs = WarnSpecsA ++ !.WarnSpecs,
     ( if
         TermB = term.functor(term.atom(";"), ArgTermsB, _Context),
         ArgTermsB = [TermBA, TermBB],
@@ -929,17 +944,17 @@ parse_goal_disjunction(TermA, TermB, ContextPieces, !DisjunctsCord,
         )
     then
         parse_goal_disjunction(TermBA, TermBB, ContextPieces, !DisjunctsCord,
-            !Warnings, !Specs, !VarSet)
+            !ErrSpecs, !WarnSpecs, !VarSet)
     else
         parse_goal(TermB, ContextPieces, MaybeGoalB, !VarSet),
         (
-            MaybeGoalB = ok2(DisjunctB, WarningsB),
-            cord.snoc(DisjunctB, !DisjunctsCord),
-            !:Warnings = !.Warnings ++ WarningsB
+            MaybeGoalB = ok2(DisjunctB, WarnSpecsB),
+            cord.snoc(DisjunctB, !DisjunctsCord)
         ;
-            MaybeGoalB = error2(SpecsB),
-            !:Specs = !.Specs ++ one_or_more_to_list(SpecsB)
-        )
+            MaybeGoalB = error2({OoMErrSpecsB, WarnSpecsB}),
+            !:ErrSpecs = one_or_more_to_list(OoMErrSpecsB) ++ !.ErrSpecs
+        ),
+        !:WarnSpecs = WarnSpecsB ++ !.WarnSpecs
     ).
 
 :- pred append_disjunct_to_cord(goal::in,
@@ -976,21 +991,25 @@ parse_goal_else(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
             parse_goal(ElseTerm, ContextPieces, MaybeElseGoal, !VarSet),
             ( if
                 MaybeCondGoal =
-                    ok4(Vars, StateVars, CondGoal, CondWarningSpecs),
-                MaybeThenGoal = ok2(ThenGoal, ThenWarningSpecs),
-                MaybeElseGoal = ok2(ElseGoal, ElseWarningSpecs)
+                    ok4(Vars, StateVars, CondGoal, CondWarnSpecs),
+                MaybeThenGoal = ok2(ThenGoal, ThenWarnSpecs),
+                MaybeElseGoal = ok2(ElseGoal, ElseWarnSpecs)
             then
                 Goal = if_then_else_expr(CondContext, Vars, StateVars,
                     CondGoal, ThenGoal, ElseGoal),
-                WarningSpecs = CondWarningSpecs ++
-                    ThenWarningSpecs ++ ElseWarningSpecs,
-                MaybeGoal = ok2(Goal, WarningSpecs)
+                WarnSpecs = CondWarnSpecs ++ ThenWarnSpecs ++ ElseWarnSpecs,
+                MaybeGoal = ok2(Goal, WarnSpecs)
             else
-                Specs = get_any_errors_warnings4(MaybeCondGoal) ++
-                    get_any_errors_warnings2(MaybeThenGoal) ++
-                    get_any_errors_warnings2(MaybeElseGoal),
-                det_list_to_one_or_more(Specs, OoMSpecs),
-                MaybeGoal = error2(OoMSpecs)
+                get_all_errors_warnings4(MaybeCondGoal,
+                    CondErrSpecs, CondWarnSpecs),
+                get_all_errors_warnings2(MaybeThenGoal,
+                    ThenErrSpecs, ThenWarnSpecs),
+                get_all_errors_warnings2(MaybeElseGoal,
+                    ElseErrSpecs, ElseWarnSpecs),
+                ErrSpecs = CondErrSpecs ++ ThenErrSpecs ++ ElseErrSpecs,
+                WarnSpecs = CondWarnSpecs ++ ThenWarnSpecs ++ ElseWarnSpecs,
+                det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+                MaybeGoal = error2({OoMErrSpecs, WarnSpecs})
             )
         else if
             CondThenTerm = term.functor(term.atom("if"),
@@ -1004,7 +1023,7 @@ parse_goal_else(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
                 [nl],
             Spec = spec($pred, severity_error, phase_t2pt,
                 ArrowContext, Pieces),
-            MaybeGoal = error2(one_or_more(Spec, []))
+            MaybeGoal = error2({one_or_more(Spec, []), []})
         else if
             CondThenTerm = term.functor(term.atom("->"),
                 [_CondGoalTerm, _ThenGoalTerm], ArrowContext)
@@ -1017,7 +1036,7 @@ parse_goal_else(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
                 [nl],
             Spec = spec($pred, severity_error, phase_t2pt,
                 ArrowContext, Pieces),
-            MaybeGoal = error2(one_or_more(Spec, []))
+            MaybeGoal = error2({one_or_more(Spec, []), []})
         else
             % `else' can also be part of a `try' goal.
             FullTerm = term.functor(term.atom("else"),
@@ -1039,7 +1058,7 @@ parse_goal_else(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
                 suffix(".")]) ++
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1080,7 +1099,7 @@ parse_goal_if(ArgTerms, Context, _ContextPieces, MaybeGoal) :-
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces)
     ),
-    MaybeGoal = error2(one_or_more(Spec, [])).
+    MaybeGoal = error2({one_or_more(Spec, []), []}).
 
 %---------------------%
 
@@ -1105,7 +1124,7 @@ parse_goal_then(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
                 [nl],
             Spec = spec($pred, severity_error, phase_t2pt,
                 SemiColonContext, Pieces),
-            MaybeGoal = error2(one_or_more(Spec, []))
+            MaybeGoal = error2({one_or_more(Spec, []), []})
         else
             parse_then_try_term(
                 term.functor(atom("then"), [TryTerm, ThenTerm], Context),
@@ -1133,7 +1152,7 @@ parse_goal_then(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
             quote("catch"), words("clauses, and optionally by a single"),
             quote("catch_any"), words("clause."), nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1148,7 +1167,7 @@ parse_goal_catch_any(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
         parse_catch_any_term(ArrowTerm, Context, ContextPieces,
             MaybeCatchAnyExpr, !VarSet),
         (
-            MaybeCatchAnyExpr = ok2(CatchAnyExpr, CatchWarningSpecs),
+            MaybeCatchAnyExpr = ok2(CatchAnyExpr, CatchWarnSpecs),
             ( if TermA = term.functor(atom("catch"), TermAArgs, _) then
                 parse_catch_then_try_term_args(TermAArgs, yes(CatchAnyExpr),
                     Context, ContextPieces, MaybeGoal0, !VarSet)
@@ -1157,17 +1176,17 @@ parse_goal_catch_any(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
                     Context, ContextPieces, MaybeGoal0, !VarSet)
             ),
             (
-                MaybeGoal0 = ok2(Goal, GoalWarningSpecs),
-                MaybeGoal = ok2(Goal, CatchWarningSpecs ++ GoalWarningSpecs)
+                MaybeGoal0 = ok2(Goal, GoalWarnSpecs),
+                MaybeGoal = ok2(Goal, CatchWarnSpecs ++ GoalWarnSpecs)
             ;
-                MaybeGoal0 = error2(OoMGoal0Specs),
-                append_list_one_or_more(CatchWarningSpecs,
-                    OoMGoal0Specs, OoMSpecs),
-                MaybeGoal = error2(OoMSpecs)
+                MaybeGoal0 = error2(ErrWarnError0),
+                add_warns_to_err_warn_error(ErrWarnError0, CatchWarnSpecs,
+                    ErrWarnError),
+                MaybeGoal = error2(ErrWarnError)
             )
         ;
-            MaybeCatchAnyExpr = error2(Specs),
-            MaybeGoal = error2(Specs)
+            MaybeCatchAnyExpr = error2(ErrWarnError),
+            MaybeGoal = error2(ErrWarnError)
         )
     else
         Pieces = [words("Error: the")] ++
@@ -1178,7 +1197,7 @@ parse_goal_catch_any(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
             words("and should be followed by an expression of the form"),
             quote("variable -> goal"), suffix("."), nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1194,8 +1213,8 @@ parse_goal_implication(GoalKind, ArgTerms, Context, ContextPieces,
         parse_goal(TermA, ContextPieces, MaybeGoalA, !VarSet),
         parse_goal(TermB, ContextPieces, MaybeGoalB, !VarSet),
         ( if
-            MaybeGoalA = ok2(GoalA, GoalWarningSpecsA),
-            MaybeGoalB = ok2(GoalB, GoalWarningSpecsB)
+            MaybeGoalA = ok2(GoalA, GoalWarnSpecsA),
+            MaybeGoalB = ok2(GoalB, GoalWarnSpecsB)
         then
             (
                 GoalKind = gk_imply_to_left,
@@ -1207,18 +1226,20 @@ parse_goal_implication(GoalKind, ArgTerms, Context, ContextPieces,
                 GoalKind = gk_imply_to_both,
                 Goal = equivalent_expr(Context, GoalA, GoalB)
             ),
-            WarningSpecs = GoalWarningSpecsA ++ GoalWarningSpecsB,
-            MaybeGoal = ok2(Goal, WarningSpecs)
+            WarnSpecs = GoalWarnSpecsA ++ GoalWarnSpecsB,
+            MaybeGoal = ok2(Goal, WarnSpecs)
         else
-            Specs = get_any_errors_warnings2(MaybeGoalA) ++
-                get_any_errors_warnings2(MaybeGoalB),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoal = error2(OoMSpecs)
+            get_all_errors_warnings2(MaybeGoalA, ErrSpecsA, WarnSpecsA),
+            get_all_errors_warnings2(MaybeGoalB, ErrSpecsB, WarnSpecsB),
+            ErrSpecs = ErrSpecsA ++ ErrSpecsB,
+            WarnSpecs = WarnSpecsA ++ WarnSpecsB,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            MaybeGoal = error2({OoMErrSpecs, WarnSpecs})
         )
     else
         string_goal_kind(Functor, GoalKind),
         Spec = should_have_two_goals_infix(ContextPieces, Context, Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1235,30 +1256,30 @@ parse_goal_trace(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
         parse_goal(SubGoalTerm, ContextPieces, MaybeSubGoal, !VarSet),
         ( if
             MaybeParams = ok1(Params),
-            MaybeSubGoal = ok2(SubGoal, SubGoalWarningSpecs)
+            MaybeSubGoal = ok2(SubGoal, SubGoalWarnSpecs)
         then
             convert_trace_params(Params, MaybeComponents),
             (
                 MaybeComponents = ok4(CompileTime, RunTime, MaybeIO, MutVars),
                 Goal = trace_expr(Context, CompileTime, RunTime,
                     MaybeIO, MutVars, SubGoal),
-                MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+                MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
             ;
-                MaybeComponents = error4(OoMComponentSpecs),
-                append_one_or_more_list(OoMComponentSpecs,
-                    SubGoalWarningSpecs, OoMSpecs),
-                MaybeGoal = error2(OoMSpecs)
+                MaybeComponents = error4(OoMComponentErrSpecs),
+                MaybeGoal = error2({OoMComponentErrSpecs, SubGoalWarnSpecs})
             )
         else
-            Specs = get_any_errors1(MaybeParams) ++
-                get_any_errors_warnings2(MaybeSubGoal),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoal = error2(OoMSpecs)
+            ParamErrSpecs = get_any_errors1(MaybeParams),
+            get_all_errors_warnings2(MaybeSubGoal,
+                SubGoalErrSpecs, SubGoalWarnSpecs),
+            ErrSpecs = ParamErrSpecs ++ SubGoalErrSpecs,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            MaybeGoal = error2({OoMErrSpecs, SubGoalWarnSpecs})
         )
     else
         Spec = should_have_one_x_one_goal_prefix(ContextPieces, Context,
             "a list of trace parameters", "trace"),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1275,30 +1296,30 @@ parse_goal_atomic(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
         parse_atomic_subgoals(SubGoalsTerm, MaybeSubGoals, !VarSet),
         ( if
             MaybeParams = ok1(Params),
-            MaybeSubGoals = ok3(MainGoal, OrElseGoals, SubGoalWarningSpecs)
+            MaybeSubGoals = ok3(MainGoal, OrElseGoals, SubGoalWarnSpecs)
         then
             convert_atomic_params(ParamsTerm, Params, MaybeComponents),
             (
                 MaybeComponents = ok3(Outer, Inner, MaybeOutputVars),
                 Goal = atomic_expr(Context, Outer, Inner, MaybeOutputVars,
                     MainGoal, OrElseGoals),
-                MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+                MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
             ;
-                MaybeComponents = error3(OoMComponentSpecs),
-                append_one_or_more_list(OoMComponentSpecs,
-                    SubGoalWarningSpecs, OoMSpecs),
-                MaybeGoal = error2(OoMSpecs)
+                MaybeComponents = error3(OoMComponentErrSpecs),
+                MaybeGoal = error2({OoMComponentErrSpecs, SubGoalWarnSpecs})
             )
         else
-            Specs = get_any_errors1(MaybeParams) ++
-                get_any_errors_warnings3(MaybeSubGoals),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoal = error2(OoMSpecs)
+            ParamErrSpecs = get_any_errors1(MaybeParams),
+            get_all_errors_warnings3(MaybeSubGoals,
+                SubGoalsErrSpecs, SubGoalsWarnSpecs),
+            ErrSpecs = ParamErrSpecs ++ SubGoalsErrSpecs,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            MaybeGoal = error2({OoMErrSpecs, SubGoalsWarnSpecs})
         )
     else
         Spec = should_have_one_x_one_goal_prefix(ContextPieces, Context,
             "a list of atomic parameters", "atomic"),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1319,7 +1340,7 @@ parse_goal_promise_eqv_solns(GoalKind, ArgTerms, Context, ContextPieces,
         ( if
             MaybeVars = ok1(plain_state_dot_colon_vars(Vars0,
                 StateVars0, DotSVars0, ColonSVars0)),
-            MaybeSubGoal = ok2(SubGoal, SubGoalWarningSpecs)
+            MaybeSubGoal = ok2(SubGoal, SubGoalWarnSpecs)
         then
             list.map(term.coerce_var, Vars0, Vars),
             list.map(term.coerce_var, StateVars0, StateVars),
@@ -1328,25 +1349,26 @@ parse_goal_promise_eqv_solns(GoalKind, ArgTerms, Context, ContextPieces,
             (
                 GoalKind = gk_promise_eqv_solns,
                 Goal = promise_equivalent_solutions_expr(Context, Vars,
-                    StateVars, DotSVars, ColonSVars, SubGoal),
-                MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+                    StateVars, DotSVars, ColonSVars, SubGoal)
             ;
                 GoalKind = gk_promise_eqv_soln_sets,
                 Goal = promise_equivalent_solution_sets_expr(Context, Vars,
-                    StateVars, DotSVars, ColonSVars, SubGoal),
-                MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
-            )
+                    StateVars, DotSVars, ColonSVars, SubGoal)
+            ),
+            MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
         else
-            Specs = get_any_errors1(MaybeVars) ++
-                get_any_errors_warnings2(MaybeSubGoal),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoal = error2(OoMSpecs)
+            VarErrSpecs = get_any_errors1(MaybeVars),
+            get_all_errors_warnings2(MaybeSubGoal,
+                SubGoalErrSpecs, SubGoalWarnSpecs),
+            ErrSpecs = VarErrSpecs ++ SubGoalErrSpecs,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            MaybeGoal = error2({OoMErrSpecs, SubGoalWarnSpecs})
         )
     else
         string_goal_kind(Functor, GoalKind),
         Spec = should_have_one_x_one_goal_prefix(ContextPieces, Context,
             "a list of variables", Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1365,7 +1387,7 @@ parse_goal_arbitrary(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
         ( if
             MaybeVars = ok1(plain_state_dot_colon_vars(Vars0,
                 StateVars0, DotSVars0, ColonSVars0)),
-            MaybeSubGoal = ok2(SubGoal, SubGoalWarningSpecs)
+            MaybeSubGoal = ok2(SubGoal, SubGoalWarnSpecs)
         then
             list.map(term.coerce_var, Vars0, Vars),
             list.map(term.coerce_var, StateVars0, StateVars),
@@ -1373,17 +1395,19 @@ parse_goal_arbitrary(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
             list.map(term.coerce_var, ColonSVars0, ColonSVars),
             Goal = promise_equivalent_solution_arbitrary_expr(Context,
                 Vars, StateVars, DotSVars, ColonSVars, SubGoal),
-            MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+            MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
         else
-            Specs = get_any_errors1(MaybeVars) ++
-                get_any_errors_warnings2(MaybeSubGoal),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoal = error2(OoMSpecs)
+            VarErrSpecs = get_any_errors1(MaybeVars),
+            get_all_errors_warnings2(MaybeSubGoal,
+                SubGoalErrSpecs, SubGoalWarnSpecs),
+            ErrSpecs = VarErrSpecs ++ SubGoalErrSpecs,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            MaybeGoal = error2({OoMErrSpecs, SubGoalWarnSpecs})
         )
     else
         Spec = should_have_one_x_one_goal_prefix(ContextPieces, Context,
             "a list of variables", "arbitrary"),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1407,17 +1431,17 @@ parse_goal_require_detism(GoalKind, ArgTerms, Context, ContextPieces,
     ( if ArgTerms = [SubGoalTerm] then
         parse_goal(SubGoalTerm, ContextPieces, MaybeSubGoal, !VarSet),
         (
-            MaybeSubGoal = ok2(SubGoal, SubGoalWarningSpecs),
+            MaybeSubGoal = ok2(SubGoal, SubGoalWarnSpecs),
             Goal = require_detism_expr(Context, Detism, SubGoal),
-            MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+            MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
         ;
-            MaybeSubGoal = error2(Specs),
-            MaybeGoal = error2(Specs)
+            MaybeSubGoal = error2(ErrWarnError),
+            MaybeGoal = error2(ErrWarnError)
         )
     else
         string_goal_kind(Functor, GoalKind),
         Spec = should_have_one_goal_prefix(ContextPieces, Context, Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1436,30 +1460,30 @@ parse_goal_require_complete_switch(ArgTerms, Context, ContextPieces,
         parse_goal(SubGoalTerm, ContextPieces, MaybeSubGoal, !VarSet),
         ( if
             MaybePSDCVars = ok1(PSDCVars0),
-            MaybeSubGoal = ok2(SubGoal, SubGoalWarningSpecs)
+            MaybeSubGoal = ok2(SubGoal, SubGoalWarnSpecs)
         then
             parse_one_plain_or_dot_var(PSDCVars0, SubGoal,
                 ContextPieces, "require_complete_switch", MaybePODVar),
             (
                 MaybePODVar = ok1(PODVar),
                 Goal = require_complete_switch_expr(Context, PODVar, SubGoal),
-                MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+                MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
             ;
-                MaybePODVar = error1(OoMRCSSpecs),
-                append_one_or_more_list(OoMRCSSpecs,
-                    SubGoalWarningSpecs, OoMSpecs),
-                MaybeGoal = error2(OoMSpecs)
+                MaybePODVar = error1(OoMVarErrSpecs),
+                MaybeGoal = error2({OoMVarErrSpecs, SubGoalWarnSpecs})
             )
         else
-            Specs = get_any_errors1(MaybePSDCVars) ++
-                get_any_errors_warnings2(MaybeSubGoal),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoal = error2(OoMSpecs)
+            VarErrSpecs = get_any_errors1(MaybePSDCVars),
+            get_all_errors_warnings2(MaybeSubGoal,
+                SubGoalErrSpecs, SubGoalWarnSpecs),
+            ErrSpecs = VarErrSpecs ++ SubGoalErrSpecs,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            MaybeGoal = error2({OoMErrSpecs, SubGoalWarnSpecs})
         )
     else
         Spec = should_have_one_x_one_goal_prefix(ContextPieces, Context,
             "a variable in a singleton list", "require_complete_switch"),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1512,7 +1536,7 @@ parse_goal_require_switch_arm_detism(GoalKind, ArgTerms,
         parse_goal(SubGoalTerm, ContextPieces, MaybeSubGoal, !VarSet),
         ( if
             MaybePSDCVars = ok1(PSDCVars0),
-            MaybeSubGoal = ok2(SubGoal, SubGoalWarningSpecs)
+            MaybeSubGoal = ok2(SubGoal, SubGoalWarnSpecs)
         then
             parse_one_plain_or_dot_var(PSDCVars0, SubGoal,
                 ContextPieces, Functor, MaybePODVar),
@@ -1520,23 +1544,23 @@ parse_goal_require_switch_arm_detism(GoalKind, ArgTerms,
                 MaybePODVar = ok1(PODVar),
                 Goal = require_switch_arms_detism_expr(Context, PODVar,
                     Detism, SubGoal),
-                MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+                MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
             ;
-                MaybePODVar = error1(OoMRCSSpecs),
-                append_one_or_more_list(OoMRCSSpecs,
-                    SubGoalWarningSpecs, OoMSpecs),
-                MaybeGoal = error2(OoMSpecs)
+                MaybePODVar = error1(OoMVarErrSpecs),
+                MaybeGoal = error2({OoMVarErrSpecs, SubGoalWarnSpecs})
             )
         else
-            Specs = get_any_errors1(MaybePSDCVars) ++
-                get_any_errors_warnings2(MaybeSubGoal),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoal = error2(OoMSpecs)
+            VarErrSpecs = get_any_errors1(MaybePSDCVars),
+            get_all_errors_warnings2(MaybeSubGoal,
+                SubGoalErrSpecs, SubGoalWarnSpecs),
+            ErrSpecs = VarErrSpecs ++ SubGoalErrSpecs,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            MaybeGoal = error2({OoMErrSpecs, SubGoalWarnSpecs})
         )
     else
         Spec = should_have_one_x_one_goal_prefix(ContextPieces, Context,
             "a variable in a singleton list", Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1550,7 +1574,7 @@ parse_goal_event(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
     ( if ArgTerms = [SubGoalTerm] then
         parse_goal(SubGoalTerm, ContextPieces, MaybeSubGoal, !VarSet),
         (
-            MaybeSubGoal = ok2(SubGoal, SubGoalWarningSpecs),
+            MaybeSubGoal = ok2(SubGoal, SubGoalWarnSpecs),
             ( if
                 SubGoal = call_expr(SubContext, SymName, CallArgs, Purity)
             then
@@ -1559,7 +1583,7 @@ parse_goal_event(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
                     Purity = purity_pure
                 then
                     Goal = event_expr(Context, EventName, CallArgs),
-                    MaybeGoal = ok2(Goal, SubGoalWarningSpecs)
+                    MaybeGoal = ok2(Goal, SubGoalWarnSpecs)
                 else
                     some [!Specs] (
                         !:Specs = [],
@@ -1595,21 +1619,21 @@ parse_goal_event(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-
                             !:Specs = [PuritySpec | !.Specs]
                         ),
                         det_list_to_one_or_more(!.Specs, OoMSpecs),
-                        MaybeGoal = error2(OoMSpecs)
+                        MaybeGoal = error2({OoMSpecs, []})
                     )
                 )
             else
                 Spec = should_have_one_call_prefix(ContextPieces, Context,
                     "event"),
-                MaybeGoal = error2(one_or_more(Spec, SubGoalWarningSpecs))
+                MaybeGoal = error2({one_or_more(Spec, []), SubGoalWarnSpecs})
             )
         ;
-            MaybeSubGoal = error2(Specs),
-            MaybeGoal = error2(Specs)
+            MaybeSubGoal = error2(ErrWarnError),
+            MaybeGoal = error2(ErrWarnError)
         )
     else
         Spec = should_have_one_call_prefix(ContextPieces, Context, "event"),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1634,7 +1658,7 @@ parse_goal_true_fail(GoalKind, ArgTerms, Context, ContextPieces, MaybeGoal) :-
         ArgTerms = [_ | _],
         string_goal_kind(Functor, GoalKind),
         Spec = should_have_no_args(ContextPieces, Context, Functor),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------%
@@ -1664,14 +1688,14 @@ parse_goal_equal(VarSet, ArgTerms, Context, ContextPieces, MaybeGoal) :-
                 color_as_incorrect([quote("="), suffix(".")]) ++ [nl],
             Severity = severity_warning(warn_dodgy_simple_code),
             WarningSpec = spec($pred, Severity, phase_pt2h, Context, Pieces),
-            WarningSpecs = [WarningSpec]
+            WarnSpecs = [WarningSpec]
         else
-            WarningSpecs = []
+            WarnSpecs = []
         ),
-        MaybeGoal = ok2(Goal, WarningSpecs)
+        MaybeGoal = ok2(Goal, WarnSpecs)
     else
         Spec = should_have_two_terms_infix(ContextPieces, Context, "="),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 %---------------------------------------------------------------------------%
@@ -1697,7 +1721,7 @@ parse_one_plain_or_dot_var(PSDCVars, Goal, ContextPieces, ConstructName,
                 words(ConstructName)]) ++
             color_as_incorrect([words("may not contain")]) ++
             [words("a state variable pair."), nl],
-        StateSpec = spec($pred, severity_error, phase_t2pt,
+        StateSpec : err_spec = spec($pred, severity_error, phase_t2pt,
             Context, StatePieces),
         MaybeStateVars = error1(one_or_more(StateSpec, []))
     ),
@@ -1712,7 +1736,7 @@ parse_one_plain_or_dot_var(PSDCVars, Goal, ContextPieces, ConstructName,
                 words(ConstructName)]) ++
             color_as_incorrect([words("may not contain")]) ++
             [words("a reference to the next value of a state variable."), nl],
-        ColonSpec = spec($pred, severity_error, phase_t2pt,
+        ColonSpec : err_spec = spec($pred, severity_error, phase_t2pt,
             Context, ColonPieces),
         MaybeColonVars = error1(one_or_more(ColonSpec, []))
     ),
@@ -1732,7 +1756,7 @@ parse_one_plain_or_dot_var(PSDCVars, Goal, ContextPieces, ConstructName,
                 words(ConstructName)]) ++
             color_as_incorrect([words("may not contain")]) ++
             [words("more than one variable."), nl],
-        PlainSpec = spec($pred, severity_error, phase_t2pt,
+        PlainSpec : err_spec = spec($pred, severity_error, phase_t2pt,
             Context, PlainPieces),
         MaybeMaybePlainVar = error1(one_or_more(PlainSpec, []))
     ),
@@ -1752,7 +1776,7 @@ parse_one_plain_or_dot_var(PSDCVars, Goal, ContextPieces, ConstructName,
                 words(ConstructName)]) ++
             color_as_incorrect([words("may not contain")]) ++
             [words("more than one variable."), nl],
-        DotSpec = spec($pred, severity_error, phase_t2pt,
+        DotSpec : err_spec = spec($pred, severity_error, phase_t2pt,
             Context, DotPieces),
         MaybeMaybeDotVar = error1(one_or_more(DotSpec, []))
     ),
@@ -1807,7 +1831,7 @@ parse_one_plain_or_dot_var(PSDCVars, Goal, ContextPieces, ConstructName,
 
 :- pred parse_warnings(varset::in, term::in, string::in,
     cord(format_piece)::in, int::in,
-    maybe2(list(goal_warning), list(warning_spec))::out) is det.
+    parse_result2(list(goal_warning))::out) is det.
 
 parse_warnings(VarSet, Term, ScopeFunctor, ContextPieces, WarningNum,
         MaybeWarnings) :-
@@ -1815,18 +1839,19 @@ parse_warnings(VarSet, Term, ScopeFunctor, ContextPieces, WarningNum,
         MaybeWarnings = ok2([], [])
     else if Term = term.functor(term.atom("[|]"), [HeadTerm, TailTerm], _) then
         parse_warning(VarSet, HeadTerm, ScopeFunctor, ContextPieces,
-            WarningNum, HeadWarnings, HeadWarningSpecs),
+            WarningNum, HeadWarnings, HeadWarnSpecs),
         parse_warnings(VarSet, TailTerm, ScopeFunctor, ContextPieces,
             WarningNum + 1, MaybeTailWarnings),
         (
-            MaybeTailWarnings = ok2(TailWarnings, TailWarningSpecs),
+            MaybeTailWarnings = ok2(TailWarnings, TailWarnSpecs),
             Warnings = HeadWarnings ++ TailWarnings,
-            WarningSpecs = HeadWarningSpecs ++ TailWarningSpecs,
-            MaybeWarnings = ok2(Warnings, WarningSpecs)
+            WarnSpecs = HeadWarnSpecs ++ TailWarnSpecs,
+            MaybeWarnings = ok2(Warnings, WarnSpecs)
         ;
-            MaybeTailWarnings = error2(OoMTailSpecs),
-            append_list_one_or_more(HeadWarningSpecs, OoMTailSpecs, Specs),
-            MaybeWarnings = error2(Specs)
+            MaybeTailWarnings = error2(ErrWarnError0),
+            add_warns_to_err_warn_error(ErrWarnError0, HeadWarnSpecs,
+                ErrWarnError),
+            MaybeWarnings = error2(ErrWarnError)
         )
     else
         TermStr = describe_error_term(VarSet, Term),
@@ -1840,15 +1865,15 @@ parse_warnings(VarSet, Term, ScopeFunctor, ContextPieces, WarningNum,
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt,
             get_term_context(Term), Pieces),
-        MaybeWarnings = error2(one_or_more(Spec, []))
+        MaybeWarnings = error2({one_or_more(Spec, []), []})
     ).
 
 :- pred parse_warning(varset::in, term::in, string::in,
     cord(format_piece)::in, int::in,
-    list(goal_warning)::out, list(warning_spec)::out) is det.
+    list(goal_warning)::out, list(warn_spec)::out) is det.
 
 parse_warning(VarSet, Term, ScopeFunctor, ContextPieces, WarningNum,
-        Warnings, WarningSpecs) :-
+        Warnings, WarnSpecs) :-
     ( if
         Term = term.functor(term.atom(WarningFunctor), [], _),
         (
@@ -1875,7 +1900,7 @@ parse_warning(VarSet, Term, ScopeFunctor, ContextPieces, WarningNum,
         )
     then
         Warnings = [Warning],
-        WarningSpecs = []
+        WarnSpecs = []
     else
         TermStr = describe_error_term(VarSet, Term),
         Pieces = cord.list(ContextPieces) ++
@@ -1895,12 +1920,12 @@ parse_warning(VarSet, Term, ScopeFunctor, ContextPieces, WarningNum,
         Spec = spec($pred, severity_warning(warn_unknown_warning_name),
             phase_t2pt, get_term_context(Term), Pieces),
         Warnings = [],
-        WarningSpecs = [Spec]
+        WarnSpecs = [Spec]
     ).
 
 :- pred generate_warnings_for_duplicate_warnings(prog_context::in,
     cord(format_piece)::in, assoc_list(goal_warning, int)::in,
-    list(goal_warning)::out, list(diag_spec)::out) is det.
+    list(goal_warning)::out, list(err_spec)::out) is det.
 
 generate_warnings_for_duplicate_warnings(_, _, [], [], []).
 generate_warnings_for_duplicate_warnings(Context, ContextPieces,
@@ -2457,7 +2482,7 @@ convert_trace_params(Components, MaybeParams) :-
     maybe(trace_expr(trace_runtime))::out,
     maybe(prog_var)::in, maybe(prog_var)::out,
     list(trace_mutable_var)::in, list(trace_mutable_var)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 collect_trace_params([], !MaybeCompileTime, !MaybeRunTime, !MaybeIO,
         !MutableVars, !Specs).
@@ -2513,8 +2538,7 @@ collect_trace_params([Component - Context | ComponentsContexts],
 %---------------------------------------------------------------------------%
 
 :- pred parse_catch_any_term(term::in, term.context::in,
-    cord(format_piece)::in,
-    maybe2(catch_any_expr, list(warning_spec))::out,
+    cord(format_piece)::in, parse_result2(catch_any_expr)::out,
     prog_varset::in, prog_varset::out) is det.
 
 parse_catch_any_term(ArrowTerm, _Context, ContextPieces, MaybeCatchAny,
@@ -2524,12 +2548,12 @@ parse_catch_any_term(ArrowTerm, _Context, ContextPieces, MaybeCatchAny,
             term.coerce_var(Var0, Var),
             parse_goal(GoalTerm, ContextPieces, MaybeGoal, !VarSet),
             (
-                MaybeGoal = ok2(Goal, GoalWarningSpecs),
+                MaybeGoal = ok2(Goal, GoalWarnSpecs),
                 CatchAny = catch_any_expr(Var, Goal),
-                MaybeCatchAny = ok2(CatchAny, GoalWarningSpecs)
+                MaybeCatchAny = ok2(CatchAny, GoalWarnSpecs)
             ;
-                MaybeGoal = error2(Specs),
-                MaybeCatchAny = error2(Specs)
+                MaybeGoal = error2(ErrWarnError),
+                MaybeCatchAny = error2(ErrWarnError)
             )
         else
             varset.coerce(!.VarSet, VarSet0),
@@ -2543,7 +2567,7 @@ parse_catch_any_term(ArrowTerm, _Context, ContextPieces, MaybeCatchAny,
                 [nl],
             Spec = spec($pred, severity_error, phase_t2pt,
                 get_term_context(ArrowTerm), Pieces),
-            MaybeCatchAny = error2(one_or_more(Spec, []))
+            MaybeCatchAny = error2({one_or_more(Spec, []), []})
         )
     else
         varset.coerce(!.VarSet, VarSet0),
@@ -2556,7 +2580,7 @@ parse_catch_any_term(ArrowTerm, _Context, ContextPieces, MaybeCatchAny,
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt,
             get_term_context(ArrowTerm), Pieces),
-        MaybeCatchAny = error2(one_or_more(Spec, []))
+        MaybeCatchAny = error2({one_or_more(Spec, []), []})
     ).
 
 :- pred parse_catch_then_try_term_args(list(term)::in,
@@ -2569,21 +2593,21 @@ parse_catch_then_try_term_args(CatchTermArgs, MaybeCatchAnyExpr,
         parse_sub_catch_terms(TermB, Context, ContextPieces, MaybeCatches,
              !VarSet),
         (
-            MaybeCatches = ok2(Catches, CatchWarningSpecs),
+            MaybeCatches = ok2(Catches, CatchWarnSpecs),
             parse_else_then_try_term(TermA, Catches, MaybeCatchAnyExpr,
                 Context, ContextPieces, MaybeGoal0, !VarSet),
             (
-                MaybeGoal0 = ok2(Goal, GoalWarningSpecs),
-                MaybeGoal = ok2(Goal, CatchWarningSpecs ++ GoalWarningSpecs)
+                MaybeGoal0 = ok2(Goal, GoalWarnSpecs),
+                MaybeGoal = ok2(Goal, CatchWarnSpecs ++ GoalWarnSpecs)
             ;
-                MaybeGoal0 = error2(OoMGoal0Specs),
-                append_list_one_or_more(CatchWarningSpecs,
-                    OoMGoal0Specs, OoMSpecs),
-                MaybeGoal = error2(OoMSpecs)
+                MaybeGoal0 = error2(ErrWarnError0),
+                add_warns_to_err_warn_error(ErrWarnError0, CatchWarnSpecs,
+                    ErrWarnError),
+                MaybeGoal = error2(ErrWarnError)
             )
         ;
-            MaybeCatches = error2(Specs),
-            MaybeGoal = error2(Specs)
+            MaybeCatches = error2(ErrWarnSpecs),
+            MaybeGoal = error2(ErrWarnSpecs)
         )
     else
         varset.coerce(!.VarSet, ErrorVarSet),
@@ -2601,12 +2625,11 @@ parse_catch_then_try_term_args(CatchTermArgs, MaybeCatchAnyExpr,
             color_as_incorrect([words("does not have this form.")]) ++
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 :- pred parse_sub_catch_terms(term::in, term.context::in,
-    cord(format_piece)::in,
-    maybe2(list(catch_expr), list(warning_spec))::out,
+    cord(format_piece)::in, parse_result2(list(catch_expr))::out,
     prog_varset::in, prog_varset::out) is det.
 
 parse_sub_catch_terms(Term, Context, ContextPieces, MaybeCatches, !VarSet) :-
@@ -2616,32 +2639,36 @@ parse_sub_catch_terms(Term, Context, ContextPieces, MaybeCatches, !VarSet) :-
         parse_sub_catch_terms(SubTerm, Context, ContextPieces,
             TailMaybeCatches, !VarSet),
         ( if
-            HeadMaybeCatch = ok2(HeadCatch, HeadWarningSpecs),
-            TailMaybeCatches = ok2(TailCatches, TailWarningSpecs)
+            HeadMaybeCatch = ok2(HeadCatch, HeadWarnSpecs),
+            TailMaybeCatches = ok2(TailCatches, TailWarnSpecs)
         then
             Catches = [HeadCatch | TailCatches],
-            WarningSpecs = HeadWarningSpecs ++ TailWarningSpecs,
-            MaybeCatches = ok2(Catches, WarningSpecs)
+            WarnSpecs = HeadWarnSpecs ++ TailWarnSpecs,
+            MaybeCatches = ok2(Catches, WarnSpecs)
         else
-            Specs = get_any_errors_warnings2(HeadMaybeCatch) ++
-                get_any_errors_warnings2(TailMaybeCatches),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeCatches = error2(OoMSpecs)
+            get_all_errors_warnings2(HeadMaybeCatch,
+                HeadErrSpecs, HeadWarnSpecs),
+            get_all_errors_warnings2(TailMaybeCatches,
+                TailErrSpecs, TailWarnSpecs),
+            ErrSpecs = HeadErrSpecs ++ TailErrSpecs,
+            WarnSpecs = HeadWarnSpecs ++ TailWarnSpecs,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            MaybeCatches = error2({OoMErrSpecs, WarnSpecs})
         )
     else
         parse_catch_arrow_term(Term, Context, ContextPieces, MaybeCatch,
             !VarSet),
         (
-            MaybeCatch = ok2(Catch, CatchWarningSpecs),
-            MaybeCatches = ok2([Catch], CatchWarningSpecs)
+            MaybeCatch = ok2(Catch, CatchWarnSpecs),
+            MaybeCatches = ok2([Catch], CatchWarnSpecs)
         ;
-            MaybeCatch = error2(Error),
-            MaybeCatches = error2(Error)
+            MaybeCatch = error2(ErrWarnError),
+            MaybeCatches = error2(ErrWarnError)
         )
     ).
 
 :- pred parse_catch_arrow_term(term::in, term.context::in,
-    cord(format_piece)::in, maybe2(catch_expr, list(warning_spec))::out,
+    cord(format_piece)::in, parse_result2(catch_expr)::out,
     prog_varset::in, prog_varset::out) is det.
 
 parse_catch_arrow_term(ArrowTerm, _Context, ContextPieces, MaybeCatch,
@@ -2650,12 +2677,12 @@ parse_catch_arrow_term(ArrowTerm, _Context, ContextPieces, MaybeCatch,
         term.coerce(PatternTerm0, PatternTerm),
         parse_goal(GoalTerm, ContextPieces, MaybeGoal, !VarSet),
         (
-            MaybeGoal = ok2(Goal, GoalWarningSpecs),
+            MaybeGoal = ok2(Goal, GoalWarnSpecs),
             Catch = catch_expr(PatternTerm, Goal),
-            MaybeCatch = ok2(Catch, GoalWarningSpecs)
+            MaybeCatch = ok2(Catch, GoalWarnSpecs)
         ;
-            MaybeGoal = error2(Error),
-            MaybeCatch = error2(Error)
+            MaybeGoal = error2(ErrWarnError),
+            MaybeCatch = error2(ErrWarnError)
         )
     else
         varset.coerce(!.VarSet, ErrorVarSet),
@@ -2668,7 +2695,7 @@ parse_catch_arrow_term(ArrowTerm, _Context, ContextPieces, MaybeCatch,
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt,
             get_term_context(ArrowTerm), Pieces),
-        MaybeCatch = error2(one_or_more(Spec, []))
+        MaybeCatch = error2({one_or_more(Spec, []), []})
     ).
 
 :- pred parse_else_then_try_term(term::in, list(catch_expr)::in,
@@ -2681,7 +2708,7 @@ parse_else_then_try_term(Term, CatchExprs, MaybeCatchAnyExpr,
     ( if Term = term.functor(term.atom("else"), [ThenTerm, ElseTerm], _) then
         parse_goal(ElseTerm, ContextPieces, MaybeElseGoal0, !VarSet),
         (
-            MaybeElseGoal0 = ok2(ElseGoal, ElseWarningSpecs),
+            MaybeElseGoal0 = ok2(ElseGoal, ElseWarnSpecs),
             parse_then_try_term(ThenTerm, yes(ElseGoal), CatchExprs,
                 MaybeCatchAnyExpr, Context, ContextPieces, MaybeTryGoal,
                 !VarSet),
@@ -2695,7 +2722,7 @@ parse_else_then_try_term(Term, CatchExprs, MaybeCatchAnyExpr,
                     [nl],
                 Spec = spec($pred, severity_error, phase_t2pt,
                     ThenContext, Pieces),
-                MaybeGoal = error2(one_or_more(Spec, ElseWarningSpecs))
+                MaybeGoal = error2({one_or_more(Spec, []), ElseWarnSpecs})
             else
                 MaybeGoal = MaybeTryGoal
             )
@@ -2725,28 +2752,29 @@ parse_then_try_term(ThenTryTerm, MaybeElse, CatchExprs, MaybeCatchAnyExpr,
         parse_goal(ThenTerm, ContextPieces, MaybeThenGoal, !VarSet),
         ( if
             MaybeParams = ok1(Params),
-            MaybeTryGoal = ok2(TryGoal, TryWarningSpecs),
-            MaybeThenGoal = ok2(ThenGoal, ThenWarningSpecs)
+            MaybeTryGoal = ok2(TryGoal, TryWarnSpecs),
+            MaybeThenGoal = ok2(ThenGoal, ThenWarnSpecs)
         then
-            WarningSpecs = TryWarningSpecs ++ ThenWarningSpecs,
+            WarnSpecs = TryWarnSpecs ++ ThenWarnSpecs,
             convert_try_params(Params, MaybeComponents),
             (
                 MaybeComponents = ok1(MaybeIO),
                 Goal = try_expr(TryContext, MaybeIO, TryGoal, ThenGoal,
                     MaybeElse, CatchExprs, MaybeCatchAnyExpr),
-                MaybeGoal = ok2(Goal, WarningSpecs)
+                MaybeGoal = ok2(Goal, WarnSpecs)
             ;
-                MaybeComponents = error1(OoMComponentSpecs),
-                append_one_or_more_list(OoMComponentSpecs,
-                    WarningSpecs, OoMSpecs),
-                MaybeGoal = error2(OoMSpecs)
+                MaybeComponents = error1(OoMComponentErrSpecs),
+                MaybeGoal = error2({OoMComponentErrSpecs, WarnSpecs})
             )
         else
-            Specs = get_any_errors1(MaybeParams) ++
-                get_any_errors_warnings2(MaybeTryGoal) ++
-                get_any_errors_warnings2(MaybeThenGoal),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoal = error2(OoMSpecs)
+            ParamsErrSpecs = get_any_errors1(MaybeParams),
+            get_all_errors_warnings2(MaybeTryGoal, TryErrSpecs, TryWarnSpecs),
+            get_all_errors_warnings2(MaybeThenGoal,
+                ThenyErrSpecs, ThenyWarnSpecs),
+            ErrSpecs = ParamsErrSpecs ++ TryErrSpecs ++ ThenyErrSpecs,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            WarnSpecs = TryWarnSpecs ++ ThenyWarnSpecs,
+            MaybeGoal = error2({OoMErrSpecs, WarnSpecs})
         )
     else
         Pieces = [words("Error: a")] ++
@@ -2761,7 +2789,7 @@ parse_then_try_term(ThenTryTerm, MaybeElse, CatchExprs, MaybeCatchAnyExpr,
             quote("catch_any"), words("clause."), nl],
         Spec = spec($pred, severity_error, phase_t2pt,
             get_term_context(ThenTryTerm), Pieces),
-        MaybeGoal = error2(one_or_more(Spec, []))
+        MaybeGoal = error2({one_or_more(Spec, []), []})
     ).
 
 :- type try_component
@@ -2877,7 +2905,7 @@ convert_try_params(Components, MaybeParams) :-
 
 :- pred collect_try_params(assoc_list(try_component, term.context)::in,
     maybe(prog_var)::in, maybe(prog_var)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 collect_try_params([], !MaybeIO, !Specs).
 collect_try_params([Component - Context | ComponentsContexts],
@@ -3079,14 +3107,13 @@ parse_atomic_component_state_or_pair(SubTerms, State) :-
 
 %---------------------%
 
-:- pred parse_atomic_subgoals(term::in,
-    maybe3(goal, list(goal), list(warning_spec))::out,
+:- pred parse_atomic_subgoals(term::in, parse_result3(goal, list(goal))::out,
     prog_varset::in, prog_varset::out) is det.
 
 parse_atomic_subgoals(Term, MaybeOoMSubGoals, !VarSet) :-
     parse_atomic_subgoals_as_list(Term, MaybeSubGoals, !VarSet),
     (
-        MaybeSubGoals = ok2(Goals, WarningSpecs),
+        MaybeSubGoals = ok2(Goals, WarnSpecs),
         (
             Goals = [],
             Pieces = [words("Error: atomic scope")] ++
@@ -3094,10 +3121,10 @@ parse_atomic_subgoals(Term, MaybeOoMSubGoals, !VarSet) :-
                 [nl],
             Context = get_term_context(Term),
             Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-            MaybeOoMSubGoals = error3(one_or_more(Spec, WarningSpecs))
+            MaybeOoMSubGoals = error3({one_or_more(Spec, []), WarnSpecs})
         ;
             Goals = [MainSubGoal | OrElseSubGoals],
-            MaybeOoMSubGoals = ok3(MainSubGoal, OrElseSubGoals, WarningSpecs)
+            MaybeOoMSubGoals = ok3(MainSubGoal, OrElseSubGoals, WarnSpecs)
         )
     ;
         MaybeSubGoals = error2(Specs),
@@ -3105,8 +3132,7 @@ parse_atomic_subgoals(Term, MaybeOoMSubGoals, !VarSet) :-
     ).
 
 :- pred parse_atomic_subgoals_as_list(term::in,
-    maybe2(list(goal), list(warning_spec))::out,
-    prog_varset::in, prog_varset::out) is det.
+    parse_result2(list(goal))::out, prog_varset::in, prog_varset::out) is det.
 
 parse_atomic_subgoals_as_list(Term, MaybeGoals, !VarSet) :-
     ( if
@@ -3115,28 +3141,32 @@ parse_atomic_subgoals_as_list(Term, MaybeGoals, !VarSet) :-
         parse_atomic_subgoals_as_list(LeftGoal, MaybeLeftGoalList, !VarSet),
         parse_atomic_subgoals_as_list(RightGoal, MaybeRightGoalList, !VarSet),
         ( if
-            MaybeLeftGoalList = ok2(LeftGoalList, LeftWarningSpecs),
-            MaybeRightGoalList = ok2(RightGoalList, RightWarningSpecs)
+            MaybeLeftGoalList = ok2(LeftGoalList, LeftWarnSpecs),
+            MaybeRightGoalList = ok2(RightGoalList, RightWarnSpecs)
         then
             Goals = LeftGoalList ++ RightGoalList,
-            WarningSpecs = LeftWarningSpecs ++ RightWarningSpecs,
-            MaybeGoals = ok2(Goals, WarningSpecs)
+            WarnSpecs = LeftWarnSpecs ++ RightWarnSpecs,
+            MaybeGoals = ok2(Goals, WarnSpecs)
         else
-            Specs = get_any_errors_warnings2(MaybeLeftGoalList) ++
-                get_any_errors_warnings2(MaybeRightGoalList),
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeGoals = error2(OoMSpecs)
+            get_all_errors_warnings2(MaybeLeftGoalList,
+                LeftErrSpecs, LeftWarnSpecs),
+            get_all_errors_warnings2(MaybeRightGoalList,
+                RightErrSpecs, RightWarnSpecs),
+            GoalsErrSpecs = LeftErrSpecs ++ RightErrSpecs,
+            GoalsWarnSpecs = LeftWarnSpecs ++ RightWarnSpecs,
+            det_list_to_one_or_more(GoalsErrSpecs, OoMErrSpecs),
+            MaybeGoals = error2({OoMErrSpecs, GoalsWarnSpecs})
         )
     else
         % XXX Provide better ContextPieces.
         ContextPieces = cord.init,
         parse_goal(Term, ContextPieces, MaybeSubGoal, !VarSet),
         (
-            MaybeSubGoal = ok2(SubGoal, WarningSpecs),
-            MaybeGoals = ok2([SubGoal], WarningSpecs)
+            MaybeSubGoal = ok2(SubGoal, WarnSpecs),
+            MaybeGoals = ok2([SubGoal], WarnSpecs)
         ;
-            MaybeSubGoal = error2(Specs),
-            MaybeGoals = error2(Specs)
+            MaybeSubGoal = error2(ErrWarnError),
+            MaybeGoals = error2(ErrWarnError)
         )
     ).
 
@@ -3190,7 +3220,7 @@ convert_atomic_params(ErrorTerm, ComponentsContexts, MaybeParams) :-
     maybe(atomic_component_state)::in, maybe(atomic_component_state)::out,
     maybe(atomic_component_state)::in, maybe(atomic_component_state)::out,
     maybe(list(prog_var))::in, maybe(list(prog_var))::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 collect_atomic_params([], !MaybeOuter, !MaybeInner, !MaybeVars, !Specs).
 collect_atomic_params([Component - CompContext | ComponentsContexts],
diff --git a/compiler/parse_goal_util.m b/compiler/parse_goal_util.m
index 894b39f0f..b4b60baa4 100644
--- a/compiler/parse_goal_util.m
+++ b/compiler/parse_goal_util.m
@@ -23,23 +23,26 @@
 :- import_module parse_tree.prog_item.
 
 :- import_module cord.
-:- import_module list.
 :- import_module term.
 
 %---------------------------------------------------------------------------%
 
+:- type goal_result == parse_result2(goal).
+
+%---------------------------------------------------------------------------%
+
 :- func should_have_no_args(cord(format_piece),
-    term.context, string) = diag_spec.
+    term.context, string) = err_spec.
 :- func should_have_one_goal_prefix(cord(format_piece),
-    term.context, string) = diag_spec.
+    term.context, string) = err_spec.
 :- func should_have_two_terms_infix(cord(format_piece),
-    term.context, string) = diag_spec.
+    term.context, string) = err_spec.
 :- func should_have_two_goals_infix(cord(format_piece),
-    term.context, string) = diag_spec.
+    term.context, string) = err_spec.
 :- func should_have_one_x_one_goal_prefix(cord(format_piece),
-    term.context, string, string) = diag_spec.
+    term.context, string, string) = err_spec.
 :- func should_have_one_call_prefix(cord(format_piece),
-    term.context, string) = diag_spec.
+    term.context, string) = err_spec.
 
     % apply_purity_marker_to_maybe_goal(GoalTerm, Purity,
     %   MaybeGoal0, MaybeGoal):
@@ -50,8 +53,7 @@
     % are applicable.
     %
 :- pred apply_purity_marker_to_maybe_goal(term::in, purity::in,
-    maybe2(goal, list(warning_spec))::in,
-    maybe2(goal, list(warning_spec))::out) is det.
+    parse_result2(goal)::in, parse_result2(goal)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -62,6 +64,7 @@
 :- import_module mdbcomp.sym_name.
 :- import_module parse_tree.parse_tree_out_misc.
 
+:- import_module list.
 :- import_module maybe.
 :- import_module term_context.
 
diff --git a/compiler/parse_inst_mode_defn.m b/compiler/parse_inst_mode_defn.m
index 06c236de6..26ad0bf51 100644
--- a/compiler/parse_inst_mode_defn.m
+++ b/compiler/parse_inst_mode_defn.m
@@ -322,7 +322,7 @@ parse_abstract_mode_defn_item(ModuleName, VarSet, HeadTerms, Context, SeqNum,
     % Check that the inst name is available to users.
     %
 :- pred check_user_inst_name(sym_name::in, term.context::in,
-    list(diag_spec)::out) is det.
+    list(err_spec)::out) is det.
 
 check_user_inst_name(SymName, Context, NameSpecs) :-
     Name = unqualify_name(SymName),
@@ -343,7 +343,7 @@ check_user_inst_name(SymName, Context, NameSpecs) :-
     % Check that the mode name is available to users.
     %
 :- pred check_user_mode_name(sym_name::in, term.context::in,
-    list(diag_spec)::out) is det.
+    list(err_spec)::out) is det.
 
 check_user_mode_name(SymName, Context, NameSpecs) :-
     % Check that the mode name is available to users.
diff --git a/compiler/parse_item.m b/compiler/parse_item.m
index 18e2ca3da..dc74b1d23 100644
--- a/compiler/parse_item.m
+++ b/compiler/parse_item.m
@@ -22,12 +22,13 @@
 :- import_module parse_tree.prog_data.
 :- import_module parse_tree.prog_item.
 
+:- import_module list.
 :- import_module maybe.
 :- import_module term.
 :- import_module varset.
 
     % parse_item_or_marker(ModuleName, VarSet, Term, SeqNum,
-    %   MaybeItemOrMarker):
+    %   MaybeItemOrMarker, !WarnSpecs):
     %
     % Parse Term as either an item or sequence of items, or as a marker for
     % the start or end of a module, the start of a module section,
@@ -43,7 +44,8 @@
     % to an error1() wrapped around an appropriate set of error messages.
     %
 :- pred parse_item_or_marker(module_name::in, varset::in, term::in,
-    item_seq_num::in, maybe1(item_or_marker)::out) is det.
+    item_seq_num::in, maybe1(item_or_marker)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
     % parse_clause_term(MaybeDefaultModuleName, VarSet, Term, SeqNum,
     %   MaybeItemOrMarker):
@@ -55,7 +57,7 @@
     % Exported for use by parse_class.m.
     %
 :- pred parse_clause_term(maybe(module_name)::in, varset::in, term::in,
-    item_seq_num::in, maybe1(item_clause_info)::out) is det.
+    item_seq_num::in, maybe1(item_clause_info, err_warn_error)::out) is det.
 
     % parse_class_decl(ModuleName, VarSet, Term, MaybeClassDecl):
     %
@@ -68,7 +70,7 @@
     % Exported for use by parse_class.m.
     %
 :- pred parse_class_decl(module_name::in, varset::in, term::in,
-    maybe1(class_decl)::out) is det.
+    parse_result2(class_decl)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -102,7 +104,7 @@
     % Exported for use by parse_class.m.
     %
 :- pred is_the_name_a_variable(varset::in, var_term_kind::in, term::in,
-    diag_spec::out) is semidet.
+    err_spec::out) is semidet.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -133,7 +135,6 @@
 :- import_module assoc_list.
 :- import_module cord.
 :- import_module int.
-:- import_module list.
 :- import_module map.
 :- import_module one_or_more.
 :- import_module pair.
@@ -143,33 +144,36 @@
 
 %---------------------------------------------------------------------------%
 
-parse_item_or_marker(ModuleName, VarSet, Term, SeqNum, MaybeIOM) :-
+parse_item_or_marker(ModuleName, VarSet, Term, SeqNum, MaybeIOM, !WarnSpecs) :-
     ( if Term = term.functor(term.atom(":-"), [DeclTerm], _DeclContext) then
         parse_decl_term_item_or_marker(ModuleName, VarSet, DeclTerm,
-            SeqNum, MaybeIOM)
+            SeqNum, MaybeIOM, !WarnSpecs)
     else
         parse_clause_term(yes(ModuleName), VarSet, Term, SeqNum, MaybeClause),
         (
             MaybeClause = ok1(ItemClause),
             MaybeIOM = ok1(iom_item(item_clause(ItemClause)))
         ;
-            MaybeClause = error1(Specs),
-            MaybeIOM = error1(Specs)
+            MaybeClause = error1({OoMErrSpecs, ClauseWarnSpecs}),
+            MaybeIOM = error1(OoMErrSpecs),
+            !:WarnSpecs = ClauseWarnSpecs ++ !.WarnSpecs
         )
     ).
 
 %---------------------------------------------------------------------------%
 
 :- pred parse_decl_term_item_or_marker(module_name::in, varset::in, term::in,
-    item_seq_num::in, maybe1(item_or_marker)::out) is det.
-:- pragma inline(pred(parse_decl_term_item_or_marker/5)).
+    item_seq_num::in, maybe1(item_or_marker)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
+:- pragma inline(pred(parse_decl_term_item_or_marker/7)).
 
-parse_decl_term_item_or_marker(ModuleName, VarSet, DeclTerm,
-        SeqNum, MaybeIOM) :-
+parse_decl_term_item_or_marker(ModuleName, VarSet, DeclTerm, SeqNum,
+        MaybeIOM, !WarnSpecs) :-
     ( if DeclTerm = term.functor(term.atom(Functor), ArgTerms, Context) then
         ( if
             parse_decl_item_or_marker(ModuleName, VarSet, Functor, ArgTerms,
-                decl_is_not_in_class, Context, SeqNum, MaybeIOMPrime)
+                decl_is_not_in_class, Context, SeqNum,
+                MaybeIOMPrime, !WarnSpecs)
         then
             MaybeIOM = MaybeIOMPrime
         else
@@ -181,7 +185,7 @@ parse_decl_term_item_or_marker(ModuleName, VarSet, DeclTerm,
         MaybeIOM = error1(one_or_more(Spec, []))
     ).
 
-:- func decl_is_not_an_atom(varset, term) = diag_spec.
+:- func decl_is_not_an_atom(varset, term) = err_spec.
 
 decl_is_not_an_atom(VarSet, Term) = Spec :-
     TermStr = mercury_term_to_string_vs(VarSet, print_name_only, Term),
@@ -193,7 +197,7 @@ decl_is_not_an_atom(VarSet, Term) = Spec :-
         [nl],
     Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces).
 
-:- func decl_functor_is_not_valid(string, prog_context) = diag_spec.
+:- func decl_functor_is_not_valid(string, prog_context) = err_spec.
 
 decl_functor_is_not_valid(Functor, Context) = Spec :-
     Pieces = [words("Error:")] ++
@@ -207,10 +211,11 @@ decl_functor_is_not_valid(Functor, Context) = Spec :-
 
 :- pred parse_decl_item_or_marker(module_name::in, varset::in,
     string::in, list(term)::in, decl_in_class::in, prog_context::in,
-    item_seq_num::in, maybe1(item_or_marker)::out) is semidet.
+    item_seq_num::in, maybe1(item_or_marker)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is semidet.
 
 parse_decl_item_or_marker(ModuleName, VarSet, Functor, ArgTerms,
-        IsInClass, Context, SeqNum, MaybeIOM) :-
+        IsInClass, Context, SeqNum, MaybeIOM, !WarnSpecs) :-
     require_switch_arms_det [Functor]
     (
         Functor = "module",
@@ -274,23 +279,26 @@ parse_decl_item_or_marker(ModuleName, VarSet, Functor, ArgTerms,
         ; Functor = "all", QuantType = quant_type_univ
         ),
         parse_quant_attr(ModuleName, VarSet, Functor, ArgTerms, IsInClass,
-            Context, SeqNum, QuantType, cord.init, cord.init, MaybeIOM)
+            Context, SeqNum, QuantType, cord.init, cord.init,
+            MaybeIOM, !WarnSpecs)
     ;
         ( Functor = "=>", QuantType = quant_type_exist
         ; Functor = "<=", QuantType = quant_type_univ
         ),
         parse_constraint_attr(ModuleName, VarSet, Functor, ArgTerms,
             IsInClass, Context, SeqNum, QuantType, cord.init, cord.init,
-            MaybeIOM)
+            MaybeIOM, !WarnSpecs)
     ;
         ( Functor = "impure", Purity = purity_impure
         ; Functor = "semipure", Purity = purity_semipure
         ),
         parse_purity_attr(ModuleName, VarSet, Functor, ArgTerms,
-            IsInClass, Context, SeqNum, Purity, cord.init, cord.init, MaybeIOM)
+            IsInClass, Context, SeqNum, Purity, cord.init, cord.init,
+            MaybeIOM, !WarnSpecs)
     ;
         Functor = "promise",
-        parse_promise_item(VarSet, ArgTerms, Context, SeqNum, MaybeIOM)
+        parse_promise_item(VarSet, ArgTerms, Context, SeqNum, MaybeIOM0),
+        collect_warn_specs(MaybeIOM0, MaybeIOM, !WarnSpecs)
 % The supported form of promise_ex declarations is
 % ":- all [Vars] promise_ex Goal", and it is parsed by
 % parse_attr_decl_item_or_marker.
@@ -307,11 +315,13 @@ parse_decl_item_or_marker(ModuleName, VarSet, Functor, ArgTerms,
     ;
         Functor = "typeclass",
         parse_typeclass_item(ModuleName, VarSet, ArgTerms, Context, SeqNum,
-            MaybeIOM)
+            MaybeIOM0),
+        collect_warn_specs(MaybeIOM0, MaybeIOM, !WarnSpecs)
     ;
         Functor = "instance",
         parse_instance_item(ModuleName, VarSet, ArgTerms, Context, SeqNum,
-            MaybeIOM)
+            MaybeIOM0),
+        collect_warn_specs(MaybeIOM0, MaybeIOM, !WarnSpecs)
     ;
         ( Functor = "initialise"
         ; Functor = "initialize"
@@ -337,11 +347,12 @@ parse_decl_item_or_marker(ModuleName, VarSet, Functor, ArgTerms,
     string::in, list(term)::in, decl_in_class::in,
     prog_context::in, item_seq_num::in,
     cord(purity_attr)::in, cord(quant_constr_attr)::in,
-    maybe1(item_or_marker)::out) is semidet.
+    maybe1(item_or_marker)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is semidet.
 
 parse_attr_decl_item_or_marker(ModuleName, VarSet, Functor, ArgTerms,
         IsInClass, Context, SeqNum, PurityAttrs0, QuantConstrAttrs0,
-        MaybeIOM) :-
+        MaybeIOM, !WarnSpecs) :-
     % By coincidence, the kinds of items that may have purity,
     % quantification and/or constraint attributes on them, i.e.
     % the set item_pred_decl and item_mode_decl, is exactly the
@@ -389,21 +400,21 @@ parse_attr_decl_item_or_marker(ModuleName, VarSet, Functor, ArgTerms,
         ),
         parse_quant_attr(ModuleName, VarSet, Functor, ArgTerms, IsInClass,
             Context, SeqNum, QuantType, PurityAttrs0, QuantConstrAttrs0,
-            MaybeIOM)
+            MaybeIOM, !WarnSpecs)
     ;
         ( Functor = "=>", QuantType = quant_type_exist
         ; Functor = "<=", QuantType = quant_type_univ
         ),
         parse_constraint_attr(ModuleName, VarSet, Functor, ArgTerms,
             IsInClass, Context, SeqNum, QuantType, PurityAttrs0,
-            QuantConstrAttrs0, MaybeIOM)
+            QuantConstrAttrs0, MaybeIOM, !WarnSpecs)
     ;
         ( Functor = "impure", Purity = purity_impure
         ; Functor = "semipure", Purity = purity_semipure
         ),
         parse_purity_attr(ModuleName, VarSet, Functor, ArgTerms,
             IsInClass, Context, SeqNum, Purity, PurityAttrs0,
-            QuantConstrAttrs0, MaybeIOM)
+            QuantConstrAttrs0, MaybeIOM, !WarnSpecs)
     ;
         ( Functor = "promise_exclusive", PromiseType = promise_type_exclusive
         ; Functor = "promise_exhaustive", PromiseType = promise_type_exhaustive
@@ -411,9 +422,17 @@ parse_attr_decl_item_or_marker(ModuleName, VarSet, Functor, ArgTerms,
             PromiseType = promise_type_exclusive_exhaustive
         ),
         parse_promise_ex_item(VarSet, Functor, ArgTerms, Context, SeqNum,
-            PromiseType, PurityAttrs0, QuantConstrAttrs0, MaybeIOM)
+            PromiseType, PurityAttrs0, QuantConstrAttrs0, MaybeIOM0),
+        collect_warn_specs(MaybeIOM0, MaybeIOM, !WarnSpecs)
     ).
 
+:- pred collect_warn_specs(maybe1(T, err_warn_error)::in, maybe1(T)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
+
+collect_warn_specs(ok1(T), ok1(T), !WarnSpecs).
+collect_warn_specs(error1({T, WS}), error1(T), !WarnSpecs) :-
+    !:WarnSpecs = WS ++ !.WarnSpecs.
+
 %---------------------------------------------------------------------------%
 
 :- pragma inline(pred(parse_clause_term/5)).
@@ -449,10 +468,11 @@ parse_clause_term(MaybeModuleName, VarSet, Term, SeqNum, MaybeClause) :-
 parse_class_decl(ModuleName, VarSet, Term, MaybeClassMethod) :-
     TermContext = get_term_context(Term),
     parse_attributed_decl(ModuleName, VarSet, Term, decl_is_in_class,
-        TermContext, item_no_seq_num, cord.init, cord.init, MaybeIOM),
+        TermContext, item_no_seq_num, cord.init, cord.init,
+        MaybeIOM, [], WarnSpecs),
     (
-        MaybeIOM = error1(Specs),
-        MaybeClassMethod = error1(Specs)
+        MaybeIOM = error1(ErrSpecs),
+        MaybeClassMethod = error2({ErrSpecs, WarnSpecs})
     ;
         MaybeIOM = ok1(IOM),
         ( if IOM = iom_item(item_pred_decl(ItemPredDecl)) then
@@ -464,14 +484,14 @@ parse_class_decl(ModuleName, VarSet, Term, MaybeClassMethod) :-
                 WithType, WithInst, MaybeDetism, TypeVarSet, InstVarSet,
                 ExistQVars, Purity, Constraints, Context),
             ClassDecl = class_decl_pred_or_func(PredOrFuncInfo),
-            MaybeClassMethod = ok1(ClassDecl)
+            MaybeClassMethod = ok2(ClassDecl, WarnSpecs)
         else if IOM = iom_item(item_mode_decl(ItemModeDecl)) then
             ItemModeDecl = item_mode_decl_info(Name, MaybePorF, ArgModes,
                 WithInst, MaybeDetism, InstVarSet, Context, _SeqNum),
             ModeInfo = class_mode_info(Name, MaybePorF, ArgModes,
                 WithInst, MaybeDetism, InstVarSet, Context),
             ClassDecl = class_decl_mode(ModeInfo),
-            MaybeClassMethod = ok1(ClassDecl)
+            MaybeClassMethod = ok2(ClassDecl, WarnSpecs)
         else
             Pieces = [words("Error: only")] ++
                 color_as_correct(
@@ -481,7 +501,7 @@ parse_class_decl(ModuleName, VarSet, Term, MaybeClassMethod) :-
                 [words("in class interfaces."), nl],
             Spec = spec($pred, severity_error, phase_t2pt,
                 TermContext, Pieces),
-            MaybeClassMethod = error1(one_or_more(Spec, []))
+            MaybeClassMethod = error2({one_or_more(Spec, []), WarnSpecs})
         )
     ).
 
@@ -498,16 +518,18 @@ parse_class_decl(ModuleName, VarSet, Term, MaybeClassMethod) :-
     string::in, list(term)::in, decl_in_class::in,
     prog_context::in, item_seq_num::in,
     quantifier_type::in, cord(purity_attr)::in, cord(quant_constr_attr)::in,
-    maybe1(item_or_marker)::out) is det.
+    maybe1(item_or_marker)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 parse_quant_attr(ModuleName, VarSet, Functor, ArgTerms, IsInClass, Context,
-        SeqNum, QuantType, PurityAttrs, !.QuantConstrAttrs, MaybeIOM) :-
+        SeqNum, QuantType, PurityAttrs, !.QuantConstrAttrs,
+        MaybeIOM, !WarnSpecs) :-
     (
         ArgTerms = [VarsTerm, SubTerm],
         QuantAttr = qca_quant_vars(QuantType, VarsTerm),
         cord.snoc(QuantAttr, !QuantConstrAttrs),
         parse_attributed_decl(ModuleName, VarSet, SubTerm, IsInClass, Context,
-            SeqNum, PurityAttrs, !.QuantConstrAttrs, MaybeIOM)
+            SeqNum, PurityAttrs, !.QuantConstrAttrs, MaybeIOM, !WarnSpecs)
     ;
         ( ArgTerms = []
         ; ArgTerms = [_]
@@ -527,17 +549,18 @@ parse_quant_attr(ModuleName, VarSet, Functor, ArgTerms, IsInClass, Context,
     string::in, list(term)::in, decl_in_class::in,
     prog_context::in, item_seq_num::in,
     quantifier_type::in, cord(purity_attr)::in, cord(quant_constr_attr)::in,
-    maybe1(item_or_marker)::out) is det.
+    maybe1(item_or_marker)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 parse_constraint_attr(ModuleName, VarSet, Functor, ArgTerms, IsInClass,
         Context, SeqNum, QuantType, PurityAttrs, !.QuantConstrAttrs,
-        MaybeIOM) :-
+        MaybeIOM, !WarnSpecs) :-
     (
         ArgTerms = [SubTerm, ConstraintsTerm],
         ConstrAttr = qca_constraint(QuantType, ConstraintsTerm),
         cord.snoc(ConstrAttr, !QuantConstrAttrs),
         parse_attributed_decl(ModuleName, VarSet, SubTerm, IsInClass, Context,
-            SeqNum, PurityAttrs, !.QuantConstrAttrs, MaybeIOM)
+            SeqNum, PurityAttrs, !.QuantConstrAttrs, MaybeIOM, !WarnSpecs)
     ;
         ( ArgTerms = []
         ; ArgTerms = [_]
@@ -557,16 +580,18 @@ parse_constraint_attr(ModuleName, VarSet, Functor, ArgTerms, IsInClass,
     string::in, list(term)::in, decl_in_class::in,
     prog_context::in, item_seq_num::in,
     purity::in, cord(purity_attr)::in, cord(quant_constr_attr)::in,
-    maybe1(item_or_marker)::out) is det.
+    maybe1(item_or_marker)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 parse_purity_attr(ModuleName, VarSet, Functor, ArgTerms, IsInClass,
-        Context, SeqNum, Purity, !.PurityAttrs, QuantConstrAttrs, MaybeIOM) :-
+        Context, SeqNum, Purity, !.PurityAttrs, QuantConstrAttrs,
+        MaybeIOM, !WarnSpecs) :-
     (
         ArgTerms = [SubTerm],
         PurityAttr = purity_attr(Purity),
         cord.snoc(PurityAttr, !PurityAttrs),
         parse_attributed_decl(ModuleName, VarSet, SubTerm, IsInClass, Context,
-            SeqNum, !.PurityAttrs, QuantConstrAttrs, MaybeIOM)
+            SeqNum, !.PurityAttrs, QuantConstrAttrs, MaybeIOM, !WarnSpecs)
     ;
         ( ArgTerms = []
         ; ArgTerms = [_, _ | _]
@@ -584,15 +609,16 @@ parse_purity_attr(ModuleName, VarSet, Functor, ArgTerms, IsInClass,
 :- pred parse_attributed_decl(module_name::in, varset::in, term::in,
     decl_in_class::in, prog_context::in, item_seq_num::in,
     cord(purity_attr)::in, cord(quant_constr_attr)::in,
-    maybe1(item_or_marker)::out) is det.
+    maybe1(item_or_marker)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 parse_attributed_decl(ModuleName, VarSet, Term, IsInClass, _Context, SeqNum,
-        PurityAttrs, QuantConstrAttrs, MaybeIOM) :-
+        PurityAttrs, QuantConstrAttrs, MaybeIOM, !WarnSpecs) :-
     ( if Term = term.functor(term.atom(Functor), ArgTerms, FunctorContext) then
         ( if
             parse_attr_decl_item_or_marker(ModuleName, VarSet,
                 Functor, ArgTerms, IsInClass, FunctorContext, SeqNum,
-                PurityAttrs, QuantConstrAttrs, MaybeIOMPrime)
+                PurityAttrs, QuantConstrAttrs, MaybeIOMPrime, !WarnSpecs)
         then
             MaybeIOM = MaybeIOMPrime
         else if
@@ -891,7 +917,8 @@ parse_version_numbers_marker(ModuleName, Functor, ArgTerms,
 %---------------------------------------------------------------------------%
 
 :- pred parse_clause(maybe(module_name)::in, varset::in, term::in, term::in,
-    term.context::in, item_seq_num::in, maybe1(item_clause_info)::out) is det.
+    term.context::in, item_seq_num::in,
+    maybe1(item_clause_info, err_warn_error)::out) is det.
 
 parse_clause(MaybeModuleName, VarSet0, HeadTerm, BodyTerm0, Context, SeqNum,
         MaybeClause) :-
@@ -994,9 +1021,11 @@ parse_clause(MaybeModuleName, VarSet0, HeadTerm, BodyTerm0, Context, SeqNum,
         MaybeClause = ok1(ItemClause)
     ;
         MaybeFunctor = error2(OoMFunctorSpecs),
-        append_one_or_more_list(OoMFunctorSpecs,
-            get_any_errors_warnings2(MaybeBodyGoal), OoMSpecs),
-        MaybeClause = error1(OoMSpecs)
+        get_all_errors_warnings2(MaybeBodyGoal,
+            BodyGoalErrSpecs, BodyGoalWarnSpecs),
+        append_one_or_more_list(OoMFunctorSpecs, BodyGoalErrSpecs,
+            OoMErrSpecs),
+        MaybeClause = error1({OoMErrSpecs, BodyGoalWarnSpecs})
     ).
 
 %---------------------------------------------------------------------------%
@@ -1803,7 +1832,7 @@ get_class_context_and_inst_constraints_from_attrs(ModuleName, VarSet,
 
 :- pred get_class_context_and_inst_constraints_loop(module_name::in,
     varset::in, list(quant_constr_attr)::in, cord(format_piece)::in,
-    list(diag_spec)::in, list(diag_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
     cord(var)::in, cord(var)::out, cord(var)::in, cord(var)::out,
     cord(prog_constraint)::in, cord(prog_constraint)::out,
     inst_var_sub::in, inst_var_sub::out,
@@ -1868,7 +1897,8 @@ get_class_context_and_inst_constraints_loop(ModuleName, VarSet,
 %---------------------------------------------------------------------------%
 
 :- pred parse_promise_item(varset::in, list(term)::in,
-    prog_context::in, item_seq_num::in, maybe1(item_or_marker)::out) is det.
+    prog_context::in, item_seq_num::in,
+    maybe1(item_or_marker, err_warn_error)::out) is det.
 
 parse_promise_item(VarSet, ArgTerms, Context, SeqNum, MaybeIOM) :-
     ( if ArgTerms = [Term] then
@@ -1876,38 +1906,32 @@ parse_promise_item(VarSet, ArgTerms, Context, SeqNum, MaybeIOM) :-
         ContextPieces = cord.init,
         parse_goal(Term, ContextPieces, MaybeGoal0, ProgVarSet0, ProgVarSet),
         (
-            MaybeGoal0 = ok2(Goal0, GoalWarningSpecs),
+            MaybeGoal0 = ok2(Goal0, GoalWarnSpecs),
+            ( if
+                Goal0 = quant_expr(quant_all, quant_ordinary_vars, _,
+                    UnivVars0, AllGoal)
+            then
+                UnivVars0 = UnivVars,
+                Goal = AllGoal
+            else
+                UnivVars = [],
+                Goal = Goal0
+            ),
             (
-                GoalWarningSpecs = [],
-                ( if
-                    Goal0 = quant_expr(quant_all, quant_ordinary_vars, _,
-                        UnivVars0, AllGoal)
-                then
-                    UnivVars0 = UnivVars,
-                    Goal = AllGoal
-                else
-                    UnivVars = [],
-                    Goal = Goal0
-                ),
+                GoalWarnSpecs = [],
                 ItemPromise = item_promise_info(promise_type_true, Goal,
                     ProgVarSet, UnivVars, Context, SeqNum),
                 Item = item_promise(ItemPromise),
                 MaybeIOM = ok1(iom_item(Item))
             ;
-                GoalWarningSpecs = [HeadSpec | TailSpecs],
-                % We *could* try to preserve any warnings for code
-                % inside Goal0, and add the promise to the parse tree
-                % for later addition to the HLDS even in the presence
-                % of such warnings, but there doesn't seem to be any point
-                % in doing that, because at the moment, the only kind
-                % of construct that generates warning_specs is a
-                % disable_warnings scope, and those should NOT be appearing
-                % in any promise.
-                MaybeIOM = error1(one_or_more(HeadSpec, TailSpecs))
+                GoalWarnSpecs = [_ |  _],
+                ErrWarnError =
+                    report_warning_in_promise(Context, GoalWarnSpecs),
+                MaybeIOM = error1(ErrWarnError)
             )
         ;
-            MaybeGoal0 = error2(Specs),
-            MaybeIOM = error1(Specs)
+            MaybeGoal0 = error2(ErrWarnError),
+            MaybeIOM = error1(ErrWarnError)
         )
     else
         Pieces = [words("Error: a")] ++
@@ -1916,7 +1940,7 @@ parse_promise_item(VarSet, ArgTerms, Context, SeqNum, MaybeIOM) :-
                 words("which should be a goal.")]) ++
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeIOM = error1(one_or_more(Spec, []))
+        MaybeIOM = error1({one_or_more(Spec, []), []})
     ).
 
 %---------------------------------------------------------------------------%
@@ -1924,10 +1948,11 @@ parse_promise_item(VarSet, ArgTerms, Context, SeqNum, MaybeIOM) :-
 :- pred parse_promise_ex_item(varset::in, string::in, list(term)::in,
     prog_context::in, item_seq_num::in, promise_type::in,
     cord(purity_attr)::in, cord(quant_constr_attr)::in,
-    maybe1(item_or_marker)::out) is det.
+    maybe1(item_or_marker, err_warn_error)::out) is det.
 
 parse_promise_ex_item(VarSet, Functor, ArgTerms, Context, SeqNum,
-        PromiseType, PurityAttrCord, QuantConstrAttrCord, MaybeIOM) :-
+        PromiseType, PurityAttrCord, QuantConstrAttrCord,
+        MaybeIOM) :-
     ( if ArgTerms = [Term] then
         PurityAttrs = cord.list(PurityAttrCord),
         (
@@ -1971,31 +1996,33 @@ parse_promise_ex_item(VarSet, Functor, ArgTerms, Context, SeqNum,
         ( if
             PuritySpecs = [],
             MaybeUnivVars = ok1(UnivVars),
-            MaybeGoal0 = ok2(Goal, GoalWarningSpecs),
-            % We *could* try to preserve any warnings for code inside Goal,
-            % and add the promise to the parse tree for later addition
-            % to the HLDS even in the presence of such warnings, but
-            % there doesn't seem to be any point in doing that, because
-            % at the moment, the only kind of construct that generates
-            % warning_specs is a disable_warnings scope, and those
-            % should NOT be appearing in any promise.
-            GoalWarningSpecs = []
+            MaybeGoal0 = ok2(Goal, GoalWarnSpecs)
         then
-            UnivProgVars = list.map(term.coerce_var, UnivVars),
-            ItemPromise = item_promise_info(PromiseType, Goal, ProgVarSet,
-                UnivProgVars, Context, SeqNum),
-            Item = item_promise(ItemPromise),
-            MaybeIOM = ok1(iom_item(Item))
+            (
+                GoalWarnSpecs = [],
+                UnivProgVars = list.map(term.coerce_var, UnivVars),
+                ItemPromise = item_promise_info(PromiseType, Goal, ProgVarSet,
+                    UnivProgVars, Context, SeqNum),
+                Item = item_promise(ItemPromise),
+                MaybeIOM = ok1(iom_item(Item))
+            ;
+                GoalWarnSpecs = [_ | _],
+                ErrWarnError =
+                    report_warning_in_promise(Context, GoalWarnSpecs),
+                MaybeIOM = error1(ErrWarnError)
+            )
         else
             (
-                MaybeGoal0 = ok2(_, GoalSpecs)
+                MaybeGoal0 = ok2(_, GoalWarnSpecs),
+                GoalErrSpecs = []
             ;
-                MaybeGoal0 = error2(OoMGoalSpecs),
-                GoalSpecs = one_or_more_to_list(OoMGoalSpecs)
+                MaybeGoal0 = error2({OoMGoalErrSpecs, GoalWarnSpecs}),
+                GoalErrSpecs = one_or_more_to_list(OoMGoalErrSpecs)
             ),
-            Specs = PuritySpecs ++ get_any_errors1(MaybeUnivVars) ++ GoalSpecs,
-            det_list_to_one_or_more(Specs, OoMSpecs),
-            MaybeIOM = error1(OoMSpecs)
+            ErrSpecs = PuritySpecs ++ get_any_errors1(MaybeUnivVars) ++
+                GoalErrSpecs,
+            det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),
+            MaybeIOM = error1({OoMErrSpecs, GoalWarnSpecs})
         )
     else
         Pieces = [words("Error: a")] ++
@@ -2004,9 +2031,22 @@ parse_promise_ex_item(VarSet, Functor, ArgTerms, Context, SeqNum,
                 words("which should be a goal.")]) ++
             [nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        MaybeIOM = error1(one_or_more(Spec, []))
+        MaybeIOM = error1({one_or_more(Spec, []), []})
     ).
 
+:- func report_warning_in_promise(prog_context, list(warn_spec))
+    = err_warn_error.
+
+report_warning_in_promise(Context, GoalWarnSpecs) = ErrWarnError :-
+    Pieces = [words("Error: any")] ++
+        color_as_subject([words("warning")]) ++
+        [words("for the code inside a"),
+        decl("promise"), words("declaration"),
+        words("makes that promise")] ++
+        color_as_incorrect([words("invalid.")]) ++ [nl],
+    Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
+    ErrWarnError = {one_or_more(Spec, []), GoalWarnSpecs}.
+
 %---------------------------------------------------------------------------%
 
     % parse_determinism_suffix(VarSet, ContextPieces, BodyTerm,
@@ -2245,7 +2285,7 @@ is_the_name_a_variable(VarSet, Kind, Term, Spec) :-
 
 %---------------------------------------------------------------------------%
 
-:- func report_with_inst_and_detism(format_piece, term(T)) = diag_spec.
+:- func report_with_inst_and_detism(format_piece, term(T)) = err_spec.
 
 report_with_inst_and_detism(DeclKindPiece, Term) = Spec :-
     Pieces = [words("Error: a"), DeclKindPiece, words("declaration"),
@@ -2259,7 +2299,7 @@ report_with_inst_and_detism(DeclKindPiece, Term) = Spec :-
     Context = get_term_context(Term),
     Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces).
 
-:- func report_with_inst_no_arg_modes(pred_or_func, term(T)) = diag_spec.
+:- func report_with_inst_no_arg_modes(pred_or_func, term(T)) = err_spec.
 
 report_with_inst_no_arg_modes(PredOrFunc, Term) = Spec :-
     Pieces = [words("Error: a"), p_or_f(PredOrFunc), words("declaration"),
@@ -2271,7 +2311,7 @@ report_with_inst_no_arg_modes(PredOrFunc, Term) = Spec :-
     Context = get_term_context(Term),
     Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces).
 
-:- func report_with_inst_no_with_type(pred_or_func, term(T)) = diag_spec.
+:- func report_with_inst_no_with_type(pred_or_func, term(T)) = err_spec.
 
 report_with_inst_no_with_type(PredOrFunc, Term) = Spec :-
     % Keep as similar to report_with_type_no_with_inst as possible.
@@ -2285,7 +2325,7 @@ report_with_inst_no_with_type(PredOrFunc, Term) = Spec :-
     Context = get_term_context(Term),
     Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces).
 
-:- func report_with_type_no_with_inst(pred_or_func, term(T)) = diag_spec.
+:- func report_with_type_no_with_inst(pred_or_func, term(T)) = err_spec.
 
 report_with_type_no_with_inst(PredOrFunc, Term) = Spec :-
     % Keep as similar to report_with_inst_no_with_type as possible.
diff --git a/compiler/parse_module.m b/compiler/parse_module.m
index 657162d57..17ed9a3b9 100644
--- a/compiler/parse_module.m
+++ b/compiler/parse_module.m
@@ -233,7 +233,7 @@ peek_at_file(FileStream, SourceFileName0, MaybeDefaultModuleName,
         MaybeResult = error2(_PartialFileString, _FileStringLen, ErrorCode),
         io.error_message(ErrorCode, ErrorMsg0),
         ErrorMsg = "I/O error: " ++ ErrorMsg0,
-        io_error_to_diag_spec(phase_find_files(SourceFileName0, no),
+        io_error_to_err_spec(phase_find_files(SourceFileName0, no),
             ErrorMsg, Spec, !IO),
         MaybeModuleName = error1(one_or_more(Spec, []))
     ).
@@ -255,9 +255,10 @@ parse_int0_file(Globals, FileName, FileStr, FileStrLen,
     ;
         MaybeParseTreeInt = yes(ParseTreeInt),
         check_convert_parse_tree_int_to_int0(ParseTreeInt, ParseTreeInt0,
-            [], ConvertSpecs),
+            [], ConvertErrSpecs, [], ConvertWarnSpecs),
         MaybeParseTreeInt0 = yes(ParseTreeInt0),
-        maybe_add_convert_specs(Globals, ConvertSpecs, Errors0, Errors)
+        maybe_add_convert_specs(Globals, ConvertErrSpecs, ConvertWarnSpecs,
+            Errors0, Errors)
     ).
 
 parse_int1_file(Globals, FileName, FileStr, FileStrLen,
@@ -275,9 +276,10 @@ parse_int1_file(Globals, FileName, FileStr, FileStrLen,
     ;
         MaybeParseTreeInt = yes(ParseTreeInt),
         check_convert_parse_tree_int_to_int1(ParseTreeInt, ParseTreeInt1,
-            [], ConvertSpecs),
+            [], ConvertErrSpecs, [], ConvertWarnSpecs),
         MaybeParseTreeInt1 = yes(ParseTreeInt1),
-        maybe_add_convert_specs(Globals, ConvertSpecs, Errors0, Errors)
+        maybe_add_convert_specs(Globals, ConvertErrSpecs, ConvertWarnSpecs,
+            Errors0, Errors)
     ).
 
 parse_int2_file(Globals, FileName, FileStr, FileStrLen,
@@ -295,9 +297,10 @@ parse_int2_file(Globals, FileName, FileStr, FileStrLen,
     ;
         MaybeParseTreeInt = yes(ParseTreeInt),
         check_convert_parse_tree_int_to_int2(ParseTreeInt, ParseTreeInt2,
-            [], ConvertSpecs),
+            [], ConvertErrSpecs, [], ConvertWarnSpecs),
         MaybeParseTreeInt2 = yes(ParseTreeInt2),
-        maybe_add_convert_specs(Globals, ConvertSpecs, Errors0, Errors)
+        maybe_add_convert_specs(Globals, ConvertErrSpecs, ConvertWarnSpecs,
+            Errors0, Errors)
     ).
 
 parse_int3_file(Globals, FileName, FileStr, FileStrLen,
@@ -315,9 +318,10 @@ parse_int3_file(Globals, FileName, FileStr, FileStrLen,
     ;
         MaybeParseTreeInt = yes(ParseTreeInt),
         check_convert_parse_tree_int_to_int3(ParseTreeInt, ParseTreeInt3,
-            [], ConvertSpecs),
+            [], ConvertErrSpecs, [], ConvertWarnSpecs),
         MaybeParseTreeInt3 = yes(ParseTreeInt3),
-        maybe_add_convert_specs(Globals, ConvertSpecs, Errors0, Errors)
+        maybe_add_convert_specs(Globals, ConvertErrSpecs, ConvertWarnSpecs,
+            Errors0, Errors)
     ).
 
 %---------------------%
@@ -359,31 +363,33 @@ parse_trans_opt_file(FileName, FileStr, FileStrLen, DefaultModuleName,
     ;
         MaybeParseTreeOpt = yes(ParseTreeOpt),
         check_convert_parse_tree_opt_to_trans_opt(ParseTreeOpt,
-            ParseTreeTransOpt, [], ConvertSpecs),
+            ParseTreeTransOpt, [], ConvertErrSpecs),
         MaybeParseTreeTransOpt = yes(ParseTreeTransOpt),
-        add_any_nec_errors(ConvertSpecs, Errors0, Errors)
+        add_any_nec_errors(ConvertErrSpecs, Errors0, Errors)
     ).
 
 %---------------------------------------------------------------------------%
 
-:- pred maybe_add_convert_specs(globals::in, list(diag_spec)::in,
+:- pred maybe_add_convert_specs(globals::in,
+    list(err_spec)::in, list(warn_spec)::in,
     read_module_errors::in, read_module_errors::out) is det.
 
-maybe_add_convert_specs(Globals, ConvertSpecs, !Errors) :-
+maybe_add_convert_specs(Globals, ConvertErrSpecs, ConvertWarnSpecs, !Errors) :-
     globals.lookup_bool_option(Globals, halt_at_invalid_interface,
         HaltAtInvalidInterface),
     (
         HaltAtInvalidInterface = no
     ;
         HaltAtInvalidInterface = yes,
-        add_any_nec_errors(ConvertSpecs, !Errors)
+        add_any_nec_errors(ConvertErrSpecs, !Errors),
+        add_warnings(ConvertWarnSpecs, !Errors)
     ).
 
 %---------------------------------------------------------------------------%
 
 :- pred report_module_has_unexpected_name(file_name::in,
     module_name::in, list(prog_context)::in,
-    module_name::in, maybe(term.context)::in, diag_spec::out) is det.
+    module_name::in, maybe(term.context)::in, err_spec::out) is det.
 
 report_module_has_unexpected_name(FileName, ExpectedName, ExpectationContexts,
         ActualName, MaybeActualContext, Spec) :-
@@ -410,7 +416,7 @@ report_module_has_unexpected_name(FileName, ExpectedName, ExpectationContexts,
     list.map(expectation_context_to_msg, SortedExpectationContexts, SubMsgs),
     % We only get invoked if the module *has* an expected name.
     % When invoked as "mmc -f", it doesn't have one.
-    Spec = diag_spec($pred, severity_error, phase_module_name,
+    Spec = gen_spec($pred, severity_error, phase_module_name,
         [MainMsg | SubMsgs]).
 
 :- pred expectation_context_to_msg(prog_context::in, diag_msg::out) is det.
@@ -531,7 +537,7 @@ parse_int_file(IntFileKind, SourceFileName, FileString, FileStringLen,
 
 :- type version_number_result
     --->    vnr_ok(maybe_version_numbers)
-    ;       vnr_error(diag_spec, nonfatal_read_module_error).
+    ;       vnr_error(err_spec, nonfatal_read_module_error).
 
 :- pred parse_any_version_number_item(string::in, int::in,
     module_name::in, file_name::in, maybe_lookahead::in, maybe_lookahead::out,
@@ -560,7 +566,7 @@ parse_any_version_number_item(FileString, FileStringLen,
         FinalLookAhead = no_lookahead,
         VersionNumberResult = vnr_error(ItemSpec, rme_could_not_read_term)
     ;
-        ReadIOMResult = read_iom_parse_item_errors(_, _, _),
+        ReadIOMResult = read_iom_parse_item_errors(_, _, _, _),
         % Ignore the errors; our caller will compute them again,
         % and record them, if and when it parses FinalLookAhead again.
         FinalLookAhead = lookahead(ReadIOMResult),
@@ -583,7 +589,7 @@ parse_any_version_number_item(FileString, FileStringLen,
             ; IOM = iom_marker_avail(_)
             ; IOM = iom_marker_fim(_)
             ; IOM = iom_item(_)
-            ; IOM = iom_item_and_diag_specs(_, _)
+            ; IOM = iom_item_and_err_specs(_, _)
             % The reasoning for read_iom_parse_item_errors also applies
             % to iom_item_and_specs.
             ; IOM = iom_handled_no_error
@@ -709,8 +715,10 @@ parse_int_file_section(FileString, FileStringLen,
             add_nonfatal_error(rme_could_not_read_term, ItemSpec, !Errors)
         ;
             ReadIOMResult = read_iom_parse_item_errors(_IOMVarSet, _IOMTerm,
-                ItemSpecs),
-            add_nonfatal_errors(rme_could_not_parse_item, ItemSpecs, !Errors)
+                OoMErrSpecs, WarnSpecs),
+            add_nonfatal_errors(rme_could_not_parse_item, OoMErrSpecs,
+                !Errors),
+            add_warnings(WarnSpecs, !Errors)
         ),
         MaybeRawItemBlock = no,
         FinalLookAhead = no_lookahead
@@ -738,9 +746,9 @@ parse_int_file_section(FileString, FileStringLen,
             ; IOM = iom_marker_avail(_)
             ; IOM = iom_marker_fim(_)
             ; IOM = iom_item(_)
-            % The fact that IOM is not a section marker trumps any diag_specs
-            % in iom_item_and_diag_specs, and in iom_handled_error.
-            ; IOM = iom_item_and_diag_specs(_, _)
+            % The fact that IOM is not a section marker trumps any err_specs
+            % in iom_item_and_err_specs, and in iom_handled_error.
+            ; IOM = iom_item_and_err_specs(_, _)
             ; IOM = iom_handled_no_error
             ; IOM = iom_handled_error(_)
             ),
@@ -874,7 +882,7 @@ parse_src_file_components(FileString, FileStringLen,
             !SeqNumCounter, !Errors, !LineContext, !LinePosn)
     ;
         ReadIOMResult = read_iom_parse_item_errors(_IOMVarSet, IOMTerm,
-            _Specs),
+            _OoMErrSpecs, _WarnSpecs),
         % Generate an error for the missing section marker.
         % Leave the term in the lookahead, but otherwise handle the term
         % as it were an unexpected but perfectly parseable term, i.e. follow
@@ -972,7 +980,7 @@ parse_src_file_components(FileString, FileStringLen,
             ; IOM = iom_marker_avail(_)
             ; IOM = iom_marker_fim(_)
             ; IOM = iom_item(_)
-            ; IOM = iom_item_and_diag_specs(_, _)
+            ; IOM = iom_item_and_err_specs(_, _)
             ; IOM = iom_handled_no_error
             ; IOM = iom_handled_error(_)
             ),
@@ -992,7 +1000,7 @@ parse_src_file_components(FileString, FileStringLen,
                     IOM = iom_handled_error(ItemSpecs),
                     add_nonfatal_errors(rme_nec, ItemSpecs, !Errors)
                 ;
-                    IOM = iom_item_and_diag_specs(_, ItemSpecs),
+                    IOM = iom_item_and_err_specs(_, ItemSpecs),
                     add_nonfatal_errors(rme_nec, ItemSpecs, !Errors)
                 ),
                 (
@@ -1244,7 +1252,7 @@ parse_module_header(FileString, FileStringLen,
 
                 % A message for the error. The error category is
                 % always rme_no_module_decl_at_start.
-                diag_spec
+                err_spec
             )
     ;       wrong_module_decl_present(
                 % The name in the ":- module" decl, and its context.
@@ -1253,7 +1261,7 @@ parse_module_header(FileString, FileStringLen,
 
                 % A message for the error, which may be conditional.
                 % The category is always rme_unexpected_module_name.
-                diag_spec
+                err_spec
             )
     ;       right_module_decl_present(
                 % The name in the ":- module" decl, and its context.
@@ -1295,7 +1303,7 @@ parse_first_module_decl(FileString, FileStringLen,
     % - there are only two kinds of item_or_markers that we do not return
     %   for reprocessing, src file pragmas and ":- module" declarations, and
     % - these contain neither sym_names to be module qualified, nor
-    %   any diag_specs that may contain the module name.
+    %   any err_specs that may contain the module name.
     DummyDefaultModuleName = unqualified(""),
     read_term_to_iom_result(DummyDefaultModuleName, !.SourceFileName,
         FirstReadTerm, MaybeFirstIOM, !SeqNumCounter),
@@ -1345,10 +1353,10 @@ parse_first_module_decl(FileString, FileStringLen,
             ; FirstIOM = iom_marker_avail(_)
             ; FirstIOM = iom_marker_fim(_)
             ; FirstIOM = iom_item(_)
-            % Ignore the diag_specs.
-            ; FirstIOM = iom_item_and_diag_specs(_, _)
+            % Ignore the err_specs.
+            ; FirstIOM = iom_item_and_err_specs(_, _)
             ; FirstIOM = iom_handled_no_error
-            % Ignore the diag_specs.
+            % Ignore the err_specs.
             ; FirstIOM = iom_handled_error(_)
             ),
             FirstLookAhead = lookahead(MaybeFirstIOM),
@@ -1358,7 +1366,7 @@ parse_first_module_decl(FileString, FileStringLen,
                 report_missing_module_start(FirstContext))
         )
     ;
-        MaybeFirstIOM = read_iom_parse_item_errors(_, FirstTerm, _),
+        MaybeFirstIOM = read_iom_parse_item_errors(_, FirstTerm, _, _),
         LookAhead = lookahead(MaybeFirstIOM),
         FirstContext = get_term_context(FirstTerm),
         ModuleDeclPresent = no_module_decl_present(LookAhead, FirstContext,
@@ -1439,9 +1447,11 @@ parse_item_sequence_inner(FileString, FileStringLen, ModuleName,
                 add_nonfatal_error(rme_could_not_read_term, ItemSpec,
                     !Errors)
             ;
-                ReadIOMResult = read_iom_parse_item_errors(_, _, ItemSpecs),
-                add_nonfatal_errors(rme_could_not_parse_item, ItemSpecs,
-                    !Errors)
+                ReadIOMResult = read_iom_parse_item_errors(_, _,
+                    OoMErrSpecs, WarnSpecs),
+                add_nonfatal_errors(rme_could_not_parse_item, OoMErrSpecs,
+                    !Errors),
+                add_warnings(WarnSpecs, !Errors)
             ),
             parse_next_item_or_marker(!.SourceFileName,
                 FileString, FileStringLen, ModuleName, NextReadIOMResult,
@@ -1491,9 +1501,9 @@ parse_item_sequence_inner(FileString, FileStringLen, ModuleName,
                     IOM = iom_item(Item),
                     cord.snoc(Item, !ItemsCord)
                 ;
-                    IOM = iom_item_and_diag_specs(Item, ItemSpecs),
+                    IOM = iom_item_and_err_specs(Item, OoMErrSpecs),
                     cord.snoc(Item, !ItemsCord),
-                    add_nonfatal_errors(rme_nec, ItemSpecs, !Errors)
+                    add_nonfatal_errors(rme_nec, OoMErrSpecs, !Errors)
                 ;
                     IOM = iom_handled_no_error
                 ;
@@ -1551,11 +1561,12 @@ parse_next_item_or_marker(FileName, FileString, FileStringLen, ModuleName,
 :- type read_iom_result
     --->    read_iom_eof
             % We have reached end-of-file.
-    ;       read_iom_parse_term_error(diag_spec)
+    ;       read_iom_parse_term_error(err_spec)
             % The call to mercury_term_parser.read_term_from_linestr
             % has failed, which means that what we found in the file string
             % is not a valid term.
-    ;       read_iom_parse_item_errors(varset, term, one_or_more(diag_spec))
+    ;       read_iom_parse_item_errors(varset, term,
+                one_or_more(err_spec), list(warn_spec))
             % We have successfully read a term from the file string,
             % but could not parse it as an item or marker.
             % The error category is implicitly rme_could_not_parse_item.
@@ -1583,13 +1594,15 @@ read_term_to_iom_result(ModuleName, FileName, ReadTermResult, ReadIOMResult,
         ReadTermResult = term(VarSet, Term),
         counter.allocate(SeqNum, !SeqNumCounter),
         parse_item_or_marker(ModuleName, VarSet, Term, item_seq_num(SeqNum),
-            MaybeItemOrMarker),
+            MaybeItemOrMarker, [], WarnSpecs),
         (
             MaybeItemOrMarker = ok1(ItemOrMarker),
+            % XXX DIAG_SPEC This ignores WarnSpecs.
             ReadIOMResult = read_iom_ok(VarSet, Term, ItemOrMarker)
         ;
-            MaybeItemOrMarker = error1(Specs),
-            ReadIOMResult = read_iom_parse_item_errors(VarSet, Term, Specs)
+            MaybeItemOrMarker = error1(OoMErrSpecs),
+            ReadIOMResult = read_iom_parse_item_errors(VarSet, Term,
+                OoMErrSpecs, WarnSpecs)
         )
     ).
 
@@ -1624,7 +1637,7 @@ line_to_pieces(Line, Pieces) :-
 
 %---------------------------------------------------------------------------%
 
-:- func report_missing_module_start(prog_context) = diag_spec.
+:- func report_missing_module_start(prog_context) = err_spec.
 
 report_missing_module_start(FirstContext) = Spec :-
     Pieces = [invis_order_default_start(0, ""),
@@ -1635,7 +1648,7 @@ report_missing_module_start(FirstContext) = Spec :-
     Spec = spec($pred, severity_error, phase_t2pt, FirstContext, Pieces).
 
 :- func report_wrong_module_start(prog_context, module_name, module_name)
-    = diag_spec.
+    = err_spec.
 
 report_wrong_module_start(FirstContext, Expected, Actual) = Spec :-
     Pieces = [words("Error: module starts with a"), decl("module"),
@@ -1677,8 +1690,10 @@ check_for_unexpected_item_at_end(SourceFileName, FileString, FileStringLen,
         IOMResult = read_iom_parse_term_error(ItemSpec),
         add_nonfatal_error(rme_could_not_read_term, ItemSpec, !Errors)
     ;
-        IOMResult = read_iom_parse_item_errors(_VarSet, Term, ItemSpecs),
-        add_nonfatal_errors(rme_could_not_parse_item, ItemSpecs, !Errors),
+        IOMResult = read_iom_parse_item_errors(_VarSet, Term,
+            OoMErrSpecs, WarnSpecs),
+        add_nonfatal_errors(rme_could_not_parse_item, OoMErrSpecs, !Errors),
+        add_warnings(WarnSpecs, !Errors),
         report_unexpected_term_at_end(FileKind, Term, !Errors)
     ;
         IOMResult = read_iom_ok(_IOMVarSet, IOMTerm, _IOM),
diff --git a/compiler/parse_mutable.m b/compiler/parse_mutable.m
index d71310de4..0803b4e63 100644
--- a/compiler/parse_mutable.m
+++ b/compiler/parse_mutable.m
@@ -397,7 +397,7 @@ parse_mutable_attrs(VarSet, MutAttrsTerm, MaybeMutAttrs) :-
     maybe(pair(term, unit))::out,
     maybe(pair(term, unit))::in,
     maybe(pair(term, unit))::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 record_mutable_attributes(_VarSet, [], !LangMap,
         !MaybeTrailed, !MaybeConstant, !MaybeIO, !MaybeLocal, !Specs).
@@ -563,7 +563,7 @@ default_mutable_attributes =
     ).
 
 :- pred report_repeated_or_conflicting_attributes(varset::in, term::in, T::in,
-    term::in, T::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    term::in, T::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 report_repeated_or_conflicting_attributes(VarSet, Term0, Attr0, Term, Attr,
         !Specs) :-
@@ -582,7 +582,7 @@ report_repeated_or_conflicting_attributes(VarSet, Term0, Attr0, Term, Attr,
     ).
 
 :- pred report_conflicting_attributes(varset::in, term::in, term::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_conflicting_attributes(VarSet, Term0, Term, !Specs) :-
     TermStr0 = mercury_term_to_string_vs(VarSet, print_name_only, Term0),
diff --git a/compiler/parse_pragma.m b/compiler/parse_pragma.m
index cc2858fec..d4f383469 100644
--- a/compiler/parse_pragma.m
+++ b/compiler/parse_pragma.m
@@ -305,7 +305,7 @@ parse_named_pragma(ModuleName, VarSet, ErrorTerm, PragmaName, PragmaTerms,
         )
     ).
 
-:- func report_unrecognized_pragma_form(prog_context) = diag_spec.
+:- func report_unrecognized_pragma_form(prog_context) = err_spec.
 
 report_unrecognized_pragma_form(Context) = Spec :-
     Pieces = [words("Error: a"), decl("pragma"), words("declaration")] ++
@@ -1052,7 +1052,7 @@ parse_pragma_require_tail_recursion(ModuleName, PragmaName, PragmaTerms,
 :- pred parse_pragma_require_tail_recursion_options(varset::in,
     prog_context::in, list(term)::in,
     maybe(warning_or_error)::in, maybe(require_tail_recursion_type)::in,
-    maybe(report_in_which_grades)::in, list(diag_spec)::in,
+    maybe(report_in_which_grades)::in, list(err_spec)::in,
     maybe1(require_tail_recursion)::out) is det.
 
 parse_pragma_require_tail_recursion_options(_VarSet, PragmaContext, [],
@@ -1147,7 +1147,7 @@ parse_pragma_require_tail_recursion_options(VarSet, PragmaContext,
         !.MaybeWarnOrError, !.MaybeType, !.MaybeGrades, !.Specs, MaybeRTR).
 
 :- func conflicting_attributes_error(string, string, prog_context) =
-    diag_spec.
+    err_spec.
 
 conflicting_attributes_error(ThisName, EarlierName, Context) = Spec :-
     Pieces = [words("Error:")] ++
@@ -1160,7 +1160,7 @@ conflicting_attributes_error(ThisName, EarlierName, Context) = Spec :-
     Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces).
 
 :- func pragma_require_tailrec_unknown_term_error(varset, term, prog_context) =
-    diag_spec.
+    err_spec.
 
 pragma_require_tailrec_unknown_term_error(VarSet, Term, Context) = Spec :-
     TermStr = describe_error_term(VarSet, Term),
@@ -1378,7 +1378,7 @@ parse_pragma_type_spec_constr(ModuleName, VarSet0, ErrorTerm, PragmaTerms,
 %---------------------%
 
 :- pred parse_var_or_ground_constraint_list(set(string)::in, term::in,
-    list(var_or_ground_constraint)::out, list(diag_spec)::out,
+    list(var_or_ground_constraint)::out, list(err_spec)::out,
     counter::in, counter::out, varset::in, varset::out) is det.
 
 parse_var_or_ground_constraint_list(NamedVarNames, Term, Constraints, Specs,
@@ -1425,7 +1425,7 @@ parse_var_or_ground_constraint_list(NamedVarNames, Term, Constraints, Specs,
 
 :- pred parse_var_or_ground_constraint_acc(set(string)::in, term::in,
     cord(var_or_ground_constraint)::in, cord(var_or_ground_constraint)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
     counter::in, counter::out, varset::in, varset::out) is det.
 
 parse_var_or_ground_constraint_acc(NamedVarNames, Term,
@@ -1540,7 +1540,7 @@ parse_var_or_ground_types(AllowHOInstInfo, VarSet, ContextPieces, ClassId,
     ).
 
 :- pred parse_type_subst_list(set(string)::in, term::in,
-    list(type_subst)::out, list(diag_spec)::out,
+    list(type_subst)::out, list(err_spec)::out,
     counter::in, counter::out, varset::in, varset::out) is det.
 
 parse_type_subst_list(NamedVarNames, Term, TypeSubsts, Specs,
@@ -1590,7 +1590,7 @@ parse_type_subst_list(NamedVarNames, Term, TypeSubsts, Specs,
 
 :- pred parse_type_subst_acc(why_no_ho_inst_info::in, list(format_piece)::in,
     set(string)::in, term::in, cord(type_subst)::in, cord(type_subst)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
     counter::in, counter::out, varset::in, varset::out) is det.
 
 parse_type_subst_acc(WNHII, PrefixPieces, NamedVarNames, Term,
@@ -1754,7 +1754,7 @@ var_or_ground_type_acc_tvars(VoGType, !TVars) :-
     ).
 
 :- pred check_type_substs(tvarset::in, set(tvar)::in, term::in, int::in,
-    list(type_subst)::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(type_subst)::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 check_type_substs(_, _, _, _, [], !TypeSubstTVarSpecs).
 check_type_substs(TVarSet, ConstraintTVars, ErrorTerm,
@@ -1765,7 +1765,7 @@ check_type_substs(TVarSet, ConstraintTVars, ErrorTerm,
         SubstNum + 1, TypeSubsts, !TypeSubstTVarSpecs).
 
 :- pred check_type_subst(tvarset::in, set(tvar)::in, term::in, int::in,
-    type_subst::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    type_subst::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 check_type_subst(TVarSet, ConstraintTVars, ErrorTerm, SubstNum, TypeSubst,
         !Specs) :-
@@ -1778,7 +1778,7 @@ check_type_subst(TVarSet, ConstraintTVars, ErrorTerm, SubstNum, TypeSubst,
     BadRHSTVarList = set.to_sorted_list(BadRHSTVars),
     % If a type_spec_constrained_preds pragma contains N substitutions
     % in its third argument, then the process of checking those substitutions
-    % can generate up to 2N diag_specs: one for each lhs or rhs in those
+    % can generate up to 2N err_specs: one for each lhs or rhs in those
     % N substitutions. We don't have a context for any part of the third
     % argument, just the context of the third argument as a whole (our caller
     % passes us the term containing that argument as ErrorTerm). We want to
@@ -1962,7 +1962,7 @@ parse_pragma_type_spec(ModuleName, VarSet0, ErrorTerm, PragmaTerms,
 
 :- pred parse_tvar_substs(why_no_ho_inst_info::in, list(format_piece)::in,
     varset::in, term::in, list(term)::in, list(tvar_subst)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 parse_tvar_substs(WNHII, ContextPieces, VarSet, HeadTerm, TailTerms,
         TVarSubsts, !Specs) :-
@@ -1976,7 +1976,7 @@ parse_tvar_substs(WNHII, ContextPieces, VarSet, HeadTerm, TailTerms,
 :- pred parse_tvar_subst_acc(why_no_ho_inst_info::in, list(format_piece)::in,
     varset::in, term::in,
     cord(tvar_subst)::in, cord(tvar_subst)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 parse_tvar_subst_acc(WNHII, ContextPieces, VarSet, Term,
         !TVarSubstCord, !Specs) :-
@@ -2279,7 +2279,7 @@ string_to_required_feature("conservative_gc",   reqf_conservative_gc).
 
 %---------------------------------------------------------------------------%
 
-:- func report_pragma_arity_error(term(T), string, string) = diag_spec.
+:- func report_pragma_arity_error(term(T), string, string) = err_spec.
 
 report_pragma_arity_error(ErrorTerm, PragmaName, ArgNumsStr) = Spec :-
     ( if
diff --git a/compiler/parse_pragma_foreign.m b/compiler/parse_pragma_foreign.m
index 893e87c61..bb5ca3e0c 100644
--- a/compiler/parse_pragma_foreign.m
+++ b/compiler/parse_pragma_foreign.m
@@ -42,7 +42,7 @@
 :- pred parse_foreign_type_assertions(cord(format_piece)::in,
     varset::in, term::in,
     set(foreign_type_assertion)::in, set(foreign_type_assertion)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------%
 
diff --git a/compiler/parse_pragma_tabling.m b/compiler/parse_pragma_tabling.m
index dd23be6ad..9c47aa0d8 100644
--- a/compiler/parse_pragma_tabling.m
+++ b/compiler/parse_pragma_tabling.m
@@ -517,7 +517,7 @@ parse_tabling_attr_backend_warning(ContextPieces, TabledMethod, _VarSet,
 %---------------------------------------------------------------------------%
 
 :- pred require_tabling_fast_loose(cord(format_piece)::in,
-    tabled_eval_method::in, term.context::in, list(diag_spec)::out) is det.
+    tabled_eval_method::in, term.context::in, list(err_spec)::out) is det.
 
 require_tabling_fast_loose(ContextPieces, TabledMethod, Context, Specs) :-
     AllowsFastLoose = eval_method_allows_fast_loose(TabledMethod),
@@ -573,7 +573,7 @@ eval_method_allows_disable_warning_if_ignored(tabled_minimal(_)) = no.
 :- pred update_tabling_attributes(
     assoc_list(term.context, single_tabling_attribute)::in,
     table_attributes::in, table_attributes::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 update_tabling_attributes([], !Attributes, !Specs).
 update_tabling_attributes([Context - Attr | ContextAttrs],
@@ -628,7 +628,7 @@ update_tabling_attributes([Context - Attr | ContextAttrs],
     update_tabling_attributes(ContextAttrs, !Attributes, !Specs).
 
 :- pred report_duplicate_memo_attribute(prog_context::in, string::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_duplicate_memo_attribute(Context, Attr, !Specs) :-
     Pieces = [words("In"), pragma_decl("memo"), words("declaration:"), nl,
diff --git a/compiler/parse_sym_name.m b/compiler/parse_sym_name.m
index a6485c93c..59ad5b0e1 100644
--- a/compiler/parse_sym_name.m
+++ b/compiler/parse_sym_name.m
@@ -496,7 +496,7 @@ parse_sym_name_maybe_arity(VarSet, Term, MaybeSymNameArity) :-
 %-----------------------------------------------------------------------------e
 
 :- func report_no_module_name_before_dot(cord(format_piece),
-    varset(T), term(U)) = diag_spec.
+    varset(T), term(U)) = err_spec.
 
 report_no_module_name_before_dot(ContextPieces, VarSet0, ModuleTerm) = Spec :-
     varset.coerce(VarSet0, VarSet),
@@ -511,7 +511,7 @@ report_no_module_name_before_dot(ContextPieces, VarSet0, ModuleTerm) = Spec :-
     Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces).
 
 :- func report_bad_name_after_dot(cord(format_piece), varset(T), term(U))
-    = diag_spec.
+    = err_spec.
 
 report_bad_name_after_dot(ContextPieces, VarSet0, NameArgsTerm) = Spec :-
     varset.coerce(VarSet0, VarSet),
@@ -526,7 +526,7 @@ report_bad_name_after_dot(ContextPieces, VarSet0, NameArgsTerm) = Spec :-
     Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces).
 
 :- func report_no_sym_name(cord(format_piece), varset(T), term(U))
-    = diag_spec.
+    = err_spec.
 
 report_no_sym_name(ContextPieces, VarSet0, Term) = Spec :-
     varset.coerce(VarSet0, VarSet),
@@ -541,7 +541,7 @@ report_no_sym_name(ContextPieces, VarSet0, Term) = Spec :-
     Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces).
 
 :- func report_unexpected_args(cord(format_piece), term(T), sym_name)
-    = diag_spec.
+    = err_spec.
 
 report_unexpected_args(ContextPieces, Term, SymName) = Spec :-
     Pieces = cord.list(ContextPieces) ++
@@ -552,7 +552,7 @@ report_unexpected_args(ContextPieces, Term, SymName) = Spec :-
     Context = get_term_context(Term),
     Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces).
 
-:- func report_negative_arity(term(T), int) = diag_spec.
+:- func report_negative_arity(term(T), int) = err_spec.
 
 report_negative_arity(Term, Arity) = Spec :-
     ArityStr = string.int_to_string(Arity),
@@ -564,7 +564,7 @@ report_negative_arity(Term, Arity) = Spec :-
     Context = get_term_context(Term),
     Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces).
 
-:- func report_noninteger_arity_term(varset(T), term(U)) = diag_spec.
+:- func report_noninteger_arity_term(varset(T), term(U)) = err_spec.
 
 report_noninteger_arity_term(VarSet0, Term) = Spec :-
     varset.coerce(VarSet0, VarSet),
@@ -578,7 +578,7 @@ report_noninteger_arity_term(VarSet0, Term) = Spec :-
     Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces).
 
 :- func report_failed_implicit_qualification(module_name, term(T), sym_name)
-    = diag_spec.
+    = err_spec.
 
 report_failed_implicit_qualification(ExpectedSymName, Term, SymName) = Spec :-
     Pieces = [words("Error: the module qualifier in")] ++
diff --git a/compiler/parse_tree_out.m b/compiler/parse_tree_out.m
index 8eff7feaa..49609103c 100644
--- a/compiler/parse_tree_out.m
+++ b/compiler/parse_tree_out.m
@@ -323,7 +323,7 @@ mercury_format_parse_tree_module_src(Info, S, ParseTreeModuleSrc, !U) :-
         IntFIMSpecMap, ImpFIMSpecMap, IntSelfFIMLangs, ImpSelfFIMLangs,
 
         TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,
-        _TypeSpecs, _InstModeSpecs,
+        _TypeErrSpecs, _TypeWarnSpecs, _InstModeErrSpecs, _InstModeWarnSpecs,
 
         IntTypeClasses, IntInstances, IntPredDecls, IntModeDecls,
         IntDeclPragmas, IntDeclMarkers, IntPromises, _IntBadPreds,
diff --git a/compiler/parse_tree_out_clause.m b/compiler/parse_tree_out_clause.m
index 5b71d1883..d41d23fa4 100644
--- a/compiler/parse_tree_out_clause.m
+++ b/compiler/parse_tree_out_clause.m
@@ -117,7 +117,7 @@ mercury_format_instance_method_clause(MethodName, ItemClause, S, !U) :-
             FuncArgTerms, ResultTerm, BodyGoal, !U)
     ).
 
-:- pred get_clause_body_goal(maybe2(goal, T)::in, goal::out) is det.
+:- pred get_clause_body_goal(parse_result2(goal)::in, goal::out) is det.
 
 get_clause_body_goal(MaybeBodyGoal, BodyGoal) :-
     (
diff --git a/compiler/parse_type_defn.m b/compiler/parse_type_defn.m
index a2c1a3103..6de65fb51 100644
--- a/compiler/parse_type_defn.m
+++ b/compiler/parse_type_defn.m
@@ -261,7 +261,7 @@ parse_du_type_defn(ModuleName, VarSet, HeadTerm, BodyTerm, Context, SeqNum,
             ;
                 RecoverableSpecs = [HeadSpec | TailSpecs],
                 OoMRecoverableSpecs = one_or_more(HeadSpec, TailSpecs),
-                IOM = iom_item_and_diag_specs(Item, OoMRecoverableSpecs)
+                IOM = iom_item_and_err_specs(Item, OoMRecoverableSpecs)
             ),
             MaybeIOM = ok1(IOM)
         ;
@@ -582,7 +582,7 @@ convert_constructor_arg_list_2(ModuleName, VarSet, MaybeCtorFieldName,
 %---------------------%
 
 :- pred process_du_ctors(list(type_param)::in, varset::in, term::in,
-    list(constructor)::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(constructor)::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 process_du_ctors(_Params, _, _, [], !Specs).
 process_du_ctors(Params, VarSet, BodyTerm, [Ctor | Ctors], !Specs) :-
@@ -735,7 +735,7 @@ process_du_ctors(Params, VarSet, BodyTerm, [Ctor | Ctors], !Specs) :-
 
 :- pred check_direct_arg_ctors(list(constructor)::in,
     list(sym_name_arity)::in, term::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 check_direct_arg_ctors(_Ctors, [], _ErrorTerm, !Specs).
 check_direct_arg_ctors(Ctors, [DirectArgCtor | DirectArgCtors], ErrorTerm,
@@ -804,7 +804,7 @@ find_constructor([Ctor | Ctors], SymName, Arity, NamedCtor) :-
     sym_name::in, list(tvar)::in, one_or_more(constructor)::in,
     maybe_canonical::in, maybe(list(sym_name_arity))::in,
     mer_type::in, prog_context::in, type_defn::out,
-    list(diag_spec)::in, list(diag_spec)::out, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out, list(err_spec)::out) is det.
 
 check_subtype(VarSet, Context, TypeSymName, Params, OneOrMoreCtors,
         MaybeCanonical, MaybeDirectArgIs, SuperType, SuperTypeContext,
@@ -861,7 +861,7 @@ check_subtype(VarSet, Context, TypeSymName, Params, OneOrMoreCtors,
 %---------------------%
 
 :- pred check_supertype_vars(list(type_param)::in, varset::in, mer_type::in,
-    prog_context::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    prog_context::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 check_supertype_vars(Params, VarSet, SuperType, Context, !Specs) :-
     type_vars_in_type(SuperType, VarsInSuperType0),
@@ -1289,7 +1289,7 @@ parse_where_unify_compare(ModuleName, VarSet, Term0, MaybeMaybeCanonical) :-
                     [quote("comparison is <<comparison pred name>>"),
                     suffix(".")]) ++
                 [nl_indent_delta(-1)],
-            EndSpec = diag_spec($pred, severity_error, phase_t2pt,
+            EndSpec = gen_spec($pred, severity_error, phase_t2pt,
                 [simple_msg(get_term_context(EndTerm),
                     [always(Pieces),
                     verbose_only(verbose_always, VerbosePieces)])]),
@@ -1699,7 +1699,7 @@ make_maybe_where_details_2(IsSolverType, TypeIsAbstractNoncanonical,
         )
     ).
 
-:- func abstract_noncanonical_excludes_others(term) = diag_spec.
+:- func abstract_noncanonical_excludes_others(term) = err_spec.
 
 abstract_noncanonical_excludes_others(Term) = Spec :-
     Pieces = [words("Error:"),
@@ -1830,7 +1830,7 @@ parse_type_defn_head(ContextPieces, ModuleName, VarSet, Term,
     % Check that the type name is available to users.
     %
 :- pred check_user_type_name(sym_name::in, term.context::in,
-    list(diag_spec)::out) is det.
+    list(err_spec)::out) is det.
 
 check_user_type_name(SymName, Context, NameSpecs) :-
     % Check that the mode name is available to users.
@@ -1851,7 +1851,7 @@ check_user_type_name(SymName, Context, NameSpecs) :-
         NameSpecs = []
     ).
 
-:- func report_reserved_type_name(prog_context, string) = diag_spec.
+:- func report_reserved_type_name(prog_context, string) = err_spec.
 
 report_reserved_type_name(Context, Name) = Spec :-
     Pieces = [words("Error: the type name")] ++
@@ -1865,7 +1865,7 @@ report_reserved_type_name(Context, Name) = Spec :-
     % Return a nonempty list of error specs if some do.
     %
 :- pred check_no_free_body_vars(tvarset::in, list(tvar)::in, mer_type::in,
-    prog_context::in, list(diag_spec)::out) is det.
+    prog_context::in, list(err_spec)::out) is det.
 
 check_no_free_body_vars(TVarSet, ParamTVars, BodyType, BodyContext, Specs) :-
     % Check that all the variables in the body occur in the head.
diff --git a/compiler/parse_type_name.m b/compiler/parse_type_name.m
index 20d1e150d..84edec09a 100644
--- a/compiler/parse_type_name.m
+++ b/compiler/parse_type_name.m
@@ -83,7 +83,7 @@
     maybe_require_tm_mode::in, why_no_ho_inst_info::in,
     varset::in, arg_context_func::in,
     list(term)::in, int::in, list(type_and_maybe_mode)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 :- pred parse_type_and_maybe_mode(maybe_constrain_inst_vars::in,
     maybe_require_tm_mode::in, why_no_ho_inst_info::in,
@@ -470,7 +470,7 @@ parse_ho_type_and_inst(VarSet, ContextPieces, BeforeIsTerm, AfterIsTerm,
     ).
 
 :- pred parse_ho_type_and_inst_2(cord(format_piece)::in,
-    purity::in, list(type_and_maybe_mode)::in, list(diag_spec)::in,
+    purity::in, list(type_and_maybe_mode)::in, list(err_spec)::in,
     maybe(maybe1(type_and_maybe_mode))::in, maybe1(determinism)::in,
     maybe1(mer_type)::out) is det.
 
@@ -534,7 +534,7 @@ project_tm_type_and_mode(type_only(_), _, _) :-
 
 :- pred parse_types_no_modes(why_no_ho_inst_info::in, varset::in,
     arg_context_func::in, list(term)::in, int::in, list(mer_type)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 parse_types_no_modes(_, _, _, [], _, [], !Specs).
 parse_types_no_modes(WhyNotHOInstInfo, VarSet, ArgContextFunc, [Term | Terms],
@@ -599,7 +599,7 @@ parse_types(AllowHOInstInfo, VarSet, ContextPieces, Terms, Result) :-
 :- pred parse_types_acc(allow_ho_inst_info::in, varset::in,
     cord(format_piece)::in, list(term)::in,
     list(mer_type)::in, list(mer_type)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 parse_types_acc(_, _, _, [], !RevTypes, !Specs).
 parse_types_acc(AllowHOInstInfo, VarSet, ContextPieces, [Term | Terms],
diff --git a/compiler/parse_type_repn.m b/compiler/parse_type_repn.m
index 5ba69f2d5..08be19fd2 100644
--- a/compiler/parse_type_repn.m
+++ b/compiler/parse_type_repn.m
@@ -581,7 +581,7 @@ parse_type_repn_du_gen_du_more_functors(VarSet, TermContext, AtomStr, ArgTerms,
 %---------------------%
 
 :- pred parse_du_functors(varset::in, list(term)::in,
-    list(gen_du_functor_repn)::out, list(diag_spec)::out) is det.
+    list(gen_du_functor_repn)::out, list(err_spec)::out) is det.
 
 parse_du_functors(_, [], [], []).
 parse_du_functors(VarSet, [Term | Terms], !:DuFunctors, !:Specs) :-
@@ -1263,7 +1263,7 @@ parse_remote_sectag_word_or_size(VarSet, Term, MaybeSectagSize) :-
 %-----------------------------------------------------------------------------e
 
 :- pred parse_local_arg_repns(varset::in, list(term)::in,
-    list(local_arg_repn)::out, list(diag_spec)::out) is det.
+    list(local_arg_repn)::out, list(err_spec)::out) is det.
 
 parse_local_arg_repns(_VarSet, [], [], []).
 parse_local_arg_repns(VarSet, [HeadTerm | TailTerms], LocalArgRepns, Specs) :-
@@ -1356,7 +1356,7 @@ parse_local_arg_repn_partial(VarSet, AtomStr, ArgTerms, TermContext,
 %-----------------------------------------------------------------------------e
 
 :- pred parse_remote_arg_repns(varset::in, list(term)::in,
-    list(remote_arg_repn)::out, list(diag_spec)::out) is det.
+    list(remote_arg_repn)::out, list(err_spec)::out) is det.
 
 parse_remote_arg_repns(_VarSet, [], [], []).
 parse_remote_arg_repns(VarSet, [HeadTerm | TailTerms],
@@ -1500,7 +1500,7 @@ parse_remote_arg_repn_double(VarSet, AtomStr, ArgTerms, TermContext,
                 quote("dw_uint64"), suffix("."), nl],
             DwSpec = spec($pred, severity_error, phase_t2pt,
                 get_term_context(ArgTerm3), DwPieces),
-            MaybeDW = error1([DwSpec])
+            MaybeDW = error1(one_or_more(DwSpec, []))
         ),
         ( if
             MaybeArgOnlyOffset = ok1(ArgOnlyOffset),
@@ -1513,7 +1513,8 @@ parse_remote_arg_repn_double(VarSet, AtomStr, ArgTerms, TermContext,
         else
             Specs =
                 get_any_errors1(MaybeArgOnlyOffset) ++
-                get_any_errors1(MaybeCellOffset),
+                get_any_errors1(MaybeCellOffset) ++
+                get_any_errors1(MaybeDW),
             det_list_to_one_or_more(Specs, OoMSpecs),
             MaybeRemoteArgRepn = error1(OoMSpecs)
         )
@@ -2311,7 +2312,7 @@ parse_c_repns(DescPieces, ParseRepn, VarSet, Term, MaybeCRepns) :-
 %-----------------------------------------------------------------------------e
 
 :- pred parse_strings(list(format_piece)::in, int::in, varset::in,
-    list(term)::in, list(string)::out, list(diag_spec)::out) is det.
+    list(term)::in, list(string)::out, list(err_spec)::out) is det.
 
 parse_strings(_, _, _, [], [], []).
 parse_strings(DescPieces, Nth, VarSet, [Term | Terms], !:Strs, !:Specs) :-
diff --git a/compiler/parse_types.m b/compiler/parse_types.m
index 4b6bd4a83..dc6cfee92 100644
--- a/compiler/parse_types.m
+++ b/compiler/parse_types.m
@@ -32,7 +32,7 @@
     --->    iom_item(item)
             % The term contains an item.
 
-    ;       iom_item_and_diag_specs(item, one_or_more(diag_spec))
+    ;       iom_item_and_err_specs(item, one_or_more(err_spec))
             % The term contains an item. This item has errors that we want
             % to report, but from which we have recovered in a useful
             % though probably not perfect manner.
@@ -74,7 +74,7 @@
             % and sequence number of the declaration.
 
     ;       iom_handled_no_error
-    ;       iom_handled_error(one_or_more(diag_spec)).
+    ;       iom_handled_error(one_or_more(err_spec)).
             % The term was completely dealt with during parsing.
             % If there was an error, one or more messages for it are attached.
             %
@@ -93,7 +93,7 @@
 iom_desc_pieces(IOM) = Pieces :-
     (
         ( IOM = iom_item(Item)
-        ; IOM = iom_item_and_diag_specs(Item, _Specs)
+        ; IOM = iom_item_and_err_specs(Item, _Specs)
         ),
         Pieces = item_desc_pieces(Item)
     ;
diff --git a/compiler/parse_util.m b/compiler/parse_util.m
index e8968e14a..0aa10032a 100644
--- a/compiler/parse_util.m
+++ b/compiler/parse_util.m
@@ -175,7 +175,7 @@
     % field of the relevent member of Conflicts.
     %
 :- pred report_any_conflicts(prog_context::in, string::in,
-    list(conflict(T))::in, list(T)::in, list(diag_spec)::out) is det.
+    list(conflict(T))::in, list(T)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -668,7 +668,7 @@ parse_list_elements(Where, What, Pred, VarSet, Term, Result) :-
     ).
 
 :- pred make_expected_got_spec(cord(format_piece)::in, varset::in, string::in,
-    term::in, diag_spec::out) is det.
+    term::in, err_spec::out) is det.
 
 make_expected_got_spec(Where, VarSet, What, Term, Spec) :-
     TermStr = describe_error_term(VarSet, Term),
@@ -691,7 +691,7 @@ report_any_conflicts(Context, ConflictingWhatInWhat, Conflicts, Specified,
 
 :- pred accumulate_conflict_specs(prog_context::in, string::in,
     list(T)::in, conflict(T)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 accumulate_conflict_specs(Context, ConflictingWhatInWhat, Specified,
         Conflict, !Specs) :-
@@ -861,7 +861,7 @@ terms_to_one_or_more_distinct_vars(VarSet, AAn, Kind, ConjTerm,
 
 :- pred terms_to_distinct_vars_loop(varset(T)::in, string::in, string::in,
     set(var(T))::in, list(term(T))::in,
-    list(var(T))::out, list(diag_spec)::out) is det.
+    list(var(T))::out, list(err_spec)::out) is det.
 
 terms_to_distinct_vars_loop(_, _, _, _, [], [], []).
 terms_to_distinct_vars_loop(VarSet, AAn, Kind, !.SeenVars, [Term | Terms],
@@ -887,7 +887,7 @@ terms_to_distinct_vars_loop(VarSet, AAn, Kind, !.SeenVars, [Term | Terms],
     ).
 
 :- func report_nonvar_parameter(varset(T), string, string, term(T))
-    = diag_spec.
+    = err_spec.
 
 report_nonvar_parameter(VarSet, AAn, Kind, Term) = Spec :-
     TermStr = describe_error_term(VarSet, Term),
@@ -899,7 +899,7 @@ report_nonvar_parameter(VarSet, AAn, Kind, Term) = Spec :-
     TermContext = get_term_context(Term),
     Spec = spec($pred, severity_error, phase_t2pt, TermContext, Pieces).
 
-:- func report_repeated_parameter(varset(T), string, term(T)) = diag_spec.
+:- func report_repeated_parameter(varset(T), string, term(T)) = err_spec.
 
 report_repeated_parameter(VarSet, Kind, Term) = Spec :-
     TermStr = describe_error_term(VarSet, Term),
diff --git a/compiler/parse_vars.m b/compiler/parse_vars.m
index 849a7bb2b..12b12bd9c 100644
--- a/compiler/parse_vars.m
+++ b/compiler/parse_vars.m
@@ -351,7 +351,7 @@ parse_vars_state_dot_colon_vars(Term, VarSet, ContextPieces, MaybeVars) :-
 %---------------------------------------------------------------------------%
 
 :- pred generate_repeated_var_msg(cord(format_piece)::in,
-    varset(T)::in, term(T)::in, diag_spec::out) is det.
+    varset(T)::in, term(T)::in, err_spec::out) is det.
 
 generate_repeated_var_msg(ContextPieces, VarSet, Term, Spec) :-
     TermStr = describe_error_term(VarSet, Term),
@@ -363,7 +363,7 @@ generate_repeated_var_msg(ContextPieces, VarSet, Term, Spec) :-
         get_term_context(Term), Pieces).
 
 :- pred generate_repeated_state_var_msg(cord(format_piece)::in,
-    varset(T)::in, term(T)::in, diag_spec::out) is det.
+    varset(T)::in, term(T)::in, err_spec::out) is det.
 
 generate_repeated_state_var_msg(ContextPieces, VarSet, Term, Spec) :-
     TermStr = describe_error_term(VarSet, Term),
@@ -375,7 +375,7 @@ generate_repeated_state_var_msg(ContextPieces, VarSet, Term, Spec) :-
         get_term_context(Term), Pieces).
 
 :- pred generate_unexpected_term_message(cord(format_piece)::in,
-    varset(T)::in, string::in, term(T)::in, diag_spec::out) is det.
+    varset(T)::in, string::in, term(T)::in, err_spec::out) is det.
 
 generate_unexpected_term_message(ContextPieces, VarSet, Expected, Term,
         Spec) :-
diff --git a/compiler/pd_util.m b/compiler/pd_util.m
index 90d45fabd..e11efac40 100644
--- a/compiler/pd_util.m
+++ b/compiler/pd_util.m
@@ -328,7 +328,7 @@ unique_modecheck_goal_live_vars(LiveVars, Goal0, Goal, Errors, !PDInfo) :-
         trace [io(!IO)] (
             module_info_get_globals(ModuleInfo, Globals),
             ErrorSpecs = list.map(mode_error_info_to_spec(ModeInfo), Errors),
-            write_error_specs(DebugStream, Globals, ErrorSpecs, !IO)
+            write_diag_specs(DebugStream, Globals, ErrorSpecs, !IO)
         )
     ),
 
diff --git a/compiler/polymorphism_goal.m b/compiler/polymorphism_goal.m
index 606b5735c..caf511c10 100644
--- a/compiler/polymorphism_goal.m
+++ b/compiler/polymorphism_goal.m
@@ -520,7 +520,7 @@ polymorphism_process_unify_functor(GoalExpr0, ConsId0, ArgVars0, GoalInfo0,
         ;
             MaybeRHS1 = error1(SpecsRHS),
             poly_info_get_errors(!.Info, Specs0),
-            Specs = one_or_more_to_list(SpecsRHS) ++ Specs0,
+            Specs = coerce(one_or_more_to_list(SpecsRHS)) ++ Specs0,
             poly_info_set_errors(Specs, !Info),
             % It does not matter what Goal we return, since it won't be used.
             RHS1 = rhs_functor(some_int_const(int_const(42)),
diff --git a/compiler/post_typecheck.m b/compiler/post_typecheck.m
index f6f320c34..b8b64a753 100644
--- a/compiler/post_typecheck.m
+++ b/compiler/post_typecheck.m
@@ -340,7 +340,7 @@ report_unsatisfied_constraints(ModuleInfo, PredId, PredInfo, Constraints)
             ConstrainedGoals),
         ContextMsgs = [ContextMsgsPrefix | ContextMsgsList]
     ),
-    Spec = diag_spec($pred, severity_error, phase_type_check,
+    Spec = gen_spec($pred, severity_error, phase_type_check,
         [MainMsg | ContextMsgs]).
 
 :- func constraint_to_error_pieces(tvarset, prog_constraint)
@@ -728,7 +728,7 @@ report_unresolved_type_warning(ModuleInfo, PredId, PredInfo, VarsEntries,
         words("My apologies.)"), nl],
     Msg = simple_msg(Context,
         [always(MainPieces), verbose_only(verbose_once, VerbosePieces)]),
-    Spec = diag_spec($pred, severity_warning(warn_unresolved_polymorphism),
+    Spec = gen_spec($pred, severity_warning(warn_unresolved_polymorphism),
         phase_type_check, [Msg | AnonVarMsgs]),
     !:Specs = [Spec | !.Specs].
 
@@ -986,7 +986,7 @@ report_indistinguishable_modes_error(ModuleInfo, OldProcId, NewProcId,
         color_as_incorrect([words("indistinguishable.")]) ++
         [nl],
     OldPieces = [words("Here is the conflicting mode declaration."), nl],
-    Spec = diag_spec($pred, severity_error,
+    Spec = gen_spec($pred, severity_error,
         phase_mode_check(report_in_any_mode),
         [simple_msg(NewContext,
             [always(MainPieces), verbose_only(verbose_always, VerbosePieces)]),
diff --git a/compiler/prog_event.m b/compiler/prog_event.m
index 619306d67..f07adf952 100644
--- a/compiler/prog_event.m
+++ b/compiler/prog_event.m
@@ -32,7 +32,7 @@
     % errors discovered during the process.
     %
 :- pred read_event_set(string::in, string::out, event_spec_map::out,
-    list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::out, io::di, io::uo) is det.
 
     % Return a description of the given event set.
     %
@@ -374,7 +374,7 @@ read_specs_file_4(MR_AllocSiteInfoPtr alloc_id, MR_String specs_file_name,
 
 :- pred convert_list_to_spec_map(string::in, list(event_spec_term)::in,
     event_spec_map::in, event_spec_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 convert_list_to_spec_map(_, [], !EventSpecMap, !ErrorSpecs).
 convert_list_to_spec_map(FileName, [SpecTerm | SpecTerms],
@@ -384,7 +384,7 @@ convert_list_to_spec_map(FileName, [SpecTerm | SpecTerms],
 
 :- pred convert_term_to_spec_map(string::in, event_spec_term::in,
     event_spec_map::in, event_spec_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 convert_term_to_spec_map(FileName, SpecTerm, !EventSpecMap, !ErrorSpecs) :-
     SpecTerm = event_spec_term(EventName, EventNumber, EventLineNumber,
@@ -457,7 +457,7 @@ convert_term_to_spec_map(FileName, SpecTerm, !EventSpecMap, !ErrorSpecs) :-
             quote(EventName), words("is here."), nl],
         EventContext = term_context.context(FileName, EventLineNumber),
         OldContext = term_context.context(FileName, OldLineNumber),
-        DuplErrorSpec = diag_spec($pred, severity_error, phase_t2pt,
+        DuplErrorSpec = gen_spec($pred, severity_error, phase_t2pt,
             [msg(EventContext, Pieces1),
             msg(OldContext, Pieces2)]),
         !:ErrorSpecs = [DuplErrorSpec | !.ErrorSpecs]
@@ -481,7 +481,7 @@ acc_self_dependent_nodes(From - To, !RevSelfRecSccs) :-
     ).
 
 :- pred acc_circular_synth_attr_error(prog_context::in, string::in,
-    set(string)::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    set(string)::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 acc_circular_synth_attr_error(Context, EventName, Scc, !ErrorSpecs) :-
     Attrs = set.to_sorted_list(Scc),
@@ -570,7 +570,7 @@ keep_only_synth_attr_nums(AttrMap, [AttrName | AttrNames], SynthAttrNums) :-
     attr_name_map::in, attr_name_map::out,
     attr_type_map::in, attr_type_map::out,
     attr_key_map::in, attr_key_map::out, attr_dep_rel::in, attr_dep_rel::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 build_plain_type_map(_, _, _, [], _, !AttrNumMap, !AttrNameMap, !AttrTypeMap,
         !KeyMap, !DepRel, !ErrorSpecs).
@@ -617,7 +617,7 @@ build_plain_type_map(EventName, FileName, EventLineNumber,
 :- pred build_dep_map(string::in, string::in,
     attr_name_map::in, attr_key_map::in, list(event_attr_term)::in,
     attr_type_map::in, attr_type_map::out, attr_dep_rel::in, attr_dep_rel::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 build_dep_map(_, _, _, _, [], !AttrTypeMap, !DepRel, !ErrorSpecs).
 build_dep_map(EventName, FileName, AttrNameMap, KeyMap, [AttrTerm | AttrTerms],
@@ -706,7 +706,7 @@ build_dep_map(EventName, FileName, AttrNameMap, KeyMap, [AttrTerm | AttrTerms],
 :- pred record_arg_dependencies(string::in, string::in, int::in,
     attr_key_map::in, string::in, attr_key::in,
     list(string)::in, attr_dep_rel::in, attr_dep_rel::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 record_arg_dependencies(_, _, _, _, _, _, [], !DepRel, !ErrorSpecs).
 record_arg_dependencies(EventName, FileName, AttrLineNumber, KeyMap,
@@ -734,7 +734,7 @@ record_arg_dependencies(EventName, FileName, AttrLineNumber, KeyMap,
 :- pred convert_terms_to_attrs(string::in, string::in, attr_name_map::in,
     attr_type_map::in, int::in, list(event_attr_term)::in,
     list(event_attribute)::in, list(event_attribute)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 convert_terms_to_attrs(_, _, _, _, _, [], !RevAttrs, !ErrorSpecs).
 convert_terms_to_attrs(EventName, FileName, AttrNameMap,
diff --git a/compiler/prog_foreign_enum.m b/compiler/prog_foreign_enum.m
index 4ff8252ff..6f7d8c27e 100644
--- a/compiler/prog_foreign_enum.m
+++ b/compiler/prog_foreign_enum.m
@@ -51,7 +51,7 @@
     prog_context::in, list(format_piece)::in, module_name::in,
     set_tree234(string)::in, assoc_list(sym_name, string)::in,
     bimap(string, string)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -253,7 +253,7 @@ build_ctor_name_to_foreign_name_map_loop(TypeModuleName, ValidCtorNames,
 %---------------------------------------------------------------------------%
 
 :- pred add_bad_qual_ctors_error(prog_context::in, list(format_piece)::in,
-    list(sym_name)::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(sym_name)::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 add_bad_qual_ctors_error(Context, ContextPieces, Ctors, !Specs) :-
     HasOrHave = choose_number(Ctors, "symbol has", "symbols have"),
@@ -286,7 +286,7 @@ qual_ctor_to_format_piece(SymName) = [qual_sym_name(SymName)].
     % not being constructor(s) of that type.
     %
 :- pred add_unknown_ctors_error(prog_context::in, list(format_piece)::in,
-    list(sym_name)::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(sym_name)::in, list(err_spec)::in, list(err_spec)::out) is det.
 
 add_unknown_ctors_error(Context, ContextPieces, Ctors, !Specs) :-
     IsOrAre = choose_number(Ctors, "symbol is", "symbols are"),
@@ -320,9 +320,8 @@ unqual_ctor_to_format_piece(SymName) = [unqual_sym_name(SymName)].
     % not being mapped to a foreign language value.
     %
 :- pred add_foreign_enum_unmapped_ctors_error(prog_context::in,
-    list(format_piece)::in,
-    list(string)::in(non_empty_list),
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(format_piece)::in, list(string)::in(non_empty_list),
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_foreign_enum_unmapped_ctors_error(Context, ContextPieces, CtorNames0,
         !Specs) :-
@@ -360,7 +359,7 @@ add_foreign_enum_unmapped_ctors_error(Context, ContextPieces, CtorNames0,
             verbose_and_nonverbose(VerboseCtorsPieces, NonVerboseCtorsPieces)
     ),
     Msg = simple_msg(Context, [always(PrefixPieces), CtorsComponent]),
-    Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg]),
+    Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg]),
     !:Specs = [Spec | !.Specs].
 
 %---------------------------------------------------------------------------%
diff --git a/compiler/prog_item.m b/compiler/prog_item.m
index b52182098..503a01d23 100644
--- a/compiler/prog_item.m
+++ b/compiler/prog_item.m
@@ -34,7 +34,6 @@
 :- import_module mdbcomp.
 :- import_module mdbcomp.prim_data.
 :- import_module mdbcomp.sym_name.
-:- import_module parse_tree.error_spec.
 :- import_module parse_tree.maybe_error.
 :- import_module parse_tree.prog_data.
 :- import_module parse_tree.prog_data_foreign.
@@ -289,8 +288,7 @@
                 cl_predname                     :: sym_name,
                 cl_head_args                    :: list(prog_term),
                 cl_varset                       :: prog_varset,
-                cl_body                         :: maybe2(goal,
-                                                    list(warning_spec)),
+                cl_body                         :: parse_result2(goal),
                 cl_context                      :: prog_context,
                 cl_seq_num                      :: item_seq_num
             ).
@@ -2429,6 +2427,7 @@
 
 :- implementation.
 
+:- import_module parse_tree.error_spec.
 :- import_module parse_tree.prog_util.
 
 :- import_module term.
diff --git a/compiler/prog_mode.m b/compiler/prog_mode.m
index 768684ca2..d3258f37b 100644
--- a/compiler/prog_mode.m
+++ b/compiler/prog_mode.m
@@ -235,7 +235,7 @@
     list(type_and_mode)::in, list(inst_var)::out) is det.
 
 :- pred report_inconsistent_constrained_inst_vars(string::in, term.context::in,
-    inst_varset::in, inst_var::in, list(inst_var)::in, diag_spec::out) is det.
+    inst_varset::in, inst_var::in, list(inst_var)::in, err_spec::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
diff --git a/compiler/prog_parse_tree.m b/compiler/prog_parse_tree.m
index e542c551a..09710103f 100644
--- a/compiler/prog_parse_tree.m
+++ b/compiler/prog_parse_tree.m
@@ -301,17 +301,19 @@
                 ptms_type_defns             :: type_ctor_checked_map,
                 ptms_inst_defns             :: inst_ctor_checked_map,
                 ptms_mode_defns             :: mode_ctor_checked_map,
-                % The error messages generated during the construction
+                % The errors and warnings generated during the construction
                 % of ptms_type_defns. We have found some invalid types if
                 % some of these diag_specs (a) are severity_error, and
                 % (b) are phase_tim_check_invalid_type.
-                ptms_type_specs             :: list(diag_spec),
-                % The error messages generated during the construction
+                ptms_type_err_specs         :: list(err_spec),
+                ptms_type_warn_specs        :: list(warn_spec),
+                % The error s and warnings generated during the construction
                 % of ptms_inst_defns and ptms_mode_defns. We have found
                 % some invalid insts and/or modes if some of these diag_specs
                 % (a) are severity_error, and (b) are
                 % phase_tim_check_invalid_inst_mode.
-                ptms_inst_mode_specs        :: list(diag_spec),
+                ptms_inst_mode_err_specs    :: list(err_spec),
+                ptms_inst_mode_warn_specs   :: list(warn_spec),
 
                 % Items of various kinds in the interface.
                 % All these items are to be treated as being in the
diff --git a/compiler/purity.m b/compiler/purity.m
index b8582d5ca..a25295c20 100644
--- a/compiler/purity.m
+++ b/compiler/purity.m
@@ -1493,7 +1493,7 @@ error_inconsistent_purity_promise(PredInfo, Purity) = Spec :-
         words("no impurity declaration."), nl],
     Msg = simple_msg(Context,
         [always(MainPieces), verbose_only(verbose_always, VerbosePieces)]),
-    Spec = diag_spec($pred, severity_error, phase_purity_check, [Msg]).
+    Spec = gen_spec($pred, severity_error, phase_purity_check, [Msg]).
 
 :- func warn_pred_body_too_pure(module_info, pred_info, pred_id,
     purity, purity) = diag_spec.
@@ -1551,7 +1551,7 @@ warn_unnecessary_purity_promise(ModuleInfo, PredInfo, PredId, PromisedPurity)
         nl],
     Msg = simple_msg(Context,
         [always(MainPieces), verbose_only(verbose_always, VerbosePieces)]),
-    Spec = diag_spec($pred, severity_warning(warn_unneeded_purity_pragma),
+    Spec = gen_spec($pred, severity_warning(warn_unneeded_purity_pragma),
         phase_purity_check, [Msg]).
 
 :- func error_not_pure_enough(module_info, pred_info, pred_id, purity)
diff --git a/compiler/qual_info.m b/compiler/qual_info.m
index b51d2375f..64102b2a7 100644
--- a/compiler/qual_info.m
+++ b/compiler/qual_info.m
@@ -77,7 +77,7 @@
     %
 :- pred process_type_qualification(prog_var::in, mer_type::in, tvarset::in,
     prog_context::in, qual_info::in, qual_info::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 :- pred make_atomic_unification(prog_var::in, unify_rhs::in, prog_context::in,
     unify_main_context::in, list(unify_sub_context)::in, purity::in,
@@ -255,7 +255,7 @@ process_type_qualification(Var, Type0, VarSet, Context, !QualInfo, !Specs) :-
 
 :- pred update_var_types(prog_var::in, mer_type::in, prog_context::in,
     vartypes::in, vartypes::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 update_var_types(Var, Type, Context, !VarTypes, !Specs) :-
     ( if search_var_type(!.VarTypes, Var, Type0) then
diff --git a/compiler/read_modules.m b/compiler/read_modules.m
index 24482f774..dc2c19124 100644
--- a/compiler/read_modules.m
+++ b/compiler/read_modules.m
@@ -1487,7 +1487,10 @@ record_and_report_missing_timestamp(Globals, FileName, IOError,
             words("Smart recompilation will not work."), nl],
         Severity = severity_warning(warn_smart_recompilation),
         Spec = no_ctxt_spec($pred, Severity, phase_read_files, Pieces),
-        add_nonfatal_error(rme_cannot_find_modify_time, Spec, !Errors)
+        % XXX DIAG_SPEC This used to be:
+        %   add_nonfatal_error(rme_cannot_find_modify_time, Spec, !Errors)
+        % but this is a warning, not an error.
+        add_warning(Spec, !Errors)
     ;
         Warn = no
     ).
diff --git a/compiler/recompilation.check.m b/compiler/recompilation.check.m
index 532ed092a..96c22f692 100644
--- a/compiler/recompilation.check.m
+++ b/compiler/recompilation.check.m
@@ -1706,11 +1706,11 @@ report_used_file_read_error(Globals, ModuleName, UsedFileError, Stream, !IO) :-
     ;
         UsedFileError = uf_unreadable_used_items(OoMUsedItemSpecs),
         list.map(extract_spec_msgs_and_maybe_add_id(Globals),
-            one_or_more_to_list(OoMUsedItemSpecs), MsgsList),
+            coerce(one_or_more_to_list(OoMUsedItemSpecs)), MsgsList),
         list.condense(MsgsList, Msgs),
-        Spec = diag_spec($pred, Severity, phase_read_files, Msgs)
+        Spec = gen_spec($pred, Severity, phase_read_files, Msgs)
     ),
-    write_error_spec(Stream, Globals, Spec, !IO).   % informational only
+    write_diag_spec(Stream, Globals, Spec, !IO).   % informational only
 
 %---------------------%
 
@@ -1791,7 +1791,7 @@ write_recompile_reason(Globals, Stream, ThisModuleName, Reason, !IO) :-
         phase_read_files, AllPieces),
     % Since these messages are informational, there should be no warnings
     % or errors.
-    write_error_spec(Stream, Globals, Spec, !IO). % informational only
+    write_diag_spec(Stream, Globals, Spec, !IO). % informational only
 
 :- func describe_item(recomp_item_id) = list(format_piece).
 
diff --git a/compiler/recompilation.used_file.m b/compiler/recompilation.used_file.m
index 5ed5a9e08..b0799804d 100644
--- a/compiler/recompilation.used_file.m
+++ b/compiler/recompilation.used_file.m
@@ -163,7 +163,7 @@
     ;       uf_invalid_file_format(file_name)
             % The named file does not start with a valid version number
             % for a .used file.
-    ;       uf_unreadable_used_items(one_or_more(diag_spec)).
+    ;       uf_unreadable_used_items(one_or_more(err_spec)).
             % XXX document this
 
     % This type represents the part of the .used file *after*
diff --git a/compiler/simplify_goal.m b/compiler/simplify_goal.m
index 17cdebdf2..28b668ffa 100644
--- a/compiler/simplify_goal.m
+++ b/compiler/simplify_goal.m
@@ -238,7 +238,7 @@ maybe_simplify_goal_to_true_or_fail(InstMap0, Goal0ContainsTrace,
             Msg = simple_msg(Context,
                 [always(MainPieces),
                 verbose_only(verbose_always, VerbosePieces)]),
-            Spec = diag_spec($pred, severity_warning(warn_dodgy_simple_code),
+            Spec = gen_spec($pred, severity_warning(warn_dodgy_simple_code),
                 phase_simplify(report_only_if_in_all_modes), [Msg]),
             simplify_info_add_message(Spec, !Info)
         else
diff --git a/compiler/simplify_goal_call.m b/compiler/simplify_goal_call.m
index 194c48eae..9fe5e15dd 100644
--- a/compiler/simplify_goal_call.m
+++ b/compiler/simplify_goal_call.m
@@ -644,7 +644,7 @@ maybe_generate_warning_for_infinite_loop_call(PredId, ProcId, ArgVars,
                 Msgs = [simple_msg(goal_info_get_context(GoalInfo),
                     [always(MainPieces),
                     verbose_only(verbose_once, VerbosePieces)])],
-                Spec = diag_spec($pred,
+                Spec = gen_spec($pred,
                     severity_warning(warn_dodgy_simple_code),
                     phase_simplify(report_in_any_mode), Msgs),
                 simplify_info_add_message(Spec, !Info)
@@ -659,7 +659,7 @@ maybe_generate_warning_for_infinite_loop_call(PredId, ProcId, ArgVars,
                         words("the call use state variable notation."), nl],
                     Msgs = [simple_msg(goal_info_get_context(GoalInfo),
                         [always(Pieces), shut_up_suspicious_recursion_msg])],
-                    Spec = diag_spec($pred,
+                    Spec = gen_spec($pred,
                         severity_warning(warn_dodgy_simple_code),
                         phase_simplify(report_in_any_mode), Msgs),
                     simplify_info_add_message(Spec, !Info)
@@ -684,7 +684,7 @@ maybe_generate_warning_for_infinite_loop_call(PredId, ProcId, ArgVars,
                 Msg = simple_msg(goal_info_get_context(GoalInfo),
                     [always(Pieces), shut_up_suspicious_recursion_msg]),
                 Severity = severity_warning(warn_suspicious_recursion),
-                Spec = diag_spec($pred, Severity,
+                Spec = gen_spec($pred, Severity,
                     phase_simplify(report_in_any_mode), [Msg]),
                 simplify_info_add_message(Spec, !Info)
             else
diff --git a/compiler/source_file_map.m b/compiler/source_file_map.m
index b1d907606..0ee10281d 100644
--- a/compiler/source_file_map.m
+++ b/compiler/source_file_map.m
@@ -50,7 +50,7 @@
     %
     % Given a list of file names, produce the Mercury.modules file.
     %
-:- pred write_source_file_map(list(string)::in, list(diag_spec)::out,
+:- pred write_source_file_map(list(string)::in, list(err_spec)::out,
     io::di, io::uo) is det.
 
 %---------------------------------------------------------------------------%
@@ -162,7 +162,7 @@ write_source_file_map(FileNames, Specs, !IO) :-
 :- pred acc_source_file_map_line(file_name::in,
     source_file_map::in, source_file_map::out,
     cord(string)::in, cord(string)::out,
-    list(diag_spec)::in, list(diag_spec)::out, io::di, io::uo) is det.
+    list(err_spec)::in, list(err_spec)::out, io::di, io::uo) is det.
 
 acc_source_file_map_line(FileName, Mn2FnMap0, Mn2FnMap,
         !MapFileLineCord, !Specs, !IO) :-
diff --git a/compiler/split_parse_tree_src.m b/compiler/split_parse_tree_src.m
index c0d393d99..b33f7780e 100644
--- a/compiler/split_parse_tree_src.m
+++ b/compiler/split_parse_tree_src.m
@@ -38,7 +38,8 @@
     %
 :- pred split_into_component_modules_perform_checks(globals::in,
     parse_tree_src::in, list(parse_tree_module_src)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -64,7 +65,7 @@
 %---------------------------------------------------------------------------%
 
 split_into_component_modules_perform_checks(Globals, ParseTreeSrc,
-        ParseTreeModuleSrcs, !Specs) :-
+        ParseTreeModuleSrcs, !ErrSpecs, !WarnSpecs) :-
     % This algorithm has two phases.
     %
     % The first phase, split_parse_tree_discover_submodules, builds up
@@ -82,12 +83,13 @@ split_into_component_modules_perform_checks(Globals, ParseTreeSrc,
     % Going from ParseTreeSrc to directly to ParseTreeModuleSrcs would
     % therefore be possible only with excessively-complicated code.
     split_parse_tree_discover_submodules(ParseTreeSrc, ma_no_parent,
-        map.init, SplitModuleMap, map.init, SubModulesMap, !Specs),
+        map.init, SplitModuleMap, map.init, SubModulesMap,
+        !ErrSpecs, !WarnSpecs),
     ParseTreeSrc = parse_tree_src(TopModuleName, _, _),
     create_component_modules_depth_first(Globals, TopModuleName,
         SplitModuleMap, LeftOverSplitModuleMap,
         SubModulesMap, LeftOverSubModulesMap,
-        cord.init, ParseTreeModuleSrcCord, !Specs),
+        cord.init, ParseTreeModuleSrcCord, !ErrSpecs, !WarnSpecs),
     expect(map.is_empty(LeftOverSplitModuleMap), $pred,
         "LeftOverSplitModuleMap is not empty"),
     expect(map.is_empty(LeftOverSubModulesMap), $pred,
@@ -228,10 +230,11 @@ split_into_component_modules_perform_checks(Globals, ParseTreeSrc,
 :- pred split_parse_tree_discover_submodules(parse_tree_src::in,
     module_ancestors::in, split_module_map::in, split_module_map::out,
     module_to_submodules_map::in, module_to_submodules_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 split_parse_tree_discover_submodules(ParseTree, ModuleAncestors,
-        !SplitModuleMap, !SubModulesMap, !Specs) :-
+        !SplitModuleMap, !SubModulesMap, !ErrSpecs, !WarnSpecs) :-
     ParseTree = parse_tree_src(ModuleName, Context, ModuleComponentsCord),
     ModuleComponents = cord.list(ModuleComponentsCord),
     % If this module is a submodule, record its relationship to its parent.
@@ -241,7 +244,8 @@ split_parse_tree_discover_submodules(ParseTree, ModuleAncestors,
     SubModuleSectionAncestors = sa_parent(ModuleName, ModuleAncestors),
     split_components_discover_submodules(ModuleName, ModuleComponents,
         SubModuleSectionAncestors, !SplitModuleMap, !SubModulesMap,
-        map.init, SubInclInfoMap0, cord.init, ItemBlockCord0, !Specs),
+        map.init, SubInclInfoMap0, cord.init, ItemBlockCord0,
+        !ErrSpecs, !WarnSpecs),
     (
         ModuleAncestors = ma_no_parent,
         ( if map.search(!.SplitModuleMap, ModuleName, OldEntry) then
@@ -267,9 +271,9 @@ split_parse_tree_discover_submodules(ParseTree, ModuleAncestors,
             ),
             Msg = msg(Context, Pieces),
             OldMsg = msg(OldContext, OldPieces),
-            Spec = diag_spec($pred, severity_error, phase_pt2h,
+            Spec = gen_spec($pred, severity_error, phase_pt2h,
                 [Msg, OldMsg]),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         else
             Entry = split_nested(split_nested_top_module(Context),
                 ItemBlockCord0, SubInclInfoMap0),
@@ -285,10 +289,10 @@ split_parse_tree_discover_submodules(ParseTree, ModuleAncestors,
             SeenInt = no,
             SeenImp = no,
             warn_empty_submodule(ModuleName, Context, ParentModuleName,
-                !Specs),
+                !WarnSpecs),
             ( if map.search(!.SplitModuleMap, ModuleName, OldEntry) then
                 report_duplicate_submodule(ModuleName, Context,
-                    dup_empty, ParentModuleName, OldEntry, !Specs)
+                    dup_empty, ParentModuleName, OldEntry, !ErrSpecs)
             else
                 SplitNested = split_nested_empty(Context),
                 Entry = split_nested(SplitNested, ItemBlockCord0,
@@ -316,7 +320,8 @@ split_parse_tree_discover_submodules(ParseTree, ModuleAncestors,
                     ;
                         OldSplitNested = split_nested_empty(EmptyContext),
                         warn_duplicate_of_empty_submodule(ModuleName,
-                            ParentModuleName, Context, EmptyContext, !Specs),
+                            ParentModuleName, Context, EmptyContext,
+                            !WarnSpecs),
                         NewSplitNested = split_nested_only_int(Context),
                         NewEntry = split_nested(NewSplitNested, ItemBlockCord0,
                             SubInclInfoMap0),
@@ -327,12 +332,12 @@ split_parse_tree_discover_submodules(ParseTree, ModuleAncestors,
                         ; OldSplitNested = split_nested_int_imp(_, _)
                         ),
                         report_duplicate_submodule(ModuleName, Context,
-                            dup_int_only, ParentModuleName, OldEntry, !Specs)
+                            dup_int_only, ParentModuleName, OldEntry, !ErrSpecs)
                     )
                 ;
                     OldEntry = split_included(_),
                     report_duplicate_submodule(ModuleName, Context,
-                        dup_int_only, ParentModuleName, OldEntry, !Specs),
+                        dup_int_only, ParentModuleName, OldEntry, !ErrSpecs),
                     % Record the nested module, to prevent any complaints by
                     % warn_about_any_unread_modules_with_read_ancestors.
                     NewSplitNested = split_nested_only_int(Context),
@@ -367,7 +372,8 @@ split_parse_tree_discover_submodules(ParseTree, ModuleAncestors,
                     ;
                         OldSplitNested = split_nested_empty(EmptyContext),
                         warn_duplicate_of_empty_submodule(ModuleName,
-                            ParentModuleName, Context, EmptyContext, !Specs),
+                            ParentModuleName, Context, EmptyContext,
+                            !WarnSpecs),
                         NewSplitNested = split_nested_only_imp(Context),
                         NewEntry = split_nested(NewSplitNested, ItemBlockCord0,
                             SubInclInfoMap0),
@@ -378,12 +384,13 @@ split_parse_tree_discover_submodules(ParseTree, ModuleAncestors,
                         ; OldSplitNested = split_nested_int_imp(_, _)
                         ),
                         report_duplicate_submodule(ModuleName, Context,
-                            dup_imp_only, ParentModuleName, OldEntry, !Specs)
+                            dup_imp_only, ParentModuleName, OldEntry,
+                            !ErrSpecs)
                     )
                 ;
                     OldEntry = split_included(_),
                     report_duplicate_submodule(ModuleName, Context,
-                        dup_int_only, ParentModuleName, OldEntry, !Specs),
+                        dup_int_only, ParentModuleName, OldEntry, !ErrSpecs),
                     % Record the nested module, to prevent any complaints by
                     % warn_about_any_unread_modules_with_read_ancestors.
                     NewSplitNested = split_nested_only_imp(Context),
@@ -407,7 +414,8 @@ split_parse_tree_discover_submodules(ParseTree, ModuleAncestors,
                     (
                         OldSplitNested = split_nested_empty(EmptyContext),
                         warn_duplicate_of_empty_submodule(ModuleName,
-                            ParentModuleName, Context, EmptyContext, !Specs),
+                            ParentModuleName, Context, EmptyContext,
+                            !WarnSpecs),
                         NewSplitNested =
                             split_nested_int_imp(Context, Context),
                         NewEntry = split_nested(NewSplitNested, ItemBlockCord0,
@@ -420,12 +428,12 @@ split_parse_tree_discover_submodules(ParseTree, ModuleAncestors,
                         ; OldSplitNested = split_nested_int_imp(_, _)
                         ),
                         report_duplicate_submodule(ModuleName, Context,
-                            dup_int_imp, ParentModuleName, OldEntry, !Specs)
+                            dup_int_imp, ParentModuleName, OldEntry, !ErrSpecs)
                     )
                 ;
                     OldEntry = split_included(_),
                     report_duplicate_submodule(ModuleName, Context,
-                        dup_int_only, ParentModuleName, OldEntry, !Specs),
+                        dup_int_only, ParentModuleName, OldEntry, !ErrSpecs),
                     % Record the nested module, to prevent any complaints by
                     % warn_about_any_unread_modules_with_read_ancestors.
                     NewSplitNested = split_nested_int_imp(Context, Context),
@@ -466,20 +474,21 @@ get_raw_item_block_section_kinds([ItemBlock | ItemBlocks],
     module_to_submodules_map::in, module_to_submodules_map::out,
     submodule_include_info_map::in, submodule_include_info_map::out,
     cord(raw_item_block)::in, cord(raw_item_block)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 split_components_discover_submodules(_, [],
         _, !SplitModuleMap, !SubModulesMap,
-        !SubInclInfoMap, !RawItemBlockCord, !Specs).
+        !SubInclInfoMap, !RawItemBlockCord, !ErrSpecs, !WarnSpecs).
 split_components_discover_submodules(ModuleName, [Component | Components],
         SectionAncestors, !SplitModuleMap, !SubModulesMap,
-        !SubInclInfoMap, !RawItemBlockCord, !Specs) :-
+        !SubInclInfoMap, !RawItemBlockCord, !ErrSpecs, !WarnSpecs) :-
     split_component_discover_submodules(ModuleName, Component,
         SectionAncestors, !SplitModuleMap, !SubModulesMap,
-        !SubInclInfoMap, !RawItemBlockCord, !Specs),
+        !SubInclInfoMap, !RawItemBlockCord, !ErrSpecs, !WarnSpecs),
     split_components_discover_submodules(ModuleName, Components,
         SectionAncestors, !SplitModuleMap, !SubModulesMap,
-        !SubInclInfoMap, !RawItemBlockCord, !Specs).
+        !SubInclInfoMap, !RawItemBlockCord, !ErrSpecs, !WarnSpecs).
 
 :- pred split_component_discover_submodules(module_name::in,
     module_component::in, section_ancestors::in,
@@ -487,11 +496,12 @@ split_components_discover_submodules(ModuleName, [Component | Components],
     module_to_submodules_map::in, module_to_submodules_map::out,
     submodule_include_info_map::in, submodule_include_info_map::out,
     cord(raw_item_block)::in, cord(raw_item_block)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 split_component_discover_submodules(ModuleName, Component, SectionAncestors,
         !SplitModuleMap, !SubModulesMap, !SubInclInfoMap,
-        !RawItemBlockCord, !Specs) :-
+        !RawItemBlockCord, !ErrSpecs, !WarnSpecs) :-
     (
         Component = mc_section(ComponentModuleName, SectionKind,
             SectionContext, IncludesCord, AvailsCord, FIMsCord, ItemsCord),
@@ -501,7 +511,7 @@ split_component_discover_submodules(ModuleName, Component, SectionAncestors,
         FIMs = cord.list(FIMsCord),
         discover_included_submodules(Includes, SectionAncestors,
             cord.init, OKIncludesCord,
-            !SplitModuleMap, !SubModulesMap, !Specs),
+            !SplitModuleMap, !SubModulesMap, !ErrSpecs, !WarnSpecs),
         OKIncludes = cord.list(OKIncludesCord),
         RawItemBlock = item_block(ComponentModuleName, SectionKind,
             OKIncludes, Avails, FIMs, Items),
@@ -540,7 +550,7 @@ split_component_discover_submodules(ModuleName, Component, SectionAncestors,
                     [nl],
                 Spec = spec($pred, severity_error, phase_pt2h,
                     SectionContext, Pieces),
-                !:Specs = [Spec | !.Specs]
+                !:ErrSpecs = [Spec | !.ErrSpecs]
             )
         )
     ;
@@ -567,7 +577,8 @@ split_component_discover_submodules(ModuleName, Component, SectionAncestors,
         NestedModuleAncestors = ma_parent(SectionKind, SectionContext,
             SectionAncestors),
         split_parse_tree_discover_submodules(NestedModuleParseTree,
-            NestedModuleAncestors, !SplitModuleMap, !SubModulesMap, !Specs)
+            NestedModuleAncestors, !SplitModuleMap, !SubModulesMap,
+            !ErrSpecs, !WarnSpecs)
     ).
 
 %---------------------%
@@ -576,12 +587,15 @@ split_component_discover_submodules(ModuleName, Component, SectionAncestors,
     section_ancestors::in, cord(item_include)::in, cord(item_include)::out,
     split_module_map::in, split_module_map::out,
     module_to_submodules_map::in, module_to_submodules_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 discover_included_submodules([], _,
-        !OKIncludesCord, !SplitModuleMap, !SubModulesMap, !Specs).
+        !OKIncludesCord, !SplitModuleMap, !SubModulesMap,
+        !ErrSpecs, !WarnSpecs).
 discover_included_submodules([Include | Includes], SectionAncestors,
-        !OKIncludesCord, !SplitModuleMap, !SubModulesMap, !Specs) :-
+        !OKIncludesCord, !SplitModuleMap, !SubModulesMap,
+        !ErrSpecs, !WarnSpecs) :-
     Include = item_include(InclModuleName, Context, _SeqNum),
     ( if map.search(!.SplitModuleMap, InclModuleName, OldEntry) then
         SectionAncestors = sa_parent(ParentModuleName, _),
@@ -604,8 +618,8 @@ discover_included_submodules([Include | Includes], SectionAncestors,
             words("of that previous declaration."), nl],
         Msg = msg(Context, Pieces1 ++ Pieces2),
         OldMsg = msg(OldContext, OldPieces),
-        Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg, OldMsg]),
-        !:Specs = [Spec | !.Specs]
+        Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg, OldMsg]),
+        !:ErrSpecs = [Spec | !.ErrSpecs]
     else
         Entry = split_included(Context),
         map.det_insert(InclModuleName, Entry, !SplitModuleMap),
@@ -614,7 +628,8 @@ discover_included_submodules([Include | Includes], SectionAncestors,
         cord.snoc(Include, !OKIncludesCord)
     ),
     discover_included_submodules(Includes, SectionAncestors,
-        !OKIncludesCord, !SplitModuleMap, !SubModulesMap, !Specs).
+        !OKIncludesCord, !SplitModuleMap, !SubModulesMap,
+        !ErrSpecs, !WarnSpecs).
 
 %---------------------------------------------------------------------------%
 %
@@ -739,10 +754,12 @@ split_nested_info_get_context(SplitNested) = Context :-
     module_name::in, split_module_map::in, split_module_map::out,
     module_to_submodules_map::in, module_to_submodules_map::out,
     cord(parse_tree_module_src)::in, cord(parse_tree_module_src)::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out,
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 create_component_modules_depth_first(Globals, ModuleName,
-        !SplitModuleMap, !SubModulesMap, !ParseTreeModuleSrcCord, !Specs) :-
+        !SplitModuleMap, !SubModulesMap, !ParseTreeModuleSrcCord,
+        !ErrSpecs, !WarnSpecs) :-
     map.det_remove(ModuleName, Entry, !SplitModuleMap),
     (
         Entry = split_included(_),
@@ -767,7 +784,7 @@ create_component_modules_depth_first(Globals, ModuleName,
                     [words("missing its interface section.")]) ++
                 [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            !:Specs = [Spec | !.Specs]
+            !:ErrSpecs = [Spec | !.ErrSpecs]
         ),
 
         % The reason why we do this even for split_nested_empty is that
@@ -783,15 +800,17 @@ create_component_modules_depth_first(Globals, ModuleName,
         RawCompUnit = raw_compilation_unit(ModuleName, Context,
             RawItemBlocks),
         check_convert_raw_comp_unit_to_module_src(Globals, RawCompUnit,
-            ParseTreeModuleSrc, !Specs),
+            ParseTreeModuleSrc, ConvertErrSpecs, ConvertWarnSpecs),
         cord.snoc(ParseTreeModuleSrc, !ParseTreeModuleSrcCord),
+        !:ErrSpecs = ConvertErrSpecs ++ !.ErrSpecs,
+        !:WarnSpecs = ConvertWarnSpecs ++ !.WarnSpecs,
 
         ( if map.remove(ModuleName, SubModulesCord, !SubModulesMap) then
             list.sort_and_remove_dups(cord.list(SubModulesCord), SubModules),
-            list.foldl4(
+            list.foldl5(
                 create_component_modules_depth_first(Globals),
                 SubModules, !SplitModuleMap, !SubModulesMap,
-                !ParseTreeModuleSrcCord, !Specs)
+                !ParseTreeModuleSrcCord, !ErrSpecs, !WarnSpecs)
         else
             % ModuleName has no submodules for us to process.
             true
@@ -882,7 +901,7 @@ submodule_include_info_map_to_item_includes_acc(IntMods, ImpMods,
 %---------------------------------------------------------------------------%
 
 :- pred warn_empty_submodule(module_name::in, prog_context::in,
-    module_name::in, list(diag_spec)::in, list(diag_spec)::out) is det.
+    module_name::in, list(warn_spec)::in, list(warn_spec)::out) is det.
 
 warn_empty_submodule(ModuleName, Context, ParentModuleName, !Specs) :-
     Pieces = [words("Warning:")] ++
@@ -899,7 +918,7 @@ warn_empty_submodule(ModuleName, Context, ParentModuleName, !Specs) :-
 
 :- pred warn_duplicate_of_empty_submodule(module_name::in, module_name::in,
     prog_context::in, prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 warn_duplicate_of_empty_submodule(ModuleName, ParentModuleName,
         Context, EmptyContext, !Specs) :-
@@ -911,7 +930,7 @@ warn_duplicate_of_empty_submodule(ModuleName, ParentModuleName,
     Msg1 = msg(Context, Pieces1),
     Pieces2 = [words("This is the location of the empty submodule,"), nl],
     Msg2 = msg(EmptyContext, Pieces2),
-    Spec = diag_spec($pred, severity_warning(warn_nothing_exported),
+    Spec = gen_spec($pred, severity_warning(warn_nothing_exported),
         phase_pt2h, [Msg1, Msg2]),
     !:Specs = [Spec | !.Specs].
 
@@ -925,7 +944,7 @@ warn_duplicate_of_empty_submodule(ModuleName, ParentModuleName,
 
 :- pred report_duplicate_submodule(module_name::in, prog_context::in,
     duplicated_section::in, module_name::in, split_module_entry::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 report_duplicate_submodule(ModuleName, Context, DupSection,
         ParentModuleName, OldEntry, !Specs) :-
@@ -943,7 +962,7 @@ report_duplicate_submodule(ModuleName, Context, DupSection,
             words("of that previous declaration."), nl],
         Msg = msg(Context, Pieces),
         OldMsg = msg(OldContext, OldPieces),
-        Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg, OldMsg])
+        Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg, OldMsg])
     ;
         OldEntry = split_nested(SplitNested, _, _),
         (
@@ -959,7 +978,7 @@ report_duplicate_submodule(ModuleName, Context, DupSection,
             OldPieces = [words("That previous declaration was here."), nl],
             Msg = msg(Context, Pieces),
             OldMsg = msg(OldContext, OldPieces),
-            Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg, OldMsg])
+            Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg, OldMsg])
         ;
             DupSection = dup_int_only,
             report_duplicate_submodule_one_section(ModuleName, Context,
@@ -998,7 +1017,7 @@ report_duplicate_submodule(ModuleName, Context, DupSection,
 
 :- pred report_duplicate_submodule_one_section(module_name::in,
     prog_context::in, module_section::in, module_name::in,
-    split_nested_info::in, diag_spec::out) is det.
+    split_nested_info::in, err_spec::out) is det.
 
 report_duplicate_submodule_one_section(ModuleName, Context, Section,
         ParentModuleName, SplitNested, Spec) :-
@@ -1054,7 +1073,7 @@ report_duplicate_submodule_one_section(ModuleName, Context, Section,
 
 :- pred report_duplicate_submodule_one_section_2(module_name::in,
     prog_context::in, string::in, module_name::in, prog_context::in,
-    diag_spec::out) is det.
+    err_spec::out) is det.
 
 report_duplicate_submodule_one_section_2(ModuleName, Context,
         SectionWord, ParentModuleName, OldContext, Spec) :-
@@ -1070,11 +1089,11 @@ report_duplicate_submodule_one_section_2(ModuleName, Context,
         [nl],
     Msg = msg(Context, Pieces),
     OldMsg = msg(OldContext, OldPieces),
-    Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg, OldMsg]).
+    Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg, OldMsg]).
 
 :- pred report_duplicate_submodule_both_sections(module_name::in,
     prog_context::in, module_name::in, prog_context::in, prog_context::in,
-    diag_spec::out) is det.
+    err_spec::out) is det.
 
 report_duplicate_submodule_both_sections(ModuleName, Context,
         ParentModuleName, OldIntContext, OldImpContext, Spec) :-
@@ -1093,7 +1112,7 @@ report_duplicate_submodule_both_sections(ModuleName, Context,
             [nl],
         Msg = msg(Context, Pieces),
         OldMsg = msg(OldIntContext, OldPieces),
-        Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg, OldMsg])
+        Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg, OldMsg])
     else
         OldIntPieces = [words("However, its interface"),
             words("was also declared")] ++
@@ -1106,12 +1125,12 @@ report_duplicate_submodule_both_sections(ModuleName, Context,
         Msg = msg(Context, Pieces),
         OldIntMsg = msg(OldIntContext, OldIntPieces),
         OldImpMsg = msg(OldImpContext, OldImpPieces),
-        Spec = diag_spec($pred, severity_error, phase_pt2h,
+        Spec = gen_spec($pred, severity_error, phase_pt2h,
             [Msg, OldIntMsg, OldImpMsg])
     ).
 
 :- pred report_duplicate_submodule_vs_top(module_name::in, prog_context::in,
-    module_name::in, diag_spec::out) is det.
+    module_name::in, err_spec::out) is det.
 
 report_duplicate_submodule_vs_top(ModuleName, Context, ParentModuleName,
         Spec) :-
diff --git a/compiler/state_var.m b/compiler/state_var.m
index aafda0227..d6fd8ffa1 100644
--- a/compiler/state_var.m
+++ b/compiler/state_var.m
@@ -83,10 +83,11 @@
                 ui_state_var_store  :: svar_store,
 
                 % The errors and warnings that we definitely want to print.
-                % (The svar_store also contains diag_specs, but we print those
+                % (The svar_store also contains warn_specs, but we print those
                 % only as hints *if and when* we later find certain other kinds
                 % of errors.)
-                ui_diag_specs      :: list(diag_spec)
+                ui_err_specs       :: list(err_spec),
+                ui_warn_specs      :: list(warn_spec)
             ).
 
 %---------------------------------------------------------------------------%
@@ -100,11 +101,16 @@
 :- pred record_unravel_found_syntax_error(
     unravel_info::in, unravel_info::out) is det.
 
-:- pred add_unravel_spec(diag_spec::in,
+:- pred add_unravel_err(err_spec::in,
     unravel_info::in, unravel_info::out) is det.
-:- pred add_unravel_specs(list(diag_spec)::in,
+:- pred add_unravel_errs(list(err_spec)::in,
     unravel_info::in, unravel_info::out) is det.
-:- pred add_unravel_oom_specs(one_or_more(diag_spec)::in,
+:- pred add_unravel_oom_errs(one_or_more(err_spec)::in,
+    unravel_info::in, unravel_info::out) is det.
+
+:- pred add_unravel_warn(warn_spec::in,
+    unravel_info::in, unravel_info::out) is det.
+:- pred add_unravel_warns(list(warn_spec)::in,
     unravel_info::in, unravel_info::out) is det.
 
 %---------------------------------------------------------------------------%
@@ -200,7 +206,7 @@
 :- pred svar_finish_clause_body(prog_context::in, new_statevar_map::in,
     map(svar, prog_var)::in, svar_state::in, svar_state::in,
     hlds_goal::in, hlds_goal::in, hlds_goal::out,
-    list(diag_spec)::out, unused_statevar_arg_map::out,
+    list(warn_spec)::out, unused_statevar_arg_map::out,
     unravel_info::in, unravel_info::out) is det.
 
     % Finish processing a lambda expression.
@@ -385,12 +391,12 @@
 :- pred report_illegal_func_svar_result(prog_context::in, svar::in,
     unravel_info::in, unravel_info::out) is det.
 :- func report_illegal_func_svar_result_raw(prog_context,
-    prog_varset, svar) = diag_spec.
+    prog_varset, svar) = err_spec.
 
 :- pred report_illegal_bang_svar_lambda_arg(prog_context::in, svar::in,
     unravel_info::in, unravel_info::out) is det.
 :- func report_illegal_bang_svar_lambda_arg_raw(prog_context,
-    prog_varset, svar) = diag_spec.
+    prog_varset, svar) = err_spec.
 
 :- pred report_svar_unify_error(prog_context::in, svar::in,
     svar_state::in, svar_state::out,
@@ -446,25 +452,35 @@ record_unravel_found_syntax_error(!UrInfo) :-
     qual_info_set_found_syntax_error(yes, QualInfo0, QualInfo),
     !UrInfo ^ ui_qual_info := QualInfo.
 
-add_unravel_spec(NewSpec, !UrInfo) :-
-    Specs0 = !.UrInfo ^ ui_diag_specs,
+add_unravel_err(NewSpec, !UrInfo) :-
+    Specs0 = !.UrInfo ^ ui_err_specs,
     Specs = [NewSpec | Specs0],
-    !UrInfo ^ ui_diag_specs := Specs.
+    !UrInfo ^ ui_err_specs := Specs.
 
-add_unravel_specs(NewSpecs, !UrInfo) :-
+add_unravel_errs(NewSpecs, !UrInfo) :-
     (
         NewSpecs = []
     ;
         NewSpecs = [_ | _],
-        Specs0 = !.UrInfo ^ ui_diag_specs,
+        Specs0 = !.UrInfo ^ ui_err_specs,
         Specs = NewSpecs ++ Specs0,
-        !UrInfo ^ ui_diag_specs := Specs
+        !UrInfo ^ ui_err_specs := Specs
     ).
 
-add_unravel_oom_specs(one_or_more(HeadSpec, TailSpecs), !UrInfo) :-
-    Specs0 = !.UrInfo ^ ui_diag_specs,
+add_unravel_oom_errs(one_or_more(HeadSpec, TailSpecs), !UrInfo) :-
+    Specs0 = !.UrInfo ^ ui_err_specs,
     Specs = [HeadSpec | TailSpecs] ++ Specs0,
-    !UrInfo ^ ui_diag_specs := Specs.
+    !UrInfo ^ ui_err_specs := Specs.
+
+add_unravel_warn(NewSpec, !UrInfo) :-
+    Specs0 = !.UrInfo ^ ui_warn_specs,
+    Specs = [NewSpec | Specs0],
+    !UrInfo ^ ui_warn_specs := Specs.
+
+add_unravel_warns(NewSpecs, !UrInfo) :-
+    Specs0 = !.UrInfo ^ ui_warn_specs,
+    Specs = NewSpecs ++ Specs0,
+    !UrInfo ^ ui_warn_specs := Specs.
 
 %---------------------------------------------------------------------------%
 %
@@ -570,7 +586,7 @@ add_unravel_oom_specs(one_or_more(HeadSpec, TailSpecs), !UrInfo) :-
                 % As of 2025 feb 20, these messages are all about situations
                 % in which a disjunction or an if-then-else initialises
                 % a state variable in some branches but not in others.
-                store_missing_init_specs    ::  list(diag_spec)
+                store_missing_init_specs    ::  list(warn_spec)
             ).
 
     % Create a new svar_state/store set up to start processing a clause head.
@@ -755,9 +771,10 @@ svar_prepare_for_clause_head(ModuleInfo0, QualInfo0, VarSet0,
     Threshold = OptTuple ^ ot_from_ground_term_threshold,
     !:SVarState = new_svar_state,
     SVarStore0 = new_svar_store,
-    Specs0 = [],
+    ErrSpecs0 = [],
+    WarnSpecs0 = [],
     !:UrInfo = unravel_info(ModuleInfo0, Threshold, QualInfo0, VarSet0,
-        SVarStore0, Specs0),
+        SVarStore0, ErrSpecs0, WarnSpecs0),
     svar_prepare_head_terms(0u, 1u, Args0, Args, map.init, FinalMap,
         !SVarState, init_new_statevar_map, NewSVars, !UrInfo).
 
@@ -1342,7 +1359,7 @@ find_changes_in_arm_and_update_changed_status_map([Before | Befores],
     list(hlds_goal)::in, list(hlds_goal)::out,
     ucounter::in, ucounter::out,
     incremental_rename_map::in, incremental_rename_map::out,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 merge_changes_made_by_arms(_, [], _, _,
         !RevArms, !NextGoalId, !DelayedRenamings, !Specs).
@@ -2563,8 +2580,8 @@ report_illegal_state_var_update(Context, RO_Construct, RO_Context,
     Pieces2 = [words("Here is the surrounding context that makes"),
         words("state variable"), quote(Name), words("readonly."), nl],
     Msg2 = msg(RO_Context, Pieces2),
-    Spec = diag_spec($pred, severity_error, phase_pt2h, [Msg1, Msg2]),
-    add_unravel_spec(Spec, !UrInfo).
+    Spec = gen_spec($pred, severity_error, phase_pt2h, [Msg1, Msg2]),
+    add_unravel_err(Spec, !UrInfo).
 
 :- func ro_construct_name(readonly_context_kind) = string.
 
@@ -2575,7 +2592,7 @@ ro_construct_name(roc_lambda) = "lambda expression".
 report_illegal_func_svar_result(Context, StateVar, !UrInfo) :-
     VarSet = !.UrInfo ^ ui_varset,
     Spec = report_illegal_func_svar_result_raw(Context, VarSet, StateVar),
-    add_unravel_spec(Spec, !UrInfo).
+    add_unravel_err(Spec, !UrInfo).
 
 report_illegal_func_svar_result_raw(Context, VarSet, StateVar) = Spec :-
     Name = varset.lookup_name(VarSet, StateVar),
@@ -2593,7 +2610,7 @@ report_illegal_func_svar_result_raw(Context, VarSet, StateVar) = Spec :-
 report_illegal_bang_svar_lambda_arg(Context, StateVar, !UrInfo) :-
     VarSet = !.UrInfo ^ ui_varset,
     Spec = report_illegal_bang_svar_lambda_arg_raw(Context, VarSet, StateVar),
-    add_unravel_spec(Spec, !UrInfo).
+    add_unravel_err(Spec, !UrInfo).
 
 report_illegal_bang_svar_lambda_arg_raw(Context, VarSet, StateVar) = Spec :-
     Name = varset.lookup_name(VarSet, StateVar),
@@ -2618,7 +2635,7 @@ report_non_visible_state_var(DorC, Context, StateVar, !UrInfo) :-
         color_as_incorrect([quote("!" ++ DorC ++ Name)]) ++
         [words("is not visible in this context."), nl],
     Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-    add_unravel_spec(Spec, !UrInfo).
+    add_unravel_err(Spec, !UrInfo).
 
 %---------------------------------------------------------------------------%
 
@@ -2635,7 +2652,7 @@ report_uninitialized_state_var(WarnOption, Context, StateVar, !UrInfo) :-
         [words("yet."), nl],
     Spec = spec($pred, severity_warning(WarnOption), phase_pt2h,
         Context, Pieces),
-    add_unravel_spec(Spec, !UrInfo).
+    add_unravel_warn(Spec, !UrInfo).
 
 %---------------------------------------------------------------------------%
 
@@ -2649,7 +2666,7 @@ report_repeated_head_state_var(Context, StateVar, !UrInfo) :-
         color_as_incorrect([words("state variable"), quote(Name)]) ++
         [words("more than once."), nl],
     Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-    add_unravel_spec(Spec, !UrInfo).
+    add_unravel_err(Spec, !UrInfo).
 
 %---------------------------------------------------------------------------%
 
@@ -2664,7 +2681,7 @@ report_state_var_shadow(Context, StateVar, !UrInfo) :-
         color_as_incorrect([words("shadows old one.")]) ++ [nl],
     Spec = spec($pred, severity_warning(warn_state_var_shadowing), phase_pt2h,
         Context, Pieces),
-    add_unravel_spec(Spec, !UrInfo).
+    add_unravel_warn(Spec, !UrInfo).
 
 %---------------------------------------------------------------------------%
 
@@ -2688,7 +2705,7 @@ report_missing_inits_in_ite(Context, NextStateVars,
     !UrInfo ^ ui_state_var_store ^ store_missing_init_specs := Specs.
 
 :- pred report_missing_inits_in_disjunct(prog_context::in, list(string)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 report_missing_inits_in_disjunct(Context, NextStateVars, !Specs) :-
     Pieces = [words("Other disjuncts define")] ++
@@ -2713,7 +2730,7 @@ report_svar_unify_error(Context, StateVar, !SVarState, !UrInfo) :-
         color_as_correct([fixed("!." ++ Name)]) ++ [words("or")] ++
         color_as_correct([fixed("!:" ++ Name), suffix(".")]) ++ [nl],
     Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-    add_unravel_spec(Spec, !UrInfo),
+    add_unravel_err(Spec, !UrInfo),
     !.SVarState = svar_state(StatusMap0),
     % If StateVar was not known before, then this is the first occurrence
     % of this state variable, and the user almost certainly intended it
@@ -2820,7 +2837,7 @@ report_unneeded_svar_in_lambda(Context, Modes, ParseTreeGoal, GoalVarSVarNames,
             words("replaced with an ordinary variable."), nl],
         Severity = severity_warning(warn_unneeded_initial_statevars_lambda),
         Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),
-        add_unravel_spec(Spec, !UrInfo)
+        add_unravel_warn(Spec, !UrInfo)
     ;
         InitOrFinal = init_and_final_arg(_),
         % Please keep this wording in sync with the code of the
@@ -2859,7 +2876,7 @@ report_unneeded_svar_in_lambda(Context, Modes, ParseTreeGoal, GoalVarSVarNames,
                 Severity =
                     severity_warning(warn_unneeded_final_statevars_lambda),
                 Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),
-                add_unravel_spec(Spec, !UrInfo)
+                add_unravel_warn(Spec, !UrInfo)
             else
                 true
             )
@@ -2878,7 +2895,7 @@ report_unneeded_svar_in_lambda(Context, Modes, ParseTreeGoal, GoalVarSVarNames,
                 words("is always the same as the initial value."), nl],
             Severity = severity_warning(warn_unneeded_final_statevars_lambda),
             Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),
-            add_unravel_spec(Spec, !UrInfo)
+            add_unravel_warn(Spec, !UrInfo)
         )
     ).
 
diff --git a/compiler/stratify.m b/compiler/stratify.m
index 7c7b89656..f79e47efc 100644
--- a/compiler/stratify.m
+++ b/compiler/stratify.m
@@ -1037,7 +1037,7 @@ generate_stratify_error(ModuleInfo, PredProcId, Context, Message,
     Msg = simple_msg(Context,
         [always(Preamble ++ MainPieces),
         verbose_only(verbose_once, VerbosePieces)]),
-    Spec = diag_spec($pred, Severity, phase_code_gen, [Msg]).
+    Spec = gen_spec($pred, Severity, phase_code_gen, [Msg]).
 
 %-----------------------------------------------------------------------------%
 :- end_module check_hlds.stratify.
diff --git a/compiler/style_checks.m b/compiler/style_checks.m
index d24dc5f90..87910c77e 100644
--- a/compiler/style_checks.m
+++ b/compiler/style_checks.m
@@ -605,7 +605,7 @@ report_any_inc_gaps(PredInfo, FirstINC, SecondINC, LaterINCs,
         FirstMsg = msg(FirstContext, FirstPieces),
         SecondMsg = msg(SecondContext, SecondPieces),
         Severity = severity_warning(warn_non_contiguous_decls),
-        Spec = diag_spec($pred, Severity, phase_style, [FirstMsg, SecondMsg]),
+        Spec = gen_spec($pred, Severity, phase_style, [FirstMsg, SecondMsg]),
         Specs0 = !.StyleInfo ^ style_decl_gap_specs,
         Specs = [Spec | Specs0],
         !StyleInfo ^ style_decl_gap_specs := Specs
@@ -784,7 +784,7 @@ report_non_contiguous_clauses(ModuleInfo, ItemKind, OtherPredIds, MainPredId,
         ItemKind = clauses_and_foreign_procs,
         WarnOption = warn_non_contiguous_foreign_procs
     ),
-    Spec = diag_spec($pred, severity_warning(WarnOption),
+    Spec = gen_spec($pred, severity_warning(WarnOption),
         phase_type_check, Msgs),
     !:Specs = [Spec | !.Specs].
 
diff --git a/compiler/superhomogeneous.m b/compiler/superhomogeneous.m
index 0b562c8a4..8d0d5f5fd 100644
--- a/compiler/superhomogeneous.m
+++ b/compiler/superhomogeneous.m
@@ -506,7 +506,7 @@ maybe_unravel_special_var_functor_unification(XVar, YAtom, YArgTerms,
 %               words("of the form"), quote("<term> " ++ YAtom ++ " <type>"),
 %               suffix("."), nl],
 %           Msg = simple_msg(YFunctorContext, [always(Pieces)]),
-%           Spec = diag_spec(severity_error, phase_pt2h, [Msg]),
+%           Spec = gen_spec(severity_error, phase_pt2h, [Msg]),
 %           !:Specs = [Spec | !.Specs],
 %           qual_info_set_found_syntax_error(yes, !QualInfo),
 %           Expansion = expansion(not_fgti, cord.empty)
@@ -543,7 +543,7 @@ maybe_unravel_special_var_functor_unification(XVar, YAtom, YArgTerms,
 %               words("of the form"), quote("<term> " ++ YAtom ++ " <term>"),
 %               suffix("."), nl],
 %           Msg = simple_msg(YFunctorContext, [always(Pieces)]),
-%           Spec = diag_spec(severity_error, phase_pt2h, [Msg]),
+%           Spec = gen_spec(severity_error, phase_pt2h, [Msg]),
 %           !:Specs = [Spec | !.Specs],
 %           qual_info_set_found_syntax_error(yes, !QualInfo),
 %           Expansion = expansion(not_fgti, cord.empty)
@@ -595,7 +595,7 @@ maybe_unravel_special_var_functor_unification(XVar, YAtom, YArgTerms,
 %               words("can be used only in expressions of the form"),
 %               quote("<term> ^ <fieldname>"), suffix("."), nl],
 %           Msg = simple_msg(YFunctorContext, [always(Pieces)]),
-%           Spec = diag_spec(severity_error, phase_pt2h, [Msg]),
+%           Spec = gen_spec(severity_error, phase_pt2h, [Msg]),
 %           !:Specs = [Spec | !.Specs],
 %           qual_info_set_found_syntax_error(yes, !QualInfo),
 %           Expansion = expansion(not_fgti, cord.empty)
@@ -621,7 +621,7 @@ maybe_unravel_special_var_functor_unification(XVar, YAtom, YArgTerms,
 %               quote("<term> ^ <fieldname> := <newfieldvalueterm>"),
 %               suffix("."), nl],
 %           Msg = simple_msg(YFunctorContext, [always(Pieces)]),
-%           Spec = diag_spec(severity_error, phase_pt2h, [Msg]),
+%           Spec = gen_spec(severity_error, phase_pt2h, [Msg]),
 %           !:Specs = [Spec | !.Specs],
 %           qual_info_set_found_syntax_error(yes, !QualInfo),
 %           Expansion = expansion(not_fgti, cord.empty)
@@ -655,7 +655,7 @@ maybe_unravel_special_var_functor_unification(XVar, YAtom, YArgTerms,
                 [nl],
             Spec = spec($pred, severity_error, phase_pt2h,
                 YFunctorContext, Pieces),
-            add_unravel_spec(Spec, !UrInfo),
+            add_unravel_err(Spec, !UrInfo),
             record_unravel_found_syntax_error(!UrInfo),
             Expansion = expansion(not_fgti, cord.empty)
         )
@@ -730,12 +730,12 @@ unravel_special_with_type(XVar, RValTerm, DeclTypeTerm0,
             YFunctorContext, QualInfo0, QualInfo, [], TypeQualSpecs),
         !UrInfo ^ ui_qual_info := QualInfo,
         % Note that most of time, TypeQualSpecs will be [].
-        add_unravel_specs(TypeQualSpecs, !UrInfo)
+        add_unravel_errs(TypeQualSpecs, !UrInfo)
     ;
         DeclTypeResult = error1(DeclTypeSpecs),
         % The varset is a prog_varset even though it contains the names
         % of type variables in ErrorTerm, which is a generic term.
-        add_unravel_oom_specs(DeclTypeSpecs, !UrInfo)
+        add_unravel_oom_errs(DeclTypeSpecs, !UrInfo)
     ),
     do_unravel_var_unification(XVar, RValTerm,
         Context, MainContext, SubContext, Purity, Order, Expansion,
@@ -792,7 +792,7 @@ unravel_special_if_then_else(XVar, CondTerm0, ThenTerm0, ElseTerm0,
     (
         MaybeVarsCond =
             ok4(Vars, StateVars, CondParseTree, CondWarningSpecs),
-        add_unravel_specs(CondWarningSpecs, !UrInfo),
+        add_unravel_warns(CondWarningSpecs, !UrInfo),
         BeforeSVarState = !.SVarState,
         svar_prepare_for_local_state_vars(Context, StateVars,
             BeforeSVarState, BeforeInsideSVarState, !UrInfo),
@@ -839,8 +839,9 @@ unravel_special_if_then_else(XVar, CondTerm0, ThenTerm0, ElseTerm0,
         Goal = hlds_goal(GoalExpr, GoalInfo),
         Expansion = expansion(not_fgti, cord.singleton(Goal))
     ;
-        MaybeVarsCond = error4(VarsCondSpecs),
-        add_unravel_oom_specs(VarsCondSpecs, !UrInfo),
+        MaybeVarsCond = error4({OoMVarsCondErrSpecs, VarsConsWarnSpecs}),
+        add_unravel_oom_errs(OoMVarsCondErrSpecs, !UrInfo),
+        add_unravel_warns(VarsConsWarnSpecs, !UrInfo),
         Expansion = expansion(not_fgti,
             cord.singleton(true_goal_with_context(Context)))
     ).
@@ -1022,7 +1023,7 @@ parse_ordinary_cons_id(Functor, ArgTerms, Context, ConsId, !UrInfo) :-
             MaybeConsId = ok1(ConsId)
         ;
             MaybeConsId = error1(ConsIdSpecs),
-            add_unravel_oom_specs(ConsIdSpecs, !UrInfo),
+            add_unravel_oom_errs(ConsIdSpecs, !UrInfo),
             % This is a dummy.
             ConsId = some_int_const(int_const(0))
         )
@@ -1063,7 +1064,7 @@ parse_ordinary_cons_id(Functor, ArgTerms, Context, ConsId, !UrInfo) :-
                 [words("and")] ++
                 color_as_correct([quote("$grade"), suffix(".")]) ++ [nl],
             Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),
-            add_unravel_spec(Spec, !UrInfo),
+            add_unravel_err(Spec, !UrInfo),
             % This is a dummy.
             ConsId = impl_defined_const(idc_line)
         )
@@ -1386,7 +1387,7 @@ perform_occurs_check(AncestorVarMap, Var, !UrInfo) :-
                 [nl],
             Severity = severity_warning(warn_suspected_occurs_check_failure),
             Spec = spec($pred, Severity, phase_pt2h, AncestorContext, Pieces),
-            add_unravel_spec(Spec, !UrInfo)
+            add_unravel_warn(Spec, !UrInfo)
         )
     else
         true
diff --git a/compiler/superhomogeneous_lambda.m b/compiler/superhomogeneous_lambda.m
index 049d3d4b2..bf9ea5ef2 100644
--- a/compiler/superhomogeneous_lambda.m
+++ b/compiler/superhomogeneous_lambda.m
@@ -116,19 +116,19 @@ parse_lambda_expr(XVar, Purity, Context, MainContext, SubContext,
         ),
         !UrInfo ^ ui_varset := VarSet,
         (
-            MaybeBodyGoal0 = ok2(BodyGoal, BodyGoalWarningSpecs),
-            add_unravel_specs(BodyGoalWarningSpecs, !UrInfo),
+            MaybeBodyGoal0 = ok2(BodyGoal, BodyGoalWarnSpecs),
             MaybeBodyGoal = ok1(BodyGoal)
         ;
-            MaybeBodyGoal0 = error2(BodyGoalSpecs),
-            MaybeBodyGoal = error1(BodyGoalSpecs)
-        )
+            MaybeBodyGoal0 = error2({BodyGoalErrSpecs, BodyGoalWarnSpecs}),
+            MaybeBodyGoal = error1(BodyGoalErrSpecs)
+        ),
+        add_unravel_warns(BodyGoalWarnSpecs, !UrInfo)
     ),
     parse_lambda_purity_pf_args_det_term(PurityPFArgsDetTerm, MaybeDCGVars,
         MaybeLambdaHead, !UrInfo),
     (
         MaybeLambdaHead = error1(LambdaHeadSpecs),
-        add_unravel_oom_specs(LambdaHeadSpecs, !UrInfo),
+        add_unravel_oom_errs(LambdaHeadSpecs, !UrInfo),
         record_unravel_found_syntax_error(!UrInfo),
         Expansion = expansion(not_fgti, cord.empty)
     ;
@@ -366,7 +366,7 @@ split_last_two(Element1, Element2, Elements3plus, Main, LastButOne, Last) :-
 %---------------------------------------------------------------------------%
 
 :- pred parse_lambda_args_func(term.context::in, list(term)::in, term::in,
-    list(lambda_arg)::out, list(diag_spec)::out, list(diag_spec)::out,
+    list(lambda_arg)::out, list(err_spec)::out, list(err_spec)::out,
     unravel_info::in, unravel_info::out) is det.
 
 parse_lambda_args_func(Context, ArgModeTerms, FuncRetArgModeTerm,
@@ -400,7 +400,7 @@ parse_lambda_args_func(Context, ArgModeTerms, FuncRetArgModeTerm,
     ).
 
 :- pred parse_lambda_args_pred(term.context::in, list(term)::in,
-    list(lambda_arg)::out, list(diag_spec)::out, list(diag_spec)::out,
+    list(lambda_arg)::out, list(err_spec)::out, list(err_spec)::out,
     unravel_info::in, unravel_info::out) is det.
 
 parse_lambda_args_pred(Context, ArgModeTerms,
@@ -447,7 +447,7 @@ classify_lambda_arg_modes_present_absent([LambdaArg | LambdaArgs],
 
 :- pred add_some_not_all_args_have_modes_error(prog_context::in,
     list(lambda_arg)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_some_not_all_args_have_modes_error(Context, AbsentArgs, !Specs) :-
     AbsentArgPieces =
@@ -464,7 +464,7 @@ add_some_not_all_args_have_modes_error(Context, AbsentArgs, !Specs) :-
     !:Specs = [Spec | !.Specs].
 
 :- pred add_pred_no_args_have_modes_error(prog_context::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(err_spec)::in, list(err_spec)::out) is det.
 
 add_pred_no_args_have_modes_error(Context, !Specs) :-
     % We could use _AbsentArgs to make the error message more detailed.
@@ -541,8 +541,8 @@ project_lambda_var_arg_mode(LambdaArg) = LambdaVar - Mode :-
     %
 :- pred parse_lambda_args(lambda_arg_kind::in,
     list(term)::in, list(lambda_arg)::out, int::in, int::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
     unravel_info::in, unravel_info::out) is det.
 
 parse_lambda_args(_Kind, [], [], !ArgNum, !BadModeSpecs, !SVarSpecs, !UrInfo).
@@ -556,8 +556,8 @@ parse_lambda_args(Kind, [HeadArgModeTerm | TailArgModeTerms],
 
 :- pred parse_lambda_arg(lambda_arg_kind::in,
     term::in, lambda_arg::out, int::in, int::out,
-    list(diag_spec)::in, list(diag_spec)::out,
-    list(diag_spec)::in, list(diag_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
+    list(err_spec)::in, list(err_spec)::out,
     unravel_info::in, unravel_info::out) is det.
 
 parse_lambda_arg(Kind, ArgModeTerm, LambdaArg, !ArgNum,
@@ -678,9 +678,9 @@ parse_lambda_detism(VarSet, DetismTerm, MaybeDetism) :-
                 ho_groundness,
                 pred_or_func,
                 list(lambda_arg),
-                list(diag_spec),       % Errors about unparseable and/or
+                list(err_spec),         % Errors about unparseable and/or
                                         % missing arg modes.
-                list(diag_spec),       % Errors about !X arguments.
+                list(err_spec),         % Errors about !X arguments.
                 maybe1(determinism)     % The determinism of the lambda expr.
             ).
 
@@ -745,7 +745,7 @@ build_lambda_expression(LHSVar, UnificationPurity,
         MaybeDetism = ok1(Detism)
     ;
         MaybeDetism = error1(DetismSpecs),
-        add_unravel_oom_specs(DetismSpecs, !UrInfo),
+        add_unravel_oom_errs(DetismSpecs, !UrInfo),
         % Due to the error, this dummy value won't be used.
         Detism = detism_det
     ),
@@ -753,7 +753,7 @@ build_lambda_expression(LHSVar, UnificationPurity,
         MaybeBodyGoal = ok1(BodyGoal)
     ;
         MaybeBodyGoal = error1(BodyGoalSpecs),
-        add_unravel_oom_specs(BodyGoalSpecs, !UrInfo),
+        add_unravel_oom_errs(BodyGoalSpecs, !UrInfo),
         record_unravel_found_syntax_error(!UrInfo),
         % Due to the error, this dummy value won't be used.
         BodyGoal = true_expr(Context)
@@ -762,7 +762,7 @@ build_lambda_expression(LHSVar, UnificationPurity,
     ArgSpecs = BadModeSpecs ++ SVarSpecs,
     (
         ArgSpecs = [_ | _],
-        add_unravel_specs(ArgSpecs, !UrInfo),
+        add_unravel_errs(ArgSpecs, !UrInfo),
         record_unravel_found_syntax_error(!UrInfo),
         Goal = true_goal_with_context(Context)
     ;
@@ -896,7 +896,7 @@ warn_about_any_inconsistent_inst_vars(InstVarSet, Context, Modes, !UrInfo) :-
             piece_list_to_color_pieces(color_subject, "and", [], VarPieces) ++
             color_as_incorrect([words("are inconsistent.")]) ++ [nl],
         Spec = spec($pred, severity_error, phase_t2pt, Context, Pieces),
-        add_unravel_spec(Spec, !UrInfo)
+        add_unravel_err(Spec, !UrInfo)
     ).
 
     % Partition the lists of arguments and variables into lists
diff --git a/compiler/term_constr_errors.m b/compiler/term_constr_errors.m
index 8e5832b20..82f6ee72d 100644
--- a/compiler/term_constr_errors.m
+++ b/compiler/term_constr_errors.m
@@ -207,7 +207,7 @@ report_term2_errors(ModuleInfo, SCC, Errors, !Specs) :-
     ReasonMsgs = cord.list(ReasonMsgsCord),
     Msgs = [simple_msg(Context, [always(Pieces1 ++ Pieces2)]) | ReasonMsgs],
     Severity = severity_warning(warn_requested_by_option),
-    Spec = diag_spec($pred, Severity, phase_termination_analysis, Msgs),
+    Spec = gen_spec($pred, Severity, phase_termination_analysis, Msgs),
     !:Specs = [Spec | !.Specs].
 
 :- pred describe_term2_errors(module_info::in, maybe(pred_proc_id)::in,
diff --git a/compiler/term_errors.m b/compiler/term_errors.m
index 3a0568964..5611b1b5a 100644
--- a/compiler/term_errors.m
+++ b/compiler/term_errors.m
@@ -214,7 +214,7 @@ report_term_errors(ModuleInfo, SCC, Errors, !Specs) :-
     ReasonMsgs = cord.list(ReasonMsgsCord),
     Msgs = [msg(Context, Pieces) | ReasonMsgs],
     Severity = severity_warning(warn_requested_by_option),
-    Spec = diag_spec($pred, Severity, phase_termination_analysis, Msgs),
+    Spec = gen_spec($pred, Severity, phase_termination_analysis, Msgs),
     !:Specs = [Spec | !.Specs].
 
 :- pred report_arg_size_errors(module_info::in, scc::in, list(term_error)::in,
@@ -253,7 +253,7 @@ report_arg_size_errors(ModuleInfo, SCC, Errors, !Specs) :-
     ReasonMsgs = cord.list(ReasonMsgsCord),
     Msgs = [msg(Context, Pieces) | ReasonMsgs],
     Severity = severity_warning(warn_requested_by_option),
-    Spec = diag_spec($pred, Severity, phase_termination_analysis, Msgs),
+    Spec = gen_spec($pred, Severity, phase_termination_analysis, Msgs),
     !:Specs = [Spec | !.Specs].
 
 :- pred describe_term_errors(module_info::in, maybe(pred_proc_id)::in,
diff --git a/compiler/typecheck.m b/compiler/typecheck.m
index fbe58a5df..9f791463e 100644
--- a/compiler/typecheck.m
+++ b/compiler/typecheck.m
@@ -230,7 +230,7 @@ typecheck_to_fixpoint(ProgressStream, Iteration, MaxIterations, !ModuleInfo,
             trace [io(!IO)] (
                 module_info_get_name(!.ModuleInfo, ModuleName),
                 get_debug_output_stream(Globals, ModuleName, DebugStream, !IO),
-                write_error_specs(DebugStream, Globals, ProgressSpecs, !IO)
+                write_diag_specs(DebugStream, Globals, ProgressSpecs, !IO)
             )
         ;
             DebugTypes = no
diff --git a/compiler/typecheck_error_arg_vector.m b/compiler/typecheck_error_arg_vector.m
index 5548372fa..c7cd257fd 100644
--- a/compiler/typecheck_error_arg_vector.m
+++ b/compiler/typecheck_error_arg_vector.m
@@ -108,7 +108,7 @@ report_error_wrong_types_in_arg_vector(Info, Context,
     Msg = simple_msg(Context,
         [always(InClauseForPieces), always(ArgVectorKindPieces),
         always(ArgErrorPieces ++ InvisIntPieces), VerboseComponent]),
-    Spec = diag_spec($pred, severity_error, phase_type_check, [Msg]).
+    Spec = gen_spec($pred, severity_error, phase_type_check, [Msg]).
 
 :- pred arg_vector_type_errors_to_pieces(prog_varset::in,
     list(arg_vector_type_error)::in,
diff --git a/compiler/typecheck_error_overload.m b/compiler/typecheck_error_overload.m
index 9bdcb38f6..e7407a2b3 100644
--- a/compiler/typecheck_error_overload.m
+++ b/compiler/typecheck_error_overload.m
@@ -95,7 +95,7 @@ report_warning_too_much_overloading(ClauseContext, Context,
         InitPieces, VerbosePieces),
     LaterMsgs = describe_overloaded_symbols(ClauseContext, Context,
         OverloadedSymbolMap),
-    Spec = diag_spec($pred, severity_warning(warn_typecheck_ambiguity_limit),
+    Spec = gen_spec($pred, severity_warning(warn_typecheck_ambiguity_limit),
         phase_type_check, [FirstMsg | LaterMsgs]).
 
 report_error_too_much_overloading(ClauseContext, Context,
@@ -108,7 +108,7 @@ report_error_too_much_overloading(ClauseContext, Context,
         InitPieces, VerbosePieces),
     LaterMsgs = describe_overloaded_symbols(ClauseContext, Context,
         OverloadedSymbolMap),
-    Spec = diag_spec($pred, severity_error,
+    Spec = gen_spec($pred, severity_error,
         phase_type_check, [FirstMsg | LaterMsgs]).
 
 %---------------------------------------------------------------------------%
@@ -242,7 +242,7 @@ report_ambiguity_error(ClauseContext, Context, OverloadedSymbolMap,
         LaterMsgs = [VarMsg]
     ),
     Msgs = [FirstMsg | LaterMsgs],
-    Spec = diag_spec($pred, severity_error, phase_type_check, Msgs).
+    Spec = gen_spec($pred, severity_error, phase_type_check, Msgs).
 
 :- func var_ambiguity_to_pieces(prog_varset, inst_varset, list(type_assign),
     prog_var) = list(format_piece).
diff --git a/compiler/typecheck_error_undef.m b/compiler/typecheck_error_undef.m
index 964d6a3b2..a6b2a824d 100644
--- a/compiler/typecheck_error_undef.m
+++ b/compiler/typecheck_error_undef.m
@@ -129,7 +129,7 @@ report_error_call_to_undef_pred(ClauseContext, Context, SymNameArity) = Spec :-
             InClauseForComponent = always(InClauseForPieces),
             Msg = simple_msg(Context,
                 [InClauseForComponent | SpecialComponents]),
-            Spec = diag_spec($pred, severity_error, phase_type_check, [Msg])
+            Spec = gen_spec($pred, severity_error, phase_type_check, [Msg])
         ;
             UndefClass = undef_ordinary(MissingImportModules, AddendumPieces,
                 MaySuggestDefiningModules),
@@ -502,7 +502,7 @@ report_error_pred_wrong_full_name(ClauseContext, Context, PredicateTable,
         % XXX Should we print SuggestedNamesMsg as well even in this case?
         Msgs = [UndefMsg] ++ KindQualMsgs
     ),
-    Spec = diag_spec($pred, severity_error, phase_type_check, Msgs).
+    Spec = gen_spec($pred, severity_error, phase_type_check, Msgs).
 
 %---------------------%
 
@@ -534,7 +534,7 @@ report_error_undef_non_du_ctor(ClauseContext, GoalContext, Context, ConsId)
         [nl],
     UndefComp = always(UndefPieces),
     Msg = simple_msg(Context, [InitComp, UndefComp]),
-    Spec = diag_spec($pred, severity_error, phase_type_check, [Msg]).
+    Spec = gen_spec($pred, severity_error, phase_type_check, [Msg]).
 
 %---------------------------------------------------------------------------%
 %---------------------------------------------------------------------------%
@@ -560,7 +560,7 @@ report_error_undef_du_ctor(ClauseContext, GoalContext, Context, DuCtor,
             fail
         )
     then
-        Spec = diag_spec($pred, severity_error, phase_type_check,
+        Spec = gen_spec($pred, severity_error, phase_type_check,
             [simple_msg(Context, [ContextComp | FunctorComps])])
     else
         report_error_undef_du_ctor_std(ClauseContext, Context, ContextComp,
@@ -839,7 +839,7 @@ report_error_undef_du_ctor_std(ClauseContext, Context, ContextComp, DuCtor,
     ),
     FirstMsg = simple_msg(Context,
         [ContextComp | ConsFuncComps] ++ PredFuncComps),
-    Spec = diag_spec($pred, severity_error, phase_type_check,
+    Spec = gen_spec($pred, severity_error, phase_type_check,
         [FirstMsg | ConsMsgs] ++ SuggestionMsgs).
 
 :- pred return_pred_func_arities(module_info::in, list(pred_id)::in,
diff --git a/compiler/typecheck_error_unify.m b/compiler/typecheck_error_unify.m
index 1740f89b2..419ae1a21 100644
--- a/compiler/typecheck_error_unify.m
+++ b/compiler/typecheck_error_unify.m
@@ -109,7 +109,7 @@ report_error_unify_var_var(Info, UnifyContext, Context, X, Y, TypeAssignSet)
         VerboseComponent),
     Msg = simple_msg(Context,
         [always(ContextPieces), always(MainPieces), VerboseComponent]),
-    Spec = diag_spec($pred, severity_error, phase_type_check, [Msg]).
+    Spec = gen_spec($pred, severity_error, phase_type_check, [Msg]).
 
 %---------------------------------------------------------------------------%
 
@@ -181,7 +181,7 @@ report_error_unify_var_lambda(Info, UnifyContext, Context, PredOrFunc,
         VerboseComponent),
     Msg = simple_msg(Context,
         [always(ContextPieces), always(MainPieces), VerboseComponent]),
-    Spec = diag_spec($pred, severity_error, phase_type_check, [Msg]).
+    Spec = gen_spec($pred, severity_error, phase_type_check, [Msg]).
 
 %---------------------------------------------------------------------------%
 
@@ -280,7 +280,7 @@ report_error_unify_var_functor_result(Info, UnifyContext, Context,
     AlwaysPieces = ContextPieces ++ MainPieces ++
         NoSuffixIntegerPieces ++ InvisIntPieces,
     Msg = simple_msg(Context, [always(AlwaysPieces), VerboseComponent]),
-    Spec = diag_spec($pred, severity_error, phase_type_check, [Msg]).
+    Spec = gen_spec($pred, severity_error, phase_type_check, [Msg]).
 
 %---------------------------------------------------------------------------%
 
@@ -422,7 +422,7 @@ report_error_unify_var_functor_args(Info, UnifyContext, Context,
     AlwaysPieces = ContextPieces ++ VarAndTermPieces ++ ArgErrorPieces ++
         InvisIntTypePieces,
     Msg = simple_msg(Context, [always(AlwaysPieces) | VerboseComponents]),
-    Spec = diag_spec($pred, severity_error, phase_type_check, [Msg]).
+    Spec = gen_spec($pred, severity_error, phase_type_check, [Msg]).
 
 :- type mismatch_info
     --->    mismatch_info(
diff --git a/compiler/typecheck_error_wrong_type.m b/compiler/typecheck_error_wrong_type.m
index edfaf72e7..af30391e1 100644
--- a/compiler/typecheck_error_wrong_type.m
+++ b/compiler/typecheck_error_wrong_type.m
@@ -113,7 +113,7 @@ report_error_var_has_wrong_type(Info, GoalContext, Context, Var, ExpectedType,
     AlwaysPieces = InClauseForPieces ++ GoalContextPieces ++
         ActualExpectedPieces ++ DiffPieces ++ NoSuffixIntegerPieces,
     Msg = simple_msg(Context, [always(AlwaysPieces), VerboseComponent]),
-    Spec = diag_spec($pred, severity_error, phase_type_check, [Msg]),
+    Spec = gen_spec($pred, severity_error, phase_type_check, [Msg]),
     SpecAndMaybeActualExpected =
         spec_and_maybe_actual_expected(Spec, MaybeActualExpected).
 
@@ -141,7 +141,7 @@ report_error_var_has_wrong_type_arg(Info, GoalContext, Context,
         [always(InClauseForPieces), always(GoalContextPieces),
         always(ActualExpectedPieces), always(DiffPieces),
         VerboseComponent]),
-    Spec = diag_spec($pred, severity_error, phase_type_check, [Msg]).
+    Spec = gen_spec($pred, severity_error, phase_type_check, [Msg]).
 
 %---------------------------------------------------------------------------%
 
diff --git a/compiler/unused_imports.m b/compiler/unused_imports.m
index da8e26182..1472d52e7 100644
--- a/compiler/unused_imports.m
+++ b/compiler/unused_imports.m
@@ -347,7 +347,7 @@ maybe_generate_redundant_avail_warnings(ModuleName, [Avail | Avails],
             color_as_incorrect([words("redundant.")]) ++
             [nl],
         MainMsg = msg(Context, MainPieces),
-        Spec = diag_spec($pred, severity_informational(warn_unused_imports),
+        Spec = gen_spec($pred, severity_informational(warn_unused_imports),
             phase_code_gen, [MainMsg | PrevMsgs]),
         !:Specs = [Spec | !.Specs]
     ),
@@ -451,7 +451,7 @@ generate_unused_import_warning(ModuleName, MsgKind - OoMUnusedAvails0,
             ),
         ModuleMsgs = list.map(UnusedAvailToMsg,
             [HeadUnusedAvail | TailUnusedAvails]),
-        Spec = diag_spec($pred, severity_warning(warn_unused_imports),
+        Spec = gen_spec($pred, severity_warning(warn_unused_imports),
             phase_code_gen, [MainMsg | ModuleMsgs])
     ),
     !:Specs = [Spec | !.Specs].
diff --git a/compiler/warn_unread_modules.m b/compiler/warn_unread_modules.m
index ba1bb522c..29c68aec4 100644
--- a/compiler/warn_unread_modules.m
+++ b/compiler/warn_unread_modules.m
@@ -22,7 +22,7 @@
 
 :- pred warn_about_any_unread_modules_with_read_ancestors(
     set_tree234(module_name)::in, set_tree234(module_name)::in,
-    list(diag_spec)::in, list(diag_spec)::out) is det.
+    list(warn_spec)::in, list(warn_spec)::out) is det.
 
 %---------------------------------------------------------------------------%
 
diff --git a/compiler/write_deps_file.m b/compiler/write_deps_file.m
index 2831a2825..3d1556718 100644
--- a/compiler/write_deps_file.m
+++ b/compiler/write_deps_file.m
@@ -57,7 +57,7 @@
 %---------------------------------------------------------------------------%
 
     % generate_and_write_dep_file_gendep(ProgressStream, Globals,
-    %   FileOrModule, DepsMap, Specs, !IO):
+    %   FileOrModule, DepsMap, ErrSpecs, WarnSpecs, !IO):
     %
     % Generate the per-program makefile dependencies files
     % (`.dep' and `.dv' files) for the program whose top-level module
@@ -72,8 +72,8 @@
     % which is used very frequently.
     %
 :- pred generate_and_write_dep_file_gendep(io.text_output_stream::in,
-    globals::in, file_or_module::in, deps_map::out, list(diag_spec)::out,
-    io::di, io::uo) is det.
+    globals::in, file_or_module::in, deps_map::out,
+    list(err_spec)::out, list(warn_spec)::out, io::di, io::uo) is det.
 
     % generate_and_write_d_file_gendep(ProgressStream, Globals, FIleOrModule,
     %   DepsMap, Specs, !IO):
@@ -85,8 +85,8 @@
     % which is almost never used.
     %
 :- pred generate_and_write_d_file_gendep(io.text_output_stream::in,
-    globals::in, file_or_module::in, deps_map::out, list(diag_spec)::out,
-    io::di, io::uo) is det.
+    globals::in, file_or_module::in, deps_map::out,
+    list(err_spec)::out, list(warn_spec)::out, io::di, io::uo) is det.
 
 %---------------------------------------------------------------------------%
 
@@ -136,40 +136,46 @@
 %---------------------------------------------------------------------------%
 
 generate_and_write_dep_file_gendep(ProgressStream, Globals, FileOrModule,
-        DepsMap, !:Specs, !IO) :-
+        DepsMap, !:ErrSpecs, !:WarnSpecs, !IO) :-
     generate_deps_map(ProgressStream, Globals, do_not_search,
-        FileOrModule, ModuleName, DepsMap, !:Specs, !IO),
+        FileOrModule, ModuleName, DepsMap, !:ErrSpecs, !:WarnSpecs, !IO),
     do_we_have_a_valid_module_dep(DepsMap, ModuleName, MaybeBurdenedModule),
     (
         MaybeBurdenedModule = error1(FatalErrorSpecs),
         % The diag_specs in FatalErrorSpecs may already be in !.Specs,
         % but even if we add them again here, they will be printed just once.
-        !:Specs = FatalErrorSpecs ++ !.Specs
+        !:ErrSpecs = FatalErrorSpecs ++ !.ErrSpecs
     ;
         MaybeBurdenedModule = ok1(BurdenedModule),
         BurdenedModule = burdened_module(Baggage, _ParseTreeModuleSrc),
         generate_and_write_dep_dv_files_gendep(ProgressStream, Globals,
             DepsMap, ModuleName, Baggage, !IO),
         compute_dep_graphs_gendep(ProgressStream, Globals, ModuleName,
-            DepsMap, DepGraphs, BurdenedModules, !Specs, !IO),
+            DepsMap, DepGraphs, BurdenedModules,
+            CdgErrSpecs, CdgWarnSpecs, !IO),
+        !:ErrSpecs = CdgErrSpecs ++ !.ErrSpecs,
+        !:WarnSpecs = CdgWarnSpecs ++ !.WarnSpecs,
         generate_and_write_d_file_gendep_depgraphs(ProgressStream, Globals,
             DepGraphs, BurdenedModules, !IO)
     ).
 
 generate_and_write_d_file_gendep(ProgressStream, Globals, FileOrModule,
-        DepsMap, !:Specs, !IO) :-
+        DepsMap, !:ErrSpecs, !:WarnSpecs, !IO) :-
     generate_deps_map(ProgressStream, Globals, do_search,
-        FileOrModule, ModuleName, DepsMap, !:Specs, !IO),
+        FileOrModule, ModuleName, DepsMap, !:ErrSpecs, !:WarnSpecs, !IO),
     do_we_have_a_valid_module_dep(DepsMap, ModuleName, MaybeBurdenedModule),
     (
         MaybeBurdenedModule = error1(FatalErrorSpecs),
         % The diag_specs in FatalErrorSpecs may already be in !.Specs,
         % but even if we add them again here, they will be printed just once.
-        !:Specs = FatalErrorSpecs ++ !.Specs
+        !:ErrSpecs = FatalErrorSpecs ++ !.ErrSpecs
     ;
         MaybeBurdenedModule = ok1(BurdenedModule),
         compute_dep_graphs_gendep(ProgressStream, Globals, ModuleName,
-            DepsMap, DepGraphs, _BurdenedModules, !Specs, !IO),
+            DepsMap, DepGraphs, _BurdenedModules,
+            CdgErrSpecs, CdgWarnSpecs, !IO),
+        !:ErrSpecs = CdgErrSpecs ++ !.ErrSpecs,
+        !:WarnSpecs = CdgWarnSpecs ++ !.WarnSpecs,
         generate_and_write_d_file_gendep_depgraphs(ProgressStream, Globals,
             DepGraphs, [BurdenedModule], !IO)
     ).
@@ -423,7 +429,7 @@ do_we_have_a_valid_module_dep(DepsMap, ModuleName, MaybeBurdenedModule) :-
         Errors = Baggage ^ mb_errors,
         FatalErrors = Errors ^ rm_fatal_errors,
         ( if set.is_non_empty(FatalErrors) then
-            FatalErrorSpecs = Errors ^ rm_fatal_diag_specs,
+            FatalErrorSpecs = Errors ^ rm_fatal_err_specs,
             (
                 FatalErrorSpecs = [],
                 string.format("FatalErrorSpecs = [], with FatalErrors = %s\n",
diff --git a/compiler/write_error_spec.m b/compiler/write_error_spec.m
index f79ebf1e8..b47699089 100644
--- a/compiler/write_error_spec.m
+++ b/compiler/write_error_spec.m
@@ -106,6 +106,7 @@
 
     % write_error_spec(Stream, Globals, Spec, !IO):
     % write_error_specs(Stream, Globals, Specs, !IO):
+    % write_oom_error_specs(Stream, Globals, Specs, !IO):
     %
     % Write out the error message(s) specified by Spec or Specs, minus the
     % parts whose conditions are false.
@@ -123,13 +124,20 @@
     % that something should have been printed out.
     %
 :- pred write_error_spec(io.text_output_stream::in, globals::in,
-    diag_spec::in, io::di, io::uo) is det.
+    err_spec::in, io::di, io::uo) is det.
 :- pred write_error_specs(io.text_output_stream::in, globals::in,
+    list(err_spec)::in, io::di, io::uo) is det.
+:- pred write_oom_error_specs(io.text_output_stream::in, globals::in,
+    one_or_more(err_spec)::in, io::di, io::uo) is det.
+
+:- pred write_diag_spec(io.text_output_stream::in, globals::in,
+    diag_spec::in, io::di, io::uo) is det.
+:- pred write_diag_specs(io.text_output_stream::in, globals::in,
     list(diag_spec)::in, io::di, io::uo) is det.
 :- pred write_oom_diag_specs(io.text_output_stream::in, globals::in,
     one_or_more(diag_spec)::in, io::di, io::uo) is det.
 
-:- pred write_error_specs_opt_table(io.text_output_stream::in,
+:- pred write_diag_specs_opt_table(io.text_output_stream::in,
     option_table::in, list(diag_spec)::in, io::di, io::uo) is det.
 
 %---------------------------------------------------------------------------%
@@ -275,44 +283,56 @@ maybe_write_not_yet_written_specs(Stream, Globals, Verbose,
 
 write_not_yet_written_specs(Stream, Globals, !MaybeWrittenSpecs, !IO) :-
     !.MaybeWrittenSpecs = maybe_written_specs(ToBeWritten0, AlreadyWritten0),
-    write_error_specs(Stream, Globals, ToBeWritten0, !IO),
+    write_diag_specs(Stream, Globals, ToBeWritten0, !IO),
     AlreadyWritten = ToBeWritten0 ++ AlreadyWritten0,
     !:MaybeWrittenSpecs = maybe_written_specs([], AlreadyWritten).
 
 %---------------------------------------------------------------------------%
 
 write_error_spec(Stream, Globals, Spec, !IO) :-
-    write_error_specs(Stream, Globals, [Spec], !IO).
+    write_diag_spec(Stream, Globals, coerce(Spec), !IO).
 
 write_error_specs(Stream, Globals, Specs0, !IO) :-
+    write_diag_specs(Stream, Globals, coerce(Specs0), !IO).
+
+write_oom_error_specs(Stream, Globals, OoMSpecs, !IO) :-
+    Specs = one_or_more_to_list(OoMSpecs),
+    write_diag_specs(Stream, Globals, coerce(Specs), !IO).
+
+%---------------------------------------------------------------------------%
+
+write_diag_spec(Stream, Globals, Spec, !IO) :-
+    write_diag_specs(Stream, Globals, [Spec], !IO).
+
+write_diag_specs(Stream, Globals, Specs0, !IO) :-
     standardize_diag_specs(Specs0, StdSpecs),
     globals.get_options(Globals, OptionTable),
     globals.get_limit_error_contexts_map(Globals, LimitErrorContextsMap),
-    sort_and_write_error_specs(Stream, OptionTable, LimitErrorContextsMap,
+    sort_and_write_std_diag_specs(Stream, OptionTable, LimitErrorContextsMap,
         StdSpecs, !IO).
 
 write_oom_diag_specs(Stream, Globals, OoMSpecs, !IO) :-
-    write_error_specs(Stream, Globals, one_or_more_to_list(OoMSpecs), !IO).
+    write_diag_specs(Stream, Globals, one_or_more_to_list(OoMSpecs), !IO).
 
 %---------------------%
 
-write_error_specs_opt_table(Stream, OptionTable, Specs, !IO) :-
+write_diag_specs_opt_table(Stream, OptionTable, Specs, !IO) :-
     standardize_diag_specs(Specs, StdSpecs),
     getopt.lookup_accumulating_option(OptionTable, limit_error_contexts,
         LimitErrorContexts),
     % There is nothing we can usefully do about _BadOptions.
     convert_limit_error_contexts(LimitErrorContexts, _BadOptions,
         LimitErrorContextsMap),
-    sort_and_write_error_specs(Stream, OptionTable, LimitErrorContextsMap,
+    sort_and_write_std_diag_specs(Stream, OptionTable, LimitErrorContextsMap,
         StdSpecs, !IO).
 
 %---------------------------------------------------------------------------%
 
-:- pred sort_and_write_error_specs(io.text_output_stream::in, option_table::in,
-    limit_error_contexts_map::in, list(std_diag_spec)::in,
+:- pred sort_and_write_std_diag_specs(io.text_output_stream::in,
+    option_table::in, limit_error_contexts_map::in, list(std_diag_spec)::in,
     io::di, io::uo) is det.
 
-sort_and_write_error_specs(Stream, OptionTable, LimitErrorContextsMap,
+sort_and_write_std_diag_specs(Stream, OptionTable, LimitErrorContextsMap,
         StdSpecs, !IO) :-
     sort_std_diag_specs_opt_table(OptionTable, StdSpecs, SortedStdSpecs),
     ColorDb = init_color_db(OptionTable),
@@ -332,21 +352,21 @@ sort_and_write_error_specs(Stream, OptionTable, LimitErrorContextsMap,
     % write_error_specs, in practice, this won't happen.
     set.init(AlreadyPrintedVerbose0),
     list.foldl2(
-        do_write_error_spec(Stream, OptionTable, LimitErrorContextsMap,
+        do_write_diag_spec(Stream, OptionTable, LimitErrorContextsMap,
             ColorDb, MaybeMaxWidth),
         SortedStdSpecs, AlreadyPrintedVerbose0, _AlreadyPrintedVerbose, !IO).
 
 %---------------------------------------------------------------------------%
 
-:- pred do_write_error_spec(io.text_output_stream::in, option_table::in,
+:- pred do_write_diag_spec(io.text_output_stream::in, option_table::in,
     limit_error_contexts_map::in, color_db::in, maybe(int)::in,
     std_diag_spec::in,
     already_printed_verbose::in, already_printed_verbose::out,
     io::di, io::uo) is det.
 
-do_write_error_spec(Stream, OptionTable, LimitErrorContextsMap, ColorDb,
+do_write_diag_spec(Stream, OptionTable, LimitErrorContextsMap, ColorDb,
         MaybeMaxWidth, StdSpec, !AlreadyPrintedVerbose, !IO) :-
-    StdSpec = diag_spec(Id, Severity, _Phase, StdMsgs1),
+    StdSpec = gen_spec(Id, Severity, _Phase, StdMsgs1),
     severity_to_maybe_actual_severity(OptionTable, Severity,
         MaybeActualSeverity),
     (
@@ -2552,7 +2572,7 @@ maybe_print_delayed_error_messages(ErrorStream, Globals, !IO) :-
         WroteSomething = no
     ;
         WroteSomething = yes,
-        write_error_specs(ErrorStream, Globals, BadColorSchemeSpecs, !IO)
+        write_diag_specs(ErrorStream, Globals, BadColorSchemeSpecs, !IO)
     ),
 
     % If we suppressed the printing of some errors, then tell the user
diff --git a/tests/invalid_options_file/undefined_var.err_exp b/tests/invalid_options_file/undefined_var.err_exp
index 20ed2b1e4..f710d83db 100644
--- a/tests/invalid_options_file/undefined_var.err_exp
+++ b/tests/invalid_options_file/undefined_var.err_exp
@@ -1,4 +1,3 @@
-mmc:
 undefined_var.options_file:002: Warning: variable `TYPE_SPEC_FLAGS' is
 undefined_var.options_file:002:   undefined.
 undefined_var.options_file:003: Warning: variable `X' is undefined.
