1 //===--- InterpreterValuePrinter.cpp - Value printing utils -----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements routines for in-process value printing in clang-repl.
11 //===----------------------------------------------------------------------===//
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"
25 #include "llvm/Support/Error.h"
26 #include "llvm/Support/raw_ostream.h"
35 llvm::Expected
<llvm::orc::ExecutorAddr
>
36 Interpreter::CompileDtorCall(CXXRecordDecl
*CXXRD
) {
37 assert(CXXRD
&& "Cannot compile a destructor for a nullptr");
38 if (auto Dtor
= Dtors
.find(CXXRD
); Dtor
!= Dtors
.end())
39 return Dtor
->getSecond();
41 if (CXXRD
->hasIrrelevantDestructor())
42 return llvm::orc::ExecutorAddr
{};
44 CXXDestructorDecl
*DtorRD
=
45 getCompilerInstance()->getSema().LookupDestructor(CXXRD
);
47 llvm::StringRef Name
=
48 getCodeGen()->GetMangledName(GlobalDecl(DtorRD
, Dtor_Base
));
49 auto AddrOrErr
= getSymbolAddress(Name
);
51 return AddrOrErr
.takeError();
53 Dtors
[CXXRD
] = *AddrOrErr
;
57 enum InterfaceKind
{ NoAlloc
, WithAlloc
, CopyArray
, NewTag
};
59 class InterfaceKindVisitor
60 : public TypeVisitor
<InterfaceKindVisitor
, InterfaceKind
> {
64 llvm::SmallVectorImpl
<Expr
*> &Args
;
67 InterfaceKindVisitor(Sema
&S
, Expr
*E
, llvm::SmallVectorImpl
<Expr
*> &Args
)
68 : S(S
), E(E
), Args(Args
) {}
70 InterfaceKind
computeInterfaceKind(QualType Ty
) {
71 return Visit(Ty
.getTypePtr());
74 InterfaceKind
VisitRecordType(const RecordType
*Ty
) {
75 return InterfaceKind::WithAlloc
;
78 InterfaceKind
VisitMemberPointerType(const MemberPointerType
*Ty
) {
79 return InterfaceKind::WithAlloc
;
82 InterfaceKind
VisitConstantArrayType(const ConstantArrayType
*Ty
) {
83 return InterfaceKind::CopyArray
;
86 InterfaceKind
VisitFunctionProtoType(const FunctionProtoType
*Ty
) {
88 return InterfaceKind::NoAlloc
;
91 InterfaceKind
VisitPointerType(const PointerType
*Ty
) {
93 return InterfaceKind::NoAlloc
;
96 InterfaceKind
VisitReferenceType(const ReferenceType
*Ty
) {
97 ExprResult AddrOfE
= S
.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf
, E
);
98 assert(!AddrOfE
.isInvalid() && "Can not create unary expression");
99 Args
.push_back(AddrOfE
.get());
100 return InterfaceKind::NoAlloc
;
103 InterfaceKind
VisitBuiltinType(const BuiltinType
*Ty
) {
104 if (Ty
->isNullPtrType())
106 else if (Ty
->isFloatingType())
108 else if (Ty
->isIntegralOrEnumerationType())
109 HandleIntegralOrEnumType(Ty
);
110 else if (Ty
->isVoidType()) {
111 // Do we need to still run `E`?
114 return InterfaceKind::NoAlloc
;
117 InterfaceKind
VisitEnumType(const EnumType
*Ty
) {
118 HandleIntegralOrEnumType(Ty
);
119 return InterfaceKind::NoAlloc
;
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, PtrBits
);
129 TypeSourceInfo
*TSI
= Ctx
.getTrivialTypeSourceInfo(UIntTy
);
130 ExprResult CastedExpr
=
131 S
.BuildCStyleCastExpr(SourceLocation(), TSI
, SourceLocation(), E
);
132 assert(!CastedExpr
.isInvalid() && "Cannot create cstyle cast expr");
133 Args
.push_back(CastedExpr
.get());
136 void HandlePtrType(const Type
*Ty
) {
137 ASTContext
&Ctx
= S
.getASTContext();
138 TypeSourceInfo
*TSI
= Ctx
.getTrivialTypeSourceInfo(Ctx
.VoidPtrTy
);
139 ExprResult CastedExpr
=
140 S
.BuildCStyleCastExpr(SourceLocation(), TSI
, SourceLocation(), E
);
141 assert(!CastedExpr
.isInvalid() && "Can not create cstyle cast expression");
142 Args
.push_back(CastedExpr
.get());
146 // This synthesizes a call expression to a speciall
147 // function that is responsible for generating the Value.
148 // In general, we transform:
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,
156 // // 3. If x is a struct, but a rvalue.
157 // new (__clang_Interpreter_SetValueWithAlloc(ThisInterp, OpaqueValue,
159 llvm::Expected
<Expr
*> Interpreter::ExtractValueFromExpr(Expr
*E
) {
160 Sema
&S
= getCompilerInstance()->getSema();
161 ASTContext
&Ctx
= S
.getASTContext();
163 // Find the value printing builtins.
164 if (!ValuePrintingInfo
[0]) {
165 assert(llvm::all_of(ValuePrintingInfo
, [](Expr
*E
) { return !E
; }));
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());
174 return llvm::make_error
<llvm::StringError
>(
175 Name
+ " not found!", llvm::inconvertibleErrorCode());
178 Interface
= S
.BuildDeclarationNameExpr(CSS
, R
, /*ADL=*/false).get();
179 return llvm::Error::success();
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
);
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
);
202 llvm::SmallVector
<Expr
*, 4> AdjustedArgs
;
203 // Create parameter `ThisInterp`.
204 AdjustedArgs
.push_back(CStyleCastPtrExpr(S
, Ctx
.VoidPtrTy
, (uintptr_t)this));
206 // Create parameter `OutVal`.
207 AdjustedArgs
.push_back(
208 CStyleCastPtrExpr(S
, Ctx
.VoidPtrTy
, (uintptr_t)&LastValue
));
210 // Build `__clang_Interpreter_SetValue*` call.
212 // Get rid of ExprWithCleanups.
213 if (auto *EWC
= llvm::dyn_cast_if_present
<ExprWithCleanups
>(E
))
214 E
= EWC
->getSubExpr();
216 QualType Ty
= E
->getType();
217 QualType DesugaredTy
= Ty
.getDesugaredType(Ctx
);
219 // For lvalue struct, we treat it as a reference.
220 if (DesugaredTy
->isRecordType() && E
->isLValue()) {
221 DesugaredTy
= Ctx
.getLValueReferenceType(DesugaredTy
);
222 Ty
= Ctx
.getLValueReferenceType(Ty
);
226 CStyleCastPtrExpr(S
, Ctx
.VoidPtrTy
, (uintptr_t)Ty
.getAsOpaquePtr());
227 // The QualType parameter `OpaqueType`, represented as `void*`.
228 AdjustedArgs
.push_back(TypeArg
);
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(DesugaredTy
);
237 case InterfaceKind::WithAlloc
:
239 case InterfaceKind::CopyArray
: {
240 // __clang_Interpreter_SetValueWithAlloc.
241 ExprResult AllocCall
=
242 S
.ActOnCallExpr(Scope
, ValuePrintingInfo
[InterfaceKind::WithAlloc
],
243 E
->getBeginLoc(), AdjustedArgs
, E
->getEndLoc());
244 assert(!AllocCall
.isInvalid() && "Can't create runtime interface call!");
246 TypeSourceInfo
*TSI
= Ctx
.getTrivialTypeSourceInfo(Ty
, SourceLocation());
248 // Force CodeGen to emit destructor.
249 if (auto *RD
= Ty
->getAsCXXRecordDecl()) {
250 auto *Dtor
= S
.LookupDestructor(RD
);
251 Dtor
->addAttr(UsedAttr::CreateImplicit(Ctx
));
252 getCompilerInstance()->getASTConsumer().HandleTopLevelDecl(
256 // __clang_Interpreter_SetValueCopyArr.
257 if (Kind
== InterfaceKind::CopyArray
) {
258 const auto *ConstantArrTy
=
259 cast
<ConstantArrayType
>(DesugaredTy
.getTypePtr());
260 size_t ArrSize
= Ctx
.getConstantArrayElementCount(ConstantArrTy
);
261 Expr
*ArrSizeExpr
= IntegerLiteralExpr(Ctx
, ArrSize
);
262 Expr
*Args
[] = {E
, AllocCall
.get(), ArrSizeExpr
};
264 S
.ActOnCallExpr(Scope
, ValuePrintingInfo
[InterfaceKind::CopyArray
],
265 SourceLocation(), Args
, SourceLocation());
267 Expr
*Args
[] = {AllocCall
.get(), ValuePrintingInfo
[InterfaceKind::NewTag
]};
268 ExprResult CXXNewCall
= S
.BuildCXXNew(
270 /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args
,
271 /*PlacementRParen=*/SourceLocation(),
272 /*TypeIdParens=*/SourceRange(), TSI
->getType(), TSI
, std::nullopt
,
273 E
->getSourceRange(), E
);
275 assert(!CXXNewCall
.isInvalid() &&
276 "Can't create runtime placement new call!");
278 SetValueE
= S
.ActOnFinishFullExpr(CXXNewCall
.get(),
279 /*DiscardedValue=*/false);
282 // __clang_Interpreter_SetValueNoAlloc.
283 case InterfaceKind::NoAlloc
: {
285 S
.ActOnCallExpr(Scope
, ValuePrintingInfo
[InterfaceKind::NoAlloc
],
286 E
->getBeginLoc(), AdjustedArgs
, E
->getEndLoc());
290 llvm_unreachable("Unhandled InterfaceKind");
293 // It could fail, like printing an array type in C. (not supported)
294 if (SetValueE
.isInvalid())
297 return SetValueE
.get();
302 using namespace clang
;
304 // Temporary rvalue struct that need special care.
305 REPL_EXTERNAL_VISIBILITY
void *
306 __clang_Interpreter_SetValueWithAlloc(void *This
, void *OutVal
,
308 Value
&VRef
= *(Value
*)OutVal
;
309 VRef
= Value(static_cast<Interpreter
*>(This
), OpaqueType
);
310 return VRef
.getPtr();
313 extern "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
);
322 va_start(args
, /*last named param*/ OpaqueType
);
324 QualType QT
= VRef
.getType();
325 if (VRef
.getKind() == Value::K_PtrOrObj
) {
326 VRef
.setPtr(va_arg(args
, void *));
328 if (const auto *ET
= QT
->getAs
<EnumType
>())
329 QT
= ET
->getDecl()->getIntegerType();
330 switch (QT
->castAs
<BuiltinType
>()->getKind()) {
332 llvm_unreachable("unknown type kind!");
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));
338 case BuiltinType::Char_S
:
339 VRef
.setChar_S(va_arg(args
, int));
341 case BuiltinType::SChar
:
342 VRef
.setSChar(va_arg(args
, int));
344 case BuiltinType::Char_U
:
345 VRef
.setChar_U(va_arg(args
, unsigned));
347 case BuiltinType::UChar
:
348 VRef
.setUChar(va_arg(args
, unsigned));
350 case BuiltinType::Short
:
351 VRef
.setShort(va_arg(args
, int));
353 case BuiltinType::UShort
:
354 VRef
.setUShort(va_arg(args
, unsigned));
356 case BuiltinType::Int
:
357 VRef
.setInt(va_arg(args
, int));
359 case BuiltinType::UInt
:
360 VRef
.setUInt(va_arg(args
, unsigned));
362 case BuiltinType::Long
:
363 VRef
.setLong(va_arg(args
, long));
365 case BuiltinType::ULong
:
366 VRef
.setULong(va_arg(args
, unsigned long));
368 case BuiltinType::LongLong
:
369 VRef
.setLongLong(va_arg(args
, long long));
371 case BuiltinType::ULongLong
:
372 VRef
.setULongLong(va_arg(args
, unsigned long long));
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));
378 case BuiltinType::Double
:
379 VRef
.setDouble(va_arg(args
, double));
381 case BuiltinType::LongDouble
:
382 VRef
.setLongDouble(va_arg(args
, long double));
384 // See REPL_BUILTIN_TYPES.
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.
395 struct __clang_Interpreter_NewTag
{};
396 REPL_EXTERNAL_VISIBILITY
void *
397 operator 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
);