1 //===--- Context.cpp - 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 #include "Context.h" 10 #include "ByteCodeEmitter.h" 11 #include "ByteCodeExprGen.h" 12 #include "ByteCodeGenError.h" 13 #include "ByteCodeStmtGen.h" 14 #include "EvalEmitter.h" 15 #include "Interp.h" 16 #include "InterpFrame.h" 17 #include "InterpStack.h" 18 #include "PrimType.h" 19 #include "Program.h" 20 #include "clang/AST/Expr.h" 21 #include "clang/Basic/TargetInfo.h" 22 23 using namespace clang; 24 using namespace clang::interp; 25 26 Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {} 27 28 Context::~Context() {} 29 30 bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) { 31 assert(Stk.empty()); 32 Function *Func = P->getFunction(FD); 33 if (!Func || !Func->hasBody()) { 34 if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) { 35 Func = *R; 36 } else { 37 handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) { 38 Parent.FFDiag(Err.getRange().getBegin(), 39 diag::err_experimental_clang_interp_failed) 40 << Err.getRange(); 41 }); 42 return false; 43 } 44 } 45 46 APValue DummyResult; 47 if (!Run(Parent, Func, DummyResult)) { 48 return false; 49 } 50 51 return Func->isConstexpr(); 52 } 53 54 bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { 55 assert(Stk.empty()); 56 ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result); 57 if (Check(Parent, C.interpretExpr(E))) { 58 assert(Stk.empty()); 59 #ifndef NDEBUG 60 // Make sure we don't rely on some value being still alive in 61 // InterpStack memory. 62 Stk.clear(); 63 #endif 64 return true; 65 } 66 67 Stk.clear(); 68 return false; 69 } 70 71 bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD, 72 APValue &Result) { 73 assert(Stk.empty()); 74 ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result); 75 if (Check(Parent, C.interpretDecl(VD))) { 76 assert(Stk.empty()); 77 #ifndef NDEBUG 78 // Make sure we don't rely on some value being still alive in 79 // InterpStack memory. 80 Stk.clear(); 81 #endif 82 return true; 83 } 84 85 Stk.clear(); 86 return false; 87 } 88 89 const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); } 90 91 std::optional<PrimType> Context::classify(QualType T) const { 92 if (T->isBooleanType()) 93 return PT_Bool; 94 95 if (T->isAnyComplexType()) 96 return std::nullopt; 97 98 if (T->isSignedIntegerOrEnumerationType()) { 99 switch (Ctx.getIntWidth(T)) { 100 case 64: 101 return PT_Sint64; 102 case 32: 103 return PT_Sint32; 104 case 16: 105 return PT_Sint16; 106 case 8: 107 return PT_Sint8; 108 default: 109 return PT_IntAPS; 110 } 111 } 112 113 if (T->isUnsignedIntegerOrEnumerationType()) { 114 switch (Ctx.getIntWidth(T)) { 115 case 64: 116 return PT_Uint64; 117 case 32: 118 return PT_Uint32; 119 case 16: 120 return PT_Uint16; 121 case 8: 122 return PT_Uint8; 123 default: 124 return PT_IntAP; 125 } 126 } 127 128 if (T->isNullPtrType()) 129 return PT_Ptr; 130 131 if (T->isFloatingType()) 132 return PT_Float; 133 134 if (T->isFunctionPointerType() || T->isFunctionReferenceType() || 135 T->isFunctionType() || T->isSpecificBuiltinType(BuiltinType::BoundMember)) 136 return PT_FnPtr; 137 138 if (T->isReferenceType() || T->isPointerType()) 139 return PT_Ptr; 140 141 if (const auto *AT = dyn_cast<AtomicType>(T)) 142 return classify(AT->getValueType()); 143 144 if (const auto *DT = dyn_cast<DecltypeType>(T)) 145 return classify(DT->getUnderlyingType()); 146 147 if (const auto *DT = dyn_cast<MemberPointerType>(T)) 148 return classify(DT->getPointeeType()); 149 150 return std::nullopt; 151 } 152 153 unsigned Context::getCharBit() const { 154 return Ctx.getTargetInfo().getCharWidth(); 155 } 156 157 /// Simple wrapper around getFloatTypeSemantics() to make code a 158 /// little shorter. 159 const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const { 160 return Ctx.getFloatTypeSemantics(T); 161 } 162 163 bool Context::Run(State &Parent, const Function *Func, APValue &Result) { 164 165 { 166 InterpState State(Parent, *P, Stk, *this); 167 State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, {}); 168 if (Interpret(State, Result)) { 169 assert(Stk.empty()); 170 return true; 171 } 172 173 // State gets destroyed here, so the Stk.clear() below doesn't accidentally 174 // remove values the State's destructor might access. 175 } 176 177 Stk.clear(); 178 return false; 179 } 180 181 bool Context::Check(State &Parent, llvm::Expected<bool> &&Flag) { 182 if (Flag) 183 return *Flag; 184 handleAllErrors(Flag.takeError(), [&Parent](ByteCodeGenError &Err) { 185 Parent.FFDiag(Err.getRange().getBegin(), 186 diag::err_experimental_clang_interp_failed) 187 << Err.getRange(); 188 }); 189 return false; 190 } 191 192 // TODO: Virtual bases? 193 const CXXMethodDecl * 194 Context::getOverridingFunction(const CXXRecordDecl *DynamicDecl, 195 const CXXRecordDecl *StaticDecl, 196 const CXXMethodDecl *InitialFunction) const { 197 198 const CXXRecordDecl *CurRecord = DynamicDecl; 199 const CXXMethodDecl *FoundFunction = InitialFunction; 200 for (;;) { 201 const CXXMethodDecl *Overrider = 202 FoundFunction->getCorrespondingMethodDeclaredInClass(CurRecord, false); 203 if (Overrider) 204 return Overrider; 205 206 // Common case of only one base class. 207 if (CurRecord->getNumBases() == 1) { 208 CurRecord = CurRecord->bases_begin()->getType()->getAsCXXRecordDecl(); 209 continue; 210 } 211 212 // Otherwise, go to the base class that will lead to the StaticDecl. 213 for (const CXXBaseSpecifier &Spec : CurRecord->bases()) { 214 const CXXRecordDecl *Base = Spec.getType()->getAsCXXRecordDecl(); 215 if (Base == StaticDecl || Base->isDerivedFrom(StaticDecl)) { 216 CurRecord = Base; 217 break; 218 } 219 } 220 } 221 222 llvm_unreachable( 223 "Couldn't find an overriding function in the class hierarchy?"); 224 return nullptr; 225 } 226 227 const Function *Context::getOrCreateFunction(const FunctionDecl *FD) { 228 assert(FD); 229 const Function *Func = P->getFunction(FD); 230 bool IsBeingCompiled = Func && Func->isDefined() && !Func->isFullyCompiled(); 231 bool WasNotDefined = Func && !Func->isConstexpr() && !Func->isDefined(); 232 233 if (IsBeingCompiled) 234 return Func; 235 236 if (!Func || WasNotDefined) { 237 if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) 238 Func = *R; 239 else { 240 llvm::consumeError(R.takeError()); 241 return nullptr; 242 } 243 } 244 245 return Func; 246 } 247