forked from OSchip/llvm-project
Add userData to the diagnostic handler C API
Previously, there was no way to add context to the diagnostic engine via the C API. Adding this ability makes it much easier to reason about memory ownership, particularly in reference-counted languages such as Swift. There are more details in the review comments. Reviewed By: ftynse, mehdi_amini Differential Revision: https://reviews.llvm.org/D91738
This commit is contained in:
parent
3a1c6cec15
commit
0c5cff300f
|
@ -40,12 +40,14 @@ typedef enum MlirDiagnosticSeverity MlirDiagnosticSeverity;
|
||||||
/// Opaque identifier of a diagnostic handler, useful to detach a handler.
|
/// Opaque identifier of a diagnostic handler, useful to detach a handler.
|
||||||
typedef uint64_t MlirDiagnosticHandlerID;
|
typedef uint64_t MlirDiagnosticHandlerID;
|
||||||
|
|
||||||
/** Diagnostic handler type. Acceps a reference to a diagnostic, which is only
|
/** Diagnostic handler type. Accepts a reference to a diagnostic, which is only
|
||||||
* guaranteed to be live during the call. If the handler processed the
|
* guaranteed to be live during the call. The handler is passed the `userData`
|
||||||
* diagnostic completely, it is expected to return success. Otherwise, it is
|
* that was provided when the handler was attached to a context. If the handler
|
||||||
* expected to return failure to indicate that other handlers should attempt to
|
* processed the diagnostic completely, it is expected to return success.
|
||||||
* process the diagnostic. */
|
* Otherwise, it is expected to return failure to indicate that other handlers
|
||||||
typedef MlirLogicalResult (*MlirDiagnosticHandler)(MlirDiagnostic);
|
* should attempt to process the diagnostic. */
|
||||||
|
typedef MlirLogicalResult (*MlirDiagnosticHandler)(MlirDiagnostic,
|
||||||
|
void *userData);
|
||||||
|
|
||||||
/// Prints a diagnostic using the provided callback.
|
/// Prints a diagnostic using the provided callback.
|
||||||
MLIR_CAPI_EXPORTED void mlirDiagnosticPrint(MlirDiagnostic diagnostic,
|
MLIR_CAPI_EXPORTED void mlirDiagnosticPrint(MlirDiagnostic diagnostic,
|
||||||
|
@ -71,9 +73,15 @@ mlirDiagnosticGetNote(MlirDiagnostic diagnostic, intptr_t pos);
|
||||||
|
|
||||||
/** Attaches the diagnostic handler to the context. Handlers are invoked in the
|
/** Attaches the diagnostic handler to the context. Handlers are invoked in the
|
||||||
* reverse order of attachment until one of them processes the diagnostic
|
* reverse order of attachment until one of them processes the diagnostic
|
||||||
* completely. Returns an identifier that can be used to detach the handler. */
|
* completely. When a handler is invoked it is passed the `userData` that was
|
||||||
|
* provided when it was attached. If non-NULL, `deleteUserData` is called once
|
||||||
|
* the system no longer needs to call the handler (for instance after the
|
||||||
|
* handler is detached or the context is destroyed). Returns an identifier that
|
||||||
|
* can be used to detach the handler.
|
||||||
|
*/
|
||||||
MLIR_CAPI_EXPORTED MlirDiagnosticHandlerID mlirContextAttachDiagnosticHandler(
|
MLIR_CAPI_EXPORTED MlirDiagnosticHandlerID mlirContextAttachDiagnosticHandler(
|
||||||
MlirContext context, MlirDiagnosticHandler handler);
|
MlirContext context, MlirDiagnosticHandler handler, void *userData,
|
||||||
|
void (*deleteUserData)(void *));
|
||||||
|
|
||||||
/** Detaches an attached diagnostic handler from the context given its
|
/** Detaches an attached diagnostic handler from the context given its
|
||||||
* identifier. */
|
* identifier. */
|
||||||
|
|
|
@ -51,14 +51,19 @@ MlirDiagnostic mlirDiagnosticGetNote(MlirDiagnostic diagnostic, intptr_t pos) {
|
||||||
return wrap(*std::next(unwrap(diagnostic).getNotes().begin(), pos));
|
return wrap(*std::next(unwrap(diagnostic).getNotes().begin(), pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
MlirDiagnosticHandlerID
|
static void deleteUserDataNoop(void *userData) {}
|
||||||
mlirContextAttachDiagnosticHandler(MlirContext context,
|
|
||||||
MlirDiagnosticHandler handler) {
|
MlirDiagnosticHandlerID mlirContextAttachDiagnosticHandler(
|
||||||
|
MlirContext context, MlirDiagnosticHandler handler, void *userData,
|
||||||
|
void (*deleteUserData)(void *)) {
|
||||||
assert(handler && "unexpected null diagnostic handler");
|
assert(handler && "unexpected null diagnostic handler");
|
||||||
|
if (deleteUserData == NULL)
|
||||||
|
deleteUserData = deleteUserDataNoop;
|
||||||
|
std::shared_ptr<void> sharedUserData(userData, deleteUserData);
|
||||||
DiagnosticEngine::HandlerID id =
|
DiagnosticEngine::HandlerID id =
|
||||||
unwrap(context)->getDiagEngine().registerHandler(
|
unwrap(context)->getDiagEngine().registerHandler(
|
||||||
[handler](Diagnostic &diagnostic) {
|
[handler, sharedUserData](Diagnostic &diagnostic) {
|
||||||
return unwrap(handler(wrap(diagnostic)));
|
return unwrap(handler(wrap(diagnostic), sharedUserData.get()));
|
||||||
});
|
});
|
||||||
return static_cast<MlirDiagnosticHandlerID>(id);
|
return static_cast<MlirDiagnosticHandlerID>(id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1248,31 +1248,37 @@ int registerOnlyStd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wraps a diagnostic into additional text we can match against.
|
// Wraps a diagnostic into additional text we can match against.
|
||||||
MlirLogicalResult errorHandler(MlirDiagnostic diagnostic) {
|
MlirLogicalResult errorHandler(MlirDiagnostic diagnostic, void *userData) {
|
||||||
fprintf(stderr, "processing diagnostic <<\n");
|
fprintf(stderr, "processing diagnostic (userData: %d) <<\n", (int)userData);
|
||||||
mlirDiagnosticPrint(diagnostic, printToStderr, NULL);
|
mlirDiagnosticPrint(diagnostic, printToStderr, NULL);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
MlirLocation loc = mlirDiagnosticGetLocation(diagnostic);
|
MlirLocation loc = mlirDiagnosticGetLocation(diagnostic);
|
||||||
mlirLocationPrint(loc, printToStderr, NULL);
|
mlirLocationPrint(loc, printToStderr, NULL);
|
||||||
assert(mlirDiagnosticGetNumNotes(diagnostic) == 0);
|
assert(mlirDiagnosticGetNumNotes(diagnostic) == 0);
|
||||||
fprintf(stderr, ">> end of diagnostic\n");
|
fprintf(stderr, ">> end of diagnostic (userData: %d)\n", (int)userData);
|
||||||
return mlirLogicalResultSuccess();
|
return mlirLogicalResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Logs when the delete user data callback is called
|
||||||
|
static void deleteUserData(void *userData) {
|
||||||
|
fprintf(stderr, "deleting user data (userData: %d)\n", (int)userData);
|
||||||
|
}
|
||||||
|
|
||||||
void testDiagnostics() {
|
void testDiagnostics() {
|
||||||
MlirContext ctx = mlirContextCreate();
|
MlirContext ctx = mlirContextCreate();
|
||||||
MlirDiagnosticHandlerID id =
|
MlirDiagnosticHandlerID id = mlirContextAttachDiagnosticHandler(
|
||||||
mlirContextAttachDiagnosticHandler(ctx, errorHandler);
|
ctx, errorHandler, (void *)42, deleteUserData);
|
||||||
MlirLocation loc = mlirLocationUnknownGet(ctx);
|
MlirLocation loc = mlirLocationUnknownGet(ctx);
|
||||||
fprintf(stderr, "@test_diagnostics\n");
|
fprintf(stderr, "@test_diagnostics\n");
|
||||||
mlirEmitError(loc, "test diagnostics");
|
mlirEmitError(loc, "test diagnostics");
|
||||||
mlirContextDetachDiagnosticHandler(ctx, id);
|
mlirContextDetachDiagnosticHandler(ctx, id);
|
||||||
mlirEmitError(loc, "more test diagnostics");
|
mlirEmitError(loc, "more test diagnostics");
|
||||||
// CHECK-LABEL: @test_diagnostics
|
// CHECK-LABEL: @test_diagnostics
|
||||||
// CHECK: processing diagnostic <<
|
// CHECK: processing diagnostic (userData: 42) <<
|
||||||
// CHECK: test diagnostics
|
// CHECK: test diagnostics
|
||||||
// CHECK: loc(unknown)
|
// CHECK: loc(unknown)
|
||||||
// CHECK: >> end of diagnostic
|
// CHECK: >> end of diagnostic (userData: 42)
|
||||||
|
// CHECK: deleting user data (userData: 42)
|
||||||
// CHECK-NOT: processing diagnostic
|
// CHECK-NOT: processing diagnostic
|
||||||
// CHECK: more test diagnostics
|
// CHECK: more test diagnostics
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue