Context.cpp revision 353942
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 "ByteCodeStmtGen.h" 13#include "EvalEmitter.h" 14#include "Interp.h" 15#include "InterpFrame.h" 16#include "InterpStack.h" 17#include "PrimType.h" 18#include "Program.h" 19#include "clang/AST/Expr.h" 20 21using namespace clang; 22using namespace clang::interp; 23 24Context::Context(ASTContext &Ctx) 25 : Ctx(Ctx), ForceInterp(getLangOpts().ForceNewConstInterp), 26 P(new Program(*this)) {} 27 28Context::~Context() {} 29 30InterpResult Context::isPotentialConstantExpr(State &Parent, 31 const FunctionDecl *FD) { 32 Function *Func = P->getFunction(FD); 33 if (!Func) { 34 if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) { 35 Func = *R; 36 } else if (ForceInterp) { 37 handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) { 38 Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed); 39 }); 40 return InterpResult::Fail; 41 } else { 42 consumeError(R.takeError()); 43 return InterpResult::Bail; 44 } 45 } 46 47 if (!Func->isConstexpr()) 48 return InterpResult::Fail; 49 50 APValue Dummy; 51 return Run(Parent, Func, Dummy); 52} 53 54InterpResult Context::evaluateAsRValue(State &Parent, const Expr *E, 55 APValue &Result) { 56 ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result); 57 return Check(Parent, C.interpretExpr(E)); 58} 59 60InterpResult Context::evaluateAsInitializer(State &Parent, const VarDecl *VD, 61 APValue &Result) { 62 ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result); 63 return Check(Parent, C.interpretDecl(VD)); 64} 65 66const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); } 67 68llvm::Optional<PrimType> Context::classify(QualType T) { 69 if (T->isReferenceType() || T->isPointerType()) { 70 return PT_Ptr; 71 } 72 73 if (T->isBooleanType()) 74 return PT_Bool; 75 76 if (T->isSignedIntegerOrEnumerationType()) { 77 switch (Ctx.getIntWidth(T)) { 78 case 64: 79 return PT_Sint64; 80 case 32: 81 return PT_Sint32; 82 case 16: 83 return PT_Sint16; 84 case 8: 85 return PT_Sint8; 86 default: 87 return {}; 88 } 89 } 90 91 if (T->isUnsignedIntegerOrEnumerationType()) { 92 switch (Ctx.getIntWidth(T)) { 93 case 64: 94 return PT_Uint64; 95 case 32: 96 return PT_Uint32; 97 case 16: 98 return PT_Uint16; 99 case 8: 100 return PT_Uint8; 101 default: 102 return {}; 103 } 104 } 105 106 if (T->isNullPtrType()) 107 return PT_Ptr; 108 109 if (auto *AT = dyn_cast<AtomicType>(T)) 110 return classify(AT->getValueType()); 111 112 return {}; 113} 114 115unsigned Context::getCharBit() const { 116 return Ctx.getTargetInfo().getCharWidth(); 117} 118 119InterpResult Context::Run(State &Parent, Function *Func, APValue &Result) { 120 InterpResult Flag; 121 { 122 InterpState State(Parent, *P, Stk, *this); 123 State.Current = new InterpFrame(State, Func, nullptr, {}, {}); 124 if (Interpret(State, Result)) { 125 Flag = InterpResult::Success; 126 } else { 127 Flag = InterpResult::Fail; 128 } 129 } 130 131 if (Flag != InterpResult::Success) 132 Stk.clear(); 133 return Flag; 134} 135 136InterpResult Context::Check(State &Parent, llvm::Expected<bool> &&R) { 137 if (R) { 138 return *R ? InterpResult::Success : InterpResult::Fail; 139 } else if (ForceInterp) { 140 handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) { 141 Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed); 142 }); 143 return InterpResult::Fail; 144 } else { 145 consumeError(R.takeError()); 146 return InterpResult::Bail; 147 } 148} 149