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