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-exception
6//
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_H
17#define LLVM_CLANG_AST_INTERP_CONTEXT_H
18
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 /// If \param E evaluates to a pointer the number of accessible bytes
79 /// past the pointer is estimated in \param Result as if evaluated by
80 /// the builtin function __builtin_object_size. This is a best effort
81 /// approximation, when Kind & 2 == 0 the object size is less
82 /// than or equal to the estimated size, when Kind & 2 == 1 the
83 /// true value is greater than or equal to the estimated size.
84 /// When Kind & 1 == 1 only bytes belonging to the same subobject
85 /// as the one referred to by E are considered, when Kind & 1 == 0
86 /// bytes belonging to the same storage (stack, heap allocation,
87 /// global variable) are considered.
88 bool tryEvaluateObjectSize(State &Parent, const Expr *E, unsigned Kind,
89 uint64_t &Result);
90
91 /// Returns the AST context.
92 ASTContext &getASTContext() const { return Ctx; }
93 /// Returns the language options.
94 const LangOptions &getLangOpts() const;
95 /// Returns CHAR_BIT.
96 unsigned getCharBit() const;
97 /// Return the floating-point semantics for T.
98 const llvm::fltSemantics &getFloatSemantics(QualType T) const;
99 /// Return the size of T in bits.
100 uint32_t getBitWidth(QualType T) const { return Ctx.getIntWidth(T); }
101
102 /// Classifies a type.
103 OptPrimType classify(QualType T) const;
104
105 /// Classifies an expression.
106 OptPrimType classify(const Expr *E) const {
107 assert(E);
108 if (E->isGLValue())
109 return PT_Ptr;
110
111 return classify(T: E->getType());
112 }
113
114 bool canClassify(QualType T) const {
115 if (const auto *BT = dyn_cast<BuiltinType>(Val&: T)) {
116 if (BT->isInteger() || BT->isFloatingPoint())
117 return true;
118 if (BT->getKind() == BuiltinType::Bool)
119 return true;
120 }
121 if (T->isPointerOrReferenceType())
122 return true;
123
124 if (T->isArrayType() || T->isRecordType() || T->isAnyComplexType() ||
125 T->isVectorType())
126 return false;
127 return classify(T) != std::nullopt;
128 }
129 bool canClassify(const Expr *E) const {
130 if (E->isGLValue())
131 return true;
132 return canClassify(T: E->getType());
133 }
134
135 const CXXMethodDecl *
136 getOverridingFunction(const CXXRecordDecl *DynamicDecl,
137 const CXXRecordDecl *StaticDecl,
138 const CXXMethodDecl *InitialFunction) const;
139
140 const Function *getOrCreateFunction(const FunctionDecl *FuncDecl);
141 const Function *getOrCreateObjCBlock(const BlockExpr *E);
142
143 /// Returns whether we should create a global variable for the
144 /// given ValueDecl.
145 static bool shouldBeGloballyIndexed(const ValueDecl *VD) {
146 if (const auto *V = dyn_cast<VarDecl>(Val: VD))
147 return V->hasGlobalStorage() || V->isConstexpr();
148
149 return false;
150 }
151
152 /// Returns the program. This is only needed for unittests.
153 Program &getProgram() const { return *P; }
154
155 unsigned collectBaseOffset(const RecordDecl *BaseDecl,
156 const RecordDecl *DerivedDecl) const;
157
158 const Record *getRecord(const RecordDecl *D) const;
159
160 unsigned getEvalID() const { return EvalID; }
161
162 /// Unevaluated builtins don't get their arguments put on the stack
163 /// automatically. They instead operate on the AST of their Call
164 /// Expression.
165 /// Similar information is available via ASTContext::BuiltinInfo,
166 /// but that is not correct for our use cases.
167 static bool isUnevaluatedBuiltin(unsigned ID);
168
169private:
170 /// Runs a function.
171 bool Run(State &Parent, const Function *Func);
172
173 template <typename ResultT>
174 bool evaluateStringRepr(State &Parent, const Expr *SizeExpr,
175 const Expr *PtrExpr, ResultT &Result);
176
177 /// Current compilation context.
178 ASTContext &Ctx;
179 /// Interpreter stack, shared across invocations.
180 InterpStack Stk;
181 /// Constexpr program.
182 std::unique_ptr<Program> P;
183 /// ID identifying an evaluation.
184 unsigned EvalID = 0;
185 /// Cached widths (in bits) of common types, for a faster classify().
186 unsigned ShortWidth;
187 unsigned IntWidth;
188 unsigned LongWidth;
189 unsigned LongLongWidth;
190};
191
192} // namespace interp
193} // namespace clang
194
195#endif
196