================ @@ -0,0 +1,400 @@ +//===--- InterpreterValuePrinter.cpp - Value printing utils -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements routines for in-process value printing in clang-repl. +// +//===----------------------------------------------------------------------===// + +#include "IncrementalParser.h" +#include "InterpreterUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/Type.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/Interpreter.h" +#include "clang/Interpreter/Value.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Sema.h" + +#include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" + +#include <cassert> +#include <string> + +#include <cstdarg> + +namespace clang { + +llvm::Expected<llvm::orc::ExecutorAddr> +Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) { + assert(CXXRD && "Cannot compile a destructor for a nullptr"); + if (auto Dtor = Dtors.find(CXXRD); Dtor != Dtors.end()) + return Dtor->getSecond(); + + if (CXXRD->hasIrrelevantDestructor()) + return llvm::orc::ExecutorAddr{}; + + CXXDestructorDecl *DtorRD = + getCompilerInstance()->getSema().LookupDestructor(CXXRD); + + llvm::StringRef Name = + getCodeGen()->GetMangledName(GlobalDecl(DtorRD, Dtor_Base)); + auto AddrOrErr = getSymbolAddress(Name); + if (!AddrOrErr) + return AddrOrErr.takeError(); + + Dtors[CXXRD] = *AddrOrErr; + return AddrOrErr; +} + +enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag }; + +class InterfaceKindVisitor + : public TypeVisitor<InterfaceKindVisitor, InterfaceKind> { + + Sema &S; + Expr *E; + llvm::SmallVectorImpl<Expr *> &Args; + +public: + InterfaceKindVisitor(Sema &S, Expr *E, llvm::SmallVectorImpl<Expr *> &Args) + : S(S), E(E), Args(Args) {} + + InterfaceKind computeInterfaceKind(QualType Ty) { + return Visit(Ty.getTypePtr()); + } + + InterfaceKind VisitRecordType(const RecordType *Ty) { + return InterfaceKind::WithAlloc; + } + + InterfaceKind VisitMemberPointerType(const MemberPointerType *Ty) { + return InterfaceKind::WithAlloc; + } + + InterfaceKind VisitConstantArrayType(const ConstantArrayType *Ty) { + return InterfaceKind::CopyArray; + } + + InterfaceKind VisitFunctionProtoType(const FunctionProtoType *Ty) { + HandlePtrType(Ty); + return InterfaceKind::NoAlloc; + } + + InterfaceKind VisitPointerType(const PointerType *Ty) { + HandlePtrType(Ty); + return InterfaceKind::NoAlloc; + } + + InterfaceKind VisitReferenceType(const ReferenceType *Ty) { + ExprResult AddrOfE = S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, E); + assert(!AddrOfE.isInvalid() && "Can not create unary expression"); + Args.push_back(AddrOfE.get()); + return InterfaceKind::NoAlloc; + } + + InterfaceKind VisitBuiltinType(const BuiltinType *Ty) { + if (Ty->isNullPtrType()) + Args.push_back(E); + else if (Ty->isFloatingType()) + Args.push_back(E); + else if (Ty->isIntegralOrEnumerationType()) + HandleIntegralOrEnumType(Ty); + else if (Ty->isVoidType()) { + // Do we need to still run `E`? + } + + return InterfaceKind::NoAlloc; + } + + InterfaceKind VisitEnumType(const EnumType *Ty) { + HandleIntegralOrEnumType(Ty); + return InterfaceKind::NoAlloc; + } + +private: + // Force cast these types to the uint that fits the register size. That way we + // reduce the number of overloads of `__clang_Interpreter_SetValueNoAlloc`. + void HandleIntegralOrEnumType(const Type *Ty) { + ASTContext &Ctx = S.getASTContext(); + uint64_t PtrBits = Ctx.getTypeSize(Ctx.VoidPtrTy); + QualType UIntTy = Ctx.getBitIntType(/*Unsigned=*/true, PtrBits); + TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(UIntTy); + ExprResult CastedExpr = + S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E); + assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr"); + Args.push_back(CastedExpr.get()); + } + + void HandlePtrType(const Type *Ty) { + ASTContext &Ctx = S.getASTContext(); + TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ctx.VoidPtrTy); + ExprResult CastedExpr = + S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E); + assert(!CastedExpr.isInvalid() && "Can not create cstyle cast expression"); + Args.push_back(CastedExpr.get()); + } +}; + +// This synthesizes a call expression to a speciall +// function that is responsible for generating the Value. +// In general, we transform: +// clang-repl> x +// To: +// // 1. If x is a built-in type like int, float. +// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType, x); +// // 2. If x is a struct, and a lvalue. +// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType, +// &x); +// // 3. If x is a struct, but a rvalue. +// new (__clang_Interpreter_SetValueWithAlloc(ThisInterp, OpaqueValue, +// xQualType)) (x); +llvm::Expected<Expr *> Interpreter::AttachValuePrinting(Expr *E) { ---------------- vgvassilev wrote:
It is a private interface but I think I can change it to `ExtractValue` or something like that. What do you think? https://github.com/llvm/llvm-project/pull/107737 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits