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