1//===--- InterpreterValuePrinter.cpp - Value printing utils -----*- 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// This file implements routines for in-process value printing in clang-repl.
10//
11//===----------------------------------------------------------------------===//
12
13#include "IncrementalParser.h"
14#include "InterpreterUtils.h"
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/PrettyPrinter.h"
17#include "clang/AST/Type.h"
18#include "clang/Frontend/CompilerInstance.h"
19#include "clang/Interpreter/Interpreter.h"
20#include "clang/Interpreter/Value.h"
21#include "clang/Lex/Preprocessor.h"
22#include "clang/Sema/Lookup.h"
23#include "clang/Sema/Sema.h"
24
25#include "llvm/Support/Error.h"
26#include "llvm/Support/raw_ostream.h"
27
28#include <cassert>
29#include <string>
30
31#include <cstdarg>
32
33namespace clang {
34
35llvm::Expected<llvm::orc::ExecutorAddr>
36Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) {
37 assert(CXXRD && "Cannot compile a destructor for a nullptr");
38 if (auto Dtor = Dtors.find(Val: CXXRD); Dtor != Dtors.end())
39 return Dtor->getSecond();
40
41 if (CXXRD->hasIrrelevantDestructor())
42 return llvm::orc::ExecutorAddr{};
43
44 CXXDestructorDecl *DtorRD =
45 getCompilerInstance()->getSema().LookupDestructor(Class: CXXRD);
46
47 llvm::StringRef Name =
48 getCodeGen()->GetMangledName(GD: GlobalDecl(DtorRD, Dtor_Base));
49 auto AddrOrErr = getSymbolAddress(IRName: Name);
50 if (!AddrOrErr)
51 return AddrOrErr.takeError();
52
53 Dtors[CXXRD] = *AddrOrErr;
54 return AddrOrErr;
55}
56
57enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag };
58
59class InterfaceKindVisitor
60 : public TypeVisitor<InterfaceKindVisitor, InterfaceKind> {
61
62 Sema &S;
63 Expr *E;
64 llvm::SmallVectorImpl<Expr *> &Args;
65
66public:
67 InterfaceKindVisitor(Sema &S, Expr *E, llvm::SmallVectorImpl<Expr *> &Args)
68 : S(S), E(E), Args(Args) {}
69
70 InterfaceKind computeInterfaceKind(QualType Ty) {
71 return Visit(T: Ty.getTypePtr());
72 }
73
74 InterfaceKind VisitRecordType(const RecordType *Ty) {
75 return InterfaceKind::WithAlloc;
76 }
77
78 InterfaceKind VisitMemberPointerType(const MemberPointerType *Ty) {
79 return InterfaceKind::WithAlloc;
80 }
81
82 InterfaceKind VisitConstantArrayType(const ConstantArrayType *Ty) {
83 return InterfaceKind::CopyArray;
84 }
85
86 InterfaceKind VisitFunctionProtoType(const FunctionProtoType *Ty) {
87 HandlePtrType(Ty);
88 return InterfaceKind::NoAlloc;
89 }
90
91 InterfaceKind VisitPointerType(const PointerType *Ty) {
92 HandlePtrType(Ty);
93 return InterfaceKind::NoAlloc;
94 }
95
96 InterfaceKind VisitReferenceType(const ReferenceType *Ty) {
97 ExprResult AddrOfE = S.CreateBuiltinUnaryOp(OpLoc: SourceLocation(), Opc: UO_AddrOf, InputExpr: E);
98 assert(!AddrOfE.isInvalid() && "Can not create unary expression");
99 Args.push_back(Elt: AddrOfE.get());
100 return InterfaceKind::NoAlloc;
101 }
102
103 InterfaceKind VisitBuiltinType(const BuiltinType *Ty) {
104 if (Ty->isNullPtrType())
105 Args.push_back(Elt: E);
106 else if (Ty->isFloatingType())
107 Args.push_back(Elt: E);
108 else if (Ty->isIntegralOrEnumerationType())
109 HandleIntegralOrEnumType(Ty);
110 else if (Ty->isVoidType()) {
111 // Do we need to still run `E`?
112 }
113
114 return InterfaceKind::NoAlloc;
115 }
116
117 InterfaceKind VisitEnumType(const EnumType *Ty) {
118 HandleIntegralOrEnumType(Ty);
119 return InterfaceKind::NoAlloc;
120 }
121
122private:
123 // Force cast these types to the uint that fits the register size. That way we
124 // reduce the number of overloads of `__clang_Interpreter_SetValueNoAlloc`.
125 void HandleIntegralOrEnumType(const Type *Ty) {
126 ASTContext &Ctx = S.getASTContext();
127 uint64_t PtrBits = Ctx.getTypeSize(Ctx.VoidPtrTy);
128 QualType UIntTy = Ctx.getBitIntType(/*Unsigned=*/true, NumBits: PtrBits);
129 TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(T: UIntTy);
130 ExprResult CastedExpr =
131 S.BuildCStyleCastExpr(LParenLoc: SourceLocation(), Ty: TSI, RParenLoc: SourceLocation(), Op: E);
132 assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr");
133 Args.push_back(Elt: CastedExpr.get());
134 }
135
136 void HandlePtrType(const Type *Ty) {
137 ASTContext &Ctx = S.getASTContext();
138 TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(T: Ctx.VoidPtrTy);
139 ExprResult CastedExpr =
140 S.BuildCStyleCastExpr(LParenLoc: SourceLocation(), Ty: TSI, RParenLoc: SourceLocation(), Op: E);
141 assert(!CastedExpr.isInvalid() && "Can not create cstyle cast expression");
142 Args.push_back(Elt: CastedExpr.get());
143 }
144};
145
146// This synthesizes a call expression to a speciall
147// function that is responsible for generating the Value.
148// In general, we transform:
149// clang-repl> x
150// To:
151// // 1. If x is a built-in type like int, float.
152// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType, x);
153// // 2. If x is a struct, and a lvalue.
154// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType,
155// &x);
156// // 3. If x is a struct, but a rvalue.
157// new (__clang_Interpreter_SetValueWithAlloc(ThisInterp, OpaqueValue,
158// xQualType)) (x);
159llvm::Expected<Expr *> Interpreter::ExtractValueFromExpr(Expr *E) {
160 Sema &S = getCompilerInstance()->getSema();
161 ASTContext &Ctx = S.getASTContext();
162
163 // Find the value printing builtins.
164 if (!ValuePrintingInfo[0]) {
165 assert(llvm::all_of(ValuePrintingInfo, [](Expr *E) { return !E; }));
166
167 auto LookupInterface = [&](Expr *&Interface,
168 llvm::StringRef Name) -> llvm::Error {
169 LookupResult R(S, &Ctx.Idents.get(Name), SourceLocation(),
170 Sema::LookupOrdinaryName,
171 RedeclarationKind::ForVisibleRedeclaration);
172 S.LookupQualifiedName(R, Ctx.getTranslationUnitDecl());
173 if (R.empty())
174 return llvm::make_error<llvm::StringError>(
175 Args: Name + " not found!", Args: llvm::inconvertibleErrorCode());
176
177 CXXScopeSpec CSS;
178 Interface = S.BuildDeclarationNameExpr(SS: CSS, R, /*ADL=*/NeedsADL: false).get();
179 return llvm::Error::success();
180 };
181 static constexpr llvm::StringRef Builtin[] = {
182 "__clang_Interpreter_SetValueNoAlloc",
183 "__clang_Interpreter_SetValueWithAlloc",
184 "__clang_Interpreter_SetValueCopyArr", "__ci_newtag"};
185 if (llvm::Error Err =
186 LookupInterface(ValuePrintingInfo[NoAlloc], Builtin[NoAlloc]))
187 return std::move(Err);
188
189 if (Ctx.getLangOpts().CPlusPlus) {
190 if (llvm::Error Err =
191 LookupInterface(ValuePrintingInfo[WithAlloc], Builtin[WithAlloc]))
192 return std::move(Err);
193 if (llvm::Error Err =
194 LookupInterface(ValuePrintingInfo[CopyArray], Builtin[CopyArray]))
195 return std::move(Err);
196 if (llvm::Error Err =
197 LookupInterface(ValuePrintingInfo[NewTag], Builtin[NewTag]))
198 return std::move(Err);
199 }
200 }
201
202 llvm::SmallVector<Expr *, 4> AdjustedArgs;
203 // Create parameter `ThisInterp`.
204 AdjustedArgs.push_back(Elt: CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)this));
205
206 // Create parameter `OutVal`.
207 AdjustedArgs.push_back(
208 Elt: CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)&LastValue));
209
210 // Build `__clang_Interpreter_SetValue*` call.
211
212 // Get rid of ExprWithCleanups.
213 if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(Val: E))
214 E = EWC->getSubExpr();
215
216 QualType Ty = E->getType();
217 QualType DesugaredTy = Ty.getDesugaredType(Context: Ctx);
218
219 // For lvalue struct, we treat it as a reference.
220 if (DesugaredTy->isRecordType() && E->isLValue()) {
221 DesugaredTy = Ctx.getLValueReferenceType(T: DesugaredTy);
222 Ty = Ctx.getLValueReferenceType(T: Ty);
223 }
224
225 Expr *TypeArg =
226 CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)Ty.getAsOpaquePtr());
227 // The QualType parameter `OpaqueType`, represented as `void*`.
228 AdjustedArgs.push_back(Elt: TypeArg);
229
230 // We push the last parameter based on the type of the Expr. Note we need
231 // special care for rvalue struct.
232 InterfaceKindVisitor V(S, E, AdjustedArgs);
233 Scope *Scope = nullptr;
234 ExprResult SetValueE;
235 InterfaceKind Kind = V.computeInterfaceKind(Ty: DesugaredTy);
236 switch (Kind) {
237 case InterfaceKind::WithAlloc:
238 LLVM_FALLTHROUGH;
239 case InterfaceKind::CopyArray: {
240 // __clang_Interpreter_SetValueWithAlloc.
241 ExprResult AllocCall =
242 S.ActOnCallExpr(S: Scope, Fn: ValuePrintingInfo[InterfaceKind::WithAlloc],
243 LParenLoc: E->getBeginLoc(), ArgExprs: AdjustedArgs, RParenLoc: E->getEndLoc());
244 assert(!AllocCall.isInvalid() && "Can't create runtime interface call!");
245
246 TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(T: Ty, Loc: SourceLocation());
247
248 // Force CodeGen to emit destructor.
249 if (auto *RD = Ty->getAsCXXRecordDecl()) {
250 auto *Dtor = S.LookupDestructor(Class: RD);
251 Dtor->addAttr(UsedAttr::CreateImplicit(Ctx));
252 getCompilerInstance()->getASTConsumer().HandleTopLevelDecl(
253 D: DeclGroupRef(Dtor));
254 }
255
256 // __clang_Interpreter_SetValueCopyArr.
257 if (Kind == InterfaceKind::CopyArray) {
258 const auto *ConstantArrTy =
259 cast<ConstantArrayType>(Val: DesugaredTy.getTypePtr());
260 size_t ArrSize = Ctx.getConstantArrayElementCount(CA: ConstantArrTy);
261 Expr *ArrSizeExpr = IntegerLiteralExpr(C&: Ctx, Val: ArrSize);
262 Expr *Args[] = {E, AllocCall.get(), ArrSizeExpr};
263 SetValueE =
264 S.ActOnCallExpr(S: Scope, Fn: ValuePrintingInfo[InterfaceKind::CopyArray],
265 LParenLoc: SourceLocation(), ArgExprs: Args, RParenLoc: SourceLocation());
266 }
267 Expr *Args[] = {AllocCall.get(), ValuePrintingInfo[InterfaceKind::NewTag]};
268 ExprResult CXXNewCall = S.BuildCXXNew(
269 Range: E->getSourceRange(),
270 /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), PlacementArgs: Args,
271 /*PlacementRParen=*/SourceLocation(),
272 /*TypeIdParens=*/SourceRange(), AllocType: TSI->getType(), AllocTypeInfo: TSI, ArraySize: std::nullopt,
273 DirectInitRange: E->getSourceRange(), Initializer: E);
274
275 assert(!CXXNewCall.isInvalid() &&
276 "Can't create runtime placement new call!");
277
278 SetValueE = S.ActOnFinishFullExpr(Expr: CXXNewCall.get(),
279 /*DiscardedValue=*/false);
280 break;
281 }
282 // __clang_Interpreter_SetValueNoAlloc.
283 case InterfaceKind::NoAlloc: {
284 SetValueE =
285 S.ActOnCallExpr(S: Scope, Fn: ValuePrintingInfo[InterfaceKind::NoAlloc],
286 LParenLoc: E->getBeginLoc(), ArgExprs: AdjustedArgs, RParenLoc: E->getEndLoc());
287 break;
288 }
289 default:
290 llvm_unreachable("Unhandled InterfaceKind");
291 }
292
293 // It could fail, like printing an array type in C. (not supported)
294 if (SetValueE.isInvalid())
295 return E;
296
297 return SetValueE.get();
298}
299
300} // namespace clang
301
302using namespace clang;
303
304// Temporary rvalue struct that need special care.
305REPL_EXTERNAL_VISIBILITY void *
306__clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal,
307 void *OpaqueType) {
308 Value &VRef = *(Value *)OutVal;
309 VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
310 return VRef.getPtr();
311}
312
313extern "C" void REPL_EXTERNAL_VISIBILITY __clang_Interpreter_SetValueNoAlloc(
314 void *This, void *OutVal, void *OpaqueType, ...) {
315 Value &VRef = *(Value *)OutVal;
316 Interpreter *I = static_cast<Interpreter *>(This);
317 VRef = Value(I, OpaqueType);
318 if (VRef.isVoid())
319 return;
320
321 va_list args;
322 va_start(args, /*last named param*/ OpaqueType);
323
324 QualType QT = VRef.getType();
325 if (VRef.getKind() == Value::K_PtrOrObj) {
326 VRef.setPtr(va_arg(args, void *));
327 } else {
328 if (const auto *ET = QT->getAs<EnumType>())
329 QT = ET->getDecl()->getIntegerType();
330 switch (QT->castAs<BuiltinType>()->getKind()) {
331 default:
332 llvm_unreachable("unknown type kind!");
333 break;
334 // Types shorter than int are resolved as int, else va_arg has UB.
335 case BuiltinType::Bool:
336 VRef.setBool(va_arg(args, int));
337 break;
338 case BuiltinType::Char_S:
339 VRef.setChar_S(va_arg(args, int));
340 break;
341 case BuiltinType::SChar:
342 VRef.setSChar(va_arg(args, int));
343 break;
344 case BuiltinType::Char_U:
345 VRef.setChar_U(va_arg(args, unsigned));
346 break;
347 case BuiltinType::UChar:
348 VRef.setUChar(va_arg(args, unsigned));
349 break;
350 case BuiltinType::Short:
351 VRef.setShort(va_arg(args, int));
352 break;
353 case BuiltinType::UShort:
354 VRef.setUShort(va_arg(args, unsigned));
355 break;
356 case BuiltinType::Int:
357 VRef.setInt(va_arg(args, int));
358 break;
359 case BuiltinType::UInt:
360 VRef.setUInt(va_arg(args, unsigned));
361 break;
362 case BuiltinType::Long:
363 VRef.setLong(va_arg(args, long));
364 break;
365 case BuiltinType::ULong:
366 VRef.setULong(va_arg(args, unsigned long));
367 break;
368 case BuiltinType::LongLong:
369 VRef.setLongLong(va_arg(args, long long));
370 break;
371 case BuiltinType::ULongLong:
372 VRef.setULongLong(va_arg(args, unsigned long long));
373 break;
374 // Types shorter than double are resolved as double, else va_arg has UB.
375 case BuiltinType::Float:
376 VRef.setFloat(va_arg(args, double));
377 break;
378 case BuiltinType::Double:
379 VRef.setDouble(va_arg(args, double));
380 break;
381 case BuiltinType::LongDouble:
382 VRef.setLongDouble(va_arg(args, long double));
383 break;
384 // See REPL_BUILTIN_TYPES.
385 }
386 }
387 va_end(args);
388}
389
390// A trampoline to work around the fact that operator placement new cannot
391// really be forward declared due to libc++ and libstdc++ declaration mismatch.
392// FIXME: __clang_Interpreter_NewTag is ODR violation because we get the same
393// definition in the interpreter runtime. We should move it in a runtime header
394// which gets included by the interpreter and here.
395struct __clang_Interpreter_NewTag {};
396REPL_EXTERNAL_VISIBILITY void *
397operator new(size_t __sz, void *__p, __clang_Interpreter_NewTag) noexcept {
398 // Just forward to the standard operator placement new.
399 return operator new(__sz, __p);
400}
401

source code of clang/lib/Interpreter/InterpreterValuePrinter.cpp