xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/EvaluationResult.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
17a6dacacSDimitry Andric //===------ EvaluationResult.h - Result class  for the VM -------*- C++ -*-===//
27a6dacacSDimitry Andric //
37a6dacacSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47a6dacacSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
57a6dacacSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67a6dacacSDimitry Andric //
77a6dacacSDimitry Andric //===----------------------------------------------------------------------===//
87a6dacacSDimitry Andric 
97a6dacacSDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_EVALUATION_RESULT_H
107a6dacacSDimitry Andric #define LLVM_CLANG_AST_INTERP_EVALUATION_RESULT_H
117a6dacacSDimitry Andric 
127a6dacacSDimitry Andric #include "FunctionPointer.h"
137a6dacacSDimitry Andric #include "Pointer.h"
147a6dacacSDimitry Andric #include "clang/AST/APValue.h"
157a6dacacSDimitry Andric #include "clang/AST/Decl.h"
167a6dacacSDimitry Andric #include "clang/AST/Expr.h"
177a6dacacSDimitry Andric #include <optional>
187a6dacacSDimitry Andric #include <variant>
197a6dacacSDimitry Andric 
207a6dacacSDimitry Andric namespace clang {
217a6dacacSDimitry Andric namespace interp {
227a6dacacSDimitry Andric class EvalEmitter;
237a6dacacSDimitry Andric class Context;
247a6dacacSDimitry Andric 
257a6dacacSDimitry Andric /// Defines the result of an evaluation.
267a6dacacSDimitry Andric ///
277a6dacacSDimitry Andric /// The result might be in different forms--one of the pointer types,
287a6dacacSDimitry Andric /// an APValue, or nothing.
297a6dacacSDimitry Andric ///
307a6dacacSDimitry Andric /// We use this class to inspect and diagnose the result, as well as
317a6dacacSDimitry Andric /// convert it to the requested form.
327a6dacacSDimitry Andric class EvaluationResult final {
337a6dacacSDimitry Andric public:
347a6dacacSDimitry Andric   enum ResultKind {
357a6dacacSDimitry Andric     Empty,   // Initial state.
367a6dacacSDimitry Andric     LValue,  // Result is an lvalue/pointer.
377a6dacacSDimitry Andric     RValue,  // Result is an rvalue.
387a6dacacSDimitry Andric     Invalid, // Result is invalid.
397a6dacacSDimitry Andric     Valid,   // Result is valid and empty.
407a6dacacSDimitry Andric   };
417a6dacacSDimitry Andric 
427a6dacacSDimitry Andric   using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
437a6dacacSDimitry Andric 
447a6dacacSDimitry Andric private:
457a6dacacSDimitry Andric   const Context *Ctx = nullptr;
467a6dacacSDimitry Andric   std::variant<std::monostate, Pointer, FunctionPointer, APValue> Value;
477a6dacacSDimitry Andric   ResultKind Kind = Empty;
487a6dacacSDimitry Andric   DeclTy Source = nullptr; // Currently only needed for dump().
497a6dacacSDimitry Andric 
507a6dacacSDimitry Andric   EvaluationResult(ResultKind Kind) : Kind(Kind) {
517a6dacacSDimitry Andric     // Leave everything empty. Can be used as an
527a6dacacSDimitry Andric     // error marker or for void return values.
537a6dacacSDimitry Andric     assert(Kind == Valid || Kind == Invalid);
547a6dacacSDimitry Andric   }
557a6dacacSDimitry Andric 
567a6dacacSDimitry Andric   void setSource(DeclTy D) { Source = D; }
577a6dacacSDimitry Andric 
587a6dacacSDimitry Andric   void setValue(const APValue &V) {
59*0fca6ea1SDimitry Andric     // V could still be an LValue.
607a6dacacSDimitry Andric     assert(empty());
617a6dacacSDimitry Andric     Value = std::move(V);
627a6dacacSDimitry Andric     Kind = RValue;
637a6dacacSDimitry Andric   }
647a6dacacSDimitry Andric   void setPointer(const Pointer P) {
657a6dacacSDimitry Andric     assert(empty());
667a6dacacSDimitry Andric     Value = P;
677a6dacacSDimitry Andric     Kind = LValue;
687a6dacacSDimitry Andric   }
697a6dacacSDimitry Andric   void setFunctionPointer(const FunctionPointer &P) {
707a6dacacSDimitry Andric     assert(empty());
717a6dacacSDimitry Andric     Value = P;
727a6dacacSDimitry Andric     Kind = LValue;
737a6dacacSDimitry Andric   }
747a6dacacSDimitry Andric   void setInvalid() {
75*0fca6ea1SDimitry Andric     // We are NOT asserting empty() here, since setting it to invalid
76*0fca6ea1SDimitry Andric     // is allowed even if there is already a result.
777a6dacacSDimitry Andric     Kind = Invalid;
787a6dacacSDimitry Andric   }
797a6dacacSDimitry Andric   void setValid() {
807a6dacacSDimitry Andric     assert(empty());
817a6dacacSDimitry Andric     Kind = Valid;
827a6dacacSDimitry Andric   }
837a6dacacSDimitry Andric 
847a6dacacSDimitry Andric public:
857a6dacacSDimitry Andric   EvaluationResult(const Context *Ctx) : Ctx(Ctx) {}
867a6dacacSDimitry Andric 
877a6dacacSDimitry Andric   bool empty() const { return Kind == Empty; }
887a6dacacSDimitry Andric   bool isInvalid() const { return Kind == Invalid; }
897a6dacacSDimitry Andric   bool isLValue() const { return Kind == LValue; }
907a6dacacSDimitry Andric   bool isRValue() const { return Kind == RValue; }
917a6dacacSDimitry Andric 
927a6dacacSDimitry Andric   /// Returns an APValue for the evaluation result. The returned
937a6dacacSDimitry Andric   /// APValue might be an LValue or RValue.
947a6dacacSDimitry Andric   APValue toAPValue() const;
957a6dacacSDimitry Andric 
967a6dacacSDimitry Andric   /// If the result is an LValue, convert that to an RValue
977a6dacacSDimitry Andric   /// and return it. This may fail, e.g. if the result is an
987a6dacacSDimitry Andric   /// LValue and we can't read from it.
997a6dacacSDimitry Andric   std::optional<APValue> toRValue() const;
1007a6dacacSDimitry Andric 
101*0fca6ea1SDimitry Andric   /// Check that all subobjects of the given pointer have been initialized.
102*0fca6ea1SDimitry Andric   bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const;
103*0fca6ea1SDimitry Andric   /// Check that none of the blocks the given pointer (transitively) points
104*0fca6ea1SDimitry Andric   /// to are dynamically allocated.
105*0fca6ea1SDimitry Andric   bool checkReturnValue(InterpState &S, const Context &Ctx, const Pointer &Ptr,
106*0fca6ea1SDimitry Andric                         const SourceInfo &Info);
107*0fca6ea1SDimitry Andric 
108*0fca6ea1SDimitry Andric   QualType getSourceType() const {
109*0fca6ea1SDimitry Andric     if (const auto *D =
110*0fca6ea1SDimitry Andric             dyn_cast_if_present<ValueDecl>(Source.dyn_cast<const Decl *>()))
111*0fca6ea1SDimitry Andric       return D->getType();
112*0fca6ea1SDimitry Andric     else if (const auto *E = Source.dyn_cast<const Expr *>())
113*0fca6ea1SDimitry Andric       return E->getType();
114*0fca6ea1SDimitry Andric     return QualType();
115*0fca6ea1SDimitry Andric   }
1167a6dacacSDimitry Andric 
1177a6dacacSDimitry Andric   /// Dump to stderr.
1187a6dacacSDimitry Andric   void dump() const;
1197a6dacacSDimitry Andric 
1207a6dacacSDimitry Andric   friend class EvalEmitter;
121*0fca6ea1SDimitry Andric   friend class InterpState;
1227a6dacacSDimitry Andric };
1237a6dacacSDimitry Andric 
1247a6dacacSDimitry Andric } // namespace interp
1257a6dacacSDimitry Andric } // namespace clang
1267a6dacacSDimitry Andric 
1277a6dacacSDimitry Andric #endif
128