xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/EvaluationResult.h (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
1*7a6dacacSDimitry Andric //===------ EvaluationResult.h - Result class  for the VM -------*- C++ -*-===//
2*7a6dacacSDimitry Andric //
3*7a6dacacSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*7a6dacacSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*7a6dacacSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*7a6dacacSDimitry Andric //
7*7a6dacacSDimitry Andric //===----------------------------------------------------------------------===//
8*7a6dacacSDimitry Andric 
9*7a6dacacSDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_EVALUATION_RESULT_H
10*7a6dacacSDimitry Andric #define LLVM_CLANG_AST_INTERP_EVALUATION_RESULT_H
11*7a6dacacSDimitry Andric 
12*7a6dacacSDimitry Andric #include "FunctionPointer.h"
13*7a6dacacSDimitry Andric #include "Pointer.h"
14*7a6dacacSDimitry Andric #include "clang/AST/APValue.h"
15*7a6dacacSDimitry Andric #include "clang/AST/Decl.h"
16*7a6dacacSDimitry Andric #include "clang/AST/Expr.h"
17*7a6dacacSDimitry Andric #include <optional>
18*7a6dacacSDimitry Andric #include <variant>
19*7a6dacacSDimitry Andric 
20*7a6dacacSDimitry Andric namespace clang {
21*7a6dacacSDimitry Andric namespace interp {
22*7a6dacacSDimitry Andric class EvalEmitter;
23*7a6dacacSDimitry Andric class Context;
24*7a6dacacSDimitry Andric 
25*7a6dacacSDimitry Andric /// Defines the result of an evaluation.
26*7a6dacacSDimitry Andric ///
27*7a6dacacSDimitry Andric /// The result might be in different forms--one of the pointer types,
28*7a6dacacSDimitry Andric /// an APValue, or nothing.
29*7a6dacacSDimitry Andric ///
30*7a6dacacSDimitry Andric /// We use this class to inspect and diagnose the result, as well as
31*7a6dacacSDimitry Andric /// convert it to the requested form.
32*7a6dacacSDimitry Andric class EvaluationResult final {
33*7a6dacacSDimitry Andric public:
34*7a6dacacSDimitry Andric   enum ResultKind {
35*7a6dacacSDimitry Andric     Empty,   // Initial state.
36*7a6dacacSDimitry Andric     LValue,  // Result is an lvalue/pointer.
37*7a6dacacSDimitry Andric     RValue,  // Result is an rvalue.
38*7a6dacacSDimitry Andric     Invalid, // Result is invalid.
39*7a6dacacSDimitry Andric     Valid,   // Result is valid and empty.
40*7a6dacacSDimitry Andric   };
41*7a6dacacSDimitry Andric 
42*7a6dacacSDimitry Andric   using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
43*7a6dacacSDimitry Andric 
44*7a6dacacSDimitry Andric private:
45*7a6dacacSDimitry Andric   const Context *Ctx = nullptr;
46*7a6dacacSDimitry Andric   std::variant<std::monostate, Pointer, FunctionPointer, APValue> Value;
47*7a6dacacSDimitry Andric   ResultKind Kind = Empty;
48*7a6dacacSDimitry Andric   DeclTy Source = nullptr; // Currently only needed for dump().
49*7a6dacacSDimitry Andric 
50*7a6dacacSDimitry Andric   EvaluationResult(ResultKind Kind) : Kind(Kind) {
51*7a6dacacSDimitry Andric     // Leave everything empty. Can be used as an
52*7a6dacacSDimitry Andric     // error marker or for void return values.
53*7a6dacacSDimitry Andric     assert(Kind == Valid || Kind == Invalid);
54*7a6dacacSDimitry Andric   }
55*7a6dacacSDimitry Andric 
56*7a6dacacSDimitry Andric   void setSource(DeclTy D) { Source = D; }
57*7a6dacacSDimitry Andric 
58*7a6dacacSDimitry Andric   void setValue(const APValue &V) {
59*7a6dacacSDimitry Andric     assert(empty());
60*7a6dacacSDimitry Andric     assert(!V.isLValue());
61*7a6dacacSDimitry Andric     Value = std::move(V);
62*7a6dacacSDimitry Andric     Kind = RValue;
63*7a6dacacSDimitry Andric   }
64*7a6dacacSDimitry Andric   void setPointer(const Pointer P) {
65*7a6dacacSDimitry Andric     assert(empty());
66*7a6dacacSDimitry Andric     Value = P;
67*7a6dacacSDimitry Andric     Kind = LValue;
68*7a6dacacSDimitry Andric   }
69*7a6dacacSDimitry Andric   void setFunctionPointer(const FunctionPointer &P) {
70*7a6dacacSDimitry Andric     assert(empty());
71*7a6dacacSDimitry Andric     Value = P;
72*7a6dacacSDimitry Andric     Kind = LValue;
73*7a6dacacSDimitry Andric   }
74*7a6dacacSDimitry Andric   void setInvalid() {
75*7a6dacacSDimitry Andric     assert(empty());
76*7a6dacacSDimitry Andric     Kind = Invalid;
77*7a6dacacSDimitry Andric   }
78*7a6dacacSDimitry Andric   void setValid() {
79*7a6dacacSDimitry Andric     assert(empty());
80*7a6dacacSDimitry Andric     Kind = Valid;
81*7a6dacacSDimitry Andric   }
82*7a6dacacSDimitry Andric 
83*7a6dacacSDimitry Andric public:
84*7a6dacacSDimitry Andric   EvaluationResult(const Context *Ctx) : Ctx(Ctx) {}
85*7a6dacacSDimitry Andric 
86*7a6dacacSDimitry Andric   bool empty() const { return Kind == Empty; }
87*7a6dacacSDimitry Andric   bool isInvalid() const { return Kind == Invalid; }
88*7a6dacacSDimitry Andric   bool isLValue() const { return Kind == LValue; }
89*7a6dacacSDimitry Andric   bool isRValue() const { return Kind == RValue; }
90*7a6dacacSDimitry Andric 
91*7a6dacacSDimitry Andric   /// Returns an APValue for the evaluation result. The returned
92*7a6dacacSDimitry Andric   /// APValue might be an LValue or RValue.
93*7a6dacacSDimitry Andric   APValue toAPValue() const;
94*7a6dacacSDimitry Andric 
95*7a6dacacSDimitry Andric   /// If the result is an LValue, convert that to an RValue
96*7a6dacacSDimitry Andric   /// and return it. This may fail, e.g. if the result is an
97*7a6dacacSDimitry Andric   /// LValue and we can't read from it.
98*7a6dacacSDimitry Andric   std::optional<APValue> toRValue() const;
99*7a6dacacSDimitry Andric 
100*7a6dacacSDimitry Andric   bool checkFullyInitialized(InterpState &S) const;
101*7a6dacacSDimitry Andric 
102*7a6dacacSDimitry Andric   /// Dump to stderr.
103*7a6dacacSDimitry Andric   void dump() const;
104*7a6dacacSDimitry Andric 
105*7a6dacacSDimitry Andric   friend class EvalEmitter;
106*7a6dacacSDimitry Andric };
107*7a6dacacSDimitry Andric 
108*7a6dacacSDimitry Andric } // namespace interp
109*7a6dacacSDimitry Andric } // namespace clang
110*7a6dacacSDimitry Andric 
111*7a6dacacSDimitry Andric #endif
112