diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/check.cpp | 53 | ||||
| -rw-r--r-- | source/slang/compiler.h | 6 | ||||
| -rw-r--r-- | source/slang/diagnostic-defs.h | 10 | ||||
| -rw-r--r-- | source/slang/lower-to-ir.cpp | 35 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 50 |
5 files changed, 133 insertions, 21 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index acf473998..5fd8be2d5 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -455,6 +455,51 @@ namespace Slang innerDeclRef); } + // This routine is a bottleneck for all declaration checking, + // so that we can add some quality-of-life features for users + // in cases where the compiler crashes + void dispatchDecl(DeclBase* decl) + { + try + { + DeclVisitor::dispatch(decl); + } + // Don't emit any context message for an explicit `AbortCompilationException` + // because it should only happen when an error is already emitted. + catch(AbortCompilationException&) { throw; } + catch(...) + { + getCompileRequest()->noteInternalErrorLoc(decl->loc); + throw; + } + } + void dispatchStmt(Stmt* stmt) + { + try + { + StmtVisitor::dispatch(stmt); + } + catch(AbortCompilationException&) { throw; } + catch(...) + { + getCompileRequest()->noteInternalErrorLoc(stmt->loc); + throw; + } + } + void dispatchExpr(Expr* expr) + { + try + { + ExprVisitor::dispatch(expr); + } + catch(AbortCompilationException&) { throw; } + catch(...) + { + getCompileRequest()->noteInternalErrorLoc(expr->loc); + throw; + } + } + // Make sure a declaration has been checked, so we can refer to it. // Note that this may lead to us recursively invoking checking, // so this may not be the best way to handle things. @@ -499,7 +544,7 @@ namespace Slang } // Use visitor pattern to dispatch to correct case - DeclVisitor::dispatch(decl); + dispatchDecl(decl); if(state > decl->checkState) { @@ -2492,7 +2537,7 @@ namespace Slang { for (auto decl : declGroup->decls) { - DeclVisitor::dispatch(decl); + dispatchDecl(decl); } } @@ -2549,7 +2594,7 @@ namespace Slang void checkStmt(Stmt* stmt) { if (!stmt) return; - StmtVisitor::dispatch(stmt); + dispatchStmt(stmt); checkModifiers(stmt); } @@ -3052,7 +3097,7 @@ namespace Slang // 2. `EnsureDecl()` is specialized for `Decl*` instead of `DeclBase*` // and trying to special case `DeclGroup*` here feels silly. // - DeclVisitor::dispatch(stmt->decl); + dispatchDecl(stmt->decl); } void visitBlockStmt(BlockStmt* stmt) diff --git a/source/slang/compiler.h b/source/slang/compiler.h index 703991e36..4cda366f0 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -423,6 +423,12 @@ namespace Slang sourceManager = sm; mSink.sourceManager = sm; } + + /// During propagation of an exception for an internal + /// error, note that this source location was involved + void noteInternalErrorLoc(SourceLoc const& loc); + + int internalErrorLocsNoted = 0; }; void generateOutput( diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h index a3c51d67e..c77e75817 100644 --- a/source/slang/diagnostic-defs.h +++ b/source/slang/diagnostic-defs.h @@ -341,9 +341,11 @@ DIAGNOSTIC(51092, Error, stageDoesntHaveInputWorld, "'$0' doesn't appear to have // 99999 - Internal compiler errors, and not-yet-classified diagnostics. -DIAGNOSTIC(99999, Internal, unimplemented, "unimplemented: $0") -DIAGNOSTIC(99999, Internal, unexpected, "unexpected: $0") -DIAGNOSTIC(99999, Internal, internalCompilerError, "internal compiler error") -DIAGNOSTIC(99999, Error, compilationAborted, "compilation aborted due to internal error"); +DIAGNOSTIC(99999, Internal, unimplemented, "unimplemented feature in Slang compiler: $0") +DIAGNOSTIC(99999, Internal, unexpected, "unexpected condition encountered in Slang compiler: $0") +DIAGNOSTIC(99999, Internal, internalCompilerError, "Slang internal compiler error") +DIAGNOSTIC(99999, Error, compilationAborted, "Slang compilation aborted due to internal error"); +DIAGNOSTIC(99999, Error, compilationAbortedDueToException, "Slang compilation aborted due to an exception of $0: $1"); +DIAGNOSTIC(99999, Note, noteLocationOfInternalError, "the Slang compiler threw an exception while working on code near this location"); #undef DIAGNOSTIC diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp index e5cf19a10..fffd8acf3 100644 --- a/source/slang/lower-to-ir.cpp +++ b/source/slang/lower-to-ir.cpp @@ -355,6 +355,11 @@ struct IRGenContext { return shared->compileRequest->mSession; } + + CompileRequest* getCompileRequest() + { + return shared->compileRequest; + } }; void setGlobalValue(SharedIRGenContext* sharedContext, Decl* decl, LoweredValInfo value) @@ -2680,7 +2685,19 @@ void lowerStmt( StmtLoweringVisitor visitor; visitor.context = context; - return visitor.dispatch(stmt); + + try + { + visitor.dispatch(stmt); + } + // Don't emit any context message for an explicit `AbortCompilationException` + // because it should only happen when an error is already emitted. + catch(AbortCompilationException&) { throw; } + catch(...) + { + context->getCompileRequest()->noteInternalErrorLoc(stmt->loc); + throw; + } } static LoweredValInfo maybeMoveMutableTemp( @@ -4380,7 +4397,21 @@ LoweredValInfo lowerDecl( DeclLoweringVisitor visitor; visitor.context = &subContext; - return visitor.dispatch(decl); + + + + try + { + return visitor.dispatch(decl); + } + // Don't emit any context message for an explicit `AbortCompilationException` + // because it should only happen when an error is already emitted. + catch(AbortCompilationException&) { throw; } + catch(...) + { + context->getCompileRequest()->noteInternalErrorLoc(decl->loc); + throw; + } } // Ensure that a version of the given declaration has been emitted to the IR diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index dbd48753b..9e740d5f5 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -9,6 +9,9 @@ #include "syntax-visitors.h" #include "../slang/type-layout.h" +// Used to print exception type names in internal-compiler-error messages +#include <typeinfo> + #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #define NOMINMAX @@ -724,6 +727,23 @@ Decl * CompileRequest::lookupGlobalDecl(Name * name) return resultDecl; } +void CompileRequest::noteInternalErrorLoc(SourceLoc const& loc) +{ + // Don't consider invalid source locations. + if(!loc.isValid()) + return; + + // If this is the first source location being noted, + // then emit a message to help the user isolate what + // code might have confused the compiler. + if(internalErrorLocsNoted == 0) + { + mSink.diagnose(loc, Diagnostics::noteLocationOfInternalError); + } + internalErrorLocsNoted++; +} + + RefPtr<ModuleDecl> findOrImportModule( CompileRequest* request, Name* name, @@ -1111,27 +1131,35 @@ SLANG_API int spCompile( // // TODO: Consider supporting Windows "Structured Exception Handling" // so that we can also recover from a wider class of crashes. + int anyErrors = 1; try { - int anyErrors = req->executeActions(); - return anyErrors; + anyErrors = req->executeActions(); } catch (Slang::AbortCompilationException&) { - // This should only be thrown if we already emitted a fatal error - // message, so there is no reason to print something else. - // - // We still need to copy the diagnostic output into the variable - // that the user will query via the API. - req->mDiagnosticOutput = req->mSink.outputBuffer.ProduceString(); - return 1; + // This situation indicates a fatal (but not necesarily internal) error + // that forced compilation to terminate. There should already have been + // a diagnositc produced, so we don't need to add one here. + } + catch (Slang::Exception& e) + { + // The compiler failed due to an internal error that was detected. + // We will print out information on the exception to help out the user + // in either filing a bug, or locating what in their code created + // a problem. + req->mSink.diagnose(Slang::SourceLoc(), Slang::Diagnostics::compilationAbortedDueToException, typeid(e).name(), e.Message); } catch (...) { + // The compiler failed due to some exception that wasn't a sublass of + // `Exception`, so something really fishy is going on. We want to + // let the user know that we messed up, so they know to blame Slang + // and not some other component in their system. req->mSink.diagnose(Slang::SourceLoc(), Slang::Diagnostics::compilationAborted); - req->mDiagnosticOutput = req->mSink.outputBuffer.ProduceString(); - return 1; } + req->mDiagnosticOutput = req->mSink.outputBuffer.ProduceString(); + return anyErrors; #else // When debugging, we probably don't want to filter out any errors, since // we are probably trying to root-cause and *fix* those errors. |
