• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SRC_DEBUG_H_
16 #define SRC_DEBUG_H_
17 
18 #include <utility>
19 
20 #include "src/diagnostic/diagnostic.h"
21 #include "src/diagnostic/formatter.h"
22 #include "src/diagnostic/printer.h"
23 
24 namespace tint {
25 
26 /// Function type used for registering an internal compiler error reporter
27 using InternalCompilerErrorReporter = void(const diag::List&);
28 
29 /// Sets the global error reporter to be called in case of internal compiler
30 /// errors.
31 /// @param reporter the error reporter
32 void SetInternalCompilerErrorReporter(InternalCompilerErrorReporter* reporter);
33 
34 /// InternalCompilerError is a helper for reporting internal compiler errors.
35 /// Construct the InternalCompilerError with the source location of the ICE
36 /// fault and append any error details with the `<<` operator.
37 /// When the InternalCompilerError is destructed, the concatenated error message
38 /// is appended to the diagnostics list with the severity of
39 /// tint::diag::Severity::InternalCompilerError, and if a
40 /// InternalCompilerErrorReporter is set, then it is called with the diagnostic
41 /// list.
42 class InternalCompilerError {
43  public:
44   /// Constructor
45   /// @param file the file containing the ICE
46   /// @param line the line containing the ICE
47   /// @param system the Tint system that has raised the ICE
48   /// @param diagnostics the list of diagnostics to append the ICE message to
49   InternalCompilerError(const char* file,
50                         size_t line,
51                         diag::System system,
52                         diag::List& diagnostics);
53 
54   /// Destructor.
55   /// Adds the internal compiler error message to the diagnostics list, and then
56   /// calls the InternalCompilerErrorReporter if one is set.
57   ~InternalCompilerError();
58 
59   /// Appends `arg` to the ICE message.
60   /// @param arg the argument to append to the ICE message
61   /// @returns this object so calls can be chained
62   template <typename T>
63   InternalCompilerError& operator<<(T&& arg) {
64     msg_ << std::forward<T>(arg);
65     return *this;
66   }
67 
68  private:
69   char const* const file_;
70   const size_t line_;
71   diag::System system_;
72   diag::List& diagnostics_;
73   std::stringstream msg_;
74 };
75 
76 }  // namespace tint
77 
78 /// TINT_ICE() is a macro for appending an internal compiler error message
79 /// to the diagnostics list `diagnostics`, and calling the
80 /// InternalCompilerErrorReporter with the full diagnostic list if a reporter is
81 /// set.
82 /// The ICE message contains the callsite's file and line.
83 /// Use the `<<` operator to append an error message to the ICE.
84 #define TINT_ICE(system, diagnostics)             \
85   tint::InternalCompilerError(__FILE__, __LINE__, \
86                               ::tint::diag::System::system, diagnostics)
87 
88 /// TINT_UNREACHABLE() is a macro for appending a "TINT_UNREACHABLE"
89 /// internal compiler error message to the diagnostics list `diagnostics`, and
90 /// calling the InternalCompilerErrorReporter with the full diagnostic list if a
91 /// reporter is set.
92 /// The ICE message contains the callsite's file and line.
93 /// Use the `<<` operator to append an error message to the ICE.
94 #define TINT_UNREACHABLE(system, diagnostics) \
95   TINT_ICE(system, diagnostics) << "TINT_UNREACHABLE "
96 
97 /// TINT_UNIMPLEMENTED() is a macro for appending a "TINT_UNIMPLEMENTED"
98 /// internal compiler error message to the diagnostics list `diagnostics`, and
99 /// calling the InternalCompilerErrorReporter with the full diagnostic list if a
100 /// reporter is set.
101 /// The ICE message contains the callsite's file and line.
102 /// Use the `<<` operator to append an error message to the ICE.
103 #define TINT_UNIMPLEMENTED(system, diagnostics) \
104   TINT_ICE(system, diagnostics) << "TINT_UNIMPLEMENTED "
105 
106 /// TINT_ASSERT() is a macro for checking the expression is true, triggering a
107 /// TINT_ICE if it is not.
108 /// The ICE message contains the callsite's file and line.
109 /// @warning: Unlike TINT_ICE() and TINT_UNREACHABLE(), TINT_ASSERT() does not
110 /// append a message to an existing tint::diag::List. As such, TINT_ASSERT()
111 /// may silently fail in builds where SetInternalCompilerErrorReporter() is not
112 /// called. Only use in places where there's no sensible place to put proper
113 /// error handling.
114 #define TINT_ASSERT(system, condition)                   \
115   do {                                                   \
116     if (!(condition)) {                                  \
117       tint::diag::List diagnostics;                      \
118       TINT_ICE(system, diagnostics)                      \
119           << "TINT_ASSERT(" #system ", " #condition ")"; \
120     }                                                    \
121   } while (false)
122 
123 #endif  // SRC_DEBUG_H_
124