CppInterOp
C++ Language Interoperability Layer
Loading...
Searching...
No Matches
ErrorInternal.h
Go to the documentation of this file.
1//===--- ErrorInternal.h - Impl-side error helpers --------------*- C++ -*-===//
2//
3// Part of the compiler-research project, under the Apache License v2.0 with
4// LLVM Exceptions.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Impl-side counterpart to CppInterOp/Error.h: the ErrorSlice body,
10// the llvm::Error subclasses, and the boundary translator.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef CPPINTEROP_LIB_ERRORINTERNAL_H
15#define CPPINTEROP_LIB_ERRORINTERNAL_H
16
18#include "CppInterOp/Error.h"
19
20#include "llvm/Support/Error.h"
21#include "llvm/Support/raw_ostream.h"
22
23#include <atomic>
24#include <cstdint>
25#include <deque>
26#include <string>
27#include <system_error>
28#include <utility>
29
30namespace Cpp {
31
32struct InterpreterInfo; // defined in CppInterOp.cpp
33
34/// Owning record for one captured diagnostic. DiagnosticRef::data
35/// points at one of these.
37 std::string Message;
38 std::string File;
39 unsigned Line = 0;
40 unsigned Column = 0;
41 DiagnosticSeverity Sev = DiagnosticSeverity::Error;
42};
43
44/// Body of a slice-encoded error: drained diagnostics, producer
45/// attribution, refcount. alignas(16) keeps the low bits of an
46/// ErrorSlice* clear so ErrorRef's tag bit stays unambiguous.
47struct alignas(16) ErrorSlice {
48 // Mutable so Retain/Release can act on a `const ErrorSlice*` taken
49 // off an ErrorRef accessor without round-tripping through const_cast.
50 mutable std::atomic<uint32_t> Refcount{0};
52 Status Code = Status::Ok;
53
54 // Stable element addresses under push_back so a DiagnosticRef can
55 // address an entry safely.
56 std::deque<StoredDiagView> Diagnostics;
57
58 // Pointer into static __func__ storage. No copy.
59 const char* Producer = nullptr;
60 // Pointer into static __PRETTY_FUNCTION__ storage. No copy.
61 const char* ProducerSignature = nullptr;
62};
63
64//
65// Carry the structured information the boundary translator drains
66// into a slice. Impl code returns llvm::Expected<T> with these on
67// the failure path; makeResult wraps them into Result<T>.
68
69class CPPINTEROP_API StatusError : public llvm::ErrorInfo<StatusError> {
70public:
71 static char ID;
72 Status Code;
73 std::string Message;
74
75 StatusError(Status C, std::string M) : Code(C), Message(std::move(M)) {}
76
77 void log(llvm::raw_ostream& OS) const override;
78 [[nodiscard]] std::error_code convertToErrorCode() const override;
79};
80
81/// Allocate a fresh slice on the heap, refcount 0. Caller bumps the
82/// refcount on first use (the boundary translator does this when
83/// wrapping the slice into a returned ErrorRef).
84CPPINTEROP_API ErrorSlice* AllocSlice(InterpreterInfo* Owner);
85
86/// Build an inline-status ErrorRef (no diagnostics, no payload).
87CPPINTEROP_API ErrorRef makeError(Status S);
88
89/// Build a slice-encoded error carrying a Clang-derived message + the
90/// interp's pending diagnostics + producer attribution.
91CPPINTEROP_API ErrorRef makeError(InterpreterInfo* II, Status S,
92 std::string Message, const char* Producer,
93 const char* ProducerSig);
94
95/// Drain `E` into a fresh slice, returning the slice via ErrorRef.
96/// Handles StatusError; any other llvm::Error is stringified via
97/// llvm::ErrorInfoBase::log into the slice's first diagnostic.
98CPPINTEROP_API ErrorRef drainError(InterpreterInfo* II, llvm::Error E,
99 const char* Producer,
100 const char* ProducerSig);
101
102/// Convert llvm::Expected<T> into Result<T>. On the error path, drain
103/// the carried llvm::Error into a slice.
104template <typename T>
105Result<T> makeResult(InterpreterInfo* II, llvm::Expected<T> E,
106 const char* Producer, const char* ProducerSig) {
107 if (E)
108 return Result<T>(std::move(*E));
109 return Result<T>(drainError(II, E.takeError(), Producer, ProducerSig));
110}
111
112inline Result<void> makeResult(InterpreterInfo* II, llvm::Error E,
113 const char* Producer, const char* ProducerSig) {
114 if (!E)
115 return Result<void>();
116 return Result<void>(drainError(II, std::move(E), Producer, ProducerSig));
117}
118
119/// Drain the consumer's per-interp buffer into a slice on failure.
120/// Success paths just clear via ClearPending -- callers don't surface
121/// Ok-path warnings today.
122CPPINTEROP_API void DrainPendingInto(InterpreterInfo* II, ErrorSlice* S);
123CPPINTEROP_API void ClearPending(InterpreterInfo* II);
124
125//
126// Production callers read diagnostics off Result<T>::error() once the
127// boundary translator has drained them into a slice. These survive
128// for tests of the consumer install path and as a peek for callers
129// not yet migrated to Result-returning APIs.
130
131CPPINTEROP_API unsigned GetPendingDiagnosticCount(InterpRef I = nullptr);
132CPPINTEROP_API DiagnosticRef GetPendingDiagnostic(unsigned Idx,
133 InterpRef I = nullptr);
134CPPINTEROP_API void ClearPendingDiagnostics(InterpRef I = nullptr);
135
136} // namespace Cpp
137
138#endif // CPPINTEROP_LIB_ERRORINTERNAL_H
#define CPPINTEROP_API
StatusError(Status C, std::string M)
std::string Message
Definition Box.h:70
unsigned GetPendingDiagnosticCount(InterpRef I)
ErrorRef makeError(Status S)
Build an inline-status ErrorRef (no diagnostics, no payload).
ErrorRef drainError(InterpreterInfo *II, llvm::Error E, const char *Producer, const char *ProducerSig)
Drain E into a fresh slice, returning the slice via ErrorRef.
void ClearPendingDiagnostics(InterpRef I)
void DrainPendingInto(InterpreterInfo *II, ErrorSlice *S)
Drain the consumer's per-interp buffer into a slice on failure.
ErrorSlice * AllocSlice(InterpreterInfo *Owner)
Allocate a fresh slice on the heap, refcount 0.
DiagnosticRef GetPendingDiagnostic(unsigned Idx, InterpRef I)
Result< T > makeResult(InterpreterInfo *II, llvm::Expected< T > E, const char *Producer, const char *ProducerSig)
Convert llvm::Expected<T> into Result<T>.
void ClearPending(InterpreterInfo *II)
Body of a slice-encoded error: drained diagnostics, producer attribution, refcount.
InterpreterInfo * Owner
std::atomic< uint32_t > Refcount
const char * ProducerSignature
const char * Producer
std::deque< StoredDiagView > Diagnostics
Owning record for one captured diagnostic.
DiagnosticSeverity Sev