183 lines · c
1//===--- Context.h - Context for the constexpr VM ---------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Defines the constexpr execution context.10//11// The execution context manages cached bytecode and the global context.12// It invokes the compiler and interpreter, propagating errors.13//14//===----------------------------------------------------------------------===//15 16#ifndef LLVM_CLANG_AST_INTERP_CONTEXT_H17#define LLVM_CLANG_AST_INTERP_CONTEXT_H18 19#include "InterpStack.h"20#include "clang/AST/ASTContext.h"21 22namespace clang {23class LangOptions;24class FunctionDecl;25class VarDecl;26class APValue;27class BlockExpr;28 29namespace interp {30class Function;31class Program;32class State;33enum PrimType : uint8_t;34 35struct ParamOffset {36 unsigned Offset;37 bool IsPtr;38};39 40/// Holds all information required to evaluate constexpr code in a module.41class Context final {42public:43 /// Initialises the constexpr VM.44 Context(ASTContext &Ctx);45 46 /// Cleans up the constexpr VM.47 ~Context();48 49 /// Checks if a function is a potential constant expression.50 bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FD);51 void isPotentialConstantExprUnevaluated(State &Parent, const Expr *E,52 const FunctionDecl *FD);53 54 /// Evaluates a toplevel expression as an rvalue.55 bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result);56 57 /// Like evaluateAsRvalue(), but does no implicit lvalue-to-rvalue conversion.58 bool evaluate(State &Parent, const Expr *E, APValue &Result,59 ConstantExprKind Kind);60 61 /// Evaluates a toplevel initializer.62 bool evaluateAsInitializer(State &Parent, const VarDecl *VD, const Expr *Init,63 APValue &Result);64 65 bool evaluateCharRange(State &Parent, const Expr *SizeExpr,66 const Expr *PtrExpr, APValue &Result);67 bool evaluateCharRange(State &Parent, const Expr *SizeExpr,68 const Expr *PtrExpr, std::string &Result);69 70 /// Evaluate \param E and if it can be evaluated to a null-terminated string,71 /// copy the result into \param Result.72 bool evaluateString(State &Parent, const Expr *E, std::string &Result);73 74 /// Evalute \param E and if it can be evaluated to a string literal,75 /// run strlen() on it.76 bool evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result);77 78 /// Returns the AST context.79 ASTContext &getASTContext() const { return Ctx; }80 /// Returns the language options.81 const LangOptions &getLangOpts() const;82 /// Returns CHAR_BIT.83 unsigned getCharBit() const;84 /// Return the floating-point semantics for T.85 const llvm::fltSemantics &getFloatSemantics(QualType T) const;86 /// Return the size of T in bits.87 uint32_t getBitWidth(QualType T) const { return Ctx.getIntWidth(T); }88 89 /// Classifies a type.90 OptPrimType classify(QualType T) const;91 92 /// Classifies an expression.93 OptPrimType classify(const Expr *E) const {94 assert(E);95 if (E->isGLValue())96 return PT_Ptr;97 98 return classify(E->getType());99 }100 101 bool canClassify(QualType T) const {102 if (const auto *BT = dyn_cast<BuiltinType>(T)) {103 if (BT->isInteger() || BT->isFloatingPoint())104 return true;105 if (BT->getKind() == BuiltinType::Bool)106 return true;107 }108 if (T->isPointerOrReferenceType())109 return true;110 111 if (T->isArrayType() || T->isRecordType() || T->isAnyComplexType() ||112 T->isVectorType())113 return false;114 return classify(T) != std::nullopt;115 }116 bool canClassify(const Expr *E) const {117 if (E->isGLValue())118 return true;119 return canClassify(E->getType());120 }121 122 const CXXMethodDecl *123 getOverridingFunction(const CXXRecordDecl *DynamicDecl,124 const CXXRecordDecl *StaticDecl,125 const CXXMethodDecl *InitialFunction) const;126 127 const Function *getOrCreateFunction(const FunctionDecl *FuncDecl);128 const Function *getOrCreateObjCBlock(const BlockExpr *E);129 130 /// Returns whether we should create a global variable for the131 /// given ValueDecl.132 static bool shouldBeGloballyIndexed(const ValueDecl *VD) {133 if (const auto *V = dyn_cast<VarDecl>(VD))134 return V->hasGlobalStorage() || V->isConstexpr();135 136 return false;137 }138 139 /// Returns the program. This is only needed for unittests.140 Program &getProgram() const { return *P; }141 142 unsigned collectBaseOffset(const RecordDecl *BaseDecl,143 const RecordDecl *DerivedDecl) const;144 145 const Record *getRecord(const RecordDecl *D) const;146 147 unsigned getEvalID() const { return EvalID; }148 149 /// Unevaluated builtins don't get their arguments put on the stack150 /// automatically. They instead operate on the AST of their Call151 /// Expression.152 /// Similar information is available via ASTContext::BuiltinInfo,153 /// but that is not correct for our use cases.154 static bool isUnevaluatedBuiltin(unsigned ID);155 156private:157 /// Runs a function.158 bool Run(State &Parent, const Function *Func);159 160 template <typename ResultT>161 bool evaluateStringRepr(State &Parent, const Expr *SizeExpr,162 const Expr *PtrExpr, ResultT &Result);163 164 /// Current compilation context.165 ASTContext &Ctx;166 /// Interpreter stack, shared across invocations.167 InterpStack Stk;168 /// Constexpr program.169 std::unique_ptr<Program> P;170 /// ID identifying an evaluation.171 unsigned EvalID = 0;172 /// Cached widths (in bits) of common types, for a faster classify().173 unsigned ShortWidth;174 unsigned IntWidth;175 unsigned LongWidth;176 unsigned LongLongWidth;177};178 179} // namespace interp180} // namespace clang181 182#endif183