Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/Context.cpp
35291 views
//===--- Context.cpp - Context for the constexpr VM -------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Context.h"9#include "ByteCodeEmitter.h"10#include "Compiler.h"11#include "EvalEmitter.h"12#include "Interp.h"13#include "InterpFrame.h"14#include "InterpStack.h"15#include "PrimType.h"16#include "Program.h"17#include "clang/AST/Expr.h"18#include "clang/Basic/TargetInfo.h"1920using namespace clang;21using namespace clang::interp;2223Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {}2425Context::~Context() {}2627bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {28assert(Stk.empty());29Function *Func = P->getFunction(FD);30if (!Func || !Func->hasBody())31Func = Compiler<ByteCodeEmitter>(*this, *P).compileFunc(FD);3233if (!Func)34return false;3536APValue DummyResult;37if (!Run(Parent, Func, DummyResult))38return false;3940return Func->isConstexpr();41}4243bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {44++EvalID;45bool Recursing = !Stk.empty();46Compiler<EvalEmitter> C(*this, *P, Parent, Stk);4748auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue());4950if (Res.isInvalid()) {51C.cleanup();52Stk.clear();53return false;54}5556if (!Recursing) {57assert(Stk.empty());58#ifndef NDEBUG59// Make sure we don't rely on some value being still alive in60// InterpStack memory.61Stk.clear();62#endif63}6465Result = Res.toAPValue();6667return true;68}6970bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) {71++EvalID;72bool Recursing = !Stk.empty();73Compiler<EvalEmitter> C(*this, *P, Parent, Stk);7475auto Res = C.interpretExpr(E);76if (Res.isInvalid()) {77C.cleanup();78Stk.clear();79return false;80}8182if (!Recursing) {83assert(Stk.empty());84#ifndef NDEBUG85// Make sure we don't rely on some value being still alive in86// InterpStack memory.87Stk.clear();88#endif89}9091Result = Res.toAPValue();92return true;93}9495bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,96APValue &Result) {97++EvalID;98bool Recursing = !Stk.empty();99Compiler<EvalEmitter> C(*this, *P, Parent, Stk);100101bool CheckGlobalInitialized =102shouldBeGloballyIndexed(VD) &&103(VD->getType()->isRecordType() || VD->getType()->isArrayType());104auto Res = C.interpretDecl(VD, CheckGlobalInitialized);105if (Res.isInvalid()) {106C.cleanup();107Stk.clear();108return false;109}110111if (!Recursing) {112assert(Stk.empty());113#ifndef NDEBUG114// Make sure we don't rely on some value being still alive in115// InterpStack memory.116Stk.clear();117#endif118}119120Result = Res.toAPValue();121return true;122}123124const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }125126std::optional<PrimType> Context::classify(QualType T) const {127if (T->isBooleanType())128return PT_Bool;129130// We map these to primitive arrays.131if (T->isAnyComplexType() || T->isVectorType())132return std::nullopt;133134if (T->isSignedIntegerOrEnumerationType()) {135switch (Ctx.getIntWidth(T)) {136case 64:137return PT_Sint64;138case 32:139return PT_Sint32;140case 16:141return PT_Sint16;142case 8:143return PT_Sint8;144default:145return PT_IntAPS;146}147}148149if (T->isUnsignedIntegerOrEnumerationType()) {150switch (Ctx.getIntWidth(T)) {151case 64:152return PT_Uint64;153case 32:154return PT_Uint32;155case 16:156return PT_Uint16;157case 8:158return PT_Uint8;159default:160return PT_IntAP;161}162}163164if (T->isNullPtrType())165return PT_Ptr;166167if (T->isFloatingType())168return PT_Float;169170if (T->isSpecificBuiltinType(BuiltinType::BoundMember) ||171T->isMemberPointerType())172return PT_MemberPtr;173174if (T->isFunctionPointerType() || T->isFunctionReferenceType() ||175T->isFunctionType())176return PT_FnPtr;177178if (T->isReferenceType() || T->isPointerType() ||179T->isObjCObjectPointerType())180return PT_Ptr;181182if (const auto *AT = T->getAs<AtomicType>())183return classify(AT->getValueType());184185if (const auto *DT = dyn_cast<DecltypeType>(T))186return classify(DT->getUnderlyingType());187188return std::nullopt;189}190191unsigned Context::getCharBit() const {192return Ctx.getTargetInfo().getCharWidth();193}194195/// Simple wrapper around getFloatTypeSemantics() to make code a196/// little shorter.197const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {198return Ctx.getFloatTypeSemantics(T);199}200201bool Context::Run(State &Parent, const Function *Func, APValue &Result) {202203{204InterpState State(Parent, *P, Stk, *this);205State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, CodePtr(),206Func->getArgSize());207if (Interpret(State, Result)) {208assert(Stk.empty());209return true;210}211212// State gets destroyed here, so the Stk.clear() below doesn't accidentally213// remove values the State's destructor might access.214}215216Stk.clear();217return false;218}219220// TODO: Virtual bases?221const CXXMethodDecl *222Context::getOverridingFunction(const CXXRecordDecl *DynamicDecl,223const CXXRecordDecl *StaticDecl,224const CXXMethodDecl *InitialFunction) const {225assert(DynamicDecl);226assert(StaticDecl);227assert(InitialFunction);228229const CXXRecordDecl *CurRecord = DynamicDecl;230const CXXMethodDecl *FoundFunction = InitialFunction;231for (;;) {232const CXXMethodDecl *Overrider =233FoundFunction->getCorrespondingMethodDeclaredInClass(CurRecord, false);234if (Overrider)235return Overrider;236237// Common case of only one base class.238if (CurRecord->getNumBases() == 1) {239CurRecord = CurRecord->bases_begin()->getType()->getAsCXXRecordDecl();240continue;241}242243// Otherwise, go to the base class that will lead to the StaticDecl.244for (const CXXBaseSpecifier &Spec : CurRecord->bases()) {245const CXXRecordDecl *Base = Spec.getType()->getAsCXXRecordDecl();246if (Base == StaticDecl || Base->isDerivedFrom(StaticDecl)) {247CurRecord = Base;248break;249}250}251}252253llvm_unreachable(254"Couldn't find an overriding function in the class hierarchy?");255return nullptr;256}257258const Function *Context::getOrCreateFunction(const FunctionDecl *FD) {259assert(FD);260const Function *Func = P->getFunction(FD);261bool IsBeingCompiled = Func && Func->isDefined() && !Func->isFullyCompiled();262bool WasNotDefined = Func && !Func->isConstexpr() && !Func->isDefined();263264if (IsBeingCompiled)265return Func;266267if (!Func || WasNotDefined) {268if (auto F = Compiler<ByteCodeEmitter>(*this, *P).compileFunc(FD))269Func = F;270}271272return Func;273}274275unsigned Context::collectBaseOffset(const RecordDecl *BaseDecl,276const RecordDecl *DerivedDecl) const {277assert(BaseDecl);278assert(DerivedDecl);279const auto *FinalDecl = cast<CXXRecordDecl>(BaseDecl);280const RecordDecl *CurDecl = DerivedDecl;281const Record *CurRecord = P->getOrCreateRecord(CurDecl);282assert(CurDecl && FinalDecl);283284unsigned OffsetSum = 0;285for (;;) {286assert(CurRecord->getNumBases() > 0);287// One level up288for (const Record::Base &B : CurRecord->bases()) {289const auto *BaseDecl = cast<CXXRecordDecl>(B.Decl);290291if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) {292OffsetSum += B.Offset;293CurRecord = B.R;294CurDecl = BaseDecl;295break;296}297}298if (CurDecl == FinalDecl)299break;300}301302assert(OffsetSum > 0);303return OffsetSum;304}305306const Record *Context::getRecord(const RecordDecl *D) const {307return P->getOrCreateRecord(D);308}309310311