errors: add FatalErrorHandler to handle when an abnormal error occurs on DMDLIB

This patch introduces a FatalErrorHandler for error handling on DMD to make DMD
as a library usable with the semantic analysis.

Signed-off-by: Luís Ferreira <contact@lsferreira.net>
This commit is contained in:
Luís Ferreira 2022-03-26 16:40:22 +00:00 committed by The Dlang Bot
parent 7195063f4c
commit e672df26e1
3 changed files with 26 additions and 11 deletions

View file

@ -649,15 +649,26 @@ private void _vdeprecationSupplemental(const ref Loc loc, const(char)* format, v
} }
/** /**
* Call this after printing out fatal error messages to clean up and exit * The type of the fatal error handler
* the compiler. * Returns: true if error handling is done, false to do exit(EXIT_FAILURE)
*/
alias FatalErrorHandler = bool delegate();
/**
* The fatal error handler.
* If non-null it will be called for every fatal() call issued by the compiler.
*/
__gshared FatalErrorHandler fatalErrorHandler;
/**
* Call this after printing out fatal error messages to clean up and exit the
* compiler. You can also set a fatalErrorHandler to override this behaviour.
*/ */
extern (C++) void fatal() extern (C++) void fatal()
{ {
version (none) if (fatalErrorHandler && fatalErrorHandler())
{ return;
halt();
}
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View file

@ -13,7 +13,7 @@ module dmd.frontend;
import dmd.astcodegen : ASTCodegen; import dmd.astcodegen : ASTCodegen;
import dmd.dmodule : Module; import dmd.dmodule : Module;
import dmd.globals : CHECKENABLE, Loc, DiagnosticReporting; import dmd.globals : CHECKENABLE, Loc, DiagnosticReporting;
import dmd.errors : DiagnosticHandler, diagnosticHandler, Classification; import dmd.errors;
import std.range.primitives : isInputRange, ElementType; import std.range.primitives : isInputRange, ElementType;
import std.traits : isNarrowString; import std.traits : isNarrowString;
@ -96,12 +96,14 @@ Initializes the global variables of the DMD compiler.
This needs to be done $(I before) calling any function. This needs to be done $(I before) calling any function.
Params: Params:
handler = a delegate to configure what to do with diagnostics (other than printing to console or stderr). diagnosticHandler = a delegate to configure what to do with diagnostics (other than printing to console or stderr).
fatalErrorHandler = a delegate to configure what to do with fatal errors (default is to call exit(EXIT_FAILURE)).
contractChecks = indicates which contracts should be enabled or not contractChecks = indicates which contracts should be enabled or not
versionIdentifiers = a list of version identifiers that should be enabled versionIdentifiers = a list of version identifiers that should be enabled
*/ */
void initDMD( void initDMD(
DiagnosticHandler handler = null, DiagnosticHandler diagnosticHandler = null,
FatalErrorHandler fatalErrorHandler = null,
const string[] versionIdentifiers = [], const string[] versionIdentifiers = [],
ContractChecks contractChecks = ContractChecks() ContractChecks contractChecks = ContractChecks()
) )
@ -124,7 +126,8 @@ void initDMD(
import dmd.objc : Objc; import dmd.objc : Objc;
import dmd.target : target, defaultTargetOS; import dmd.target : target, defaultTargetOS;
diagnosticHandler = handler; .diagnosticHandler = diagnosticHandler;
.fatalErrorHandler = fatalErrorHandler;
global._init(); global._init();
@ -175,6 +178,7 @@ void deinitializeDMD()
import dmd.target : target; import dmd.target : target;
diagnosticHandler = null; diagnosticHandler = null;
fatalErrorHandler = null;
global.deinitialize(); global.deinitialize();

View file

@ -216,7 +216,7 @@ unittest
import dmd.frontend; import dmd.frontend;
import dmd.globals : global; import dmd.globals : global;
initDMD(null, ["Foo"]); initDMD(null, null, ["Foo"]);
defaultImportPaths.each!addImport; defaultImportPaths.each!addImport;
auto t = parseModule("test.d", q{ auto t = parseModule("test.d", q{