blob: dacf76b3933a877ed72178fab274432a9278b1b8 [file] [log] [blame]
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001// 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_TINT_DEBUG_H_
16#define SRC_TINT_DEBUG_H_
17
18#include <utility>
19
20#include "src/tint/diagnostic/diagnostic.h"
21#include "src/tint/diagnostic/formatter.h"
22#include "src/tint/diagnostic/printer.h"
Ben Claytona1eed912023-01-13 14:46:21 +000023#include "src/tint/utils/compiler_macros.h"
dan sinclairdee884c2023-02-28 22:22:58 +000024#include "src/tint/utils/string_stream.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000025
26namespace tint {
27
28/// Function type used for registering an internal compiler error reporter
29using InternalCompilerErrorReporter = void(const diag::List&);
30
31/// Sets the global error reporter to be called in case of internal compiler
32/// errors.
33/// @param reporter the error reporter
34void SetInternalCompilerErrorReporter(InternalCompilerErrorReporter* reporter);
35
36/// InternalCompilerError is a helper for reporting internal compiler errors.
37/// Construct the InternalCompilerError with the source location of the ICE
38/// fault and append any error details with the `<<` operator.
39/// When the InternalCompilerError is destructed, the concatenated error message
40/// is appended to the diagnostics list with the severity of
41/// tint::diag::Severity::InternalCompilerError, and if a
42/// InternalCompilerErrorReporter is set, then it is called with the diagnostic
43/// list.
44class InternalCompilerError {
dan sinclair41e4d9a2022-05-01 14:40:55 +000045 public:
46 /// Constructor
47 /// @param file the file containing the ICE
48 /// @param line the line containing the ICE
49 /// @param system the Tint system that has raised the ICE
50 /// @param diagnostics the list of diagnostics to append the ICE message to
51 InternalCompilerError(const char* file,
52 size_t line,
53 diag::System system,
54 diag::List& diagnostics);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000055
dan sinclair41e4d9a2022-05-01 14:40:55 +000056 /// Destructor.
57 /// Adds the internal compiler error message to the diagnostics list, and then
58 /// calls the InternalCompilerErrorReporter if one is set.
59 ~InternalCompilerError();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000060
dan sinclair41e4d9a2022-05-01 14:40:55 +000061 /// Appends `arg` to the ICE message.
62 /// @param arg the argument to append to the ICE message
63 /// @returns this object so calls can be chained
64 template <typename T>
65 InternalCompilerError& operator<<(T&& arg) {
66 msg_ << std::forward<T>(arg);
67 return *this;
68 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +000069
dan sinclair41e4d9a2022-05-01 14:40:55 +000070 private:
71 char const* const file_;
72 const size_t line_;
73 diag::System system_;
74 diag::List& diagnostics_;
dan sinclairdee884c2023-02-28 22:22:58 +000075 utils::StringStream msg_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000076};
77
78} // namespace tint
79
80/// TINT_ICE() is a macro for appending an internal compiler error message
81/// to the diagnostics list `diagnostics`, and calling the
82/// InternalCompilerErrorReporter with the full diagnostic list if a reporter is
83/// set.
84/// The ICE message contains the callsite's file and line.
85/// Use the `<<` operator to append an error message to the ICE.
dan sinclair41e4d9a2022-05-01 14:40:55 +000086#define TINT_ICE(system, diagnostics) \
87 tint::InternalCompilerError(__FILE__, __LINE__, ::tint::diag::System::system, diagnostics)
Ryan Harrisondbc13af2022-02-21 15:19:07 +000088
89/// TINT_UNREACHABLE() is a macro for appending a "TINT_UNREACHABLE"
90/// internal compiler error message to the diagnostics list `diagnostics`, and
91/// calling the InternalCompilerErrorReporter with the full diagnostic list if a
92/// reporter is set.
93/// The ICE message contains the callsite's file and line.
94/// Use the `<<` operator to append an error message to the ICE.
dan sinclair41e4d9a2022-05-01 14:40:55 +000095#define TINT_UNREACHABLE(system, diagnostics) TINT_ICE(system, diagnostics) << "TINT_UNREACHABLE "
Ryan Harrisondbc13af2022-02-21 15:19:07 +000096
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) \
dan sinclair41e4d9a2022-05-01 14:40:55 +0000104 TINT_ICE(system, diagnostics) << "TINT_UNIMPLEMENTED "
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000105
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.
dan sinclair41e4d9a2022-05-01 14:40:55 +0000114#define TINT_ASSERT(system, condition) \
115 do { \
Ben Claytona1eed912023-01-13 14:46:21 +0000116 if (TINT_UNLIKELY(!(condition))) { \
dan sinclair41e4d9a2022-05-01 14:40:55 +0000117 tint::diag::List diagnostics; \
118 TINT_ICE(system, diagnostics) << "TINT_ASSERT(" #system ", " #condition ")"; \
119 } \
120 } while (false)
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000121
dan sinclair792001a2023-06-01 17:03:18 +0000122/// TINT_ASSERT_OR_RETURN() is a macro for checking the expression is true, triggering a
123/// TINT_ICE if it is not and returning from the calling function.
124/// The ICE message contains the callsite's file and line.
125/// @warning: Unlike TINT_ICE() and TINT_UNREACHABLE(), TINT_ASSERT_OR_RETURN() does not
126/// append a message to an existing tint::diag::List. As such, TINT_ASSERT_OR_RETURN()
127/// may silently fail in builds where SetInternalCompilerErrorReporter() is not
128/// called. Only use in places where there's no sensible place to put proper
129/// error handling.
130#define TINT_ASSERT_OR_RETURN(system, condition) \
131 do { \
132 if (TINT_UNLIKELY(!(condition))) { \
133 tint::diag::List diagnostics; \
134 TINT_ICE(system, diagnostics) << "TINT_ASSERT(" #system ", " #condition ")"; \
135 return; \
136 } \
137 } while (false)
138
James Price55aff4e2023-06-08 17:15:08 +0000139/// TINT_ASSERT_OR_RETURN_VALUE() is a macro for checking the expression is true, triggering a
140/// TINT_ICE if it is not and returning a value from the calling function.
141/// The ICE message contains the callsite's file and line.
142/// @warning: Unlike TINT_ICE() and TINT_UNREACHABLE(), TINT_ASSERT_OR_RETURN_VALUE() does not
143/// append a message to an existing tint::diag::List. As such, TINT_ASSERT_OR_RETURN_VALUE()
144/// may silently fail in builds where SetInternalCompilerErrorReporter() is not
145/// called. Only use in places where there's no sensible place to put proper
146/// error handling.
147#define TINT_ASSERT_OR_RETURN_VALUE(system, condition, value) \
148 do { \
149 if (TINT_UNLIKELY(!(condition))) { \
150 tint::diag::List diagnostics; \
151 TINT_ICE(system, diagnostics) << "TINT_ASSERT(" #system ", " #condition ")"; \
152 return value; \
153 } \
154 } while (false)
155
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000156#endif // SRC_TINT_DEBUG_H_