CppInterOp
C++ Language Interoperability Layer
Loading...
Searching...
No Matches
CppInterOp.cpp
Go to the documentation of this file.
1//--------------------------------------------------------------------*- C++ -*-
2// CLING - the C++ LLVM-based InterpreterG :)
3// author: Vassil Vassilev <vvasilev@cern.ch>
4//
5// This file is dual-licensed: you can choose to license it under the University
6// of Illinois Open Source License or the GNU Lesser General Public License. See
7// LICENSE.TXT for details.
8//------------------------------------------------------------------------------
9
11#include "Unwrap.h"
12#include "CppInterOp/Error.h"
13
14#include "Compatibility.h"
15#include "ErrorInternal.h"
16#include "InterpreterInfo.h"
17#include "Sins.h" // for access to private members
18#include "Tracing.h"
19
20// MSan workaround for clang-repl <= 22: __clang_Interpreter_SetValueNoAlloc
21// receives JIT-emitted values through varargs, and MSan cannot track shadow
22// across that JIT/native boundary -- the returned Value carries correct bits
23// but an uninit shadow, which trips downstream reads (convertTo, ~Value).
24// Fixed upstream in llvm/llvm-project#196894; unpoison locally for older LLVM.
25#if defined(__has_feature)
26#if __has_feature(memory_sanitizer) && LLVM_VERSION_MAJOR <= 22
27#include <sanitizer/msan_interface.h>
28#define CPPINTEROP_MSAN_UNPOISON_VALUE(v) __msan_unpoison(&(v), sizeof(v))
29#else
30#define CPPINTEROP_MSAN_UNPOISON_VALUE(v) ((void)0)
31#endif
32#else
33#define CPPINTEROP_MSAN_UNPOISON_VALUE(v) ((void)0)
34#endif
35
36#include "clang/AST/Attrs.inc"
37#include "clang/AST/CXXInheritance.h"
38#include "clang/AST/Comment.h"
39#include "clang/AST/Decl.h"
40#include "clang/AST/DeclAccessPair.h"
41#include "clang/AST/DeclBase.h"
42#include "clang/AST/DeclCXX.h"
43#include "clang/AST/DeclTemplate.h"
44#include "clang/AST/DeclarationName.h"
45#include "clang/AST/Expr.h"
46#include "clang/AST/ExprCXX.h"
47#include "clang/AST/GlobalDecl.h"
48#include "clang/AST/Mangle.h"
49#include "clang/AST/NestedNameSpecifier.h"
50#include "clang/AST/QualTypeNames.h"
51#include "clang/AST/RawCommentList.h"
52#include "clang/AST/RecordLayout.h"
53#include "clang/AST/Stmt.h"
54#include "clang/AST/Type.h"
55#include "clang/AST/VTableBuilder.h"
56#include "clang/Basic/CharInfo.h"
57#include "clang/Basic/Diagnostic.h"
58#include "clang/Basic/DiagnosticSema.h"
59#include "clang/Basic/LangStandard.h"
60#include "clang/Basic/Linkage.h"
61#include "clang/Basic/OperatorKinds.h"
62#include "clang/Basic/SourceLocation.h"
63#include "clang/Basic/SourceManager.h"
64#include "clang/Basic/Specifiers.h"
65#include "clang/Basic/Version.h"
66#include "clang/Frontend/CompilerInstance.h"
67#include "clang/Interpreter/Interpreter.h"
68#include "clang/Sema/Lookup.h"
69#include "clang/Sema/Overload.h"
70#include "clang/Sema/Ownership.h"
71#include "clang/Sema/Redeclaration.h"
72#include "clang/Sema/Sema.h"
73#include "clang/Sema/TemplateDeduction.h"
74
75#include "llvm/ADT/SmallString.h"
76#include "llvm/ADT/SmallVector.h"
77#include "llvm/ADT/StringRef.h"
78#include "llvm/Demangle/Demangle.h"
79#include "llvm/ExecutionEngine/JITSymbol.h"
80#include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h"
81#include "llvm/ExecutionEngine/Orc/Core.h"
82#include "llvm/ExecutionEngine/Orc/CoreContainers.h"
83#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
84#include "llvm/IR/GlobalValue.h"
85#include "llvm/Support/Casting.h"
86#include "llvm/Support/CommandLine.h"
87#include "llvm/Support/Debug.h"
88#include "llvm/Support/Error.h"
89#include "llvm/Support/FileSystem.h"
90#include "llvm/Support/ManagedStatic.h"
91#include "llvm/Support/Path.h"
92#include "llvm/Support/Process.h"
93#include "llvm/Support/Signals.h"
94#include "llvm/Support/TargetSelect.h"
95#include "llvm/Support/raw_ostream.h"
96#include "llvm/TargetParser/Host.h"
97#include "llvm/TargetParser/Triple.h"
98
99#include <algorithm>
100#include <cassert>
101#include <cstddef>
102#include <cstdint>
103#include <cstdio>
104#include <cstdlib>
105#include <cstring>
106#include <deque>
107#include <iostream>
108#include <iterator>
109#include <map>
110#include <memory>
111#include <mutex>
112#include <set>
113#include <sstream>
114#include <stack>
115#include <string>
116#include <sys/types.h>
117#ifndef _WIN32
118#include <unistd.h>
119#endif
120#include <utility>
121// Stream redirect.
122#ifdef _WIN32
123#include <io.h>
124#ifndef STDOUT_FILENO
125#define STDOUT_FILENO 1
126#define STDERR_FILENO 2
127// For exec().
128#include <stdio.h>
129#define popen(x, y) (_popen(x, y))
130#define pclose (_pclose)
131#endif
132#else
133#include <dlfcn.h>
134#include <unistd.h>
135#endif // WIN32
136#include <vector>
137
138// Runtime symbols required if the library using JIT (Cpp::Evaluate) does
139// not link to llvm
140#if !defined(CPPINTEROP_USE_CLING) && !defined(EMSCRIPTEN)
143#if CLANG_VERSION_MAJOR > 21
144extern "C" void* __clang_Interpreter_SetValueWithAlloc(void* This, void* OutVal,
145 void* OpaqueType);
146#else
147void* __clang_Interpreter_SetValueWithAlloc(void* This, void* OutVal,
148 void* OpaqueType);
149#endif
150
151extern "C" void __clang_Interpreter_SetValueNoAlloc(void* This, void* OutVal,
152 void* OpaqueType, ...);
153#endif // CPPINTEROP_USE_CLING
154
155// LSan ships as part of ASan only on Linux and macOS. MSVC and
156// Emscripten set the ASan feature macros but do not provide
157// __lsan_ignore_object, so emitting the hook there would fail to
158// JIT-link the wrapper.
159#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && \
160 (defined(__SANITIZE_ADDRESS__) || \
161 (defined(__has_feature) && __has_feature(address_sanitizer)))
162#define CPPINTEROP_ASAN_BUILD 1
163#endif
164
165namespace Cpp {
166
167using namespace clang;
168using namespace llvm;
169
170static void DefaultProcessCrashHandler(void*);
171
172/// Set by UseExternalInterpreter to suppress llvm_shutdown at process exit
173/// -- the client owns LLVM in that case.
174static bool SkipShutDown = false;
175
176/// RAII guard whose dtor calls llvm_shutdown for the owned-interpreter case.
177/// Constructed as a function-local static AFTER sInterpreters, so its dtor
178/// fires FIRST (reverse-of-construction); llvm_shutdown then drains the
179/// ManagedStatic registry, including sInterpreters, deterministically.
180/// The llvm_shutdown call itself is gated on LLVM 23+, where
181/// Platform::lookupResolvedInitSymbols (llvm/llvm-project#196874) makes
182/// ~Interpreter's JIT deinit skip lazy materialization. On older LLVM
183/// the same chain SEGFAULTs in cleanUp against destroyed function-local
184/// statics, so the dtor is a no-op and sInterpreters leaks instead.
187 if (!SkipShutDown) {
188#if LLVM_VERSION_MAJOR > 22
189 llvm::llvm_shutdown();
190#endif
191 }
192 }
193};
194
195// Function-static storage for interpreters
196static std::deque<InterpreterInfo>&
197GetInterpreters(bool SetCrashHandler = true) {
198 static llvm::ManagedStatic<std::deque<InterpreterInfo>> sInterpreters;
199 static std::once_flag ProcessInitialized;
200 std::call_once(ProcessInitialized, [SetCrashHandler]() {
201 if (SetCrashHandler)
202 llvm::sys::PrintStackTraceOnErrorSignal("CppInterOp");
203
204 if (getenv("CPPINTEROP_LOG") != nullptr)
206
207 // Initialize all targets (required for device offloading)
208 llvm::InitializeAllTargetInfos();
209 llvm::InitializeAllTargets();
210 llvm::InitializeAllTargetMCs();
211 llvm::InitializeAllAsmParsers();
212 llvm::InitializeAllAsmPrinters();
213
214 // Pipe / OOM / crash handlers replicate what InitLLVM did before it was
215 // dropped. Skipped when the host owns LLVM -- they're its decision.
216 if (SetCrashHandler) {
217 llvm::sys::SetOneShotPipeSignalFunction(
218 llvm::sys::DefaultOneShotPipeSignalHandler);
219 llvm::sys::AddSignalHandler(DefaultProcessCrashHandler,
220 /*Cookie=*/nullptr);
221 llvm::install_out_of_memory_new_handler();
222 }
223 });
224
225 // Constructed after sInterpreters above, so its dtor fires first at
226 // process exit; see InterpreterShutdown.
227 static InterpreterShutdown Shutdown;
228
229 return *sInterpreters;
230}
231
232// Global crash handler for the entire process
233static void DefaultProcessCrashHandler(void*) {
234 // Access the static deque via the getter
235 std::deque<InterpreterInfo>& Interps = GetInterpreters();
236
237 llvm::errs() << "\n**************************************************\n";
238 llvm::errs() << " CppInterOp CRASH DETECTED\n";
241 if (!Path.empty())
242 llvm::errs() << " Reproducer saved to: " << Path << "\n";
243 else
244 llvm::errs() << " Failed to write reproducer file.\n";
245 } else {
246 llvm::errs() << " Re-run with CPPINTEROP_LOG=1 for a crash reproducer\n";
247 }
248
249 if (!Interps.empty()) {
250 llvm::errs() << " Active Interpreters:\n";
251 for (const auto& Info : Interps) {
252 if (Info.Interpreter)
253 llvm::errs() << " - " << Info.Interpreter << "\n";
254 }
255 }
256
257 llvm::errs() << "**************************************************\n";
258 llvm::errs().flush();
259
260 // Print backtrace (includes JIT symbols if registered)
261 llvm::sys::PrintStackTrace(llvm::errs());
262
263 llvm::errs() << "**************************************************\n";
264 llvm::errs().flush();
265
266 // The process must actually terminate for EXPECT_DEATH to pass.
267 // We use _exit to avoid calling atexit() handlers which might be corrupted.
268 llvm::sys::Process::Exit(/*RetCode=*/1, /*NoCleanup=*/false);
269}
270
271static void RegisterInterpreter(compat::Interpreter* I, bool Owned) {
272 std::deque<InterpreterInfo>& Interps = GetInterpreters(Owned);
273 Interps.emplace_back(I, Owned);
274 InstallDiagConsumer(&Interps.back());
275}
276
278 auto& Interps = GetInterpreters();
279 assert(!Interps.empty() &&
280 "Interpreter instance must be set before calling this!");
281 if (I) {
282 for (auto& Info : Interps)
283 if (Info.Interpreter == I)
284 return Info;
285 }
286 return Interps.back();
287}
288
289static compat::Interpreter& getInterp(InterpRef I = nullptr) {
290 if (I)
291 return *unwrap<compat::Interpreter>(I);
292 return *getInterpInfo().Interpreter;
293}
294
296 return &getInterpInfo(I ? unwrap<compat::Interpreter>(I) : nullptr);
297}
298
299InterpRef GetInterpreter() {
301 std::deque<InterpreterInfo>& Interps = GetInterpreters();
302 if (Interps.empty())
303 return INTEROP_RETURN(nullptr);
304 return INTEROP_RETURN(Interps.back().Interpreter);
305}
306
307void UseExternalInterpreter(InterpRef I) {
308 INTEROP_TRACE(I);
309 assert(GetInterpreters(false).empty() && "sInterpreter already in use!");
310 SkipShutDown = true;
311 RegisterInterpreter(unwrap<compat::Interpreter>(I), /*Owned=*/false);
312 return INTEROP_VOID_RETURN();
313}
314
315bool ActivateInterpreter(InterpRef I) {
316 INTEROP_TRACE(I);
317 if (!I)
318 return INTEROP_RETURN(false);
319
320 std::deque<InterpreterInfo>& Interps = GetInterpreters();
321 auto* Interp = unwrap<compat::Interpreter>(I);
322 auto found =
323 std::find_if(Interps.begin(), Interps.end(), [Interp](const auto& Info) {
324 return Info.Interpreter == Interp;
325 });
326 if (found == Interps.end())
327 return INTEROP_RETURN(false);
328
329 if (std::next(found) != Interps.end()) // if not already last element.
330 std::rotate(found, found + 1, Interps.end());
331
332 return INTEROP_RETURN(true); // success
333}
334
335bool DeleteInterpreter(InterpRef I /*=nullptr*/) {
336 INTEROP_TRACE(I);
337 std::deque<InterpreterInfo>& Interps = GetInterpreters();
338 if (Interps.empty())
339 return INTEROP_RETURN(false);
340
341 if (!I) {
342 Interps.pop_back(); // Triggers ~InterpreterInfo() and potential delete
343 return INTEROP_RETURN(true);
344 }
345
346 auto* Interp = unwrap<compat::Interpreter>(I);
347 auto found =
348 std::find_if(Interps.begin(), Interps.end(), [Interp](const auto& Info) {
349 return Info.Interpreter == Interp;
350 });
351 if (found == Interps.end())
352 return INTEROP_RETURN(false); // failure
353
354 Interps.erase(found);
355 return INTEROP_RETURN(true);
356}
357
358static clang::Sema& getSema() { return getInterp().getCI()->getSema(); }
359static clang::ASTContext& getASTContext() { return getSema().getASTContext(); }
360
361static void ForceCodeGen(Decl* D, compat::Interpreter& I) {
362 // The decl was deferred by CodeGen. Force its emission.
363 // FIXME: In ASTContext::DeclMustBeEmitted we should check if the
364 // Decl::isUsed is set or we should be able to access CodeGen's
365 // addCompilerUsedGlobal.
366 ASTContext& C = I.getSema().getASTContext();
367
368 D->addAttr(UsedAttr::CreateImplicit(C));
369#ifdef CPPINTEROP_USE_CLING
370 cling::Interpreter::PushTransactionRAII RAII(&I);
371 I.getCI()->getASTConsumer().HandleTopLevelDecl(DeclGroupRef(D));
372#else // CLANG_REPL
373 I.getCI()->getASTConsumer().HandleTopLevelDecl(DeclGroupRef(D));
374 // Take the newest llvm::Module produced by CodeGen and send it to JIT.
375 auto GeneratedPTU = I.Parse("");
376 if (!GeneratedPTU)
377 llvm::logAllUnhandledErrors(GeneratedPTU.takeError(), llvm::errs(),
378 "[ForceCodeGen] Failed to generate PTU:");
379
380 // From cling's BackendPasses.cpp
381 // FIXME: We need to upstream this code in IncrementalExecutor::addModule
382 for (auto& GV : GeneratedPTU->TheModule->globals()) {
383 llvm::GlobalValue::LinkageTypes LT = GV.getLinkage();
384 if (GV.isDeclaration() || !GV.hasName() ||
385 GV.getName().starts_with(".str") ||
386 !llvm::GlobalVariable::isDiscardableIfUnused(LT) ||
387 LT != llvm::GlobalValue::InternalLinkage)
388 continue; // nothing to do
389 GV.setLinkage(llvm::GlobalValue::WeakAnyLinkage);
390 }
391 if (auto Err = I.Execute(*GeneratedPTU))
392 llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(),
393 "[ForceCodeGen] Failed to execute PTU:");
394#endif
395}
396
397#define DEBUG_TYPE "jitcall"
398bool JitCall::AreArgumentsValid(void* result, ArgList args, void* self,
399 size_t nary) const {
400 bool Valid = true;
401 if (Cpp::IsConstructor(m_FD)) {
402 assert(result && "Must pass the location of the created object!");
403 Valid &= (bool)result;
404 }
405 if (Cpp::GetFunctionRequiredArgs(m_FD) > args.m_ArgSize) {
406 assert(0 && "Must pass at least the minimal number of args!");
407 Valid = false;
408 }
409 if (args.m_ArgSize) {
410 assert(args.m_Args != nullptr && "Must pass an argument list!");
411 Valid &= (bool)args.m_Args;
412 }
413 if (!Cpp::IsConstructor(m_FD) && !Cpp::IsDestructor(m_FD) &&
414 Cpp::IsMethod(m_FD) && !Cpp::IsStaticMethod(m_FD)) {
415 assert(self && "Must pass the pointer to object");
416 Valid &= (bool)self;
417 }
418 const auto* FD = cast<FunctionDecl>(unwrap<Decl>(m_FD));
419 if (!FD->getReturnType()->isVoidType() && !result) {
420 assert(0 && "We are discarding the return TyRef of the function!");
421 Valid = false;
422 }
423 if (Cpp::IsConstructor(m_FD) && nary == 0UL) {
424 assert(0 && "Number of objects to construct should be atleast 1");
425 Valid = false;
426 }
427 if (Cpp::IsConstructor(m_FD)) {
428 const auto* CD = cast<CXXConstructorDecl>(unwrap<Decl>(m_FD));
429 if (CD->getMinRequiredArguments() != 0 && nary > 1) {
430 assert(0 &&
431 "Cannot pass initialization parameters to array new construction");
432 Valid = false;
433 }
434 }
435 assert(m_Kind != kDestructorCall && "Wrong overload!");
436 Valid &= m_Kind != kDestructorCall;
437 return Valid;
438}
439
440// Trace-hook impls reached via DispatchRaw from JitCall's inline body.
441// Off-trace the slot is nullptr and these never run.
442void CppInterOpTraceJitCallInvokeImpl(const JitCall* JC, void* result,
443 void** args, std::size_t nargs,
444 void* self) {
446 if (!TI)
447 return;
448 std::string Name;
449 llvm::raw_string_ostream OS(Name);
450 const auto* FD = unwrap<FunctionDecl>(JC->m_FD);
451 FD->getNameForDiagnostic(OS, FD->getASTContext().getPrintingPolicy(),
452 /*Qualified=*/true);
453 LLVM_DEBUG(dbgs() << "Run '" << Name << "', compiled at: "
454 << (void*)JC->m_GenericCall << " with result at: " << result
455 << " , args at: " << args << " , arg count: " << nargs
456 << " , self at: " << self << "\n";);
457 std::string SelfPart = self ? TI->lookupHandle(self) : "";
458 TI->appendToLog(llvm::formatv(" // JitCall::Invoke {0}(nargs={1}, self={2})",
459 Name, nargs,
460 SelfPart.empty() ? "nullptr" : SelfPart));
461}
462
463void CppInterOpTraceJitCallInvokeDestructorImpl(const JitCall* JC, void* object,
464 unsigned long nary,
465 int withFree) {
467 if (!TI)
468 return;
469 std::string Name;
470 llvm::raw_string_ostream OS(Name);
471 const auto* FD = unwrap<FunctionDecl>(JC->m_FD);
472 FD->getNameForDiagnostic(OS, FD->getASTContext().getPrintingPolicy(),
473 /*Qualified=*/true);
474 LLVM_DEBUG(dbgs() << "Finish '" << Name
475 << "', compiled at: " << (void*)JC->m_DestructorCall);
476 std::string ObjPart = object ? TI->lookupHandle(object) : "nullptr";
477 TI->appendToLog(
478 llvm::formatv(" // JitCall::InvokeDestructor {0}(object={1}, nary={2}, "
479 "withFree={3})",
480 Name, ObjPart, nary, withFree));
481}
482
483// Post-invoke trace hook reached via DispatchRaw. Constructors and
484// pointer/reference returns deposit a fresh T* at *result; registering
485// it as vN lets later trace lines render the name instead of
486// `nullptr /*unknown*/`. No-op for value or void returns.
487void CppInterOpTraceJitCallInvokeReturnImpl(const JitCall* JC, void* result) {
489 if (!TI || !result)
490 return;
491 const auto* FD = unwrap<FunctionDecl>(JC->m_FD);
492 bool RegisterPtr = isa<CXXConstructorDecl>(FD);
493 if (!RegisterPtr) {
494 QualType RT = FD->getReturnType();
495 RegisterPtr = RT->isPointerType() || RT->isReferenceType();
496 }
497 if (!RegisterPtr)
498 return;
499 if (void* p = *static_cast<void* const*>(result))
500 TI->getOrRegisterHandle(p);
501}
502
503#undef DEBUG_TYPE
504
505std::string GetVersion() {
507 const char* const VERSION = CPPINTEROP_VERSION;
508 std::string fullVersion = "CppInterOp version";
509 fullVersion += VERSION;
510 fullVersion += "\n (based on "
511#ifdef CPPINTEROP_USE_CLING
512 "cling ";
513#else
514 "clang-repl";
515#endif // CPPINTEROP_USE_CLING
516 return INTEROP_RETURN(fullVersion + "[" + clang::getClangFullVersion() +
517 "])\n");
518}
519
520std::string GetBuildInfo() {
522 // The right-hand side is a raw-string literal expression generated from
523 // BuildInfo.inc.in via configure_file at CMake-configure time; it carries
524 // the filtered CACHE_VARIABLES snapshot. Kept out of the INTEROP_RETURN
525 // macro call so the preprocessor is not asked to expand a directive
526 // inside macro arguments.
527 std::string Info =
528#include "CppInterOp/BuildInfo.inc"
529 ;
530 return INTEROP_RETURN(Info);
531}
532
533std::string Demangle(const std::string& mangled_name) {
534 INTEROP_TRACE(mangled_name);
535 // Both itaniumDemangle and microsoftDemangle return a malloc'd buffer
536 // that the caller owns; the implicit std::string conversion copies the
537 // bytes but never frees the original. See llvm/Demangle/Demangle.h.
538#ifdef _WIN32
539 char* Raw = microsoftDemangle(mangled_name, nullptr, nullptr);
540#else
541 char* Raw = llvm::itaniumDemangle(mangled_name);
542#endif
543 std::string demangle = Raw ? Raw : "";
544 std::free(Raw);
545 return INTEROP_RETURN(demangle);
546}
547
548void EnableDebugOutput(bool value /* =true*/) {
549 INTEROP_TRACE(value);
550 llvm::DebugFlag = value;
551 return INTEROP_VOID_RETURN();
552}
553
556 return INTEROP_RETURN(llvm::DebugFlag);
557}
558
559static void InstantiateFunctionDefinition(Decl* D) {
561 if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
562 getSema().InstantiateFunctionDefinition(SourceLocation(), FD,
563 /*Recursive=*/true,
564 /*DefinitionRequired=*/true);
565 // FIXME: this can go into a RAII object
566 clang::DiagnosticsEngine& Diags = getSema().getDiagnostics();
567 if (!FD->isDefined() && Diags.hasErrorOccurred()) {
568 // instantiation failed, need to reset DiagnosticsEngine
569 Diags.Reset(/*soft=*/true);
570 Diags.getClient()->clear();
571 }
572 }
573}
574
575bool IsAggregate(ConstDeclRef DRef) {
576 INTEROP_TRACE(DRef);
577 const auto* D = unwrap<Decl>(DRef);
578
579 // Aggregates are only arrays or tag decls.
580 if (const auto* ValD = dyn_cast<ValueDecl>(D))
581 if (ValD->getType()->isArrayType())
582 return INTEROP_RETURN(true);
583
584 // struct, class, union
585 if (const auto* CXXRD = dyn_cast<CXXRecordDecl>(D))
586 return INTEROP_RETURN(CXXRD->isAggregate());
587
588 return INTEROP_RETURN(false);
589}
590
591bool IsNamespace(ConstDeclRef DRef) {
592 INTEROP_TRACE(DRef);
593 const auto* D = unwrap<Decl>(DRef);
594 return INTEROP_RETURN(isa<NamespaceDecl>(D));
595}
596
597bool IsClass(ConstDeclRef DRef) {
598 INTEROP_TRACE(DRef);
599 const auto* D = unwrap<Decl>(DRef);
600 return INTEROP_RETURN(isa<CXXRecordDecl>(D));
601}
602
603bool IsFunction(ConstDeclRef DRef) {
604 INTEROP_TRACE(DRef);
605 const auto* D = unwrap<Decl>(DRef);
606 return INTEROP_RETURN(isa<FunctionDecl>(D));
607}
608
609bool IsFunctionPointerType(ConstTypeRef TyRef) {
610 INTEROP_TRACE(TyRef);
611 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
612 return INTEROP_RETURN(QT->isFunctionPointerType());
613}
614
615bool IsClassPolymorphic(ConstDeclRef DRef) {
616 INTEROP_TRACE(DRef);
617 const auto* D = unwrap<Decl>(DRef);
618 if (const auto* CXXRD = llvm::dyn_cast<CXXRecordDecl>(D))
619 if (const auto* CXXRDD = CXXRD->getDefinition())
620 return INTEROP_RETURN(CXXRDD->isPolymorphic());
621 return INTEROP_RETURN(false);
622}
623
624static SourceLocation GetValidSLoc(Sema& semaRef) {
625 auto& SM = semaRef.getSourceManager();
626 return SM.getLocForStartOfFile(SM.getMainFileID());
627}
628
629// See TClingClassInfo::IsLoaded
630bool IsComplete(ConstDeclRef DRef) {
631 INTEROP_TRACE(DRef);
632 if (!DRef)
633 return INTEROP_RETURN(false);
634
635 const auto* D = unwrap<Decl>(DRef);
636
637 if (isa<ClassTemplateSpecializationDecl>(D)) {
638 QualType QT = QualType::getFromOpaquePtr(GetTypeFromScope(DRef).data);
639 clang::Sema& S = getSema();
640 SourceLocation fakeLoc = GetValidSLoc(S);
642 return INTEROP_RETURN(S.isCompleteType(fakeLoc, QT));
643 }
644
645 if (const auto* CXXRD = dyn_cast<CXXRecordDecl>(D))
646 return INTEROP_RETURN(CXXRD->hasDefinition());
647 else if (const auto* TD = dyn_cast<TagDecl>(D))
648 return INTEROP_RETURN(TD->getDefinition());
649
650 // Everything else is considered complete.
651 return INTEROP_RETURN(true);
652}
653
654size_t SizeOf(ConstDeclRef DRef) {
655 INTEROP_TRACE(DRef);
656 assert(DRef);
657 if (!IsComplete(DRef))
658 return INTEROP_RETURN(0);
659
660 if (const auto* RD = dyn_cast<RecordDecl>(unwrap<Decl>(DRef))) {
661 ASTContext& Context = RD->getASTContext();
662 const ASTRecordLayout& Layout = Context.getASTRecordLayout(RD);
663 return INTEROP_RETURN(Layout.getSize().getQuantity());
664 }
665
666 return INTEROP_RETURN(0);
667}
668
669bool IsBuiltin(ConstTypeRef TyRef) {
670 INTEROP_TRACE(TyRef);
671 QualType Ty = QualType::getFromOpaquePtr(TyRef.data);
672 if (Ty->isBuiltinType() || Ty->isAnyComplexType())
673 return INTEROP_RETURN(true);
674 // Check for std::complex<T> specializations.
675 if (const auto* RD = Ty->getAsCXXRecordDecl()) {
676 if (const auto* CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
677 IdentifierInfo* II = CTSD->getSpecializedTemplate()->getIdentifier();
678 if (II && II->isStr("complex") &&
679 CTSD->getDeclContext()->isStdNamespace())
680 return INTEROP_RETURN(true);
681 }
682 }
683 return INTEROP_RETURN(false);
684}
685
686bool IsTemplate(ConstDeclRef DRef) {
687 INTEROP_TRACE(DRef);
688 const auto* D = unwrap<clang::Decl>(DRef);
689 return INTEROP_RETURN(llvm::isa_and_nonnull<clang::TemplateDecl>(D));
690}
691
692bool IsTemplateSpecialization(ConstDeclRef DRef) {
693 INTEROP_TRACE(DRef);
694 const auto* D = unwrap<clang::Decl>(DRef);
695 return INTEROP_RETURN(
696 llvm::isa_and_nonnull<clang::ClassTemplateSpecializationDecl>(D));
697}
698
699bool IsTypedefed(ConstDeclRef DRef) {
700 INTEROP_TRACE(DRef);
701 const auto* D = unwrap<clang::Decl>(DRef);
702 return INTEROP_RETURN(llvm::isa_and_nonnull<clang::TypedefNameDecl>(D));
703}
704
705bool IsAbstract(ConstDeclRef DRef) {
706 INTEROP_TRACE(DRef);
707 const auto* D = unwrap<clang::Decl>(DRef);
708 if (const auto* CXXRD = llvm::dyn_cast_or_null<clang::CXXRecordDecl>(D))
709 return INTEROP_RETURN(CXXRD->isAbstract());
710
711 return INTEROP_RETURN(false);
712}
713
714bool IsEnumScope(ConstDeclRef DRef) {
715 INTEROP_TRACE(DRef);
716 const auto* D = unwrap<clang::Decl>(DRef);
717 return INTEROP_RETURN(llvm::isa_and_nonnull<clang::EnumDecl>(D));
718}
719
720bool IsEnumConstant(ConstDeclRef DRef) {
721 INTEROP_TRACE(DRef);
722 const auto* D = unwrap<clang::Decl>(DRef);
723 return INTEROP_RETURN(llvm::isa_and_nonnull<clang::EnumConstantDecl>(D));
724}
725
726bool IsEnumType(ConstTypeRef TyRef) {
727 INTEROP_TRACE(TyRef);
728 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
729 return INTEROP_RETURN(QT->isEnumeralType());
730}
731
732static bool isSmartPointer(const RecordType* RT) {
733 auto IsUseCountPresent = [](const RecordDecl* Record) {
734 ASTContext& C = Record->getASTContext();
735 return !Record->lookup(&C.Idents.get("use_count")).empty();
736 };
737 auto IsOverloadedOperatorPresent = [](const RecordDecl* Record,
738 OverloadedOperatorKind Op) {
739 ASTContext& C = Record->getASTContext();
740 DeclContextLookupResult Result =
741 Record->lookup(C.DeclarationNames.getCXXOperatorName(Op));
742 return !Result.empty();
743 };
744
745 const RecordDecl* Record = RT->getDecl();
746 if (IsUseCountPresent(Record))
747 return true;
748
749 bool foundStarOperator = IsOverloadedOperatorPresent(Record, OO_Star);
750 bool foundArrowOperator = IsOverloadedOperatorPresent(Record, OO_Arrow);
751 if (foundStarOperator && foundArrowOperator)
752 return true;
753
754 const auto* CXXRecord = dyn_cast<CXXRecordDecl>(Record);
755 if (!CXXRecord)
756 return false;
757
758 auto FindOverloadedOperators = [&](const CXXRecordDecl* Base) {
759 // If we find use_count, we are done.
760 if (IsUseCountPresent(Base))
761 return false; // success.
762 if (!foundStarOperator)
763 foundStarOperator = IsOverloadedOperatorPresent(Base, OO_Star);
764 if (!foundArrowOperator)
765 foundArrowOperator = IsOverloadedOperatorPresent(Base, OO_Arrow);
766 if (foundStarOperator && foundArrowOperator)
767 return false; // success.
768 return true;
769 };
770
771 return !CXXRecord->forallBases(FindOverloadedOperators);
772}
773
774bool IsSmartPtrType(ConstTypeRef TyRef) {
775 INTEROP_TRACE(TyRef);
776 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
777 if (const RecordType* RT = QT->getAs<RecordType>()) {
778 // Add quick checks for the std smart prts to cover most of the cases.
779 std::string typeString = GetTypeAsString(TyRef);
780 llvm::StringRef tsRef(typeString);
781 if (tsRef.starts_with("std::unique_ptr") ||
782 tsRef.starts_with("std::shared_ptr") ||
783 tsRef.starts_with("std::weak_ptr"))
784 return INTEROP_RETURN(true);
785 return INTEROP_RETURN(isSmartPointer(RT));
786 }
787 return INTEROP_RETURN(false);
788}
789
790TypeRef GetIntegerTypeFromEnumScope(ConstDeclRef DRef) {
791 INTEROP_TRACE(DRef);
792 const auto* D = unwrap<clang::Decl>(DRef);
793 if (const auto* ED = llvm::dyn_cast_or_null<clang::EnumDecl>(D)) {
794 return INTEROP_RETURN(ED->getIntegerType().getAsOpaquePtr());
795 }
796
797 return INTEROP_RETURN(nullptr);
798}
799
800TypeRef GetIntegerTypeFromEnumType(ConstTypeRef enum_type) {
801 INTEROP_TRACE(enum_type);
802 if (!enum_type)
803 return INTEROP_RETURN(nullptr);
804
805 QualType QT = QualType::getFromOpaquePtr(enum_type.data);
806 if (const auto* ET = QT->getAs<EnumType>())
807 return INTEROP_RETURN(ET->getDecl()->getIntegerType().getAsOpaquePtr());
808
809 return INTEROP_RETURN(nullptr);
810}
811
812std::vector<DeclRef> GetEnumConstants(ConstDeclRef DRef) {
813 INTEROP_TRACE(DRef);
814 const auto* D = unwrap<clang::Decl>(DRef);
815
816 if (const auto* ED = llvm::dyn_cast_or_null<clang::EnumDecl>(D)) {
817 std::vector<DeclRef> enum_constants;
818 for (auto* ECD : ED->enumerators()) {
819 enum_constants.push_back(ECD);
820 }
821
822 return INTEROP_RETURN(enum_constants);
823 }
824
825 return INTEROP_RETURN(std::vector<DeclRef>{});
826}
827
828TypeRef GetEnumConstantType(ConstDeclRef DRef) {
829 INTEROP_TRACE(DRef);
830 if (!DRef)
831 return INTEROP_RETURN(nullptr);
832
833 const auto* D = unwrap<clang::Decl>(DRef);
834 if (const auto* ECD = llvm::dyn_cast<clang::EnumConstantDecl>(D))
835 return INTEROP_RETURN(ECD->getType().getAsOpaquePtr());
836
837 return INTEROP_RETURN(nullptr);
838}
839
840size_t GetEnumConstantValue(ConstDeclRef DRef) {
841 INTEROP_TRACE(DRef);
842 const auto* D = unwrap<clang::Decl>(DRef);
843 if (const auto* ECD = llvm::dyn_cast_or_null<clang::EnumConstantDecl>(D)) {
844 const llvm::APSInt& Val = ECD->getInitVal();
845 return INTEROP_RETURN(Val.getExtValue());
846 }
847 return INTEROP_RETURN(0);
848}
849
850size_t GetSizeOfType(ConstTypeRef TyRef) {
851 INTEROP_TRACE(TyRef);
852 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
853 if (const TagType* TT = QT->getAs<TagType>())
854 return INTEROP_RETURN(SizeOf(TT->getDecl()));
855
856 // FIXME: Can we get the size of a non-tag TyRef?
857 auto TI = getSema().getASTContext().getTypeInfo(QT);
858 size_t TypeSize = TI.Width;
859 return INTEROP_RETURN(TypeSize / 8);
860}
861
862bool IsVariable(ConstDeclRef DRef) {
863 INTEROP_TRACE(DRef);
864 const auto* D = unwrap<clang::Decl>(DRef);
865 return INTEROP_RETURN(llvm::isa_and_nonnull<clang::VarDecl>(D));
866}
867
868std::string GetName(ConstDeclRef DRef) {
869 INTEROP_TRACE(DRef);
870 const auto* D = unwrap<clang::NamedDecl>(DRef);
871
872 if (llvm::isa_and_nonnull<TranslationUnitDecl>(D)) {
873 return INTEROP_RETURN("");
874 }
875
876 if (const auto* ND = llvm::dyn_cast_or_null<NamedDecl>(D)) {
877 return INTEROP_RETURN(ND->getNameAsString());
878 }
879
880 return INTEROP_RETURN("<unnamed>");
881}
882
883static std::string GetCompleteNameImpl(ConstDeclRef DRef, bool qualified) {
884 auto& C = getSema().getASTContext();
885 const auto* D = unwrap<Decl>(DRef);
886
887 if (const auto* ND = llvm::dyn_cast_or_null<NamedDecl>(D)) {
888 PrintingPolicy Policy = C.getPrintingPolicy();
889 Policy.SuppressUnwrittenScope = true;
890 if (qualified) {
891 Policy.FullyQualifiedName = true;
892 Policy.Suppress_Elab = true;
893 } else {
894 Policy.SuppressScope = true;
895 Policy.AnonymousTagLocations = false;
896 Policy.SuppressTemplateArgsInCXXConstructors = false;
897 Policy.SuppressDefaultTemplateArgs = false;
898 Policy.AlwaysIncludeTypeForTemplateArgument = true;
899 }
900
901 if (const auto* TD = llvm::dyn_cast<TagDecl>(ND)) {
902 std::string type_name;
903 QualType QT = compat::GetTypeFromDecl(TD);
904 QT.getAsStringInternal(type_name, Policy);
905 return type_name;
906 }
907 if (const auto* FD = llvm::dyn_cast<FunctionDecl>(ND)) {
908 std::string func_name;
909 llvm::raw_string_ostream name_stream(func_name);
910 FD->getNameForDiagnostic(name_stream, Policy, qualified);
911 name_stream.flush();
912 return func_name;
913 }
914
915 return qualified ? ND->getQualifiedNameAsString() : ND->getNameAsString();
916 }
917
918 if (llvm::isa_and_nonnull<TranslationUnitDecl>(D)) {
919 return "";
920 }
921
922 return "<unnamed>";
923}
924
925std::string GetCompleteName(ConstDeclRef DRef) {
926 INTEROP_TRACE(DRef);
927 return INTEROP_RETURN(GetCompleteNameImpl(DRef, /*qualified=*/false));
928}
929
930std::string GetQualifiedName(ConstDeclRef DRef) {
931 INTEROP_TRACE(DRef);
932 const auto* D = unwrap<Decl>(DRef);
933 if (const auto* ND = llvm::dyn_cast_or_null<NamedDecl>(D)) {
934 return INTEROP_RETURN(ND->getQualifiedNameAsString());
935 }
936
937 if (llvm::isa_and_nonnull<TranslationUnitDecl>(D)) {
938 return INTEROP_RETURN("");
939 }
940
941 return INTEROP_RETURN("<unnamed>");
942}
943
944std::string GetQualifiedCompleteName(ConstDeclRef DRef) {
945 INTEROP_TRACE(DRef);
946 return INTEROP_RETURN(GetCompleteNameImpl(DRef, /*qualified=*/true));
947}
948
949std::string GetDoxygenComment(ConstDeclRef DRef, bool strip_comment_markers) {
950 INTEROP_TRACE(DRef, strip_comment_markers);
951 const auto* D = unwrap<Decl>(DRef);
952 if (!D)
953 return INTEROP_RETURN("");
954
955 D = D->getCanonicalDecl();
956 ASTContext& C = D->getASTContext();
957
958 const RawComment* RC = C.getRawCommentForAnyRedecl(D);
959 if (!RC)
960 return INTEROP_RETURN("");
961
962 (void)C.getCommentForDecl(D, /*PP=*/nullptr);
963
964 const SourceManager& SM = C.getSourceManager();
965
966 if (!strip_comment_markers)
967 return INTEROP_RETURN(RC->getRawText(SM).str());
968
969 return INTEROP_RETURN(RC->getFormattedText(SM, C.getDiagnostics()));
970}
971
972std::vector<DeclRef> GetUsingNamespaces(ConstDeclRef DRef) {
973 INTEROP_TRACE(DRef);
974 const auto* D = unwrap<clang::Decl>(DRef);
975
976 if (const auto* DC = llvm::dyn_cast_or_null<clang::DeclContext>(D)) {
977 std::vector<DeclRef> namespaces;
978 for (auto UD : DC->using_directives()) {
979 namespaces.push_back(UD->getNominatedNamespace());
980 }
981 return INTEROP_RETURN(namespaces);
982 }
983
984 return INTEROP_RETURN(std::vector<DeclRef>{});
985}
986
987DeclRef GetGlobalScope() {
989 return INTEROP_RETURN(
990 getSema().getASTContext().getTranslationUnitDecl()->getFirstDecl());
991}
992
993static Decl* GetScopeFromType(QualType QT) {
994 if (auto* Type = QT.getCanonicalType().getTypePtrOrNull()) {
995 Type = Type->getPointeeOrArrayElementType();
996 Type = Type->getUnqualifiedDesugaredType();
997 if (auto* ET = llvm::dyn_cast<EnumType>(Type))
998 return ET->getDecl();
999 CXXRecordDecl* CXXRD = Type->getAsCXXRecordDecl();
1000 if (CXXRD)
1001 return CXXRD->getCanonicalDecl();
1002 }
1003 return 0;
1004}
1005
1006DeclRef GetScopeFromType(ConstTypeRef TyRef) {
1007 INTEROP_TRACE(TyRef);
1008 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
1009 return INTEROP_RETURN(GetScopeFromType(QT));
1010}
1011
1012static const clang::Decl* GetUnderlyingScopeImpl(const clang::Decl* D) {
1013 if (const auto* TND = dyn_cast_or_null<TypedefNameDecl>(D)) {
1014 if (auto* Scope = GetScopeFromType(TND->getUnderlyingType()))
1015 D = Scope;
1016 } else if (const auto* USS = dyn_cast_or_null<UsingShadowDecl>(D)) {
1017 if (const auto* Scope = USS->getTargetDecl())
1018 D = Scope;
1019 }
1020
1021 return D->getCanonicalDecl();
1022}
1023
1024DeclRef GetUnderlyingScope(ConstDeclRef DRef) {
1025 INTEROP_TRACE(DRef);
1026 if (!DRef)
1027 return INTEROP_RETURN(nullptr);
1028 // Strip const at the API boundary: GetUnderlyingScope is a CONST
1029 // operation but returns a mutable DRef (callers may use the result
1030 // for further operations).
1031 return INTEROP_RETURN(const_cast<clang::Decl*>(
1032 GetUnderlyingScopeImpl(unwrap<clang::Decl>(DRef))));
1033}
1034
1035DeclRef GetScope(const std::string& name, ConstDeclRef parent) {
1036 INTEROP_TRACE(name, parent);
1037 // FIXME: GetScope should be replaced by a general purpose lookup
1038 // and filter function. The function should be like GetNamed but
1039 // also take in a filter parameter which determines which results
1040 // to pass back
1041 if (name == "")
1043
1044 auto* ND = unwrap<NamedDecl>(GetNamed(name, parent));
1045
1046 if (!ND || ND == (NamedDecl*)-1)
1047 return INTEROP_RETURN(nullptr);
1048
1049 if (llvm::isa<NamespaceDecl>(ND) || llvm::isa<RecordDecl>(ND) ||
1050 llvm::isa<ClassTemplateDecl>(ND) || llvm::isa<TypedefNameDecl>(ND) ||
1051 llvm::isa<TypeAliasTemplateDecl>(ND) || llvm::isa<TypeAliasDecl>(ND))
1052 return INTEROP_RETURN(ND->getCanonicalDecl());
1053
1054 return INTEROP_RETURN(nullptr);
1055}
1056
1057DeclRef GetScopeFromCompleteName(const std::string& name) {
1058 INTEROP_TRACE(name);
1059 std::string delim = "::";
1060 size_t start = 0;
1061 size_t end = name.find(delim);
1062 DeclRef curr_scope = nullptr;
1063 while (end != std::string::npos) {
1064 curr_scope = GetScope(name.substr(start, end - start), curr_scope);
1065 start = end + delim.length();
1066 end = name.find(delim, start);
1067 }
1068 return INTEROP_RETURN(GetScope(name.substr(start, end), curr_scope));
1069}
1070
1071// Sema::CurScope is private, but we need to reseat it briefly to drive
1072// Sema::LookupName at a synthesized point inside `Within`. The
1073// ALLOW_ACCESS/ACCESS pair from Sins.h gets us there without patching
1074// clang.
1075ALLOW_ACCESS(clang::Sema, CurScope, clang::Scope*);
1076
1077namespace {
1078// Mirror DC's enclosing namespace nesting as a chain of clang::Scope*
1079// rooted at S.TUScope, each Scope's entity set to the matching
1080// DeclContext. Sema::CppLookupName walks this chain via getParent() and
1081// reads using-directives off each entity's NamespaceDecl, so this is
1082// enough to make unqualified lookup honour `using namespace ...;`
1083// declared inside DC.
1084clang::Scope* BuildSyntheticScopeChain(clang::Sema& S, clang::DeclContext* DC) {
1085 if (!DC || DC->isTranslationUnit())
1086 return S.TUScope;
1087 auto* Parent = BuildSyntheticScopeChain(S, DC->getParent());
1088 auto* Mine = new clang::Scope(Parent, clang::Scope::DeclScope, S.Diags);
1089 Mine->setEntity(DC);
1090 return Mine;
1091}
1092
1093// RAII: build a synthetic DRef chain for `Within`, install it as
1094// Sema::CurScope, restore + delete on destruction. CppLookupName is
1095// read-only on Scope/Sema state (only getParent/getEntity/
1096// getLookupEntity/isDeclScope reads, plus a stack-local
1097// UnqualUsingDirectiveSet); freeing the synthetic scopes is the
1098// entire teardown — no ActOnPopScope needed because we never pushed
1099// any decl onto these scopes.
1100class SyntheticScopeChain {
1101public:
1102 SyntheticScopeChain(clang::Sema& Sema, clang::DeclContext* Within)
1103 : S(Sema), Innermost(BuildSyntheticScopeChain(Sema, Within)),
1104 Saved(ACCESS(Sema, CurScope)) {
1105 ACCESS(S, CurScope) = Innermost;
1106 }
1107 ~SyntheticScopeChain() {
1108 ACCESS(S, CurScope) = Saved;
1109 while (Innermost && Innermost != S.TUScope) {
1110 auto* Next = Innermost->getParent();
1111 delete Innermost;
1112 Innermost = Next;
1113 }
1114 }
1115 SyntheticScopeChain(const SyntheticScopeChain&) = delete;
1116 SyntheticScopeChain& operator=(const SyntheticScopeChain&) = delete;
1117
1118 clang::Scope* get() const { return Innermost; }
1119
1120private:
1121 clang::Sema& S;
1122 clang::Scope* Innermost;
1123 clang::Scope* Saved;
1124};
1125
1126// Unqualified lookup of `Name` from a synthesized point inside `Within`
1127// ([basic.lookup.unqual]). Honours using-directives reachable from
1128// Within, which Sema::LookupQualifiedName does not.
1129//
1130// FIXME: longer-term we want two distinct routes — one wrapping
1131// LookupQualifiedName and one this — exposed as separate operations so
1132// callers can pick the C++ semantics they actually want. For now
1133// GetNamed gates this behind a qualified-lookup-miss + reachable
1134// using-directive check, so the common case stays on the cheap path.
1135clang::NamedDecl* LookupUnqualified(clang::Sema& S,
1136 const clang::DeclarationName& Name,
1137 clang::DeclContext* Within) {
1138 SyntheticScopeChain Chain(S, Within);
1139 // NotForRedeclaration: ForVisibleRedeclaration causes Sema::CppLookupName
1140 // to return as soon as the innermost namespace doesn't directly contain
1141 // the name (SemaLookup.cpp:1545), which prevents using-directives from
1142 // an enclosing common-ancestor namespace from firing. We're doing
1143 // ordinary name lookup, not collecting redeclarations.
1144 clang::LookupResult R(S, Name, clang::SourceLocation(),
1145 clang::Sema::LookupOrdinaryName,
1146 RedeclarationKind::NotForRedeclaration);
1147 R.suppressDiagnostics();
1148 S.LookupName(R, Chain.get());
1149 // Match LookupResult2Decl from CppInterOpInterpreter.h (clang-repl-only
1150 // header, not included in CPPINTEROP_USE_CLING builds). Empty -> null;
1151 // single -> found decl; multi -> (D*)-1 sentinel that GetNamed treats
1152 // as "ambiguous, give up".
1153 if (R.empty())
1154 return nullptr;
1155 R.resolveKind();
1156 if (R.isSingleResult())
1157 return llvm::dyn_cast<clang::NamedDecl>(R.getFoundDecl());
1158 return (clang::NamedDecl*)-1;
1159}
1160
1161// Cheap probe: does any namespace from `DC` up to TU carry at least
1162// one using-directive? Gates the synthetic-DRef-chain build below so
1163// the common case (no using-directives anywhere on the path) doesn't
1164// pay the heap-allocation tax.
1165bool HasReachableUsingDirective(const clang::DeclContext* DC) {
1166 for (; DC && !DC->isTranslationUnit(); DC = DC->getParent()) {
1167 if (const auto* NS = llvm::dyn_cast<clang::NamespaceDecl>(DC)) {
1168 auto UDs = NS->using_directives();
1169 if (UDs.begin() != UDs.end())
1170 return true;
1171 }
1172 }
1173 return false;
1174}
1175} // namespace
1176
1177DeclRef GetNamed(const std::string& name, ConstDeclRef parent /*= nullptr*/) {
1178 INTEROP_TRACE(name, parent);
1179 clang::DeclContext* Within = 0;
1180 if (parent) {
1181 auto* D = unwrap<clang::Decl>(GetUnderlyingScope(parent));
1182 Within = llvm::dyn_cast<clang::DeclContext>(D);
1183 }
1184#ifdef CPPINTEROP_USE_CLING
1185 if (Within)
1186 Within->getPrimaryContext()->buildLookup();
1187#endif
1189
1190 // Fast path: qualified lookup. Cheap, no DRef-chain allocation, and
1191 // resolves every name not brought into `Within` via a using-directive.
1192 // Lookup::Named falls back to LookupName(R, TUScope) when Within is
1193 // null, so TU-level using-directives are already handled there.
1194 auto* ND = CppInternal::utils::Lookup::Named(&getSema(), name, Within);
1195 if (ND && ND != (clang::NamedDecl*)-1)
1196 return INTEROP_RETURN(ND->getCanonicalDecl());
1197
1198 // Slow path: only when qualified lookup missed AND `Within` is a
1199 // namespace whose enclosing chain carries at least one using-directive
1200 // (the only reason qualified-vs-unqualified disagree at namespace
1201 // DRef per [basic.lookup.unqual] vs [basic.lookup.qual]).
1202 if (!Within || !llvm::isa<clang::NamespaceDecl>(Within) ||
1203 !HasReachableUsingDirective(Within))
1204 return INTEROP_RETURN(nullptr);
1205 clang::DeclarationName DName = &getSema().Context.Idents.get(name);
1206 ND = LookupUnqualified(getSema(), DName, Within);
1207 if (ND && ND != (clang::NamedDecl*)-1)
1208 return INTEROP_RETURN(ND->getCanonicalDecl());
1209
1210 return INTEROP_RETURN(nullptr);
1211}
1212
1213DeclRef GetParentScope(ConstDeclRef DRef) {
1214 INTEROP_TRACE(DRef);
1215 // const_cast: the returned DeclRef is a mutable DRef, so the caller may
1216 // mutate the AST. Walking parents is logically const, but the return TyRef
1217 // is the mutable DRef.
1218 auto* D = const_cast<Decl*>(unwrap<clang::Decl>(DRef));
1219
1220 if (llvm::isa_and_nonnull<TranslationUnitDecl>(D)) {
1221 return INTEROP_RETURN(nullptr);
1222 }
1223 auto* ParentDC = D->getDeclContext();
1224
1225 if (!ParentDC)
1226 return INTEROP_RETURN(nullptr);
1227
1228 auto* P = clang::Decl::castFromDeclContext(ParentDC)->getCanonicalDecl();
1229
1230 if (auto* TU = llvm::dyn_cast_or_null<TranslationUnitDecl>(P))
1231 return INTEROP_RETURN(TU->getFirstDecl());
1232
1233 return INTEROP_RETURN(P);
1234}
1235
1236size_t GetNumBases(ConstDeclRef DRef) {
1237 INTEROP_TRACE(DRef);
1238 const auto* D = unwrap<Decl>(DRef);
1239
1240 if (const auto* CTSD =
1241 llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(D))
1242 if (!CTSD->hasDefinition())
1244 getInterp(), const_cast<ClassTemplateSpecializationDecl*>(CTSD));
1245 if (const auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
1246 if (CXXRD->hasDefinition())
1247 return INTEROP_RETURN(CXXRD->getNumBases());
1248 }
1249
1250 return INTEROP_RETURN(0);
1251}
1252
1253DeclRef GetBaseClass(ConstDeclRef DRef, size_t ibase) {
1254 INTEROP_TRACE(DRef, ibase);
1255 const auto* D = unwrap<Decl>(DRef);
1256 const auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D);
1257 if (!CXXRD || CXXRD->getNumBases() <= ibase)
1258 return INTEROP_RETURN(nullptr);
1259
1260 auto TyRef = (CXXRD->bases_begin() + ibase)->getType();
1261 if (const auto* RT = TyRef->getAs<RecordType>())
1262 return INTEROP_RETURN(RT->getDecl()->getCanonicalDecl());
1263
1264 return INTEROP_RETURN(nullptr);
1265}
1266
1267// FIXME: Consider dropping this interface as it seems the same as
1268// IsTypeDerivedFrom.
1269bool IsSubclass(ConstDeclRef derived, ConstDeclRef base) {
1270 INTEROP_TRACE(derived, base);
1271 if (derived == base)
1272 return INTEROP_RETURN(true);
1273
1274 if (!derived || !base)
1275 return INTEROP_RETURN(false);
1276
1277 const auto* derived_D = unwrap<clang::Decl>(derived);
1278 const auto* base_D = unwrap<clang::Decl>(base);
1279
1280 if (!isa<CXXRecordDecl>(derived_D) || !isa<CXXRecordDecl>(base_D))
1281 return INTEROP_RETURN(false);
1282
1283 const auto* Derived = cast<CXXRecordDecl>(derived_D);
1284 const auto* Base = cast<CXXRecordDecl>(base_D);
1285 return INTEROP_RETURN(
1287}
1288
1289// Copied from VTableBuilder.cpp
1290// This is an internal helper function for the CppInterOp library (as evident
1291// by the 'static' declaration), while the similar GetBaseClassOffset()
1292// function below is exposed to library users.
1293static unsigned ComputeBaseOffset(const ASTContext& Context,
1294 const CXXRecordDecl* DerivedRD,
1295 const CXXBasePath& Path) {
1296 CharUnits NonVirtualOffset = CharUnits::Zero();
1297
1298 unsigned NonVirtualStart = 0;
1299 const CXXRecordDecl* VirtualBase = nullptr;
1300
1301 // First, look for the virtual base class.
1302 for (int I = Path.size(), E = 0; I != E; --I) {
1303 const CXXBasePathElement& Element = Path[I - 1];
1304
1305 if (Element.Base->isVirtual()) {
1306 NonVirtualStart = I;
1307 QualType VBaseType = Element.Base->getType();
1308 VirtualBase = VBaseType->getAsCXXRecordDecl();
1309 break;
1310 }
1311 }
1312
1313 // Now compute the non-virtual offset.
1314 for (unsigned I = NonVirtualStart, E = Path.size(); I != E; ++I) {
1315 const CXXBasePathElement& Element = Path[I];
1316
1317 // Check the base class offset.
1318 const ASTRecordLayout& Layout = Context.getASTRecordLayout(Element.Class);
1319
1320 const CXXRecordDecl* Base = Element.Base->getType()->getAsCXXRecordDecl();
1321
1322 NonVirtualOffset += Layout.getBaseClassOffset(Base);
1323 }
1324
1325 // FIXME: This should probably use CharUnits or something. Maybe we should
1326 // even change the base offsets in ASTRecordLayout to be specified in
1327 // CharUnits.
1328 // return BaseOffset(DerivedRD, VirtuaBose, aBlnVirtualOffset);
1329 if (VirtualBase) {
1330 const ASTRecordLayout& Layout = Context.getASTRecordLayout(DerivedRD);
1331 CharUnits VirtualOffset = Layout.getVBaseClassOffset(VirtualBase);
1332 return (NonVirtualOffset + VirtualOffset).getQuantity();
1333 }
1334 return NonVirtualOffset.getQuantity();
1335}
1336
1337int64_t GetBaseClassOffset(ConstDeclRef derived, ConstDeclRef base) {
1338 INTEROP_TRACE(derived, base);
1339 if (base == derived)
1340 return INTEROP_RETURN(0);
1341
1342 assert(derived || base);
1343
1344 const auto* DD = unwrap<Decl>(derived);
1345 const auto* BD = unwrap<Decl>(base);
1346 if (!isa<CXXRecordDecl>(DD) || !isa<CXXRecordDecl>(BD))
1347 return INTEROP_RETURN(-1);
1348 const auto* DCXXRD = cast<CXXRecordDecl>(DD);
1349 const auto* BCXXRD = cast<CXXRecordDecl>(BD);
1350 // GCC's -Wmaybe-uninitialized false-positives here only under ASan:
1351 // -fsanitize=address keeps the SmallDenseMap's union storage live across
1352 // poison/unpoison calls and blocks the SROA pass that normally folds away
1353 // the LargeRep read on the Small==true branch. The load survives into the
1354 // IR the uninit pass sees, and it can no longer prove the `Small` guard.
1355 // Clang's analyzer does not false-positive here; plain-O2 GCC does not
1356 // either. Narrow the suppression to GCC + ASan.
1357#if defined(__GNUC__) && !defined(__clang__) && defined(__SANITIZE_ADDRESS__)
1358#pragma GCC diagnostic push
1359#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
1360#endif
1361 CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true,
1362 /*DetectVirtual=*/false);
1363#if defined(__GNUC__) && !defined(__clang__) && defined(__SANITIZE_ADDRESS__)
1364#pragma GCC diagnostic pop
1365#endif
1366 DCXXRD->isDerivedFrom(BCXXRD, Paths);
1367
1368 // FIXME: We might want to cache these requests as they seem expensive.
1369 return INTEROP_RETURN(
1370 ComputeBaseOffset(getSema().getASTContext(), DCXXRD, Paths.front()));
1371}
1372
1373template <typename DeclType, typename HandleType>
1374static void GetClassDecls(ConstDeclRef DRef, std::vector<HandleType>& methods) {
1375 if (!DRef)
1376 return;
1377
1378 // Unwrap to mutable: ForceDeclarationOfImplicitMembers is a lazy-init
1379 // operation on the AST, logically const for the caller.
1380 Decl* D = const_cast<Decl*>(unwrap<clang::Decl>(DRef));
1381
1382 if (auto* TD = dyn_cast<TypedefNameDecl>(D)) {
1383 DeclRef Scope = GetScopeFromType(TD->getUnderlyingType());
1384 D = unwrap<clang::Decl>(Scope);
1385 }
1386
1387 if (!D || !isa<CXXRecordDecl>(D))
1388 return;
1389
1390 auto* CXXRD = dyn_cast<CXXRecordDecl>(D);
1392 if (auto* CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {
1393 QualType QT = compat::GetTypeFromDecl(CTSD);
1394 if (!getSema().isCompleteType(CTSD->getLocation(), QT))
1395 return; // Unsuccesfull instantiaton
1396 }
1397
1398 if (CXXRD->hasDefinition())
1399 CXXRD = CXXRD->getDefinition();
1400 getSema().ForceDeclarationOfImplicitMembers(CXXRD);
1401 for (Decl* DI : CXXRD->decls()) {
1402 if (auto* MD = dyn_cast<DeclType>(DI))
1403 methods.push_back(MD);
1404 else if (auto* USD = dyn_cast<UsingShadowDecl>(DI)) {
1405 auto* MD = dyn_cast<DeclType>(USD->getTargetDecl());
1406 if (!MD)
1407 continue;
1408
1409 auto* CUSD = dyn_cast<ConstructorUsingShadowDecl>(DI);
1410 if (!CUSD) {
1411 methods.push_back(MD);
1412 continue;
1413 }
1414
1415 auto* CXXCD = dyn_cast_or_null<CXXConstructorDecl>(CUSD->getTargetDecl());
1416 if (!CXXCD) {
1417 methods.push_back(MD);
1418 continue;
1419 }
1420 if (CXXCD->isDeleted())
1421 continue;
1422
1423 // Result is appended to the decls, i.e. CXXRD, iterator
1424 // non-shadowed decl will be push_back later
1425 // methods.push_back(Result);
1426 getSema().findInheritingConstructor(SourceLocation(), CXXCD, CUSD);
1427 }
1428 }
1429}
1430
1431void GetClassMethods(ConstDeclRef DRef, std::vector<FuncRef>& methods) {
1432 INTEROP_TRACE(DRef, INTEROP_OUT(methods));
1433 GetClassDecls<CXXMethodDecl>(DRef, methods);
1434 return INTEROP_VOID_RETURN();
1435}
1436
1437void GetFunctionTemplatedDecls(ConstDeclRef DRef,
1438 std::vector<FuncRef>& methods) {
1439 INTEROP_TRACE(DRef, INTEROP_OUT(methods));
1440 GetClassDecls<FunctionTemplateDecl>(DRef, methods);
1441 return INTEROP_VOID_RETURN();
1442}
1443
1444bool HasDefaultConstructor(ConstDeclRef DRef) {
1445 INTEROP_TRACE(DRef);
1446 const auto* D = unwrap<clang::Decl>(DRef);
1447
1448 if (const auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D))
1449 return INTEROP_RETURN(CXXRD->hasDefaultConstructor());
1450
1451 return INTEROP_RETURN(false);
1452}
1453
1454FuncRef GetDefaultConstructor(compat::Interpreter& interp, DeclRef DRef) {
1455 if (!HasDefaultConstructor(DRef))
1456 return nullptr;
1457
1458 auto* CXXRD = unwrap<clang::CXXRecordDecl>(DRef);
1460 return interp.getCI()->getSema().LookupDefaultConstructor(CXXRD);
1461}
1462
1463FuncRef GetDefaultConstructor(DeclRef DRef) {
1464 INTEROP_TRACE(DRef);
1466}
1467
1468FuncRef GetDestructor(ConstDeclRef DRef) {
1469 INTEROP_TRACE(DRef);
1470 // ForceDeclarationOfImplicitMembers is a lazy-init operation.
1471 auto* D = const_cast<Decl*>(unwrap<clang::Decl>(DRef));
1472
1473 if (auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
1474 getSema().ForceDeclarationOfImplicitMembers(CXXRD);
1475 return INTEROP_RETURN(CXXRD->getDestructor());
1476 }
1477
1478 return INTEROP_RETURN(nullptr);
1479}
1480
1481void DumpScope(ConstDeclRef DRef) {
1482 INTEROP_TRACE(DRef);
1483 const auto* D = unwrap<clang::Decl>(DRef);
1484 D->dump();
1485 return INTEROP_VOID_RETURN();
1486}
1487
1488// Map an operator spelling (e.g. "operator==") to the CXXOperatorName its
1489// overloads are stored under, since identifier lookup never matches them.
1490// Returns an empty DeclarationName for non-operators (e.g. "operators_count"),
1491// leaving the caller on the identifier path. We can't use LookupOperatorName
1492// for this: it ignores class members, which this entry point must also find.
1493static DeclarationName getCXXOperatorDeclName(ASTContext& Ctx,
1494 llvm::StringRef name) {
1495 static constexpr llvm::StringRef OperatorPrefix("operator");
1496 if (!name.consume_front(OperatorPrefix) || name.empty() ||
1497 clang::isAsciiIdentifierContinue(
1498 static_cast<unsigned char>(name.front())))
1499 return DeclarationName();
1500
1501 llvm::StringRef Spelling = name.trim();
1502#define OVERLOADED_OPERATOR(OpName, OpSpelling, Token, Unary, Binary, \
1503 MemberOnly) \
1504 if (Spelling == (OpSpelling)) \
1505 return Ctx.DeclarationNames.getCXXOperatorName(clang::OO_##OpName);
1506#include "clang/Basic/OperatorKinds.def"
1507#undef OVERLOADED_OPERATOR
1508 return DeclarationName();
1509}
1510
1511std::vector<FuncRef> GetFunctionsUsingName(ConstDeclRef DRef,
1512 const std::string& name) {
1513 INTEROP_TRACE(DRef, name);
1514
1515 if (!DRef || name.empty())
1516 return INTEROP_RETURN(std::vector<FuncRef>{});
1517
1518 const auto* D = unwrap<Decl>(GetUnderlyingScope(DRef));
1519
1520 std::vector<FuncRef> funcs;
1521 auto& S = getSema();
1522 auto& Ctx = getASTContext();
1523
1524 DeclarationName DName = getCXXOperatorDeclName(Ctx, name);
1525 if (!DName)
1526 DName = &Ctx.Idents.get(name);
1527
1528 clang::LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName,
1529 RedeclarationKind::ForVisibleRedeclaration);
1530
1531 CppInternal::utils::Lookup::Named(&S, R, Decl::castToDeclContext(D));
1532
1533 if (R.empty())
1534 return INTEROP_RETURN(funcs);
1535
1536 R.resolveKind();
1537
1538 for (auto* Found : R) {
1539 if (llvm::isa<FunctionDecl>(Found))
1540 funcs.push_back(Found);
1541 else if (auto* USD = llvm::dyn_cast<UsingShadowDecl>(Found)) {
1542 if (auto* FTD = llvm::dyn_cast<FunctionDecl>(USD->getTargetDecl()))
1543 funcs.push_back(FTD);
1544 }
1545 }
1546
1547 return INTEROP_RETURN(funcs);
1548}
1549
1550TypeRef GetFunctionReturnType(ConstFuncRef func) {
1551 INTEROP_TRACE(func);
1552 const auto* D = unwrap<clang::Decl>(func);
1553 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D)) {
1554 QualType Type = FD->getReturnType();
1555 if (Type->isUndeducedAutoType()) {
1556 bool needInstantiation = false;
1557 if (IsTemplatedFunction(FD) && !FD->isDefined())
1558 needInstantiation = true;
1559 if (const auto* MD = llvm::dyn_cast<clang::CXXMethodDecl>(FD)) {
1560 if (IsTemplateSpecialization(MD->getParent()))
1561 needInstantiation = true;
1562 }
1563
1564 if (needInstantiation) {
1565 // Lazy AST instantiation — logically const for the caller.
1567 const_cast<Decl*>(static_cast<const Decl*>(FD)));
1568 }
1569 Type = FD->getReturnType();
1570 }
1571 return INTEROP_RETURN(Type.getAsOpaquePtr());
1572 }
1573
1574 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
1575 return INTEROP_RETURN(
1576 (FD->getTemplatedDecl())->getReturnType().getAsOpaquePtr());
1577
1578 return INTEROP_RETURN(nullptr);
1579}
1580
1581bool IsFunctionProtoType(ConstTypeRef TyRef) {
1582 INTEROP_TRACE(TyRef);
1583 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
1584 const auto* T = QT.getTypePtr();
1585 return llvm::isa_and_nonnull<clang::FunctionProtoType>(T);
1586}
1587
1588void GetFnTypeSignature(ConstTypeRef fn_type, std::vector<TypeRef>& sig) {
1589 INTEROP_TRACE(fn_type, INTEROP_OUT(sig));
1590 QualType QT = QualType::getFromOpaquePtr(fn_type.data);
1591 const auto* FPT = QT->getAs<clang::FunctionProtoType>();
1592 if (!FPT)
1593 return INTEROP_VOID_RETURN();
1594 sig.push_back(FPT->getReturnType().getAsOpaquePtr());
1595 for (size_t i = 0; i < FPT->getNumParams(); i++)
1596 sig.push_back(FPT->getParamType(i).getAsOpaquePtr());
1597 return INTEROP_VOID_RETURN();
1598}
1599
1600// A C++23 explicit object parameter (the `this Self self` of a "deducing this"
1601// member function) is a real ParmVarDecl, but it binds to the object the method
1602// is invoked on rather than being callee-supplied. Clang's getNumParams() /
1603// getMinRequiredArguments() count it; the *NonObject* / *Explicit* variants
1604// exclude it, which is what callers introspecting the argument list want.
1605size_t GetFunctionNumArgs(ConstFuncRef func) {
1606 INTEROP_TRACE(func);
1607 const auto* D = unwrap<clang::Decl>(func);
1608 if (const auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
1609 return INTEROP_RETURN(FD->getNumNonObjectParams());
1610
1611 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
1612 return INTEROP_RETURN(FD->getTemplatedDecl()->getNumNonObjectParams());
1613
1614 return INTEROP_RETURN(0);
1615}
1616
1617size_t GetFunctionRequiredArgs(ConstFuncRef func) {
1618 INTEROP_TRACE(func);
1619 const auto* D = unwrap<clang::Decl>(func);
1620 if (const auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D))
1621 return INTEROP_RETURN(FD->getMinRequiredExplicitArguments());
1622
1623 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
1624 return INTEROP_RETURN(
1625 FD->getTemplatedDecl()->getMinRequiredExplicitArguments());
1626
1627 return INTEROP_RETURN(0);
1628}
1629
1630TypeRef GetFunctionArgType(ConstFuncRef func, size_t iarg) {
1631 INTEROP_TRACE(func, iarg);
1632 const auto* D = unwrap<clang::Decl>(func);
1633
1634 if (const auto* FTD = llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
1635 D = FTD->getTemplatedDecl();
1636
1637 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D)) {
1638 if (iarg < FD->getNumNonObjectParams()) {
1639 const auto* PVD = FD->getNonObjectParameter(iarg);
1640 return INTEROP_RETURN(PVD->getOriginalType().getAsOpaquePtr());
1641 }
1642 }
1643
1644 return INTEROP_RETURN(nullptr);
1645}
1646
1647bool IsTemplateParmType(ConstTypeRef TyRef) {
1648 INTEROP_TRACE(TyRef);
1649 clang::QualType QT = clang::QualType::getFromOpaquePtr(TyRef.data);
1650 return INTEROP_RETURN(QT->isTemplateTypeParmType());
1651}
1652
1653std::string GetFunctionSignature(ConstFuncRef func) {
1654 INTEROP_TRACE(func);
1655 if (!func)
1656 return INTEROP_RETURN("<unknown>");
1657
1658 const auto* D = unwrap<clang::Decl>(func);
1659 const clang::FunctionDecl* FD;
1660
1661 if (llvm::dyn_cast<FunctionDecl>(D))
1662 FD = llvm::dyn_cast<FunctionDecl>(D);
1663 else if (const auto* FTD = llvm::dyn_cast<clang::FunctionTemplateDecl>(D))
1664 FD = FTD->getTemplatedDecl();
1665 else
1666 return INTEROP_RETURN("<unknown>");
1667
1668 std::string Signature;
1669 raw_string_ostream SS(Signature);
1670 PrintingPolicy Policy = getASTContext().getPrintingPolicy();
1671 // Skip printing the body
1672 Policy.TerseOutput = true;
1673 Policy.FullyQualifiedName = true;
1674 Policy.SuppressDefaultTemplateArgs = false;
1675 FD->print(SS, Policy);
1676 SS.flush();
1677 return INTEROP_RETURN(Signature);
1678}
1679
1680// Internal functions that are not needed outside the library are
1681// encompassed in an anonymous namespace as follows.
1682namespace {
1683bool IsTemplatedFunction(const Decl* D) {
1684 return llvm::isa_and_nonnull<FunctionTemplateDecl>(D);
1685}
1686
1687bool IsTemplateInstantiationOrSpecialization(const Decl* D) {
1688 if (const auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
1689 auto TK = FD->getTemplatedKind();
1690 return TK ==
1691 FunctionDecl::TemplatedKind::TK_FunctionTemplateSpecialization ||
1692 TK == FunctionDecl::TemplatedKind::
1693 TK_DependentFunctionTemplateSpecialization ||
1694 TK == FunctionDecl::TemplatedKind::TK_FunctionTemplate;
1695 }
1696
1697 return false;
1698}
1699} // namespace
1700
1701bool IsFunctionDeleted(ConstFuncRef function) {
1702 INTEROP_TRACE(function);
1703 const auto* FD = cast<FunctionDecl>(unwrap<clang::Decl>(function));
1704 return INTEROP_RETURN(FD->isDeleted());
1705}
1706
1707bool IsTemplatedFunction(ConstFuncRef func) {
1708 INTEROP_TRACE(func);
1709 const auto* D = unwrap<Decl>(func);
1711 IsTemplateInstantiationOrSpecialization(D));
1712}
1713
1714// FIXME: This lookup is broken, and should no longer be used in favour of
1715// `GetClassTemplatedMethods` If the candidate set returned is =1, that means
1716// the template function exists and >1 means overloads
1717bool ExistsFunctionTemplate(const std::string& name, ConstDeclRef parent) {
1718 INTEROP_TRACE(name, parent);
1719 const DeclContext* Within = nullptr;
1720 if (parent) {
1721 const auto* D = unwrap<Decl>(parent);
1722 Within = llvm::dyn_cast<DeclContext>(D);
1723 }
1724
1725 auto* ND = CppInternal::utils::Lookup::Named(&getSema(), name, Within);
1726
1727 if ((intptr_t)ND == (intptr_t)0)
1728 return INTEROP_RETURN(false);
1729
1730 if ((intptr_t)ND != (intptr_t)-1)
1732 IsTemplateInstantiationOrSpecialization(ND));
1733
1734 // FIXME: Cycle through the Decls and check if there is a templated function
1735 return INTEROP_RETURN(true);
1736}
1737
1738// Looks up all constructors in the current DeclContext
1739void LookupConstructors(const std::string& name, ConstDeclRef parent,
1740 std::vector<FuncRef>& funcs) {
1741 INTEROP_TRACE(name, parent, INTEROP_OUT(funcs));
1742 // ForceDeclarationOfImplicitMembers / LookupConstructors are lazy-init ops.
1743 auto* D = const_cast<Decl*>(unwrap<Decl>(parent));
1744
1745 if (auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
1746 getSema().ForceDeclarationOfImplicitMembers(CXXRD);
1747 DeclContextLookupResult Result = getSema().LookupConstructors(CXXRD);
1748 // Obtaining all constructors when we intend to lookup a method under a
1749 // DRef can lead to crashes. We avoid that by accumulating constructors
1750 // only if the Decl matches the lookup name.
1751 for (auto* i : Result)
1752 if (GetName(DeclRef(i)) == name)
1753 funcs.push_back(i);
1754 }
1755 return INTEROP_VOID_RETURN();
1756}
1757
1758bool GetClassTemplatedMethods(const std::string& name, ConstDeclRef parent,
1759 std::vector<FuncRef>& funcs) {
1760 INTEROP_TRACE(name, parent, INTEROP_OUT(funcs));
1761 const auto* D = unwrap<Decl>(parent);
1762 if (!D && name.empty())
1763 return INTEROP_RETURN(false);
1764
1765 // Accumulate constructors
1766 LookupConstructors(name, parent, funcs);
1767 auto& S = getSema();
1768 auto* DU = unwrap<Decl>(GetUnderlyingScope(parent));
1769 llvm::StringRef Name(name);
1770 DeclarationName DName = &getASTContext().Idents.get(name);
1771 clang::LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName,
1772 RedeclarationKind::ForVisibleRedeclaration);
1773 auto* DC = clang::Decl::castToDeclContext(DU);
1775
1776 if (R.getResultKind() == clang_LookupResult_Not_Found && funcs.empty())
1777 return INTEROP_RETURN(false);
1778
1779 // Distinct match, single Decl
1780 else if (R.getResultKind() == clang_LookupResult_Found) {
1781 if (IsTemplatedFunction(R.getFoundDecl()))
1782 funcs.push_back(R.getFoundDecl());
1783 }
1784 // Loop over overload set
1785 else if (R.getResultKind() == clang_LookupResult_Found_Overloaded) {
1786 for (auto* Found : R) {
1787 if (IsTemplatedFunction(Found))
1788 funcs.push_back(Found);
1789 else if (auto* USD = llvm::dyn_cast<UsingShadowDecl>(Found)) {
1790 if (auto* FTD =
1791 llvm::dyn_cast<FunctionTemplateDecl>(USD->getTargetDecl()))
1792 funcs.push_back(FTD);
1793 }
1794 }
1795 }
1796
1797 // TODO: Handle ambiguously found LookupResult
1798 // else if (R.getResultKind() == clang::LookupResult::Ambiguous) {
1799 // auto kind = R.getAmbiguityKind();
1800 // ...
1801 // Produce a diagnostic describing the ambiguity that resulted
1802 // from name lookup as done in Sema::DiagnoseAmbiguousLookup
1803 //
1804 return INTEROP_RETURN(!funcs.empty());
1805}
1806
1807// Adapted from inner workings of Sema::BuildCallExpr
1808FuncRef
1809BestOverloadFunctionMatch(const std::vector<FuncRef>& candidates,
1810 const std::vector<TemplateArgInfo>& explicit_types,
1811 const std::vector<TemplateArgInfo>& arg_types) {
1812 INTEROP_TRACE(candidates, explicit_types, arg_types);
1813 auto& S = getSema();
1814 auto& C = S.getASTContext();
1815
1817
1818 // The overload resolution interfaces in Sema require a list of expressions.
1819 // However, unlike handwritten C++, we do not always have a expression.
1820 // Here we synthesize a placeholder expression to be able to use
1821 // Sema::AddOverloadCandidate. Made up expressions are fine because the
1822 // interface uses the list size and the expression types.
1823 struct WrapperExpr : public OpaqueValueExpr {
1824 WrapperExpr() : OpaqueValueExpr(clang::Stmt::EmptyShell()) {}
1825 };
1826 auto* Exprs = new WrapperExpr[arg_types.size()];
1827 llvm::SmallVector<Expr*> Args;
1828 Args.reserve(arg_types.size());
1829 size_t idx = 0;
1830 for (auto i : arg_types) {
1831 QualType Type = QualType::getFromOpaquePtr(i.m_Type);
1832 // XValue is an object that can be "moved" whereas PRValue is temporary
1833 // value. This enables overloads that require the object to be moved
1834 ExprValueKind ExprKind = ExprValueKind::VK_XValue;
1835 if (Type->isLValueReferenceType())
1836 ExprKind = ExprValueKind::VK_LValue;
1837
1838 new (&Exprs[idx]) OpaqueValueExpr(SourceLocation::getFromRawEncoding(1),
1839 Type.getNonReferenceType(), ExprKind);
1840 Args.push_back(&Exprs[idx]);
1841 ++idx;
1842 }
1843
1844 // Create a list of template arguments.
1845 llvm::SmallVector<TemplateArgument> TemplateArgs;
1846 TemplateArgs.reserve(explicit_types.size());
1847 for (auto explicit_type : explicit_types) {
1848 QualType ArgTy = QualType::getFromOpaquePtr(explicit_type.m_Type);
1849 if (explicit_type.m_IntegralValue) {
1850 // We have a non-TyRef template parameter. Create an integral value from
1851 // the string representation.
1852 auto Res = llvm::APSInt(explicit_type.m_IntegralValue);
1853 Res = Res.extOrTrunc(C.getIntWidth(ArgTy));
1854 TemplateArgs.push_back(TemplateArgument(C, Res, ArgTy));
1855 } else {
1856 TemplateArgs.push_back(ArgTy);
1857 }
1858 }
1859
1860 TemplateArgumentListInfo ExplicitTemplateArgs{};
1861 for (auto TA : TemplateArgs)
1862 ExplicitTemplateArgs.addArgument(
1863 S.getTrivialTemplateArgumentLoc(TA, QualType(), SourceLocation()));
1864
1865 // ensure valid point of instantiation, SFINAE trap keeps any failure soft
1866 SourceLocation Loc = SourceLocation::getFromRawEncoding(1);
1867 Sema::SFINAETrap Trap(S, /*ForValidityCheck=*/true);
1868
1869 OverloadCandidateSet Overloads(
1870 Loc, OverloadCandidateSet::CandidateSetKind::CSK_Normal);
1871
1872 for (auto i : candidates) {
1873 auto* D = const_cast<Decl*>(unwrap<Decl>(i));
1874 if (auto* FD = dyn_cast<FunctionDecl>(D)) {
1875 S.AddOverloadCandidate(FD, DeclAccessPair::make(FD, FD->getAccess()),
1876 Args, Overloads);
1877 } else if (auto* FTD = dyn_cast<FunctionTemplateDecl>(D)) {
1878 auto* MD = dyn_cast<CXXMethodDecl>(FTD->getTemplatedDecl());
1879 if (MD && MD->isExplicitObjectMemberFunction()) {
1880 // The explicit object parameter isn't in Args, so deduce it via the
1881 // method-template path with a synthesized receiver of the record type.
1882 CXXRecordDecl* RD = MD->getParent();
1883 QualType ObjectType = compat::GetTypeFromDecl(RD);
1884 OpaqueValueExpr ObjectExpr(SourceLocation::getFromRawEncoding(1),
1885 ObjectType, ExprValueKind::VK_LValue);
1886 S.AddMethodTemplateCandidate(
1887 FTD, DeclAccessPair::make(FTD, FTD->getAccess()), RD,
1888 &ExplicitTemplateArgs, ObjectType, ObjectExpr.Classify(C), Args,
1889 Overloads);
1890 } else {
1891 // AddTemplateOverloadCandidate is causing a memory leak
1892 // It is a known bug at clang
1893 // call stack: AddTemplateOverloadCandidate -> MakeDeductionFailureInfo
1894 // source:
1895 // https://github.com/llvm/llvm-project/blob/release/19.x/clang/lib/Sema/SemaOverload.cpp#L731-L756
1896 S.AddTemplateOverloadCandidate(
1897 FTD, DeclAccessPair::make(FTD, FTD->getAccess()),
1898 &ExplicitTemplateArgs, Args, Overloads);
1899 }
1900 }
1901 }
1902
1903 OverloadCandidateSet::iterator Best;
1904 Overloads.BestViableFunction(S, Loc, Best);
1905
1906 FunctionDecl* Result = Best != Overloads.end() ? Best->Function : nullptr;
1907 delete[] Exprs;
1908 return INTEROP_RETURN(Result);
1909}
1910
1911// Gets the AccessSpecifier of the function and checks if it is equal to
1912// the provided AccessSpecifier.
1913bool CheckMethodAccess(ConstFuncRef method, AccessSpecifier AS) {
1914 const auto* D = unwrap<Decl>(method);
1915 if (const auto* CXXMD = llvm::dyn_cast_or_null<CXXMethodDecl>(D)) {
1916 return CXXMD->getAccess() == AS;
1917 }
1918
1919 return false;
1920}
1921
1922bool IsMethod(ConstFuncRef method) {
1923 INTEROP_TRACE(method);
1924 const auto* D = unwrap<clang::Decl>(method);
1925 if (const auto* FTD = dyn_cast_or_null<FunctionTemplateDecl>(D))
1926 D = FTD->getTemplatedDecl();
1927 return INTEROP_RETURN(dyn_cast_or_null<CXXMethodDecl>(D));
1928}
1929
1930bool IsPublicMethod(ConstFuncRef method) {
1931 INTEROP_TRACE(method);
1932 return INTEROP_RETURN(CheckMethodAccess(method, AccessSpecifier::AS_public));
1933}
1934
1935bool IsProtectedMethod(ConstFuncRef method) {
1936 INTEROP_TRACE(method);
1937 return INTEROP_RETURN(
1938 CheckMethodAccess(method, AccessSpecifier::AS_protected));
1939}
1940
1941bool IsPrivateMethod(ConstFuncRef method) {
1942 INTEROP_TRACE(method);
1943 return INTEROP_RETURN(CheckMethodAccess(method, AccessSpecifier::AS_private));
1944}
1945
1946bool IsConstructor(ConstFuncRef method) {
1947 INTEROP_TRACE(method);
1948 const auto* D = unwrap<Decl>(method);
1949 if (const auto* FTD = dyn_cast<FunctionTemplateDecl>(D))
1950 return INTEROP_RETURN(IsConstructor(FTD->getTemplatedDecl()));
1951 return INTEROP_RETURN(llvm::isa_and_nonnull<CXXConstructorDecl>(D));
1952}
1953
1954bool IsDestructor(ConstFuncRef method) {
1955 INTEROP_TRACE(method);
1956 const auto* D = unwrap<Decl>(method);
1957 return INTEROP_RETURN(llvm::isa_and_nonnull<CXXDestructorDecl>(D));
1958}
1959
1960bool IsStaticMethod(ConstFuncRef method) {
1961 INTEROP_TRACE(method);
1962 const auto* D = unwrap<Decl>(method);
1963 if (const auto* FTD = llvm::dyn_cast_or_null<FunctionTemplateDecl>(D))
1964 D = FTD->getTemplatedDecl();
1965
1966 if (const auto* CXXMD = llvm::dyn_cast_or_null<CXXMethodDecl>(D)) {
1967 return INTEROP_RETURN(CXXMD->isStatic());
1968 }
1969
1970 return INTEROP_RETURN(false);
1971}
1972
1973bool IsExplicit(ConstFuncRef method) {
1974 INTEROP_TRACE(method);
1975 if (!method)
1976 return INTEROP_RETURN(false);
1977
1978 const auto* D = unwrap<Decl>(method);
1979
1980 if (const auto* FTD = llvm::dyn_cast_or_null<FunctionTemplateDecl>(D))
1981 D = FTD->getTemplatedDecl();
1982
1983 if (const auto* CD = llvm::dyn_cast_or_null<CXXConstructorDecl>(D))
1984 return INTEROP_RETURN(CD->isExplicit());
1985
1986 if (const auto* CD = llvm::dyn_cast_or_null<CXXConversionDecl>(D))
1987 return INTEROP_RETURN(CD->isExplicit());
1988
1989 if (const auto* DGD = llvm::dyn_cast_or_null<CXXDeductionGuideDecl>(D))
1990 return INTEROP_RETURN(DGD->isExplicit());
1991
1992 return INTEROP_RETURN(false);
1993}
1994
1995void* GetFunctionAddress(const char* mangled_name) {
1996 INTEROP_TRACE(mangled_name);
1997 auto& I = getInterp();
1998 auto FDAorErr = compat::getSymbolAddress(I, mangled_name);
1999 if (llvm::Error Err = FDAorErr.takeError())
2000 llvm::consumeError(std::move(Err)); // nullptr if missing
2001 else
2002 return INTEROP_RETURN(llvm::jitTargetAddressToPointer<void*>(*FDAorErr));
2003
2004 return INTEROP_RETURN(nullptr);
2005}
2006
2007static void* GetFunctionAddress(const FunctionDecl* FD) {
2008 const auto get_mangled_name = [](const FunctionDecl* FD) {
2009 auto MangleCtxt = getASTContext().createMangleContext();
2010
2011 if (!MangleCtxt->shouldMangleDeclName(FD)) {
2012 return FD->getNameInfo().getName().getAsString();
2013 }
2014
2015 std::string mangled_name;
2016 llvm::raw_string_ostream ostream(mangled_name);
2017
2018 MangleCtxt->mangleName(FD, ostream);
2019
2020 ostream.flush();
2021 delete MangleCtxt;
2022
2023 return mangled_name;
2024 };
2025
2026 // Constructor and Destructors needs to be handled differently
2027 if (!llvm::isa<CXXConstructorDecl>(FD) && !llvm::isa<CXXDestructorDecl>(FD))
2028 return GetFunctionAddress(get_mangled_name(FD).c_str());
2029
2030 return 0;
2031}
2032
2033void* GetFunctionAddress(FuncRef method) {
2034 INTEROP_TRACE(method);
2035 auto* D = unwrap<Decl>(method);
2036 if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
2037 if ((IsTemplateInstantiationOrSpecialization(FD) ||
2038 FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization) &&
2039 !FD->getDefinition())
2041 ASTContext& C = getASTContext();
2042 if (isDiscardableGVALinkage(C.GetGVALinkageForFunction(FD)))
2043 ForceCodeGen(FD, getInterp());
2045 }
2046 return INTEROP_RETURN(nullptr);
2047}
2048
2049bool IsVirtualMethod(ConstFuncRef method) {
2050 INTEROP_TRACE(method);
2051 const auto* D = unwrap<Decl>(method);
2052 if (const auto* CXXMD = llvm::dyn_cast_or_null<CXXMethodDecl>(D)) {
2053 return INTEROP_RETURN(CXXMD->isVirtual());
2054 }
2055
2056 return INTEROP_RETURN(false);
2057}
2058
2059// Vtable slot index of a virtual method in the target ABI's layout, or -1
2060// if the method is not virtual. Clang's VTableContext yields the right index
2061// for both Itanium (first user virtual after the destructor pair) and
2062// Microsoft (single deleting-dtor slot).
2063static int virtualMethodSlot(ConstFuncRef method) {
2064 const auto* MD = llvm::dyn_cast_or_null<CXXMethodDecl>(unwrap<Decl>(method));
2065 if (!MD || !MD->isVirtual())
2066 return -1;
2067
2068 ASTContext& C = getASTContext();
2069 if (C.getTargetInfo().getCXXABI().isMicrosoft()) {
2070 auto* VTC = llvm::cast<MicrosoftVTableContext>(C.getVTableContext());
2071 return (int)VTC->getMethodVFTableLocation(GlobalDecl(MD)).Index;
2072 }
2073 auto* VTC = llvm::cast<ItaniumVTableContext>(C.getVTableContext());
2074 return (int)VTC->getMethodVTableIndex(GlobalDecl(MD));
2075}
2076
2077// Number of vtable slots from the address point onward for a polymorphic
2078// class (the count applyVTableOverlay copies): destructor slots plus every
2079// virtual. -1 if DRef is not a polymorphic class.
2080static int vtableMethodSlotCount(ConstDeclRef DRef) {
2081 const auto* RD = llvm::dyn_cast_or_null<CXXRecordDecl>(unwrap<Decl>(DRef));
2082 if (RD)
2083 RD = RD->getDefinition();
2084 if (!RD || !RD->isPolymorphic())
2085 return -1;
2086
2087 ASTContext& C = getASTContext();
2088 if (C.getTargetInfo().getCXXABI().isMicrosoft()) {
2089 auto* VTC = llvm::cast<MicrosoftVTableContext>(C.getVTableContext());
2090 const VTableLayout& L = VTC->getVFTableLayout(RD, CharUnits::Zero());
2091 return (int)L.vtable_components().size();
2092 }
2093 auto* VTC = llvm::cast<ItaniumVTableContext>(C.getVTableContext());
2094 const VTableLayout& L = VTC->getVTableLayout(RD);
2095 unsigned AddrPoint = L.getAddressPointIndices()[0];
2096 return (int)(L.vtable_components().size() - AddrPoint);
2097}
2098
2099// True if \c RD's vtable layout is beyond the single-vptr overlay model:
2100// * multiple polymorphic direct bases -> secondary-base subobjects have
2101// their own vptrs that the overlay does not touch, so dispatch through
2102// a pointer to such a subobject would silently hit the original method;
2103// * any virtual base -> the primary vtable has vbase-offset entries
2104// before the address point, and the virtual-base subobject carries a
2105// vtable-in-derived with virtual thunks that the overlay does not
2106// retarget. Returns true so MakeVTableOverlay can refuse instead of
2107// quietly mis-overlaying.
2108static bool hasComplexVTableLayout(const CXXRecordDecl* RD) {
2109 if (RD->getNumVBases() > 0)
2110 return true;
2111 unsigned polymorphic_direct_bases = 0;
2112 for (const auto& B : RD->bases()) {
2113 const auto* BD = B.getType()->getAsCXXRecordDecl();
2114 if (!BD)
2115 continue;
2116 BD = BD->getDefinition();
2117 if (BD && BD->isPolymorphic() && ++polymorphic_direct_bases > 1)
2118 return true;
2119 }
2120 return false;
2121}
2122
2123// ABI-only prefix size (excludes the hidden self-pointer slot CppInterOp
2124// interposes for dtor-hook routing). Itanium has 2 slots (offset-to-top,
2125// type_info); MSVC has 1 (complete-object-locator).
2126#ifdef _WIN32
2127constexpr int kABIPrefixSize = 1;
2128#else
2129constexpr int kABIPrefixSize = 2;
2130#endif
2132 "public prefix size must equal ABI prefix + 1 hidden slot");
2133
2134// Single locus for vptr reads/writes and slot arithmetic in this file;
2135// the public header's VTableOverlayExtraSlot covers the symmetric pun
2136// thunks need on the read side. The owned block layout is:
2137//
2138// [ user extras (N) ] [ hidden self-ptr ] [ ABI prefix ] [ methods ]
2139// ^ ^
2140// address_point - kVTableOverlayPrefixSize
2141// address_point
2142//
2143// The wrapper at the deleting-dtor slot recovers its VTableOverlay from
2144// the hidden self-ptr slot via a fixed-offset load from `self`'s vptr.
2146 void** block; // owned, freed in ~VTableOverlay
2147 void** original_vptr; // restored on caller-driven teardown
2148 void* inst; // object whose vptr was replaced
2150 bool dtor_fired = false; // wrapper started -- skip vptr restore
2151 // Dtor-hook fields. orig_dtor stays null when the caller passed
2152 // on_destroy = nullptr; the wrapper is then not installed at all.
2153 void (*orig_dtor)(void*) = nullptr;
2154 VTableOverlayDtorHook cleanup = nullptr;
2155 void* cleanup_data = nullptr;
2156
2157 VTableOverlay(void** block, void** orig_vptr, void* inst,
2158 std::size_t n_extra)
2159 : block(block), original_vptr(orig_vptr), inst(inst),
2160 n_extra_prefix_slots(n_extra) {
2161 // Stash self-pointer in the hidden slot before publishing the vptr;
2162 // the wrapper reads it at fire time via a fixed offset from vptr.
2163 *hidden_slot() = this;
2165 }
2167 if (!dtor_fired)
2169 delete[] block;
2170 }
2173
2178 return reinterpret_cast<VTableOverlay**>(block + n_extra_prefix_slots);
2179 }
2180
2181 // reinterpret_cast between function and void* is only conditionally
2182 // supported per [expr.reinterpret.cast]/6; memcpy is the well-defined
2183 // alternative on every platform CppInterOp targets.
2184 template <class To, class From> static To BitCastFn(From f) noexcept {
2185 static_assert(sizeof(To) == sizeof(From));
2186 To to;
2187 std::memcpy(&to, &f, sizeof(to));
2188 return to;
2189 }
2190
2191 static void** ReadVPtr(void* inst) {
2192 return *reinterpret_cast<void***>(inst);
2193 }
2194 static void WriteVPtr(void* inst, void** new_vptr) {
2195 *reinterpret_cast<void***>(inst) = new_vptr;
2196 }
2197};
2198
2199// Wrapper installed in the deleting-dtor slot when MakeVTableOverlay was
2200// called with a non-null on_destroy. Recovers the owning VTableOverlay
2201// from `self`'s vptr (hidden-slot fixed-offset load) and runs the
2202// callback BEFORE the original destructor: `self` is alive at that
2203// point so the callback can inspect it, and after the original
2204// deleting-destructor returns memory has been freed.
2205extern "C" void cppinteropVTableOverlayDtorWrapper(void* self) {
2206 void** vptr = VTableOverlay::ReadVPtr(self);
2207 VTableOverlay* ov = *reinterpret_cast<VTableOverlay**>(
2209 // Snapshot orig_dtor before user code runs: a misbehaving callback
2210 // that destroys the overlay must not strand the C++ destructor.
2211 auto orig_dtor = ov->orig_dtor;
2212 ov->dtor_fired = true;
2213 if (ov->cleanup)
2214 ov->cleanup(self, ov->cleanup_data);
2215 orig_dtor(self);
2216}
2217
2218// Minimum slot count a polymorphic class can have from its address point:
2219// Itanium emits the destructor pair (D1 + D0) so the count is at least 2;
2220// Microsoft emits a single deleting-dtor slot so the count is at least 1.
2221// vtableMethodSlotCount returns -1 for non-polymorphic scopes.
2222#ifdef _WIN32
2223constexpr int kMinVTableMethodSlots = 1;
2224#else
2225constexpr int kMinVTableMethodSlots = 2;
2226#endif
2227
2228// Reflection-free pointer surgery: copy inst's vtable, overwrite slots with
2229// fns, install the copy and return a DRef owning it. The slot indices and
2230// count are resolved from reflection by the caller (MakeVTableOverlay).
2231// n_extra_prefix_slots prepends nullptr-initialized void* slots before the
2232// ABI prefix; the caller stashes per-instance data there and thunks read it
2233// via vptr[-(kPrefix + 1 + i)].
2234static VTableOverlay* applyVTableOverlay(void* inst, int total_method_slots,
2235 const int* slots, void* const* fns,
2236 std::size_t n,
2237 std::size_t n_extra_prefix_slots) {
2238 if (!inst || total_method_slots < kMinVTableMethodSlots)
2239 return nullptr;
2240 for (std::size_t i = 0; i < n; ++i) {
2241 if (slots[i] < 0 || slots[i] >= total_method_slots)
2242 return nullptr;
2243 }
2244
2245 // Total block size = N user extras + 1 hidden self-ptr + ABI prefix
2246 // + total_method_slots. The published vtable's address point is at
2247 // block + n_extra_prefix_slots + detail::kVTableOverlayPrefixSize.
2248 constexpr int kPrefix = detail::kVTableOverlayPrefixSize;
2249 const std::size_t total = n_extra_prefix_slots + kPrefix + total_method_slots;
2250
2251 void** orig_vptr = VTableOverlay::ReadVPtr(inst);
2252 // Zero-init so user-extra slots are nullptr (callers will populate).
2253 // The hidden slot at block[n_extra_prefix_slots] is filled by the
2254 // VTableOverlay ctor below. The memcpy then copies the original ABI
2255 // prefix + methods into the remaining region.
2256 void** block = new void*[total]();
2257 std::memcpy(block + n_extra_prefix_slots + 1, orig_vptr - kABIPrefixSize,
2258 (kABIPrefixSize + total_method_slots) * sizeof(void*));
2259
2260 for (std::size_t i = 0; i < n; ++i)
2261 block[n_extra_prefix_slots + kPrefix + slots[i]] = fns[i];
2262
2263 // Per-instance install: the new vptr is written into *this* object only.
2264 // Other live and future instances of the same TyRef continue to use the
2265 // class's original vtable; ~VTableOverlay restores `inst`'s vptr.
2266 return new VTableOverlay(block, orig_vptr, inst, n_extra_prefix_slots);
2267}
2268
2269// Itanium emits the destructor pair (D1, D0) at slots 0 and 1; the
2270// deleting-dtor (D0) at slot 1 is the path operator-delete takes for
2271// heap-allocated objects -- the relevant hook for cppyy / binding proxies
2272// whose Python wrapper drop triggers `delete cppobj`. MSVC emits a single
2273// deleting dtor at slot 0.
2274#ifdef _WIN32
2275constexpr int kDeletingDtorSlot = 0;
2276#else
2277constexpr int kDeletingDtorSlot = 1;
2278#endif
2279
2281MakeVTableOverlay(void* inst, ConstDeclRef base, const ConstFuncRef* methods,
2282 void* const* overlay_fns, std::size_t n_overlays,
2283 std::size_t n_extra_prefix_slots,
2284 VTableOverlayDtorHook on_destroy, void* cleanup_data) {
2285 INTEROP_TRACE(inst, base, methods, overlay_fns, n_overlays,
2286 n_extra_prefix_slots, on_destroy, cleanup_data);
2287 // Refuse layouts the single-primary-vptr overlay cannot fully express,
2288 // so the caller cannot silently produce mis-dispatching objects. Must run
2289 // before vtableMethodSlotCount: on MSVC, getVFTableLayout(RD, offset 0)
2290 // asserts when a virtual-inheritance class has no VFTable at that offset.
2291 if (!inst)
2292 return INTEROP_RETURN(nullptr);
2293 const auto* RD = llvm::dyn_cast_or_null<CXXRecordDecl>(unwrap<Decl>(base));
2294 if (RD)
2295 RD = RD->getDefinition();
2296 if (!RD || !RD->isPolymorphic() || hasComplexVTableLayout(RD))
2297 return INTEROP_RETURN(nullptr);
2298
2299 int total_method_slots = vtableMethodSlotCount(base);
2300 if (total_method_slots < kMinVTableMethodSlots)
2301 return INTEROP_RETURN(nullptr);
2302
2303 llvm::SmallVector<int, 8> slots;
2304 slots.reserve(n_overlays);
2305 for (std::size_t i = 0; i < n_overlays; ++i) {
2306 int slot = virtualMethodSlot(methods[i]);
2307 if (slot < 0)
2308 return INTEROP_RETURN(nullptr);
2309 slots.push_back(slot);
2310 }
2311 auto* ov = applyVTableOverlay(inst, total_method_slots, slots.data(),
2312 overlay_fns, n_overlays,
2313 n_extra_prefix_slots);
2314 if (!ov)
2315 return INTEROP_RETURN(nullptr);
2316
2317 // Optional dtor hook: capture the original D0 (already copied into
2318 // the block), wire the hook fields on the overlay, then publish the
2319 // wrapper at the deleting-dtor slot. Ordering matters -- the fields
2320 // must be set before the wrapper is reachable, otherwise a concurrent
2321 // destruction could fire the wrapper with stale state.
2322 if (on_destroy) {
2323 void** vptr = ov->address_point();
2324 ov->orig_dtor =
2325 VTableOverlay::BitCastFn<void (*)(void*)>(vptr[kDeletingDtorSlot]);
2326 ov->cleanup = on_destroy;
2327 ov->cleanup_data = cleanup_data;
2328 vptr[kDeletingDtorSlot] =
2329 VTableOverlay::BitCastFn<void*>(&cppinteropVTableOverlayDtorWrapper);
2330 }
2331
2332 return INTEROP_RETURN(ov);
2333}
2334
2336 INTEROP_TRACE(overlay);
2337 delete overlay; // ~VTableOverlay restores vptr if dtor hasn't fired.
2338 return INTEROP_VOID_RETURN();
2339}
2340
2341void GetDatamembers(DeclRef DRef, std::vector<DeclRef>& datamembers) {
2342 INTEROP_TRACE(DRef, INTEROP_OUT(datamembers));
2343 auto* D = unwrap<Decl>(DRef);
2344
2345 if (auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
2346 getSema().ForceDeclarationOfImplicitMembers(CXXRD);
2347 if (CXXRD->hasDefinition())
2348 CXXRD = CXXRD->getDefinition();
2349
2350 llvm::SmallVector<RecordDecl::decl_iterator, 2> stack_begin;
2351 llvm::SmallVector<RecordDecl::decl_iterator, 2> stack_end;
2352 stack_begin.push_back(CXXRD->decls_begin());
2353 stack_end.push_back(CXXRD->decls_end());
2354 while (!stack_begin.empty()) {
2355 if (stack_begin.back() == stack_end.back()) {
2356 stack_begin.pop_back();
2357 stack_end.pop_back();
2358 continue;
2359 }
2360 Decl* D = *(stack_begin.back());
2361 if (auto* FD = llvm::dyn_cast<FieldDecl>(D)) {
2362 if (FD->isAnonymousStructOrUnion()) {
2363 if (const auto* RT = FD->getType()->getAs<RecordType>()) {
2364 if (auto* CXXRD = llvm::dyn_cast<CXXRecordDecl>(RT->getDecl())) {
2365 stack_begin.back()++;
2366 stack_begin.push_back(CXXRD->decls_begin());
2367 stack_end.push_back(CXXRD->decls_end());
2368 continue;
2369 }
2370 }
2371 }
2372 datamembers.push_back(D);
2373
2374 } else if (auto* USD = llvm::dyn_cast<UsingShadowDecl>(D)) {
2375 if (llvm::isa<FieldDecl>(USD->getTargetDecl()))
2376 datamembers.push_back(USD);
2377 }
2378 stack_begin.back()++;
2379 }
2380 }
2381 return INTEROP_VOID_RETURN();
2382}
2383
2384void GetStaticDatamembers(ConstDeclRef DRef,
2385 std::vector<DeclRef>& datamembers) {
2386 INTEROP_TRACE(DRef, INTEROP_OUT(datamembers));
2387 GetClassDecls<VarDecl>(DRef, datamembers);
2388 return INTEROP_VOID_RETURN();
2389}
2390
2391void GetEnumConstantDatamembers(ConstDeclRef DRef,
2392 std::vector<DeclRef>& datamembers,
2393 bool include_enum_class) {
2394 INTEROP_TRACE(DRef, INTEROP_OUT(datamembers), include_enum_class);
2395 std::vector<DeclRef> EDs;
2396 GetClassDecls<EnumDecl>(DRef, EDs);
2397 for (DeclRef i : EDs) {
2398 auto* ED = unwrap<EnumDecl>(i);
2399
2400 bool is_class_tagged = ED->isScopedUsingClassTag();
2401 if (is_class_tagged && !include_enum_class)
2402 continue;
2403
2404 std::copy(ED->enumerator_begin(), ED->enumerator_end(),
2405 std::back_inserter(datamembers));
2406 }
2407 return INTEROP_VOID_RETURN();
2408}
2409
2410DeclRef LookupDatamember(const std::string& name, ConstDeclRef parent) {
2411 INTEROP_TRACE(name, parent);
2412 const clang::DeclContext* Within = nullptr;
2413 if (parent) {
2414 const auto* D = unwrap<clang::Decl>(parent);
2415 Within = llvm::dyn_cast<clang::DeclContext>(D);
2416 }
2417
2418 auto* ND = CppInternal::utils::Lookup::Named(&getSema(), name, Within);
2419 if (ND && ND != (clang::NamedDecl*)-1) {
2420 if (llvm::isa_and_nonnull<clang::FieldDecl>(ND)) {
2421 return INTEROP_RETURN(ND);
2422 }
2423 }
2424
2425 return INTEROP_RETURN(nullptr);
2426}
2427
2428bool IsLambdaClass(ConstTypeRef TyRef) {
2429 INTEROP_TRACE(TyRef);
2430 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2431 if (auto* CXXRD = QT->getAsCXXRecordDecl()) {
2432 return INTEROP_RETURN(CXXRD->isLambda());
2433 }
2434 return INTEROP_RETURN(false);
2435}
2436
2437TypeRef GetVariableType(ConstDeclRef var) {
2438 INTEROP_TRACE(var);
2439 const auto* D = unwrap<Decl>(var);
2440
2441 if (const auto* DD = llvm::dyn_cast_or_null<DeclaratorDecl>(D)) {
2442 QualType QT = DD->getType();
2443
2444 // Check if the TyRef is a typedef TyRef
2445 if (QT->isTypedefNameType()) {
2446 return INTEROP_RETURN(QT.getAsOpaquePtr());
2447 }
2448
2449 // Else, return the canonical TyRef
2450 QT = QT.getCanonicalType();
2451 return INTEROP_RETURN(QT.getAsOpaquePtr());
2452 }
2453
2454 if (const auto* ECD = llvm::dyn_cast_or_null<EnumConstantDecl>(D))
2455 return INTEROP_RETURN(ECD->getType().getAsOpaquePtr());
2456
2457 return INTEROP_RETURN(nullptr);
2458}
2459
2461 CXXRecordDecl* BaseCXXRD) {
2462 if (!D)
2463 return 0;
2464
2465 auto& C = I.getSema().getASTContext();
2466
2467 if (auto* FD = llvm::dyn_cast<FieldDecl>(D)) {
2468 clang::RecordDecl* FieldParentRecordDecl = FD->getParent();
2469 intptr_t offset = C.toCharUnitsFromBits(C.getFieldOffset(FD)).getQuantity();
2470 while (FieldParentRecordDecl->isAnonymousStructOrUnion()) {
2471 clang::RecordDecl* anon = FieldParentRecordDecl;
2472 FieldParentRecordDecl = llvm::dyn_cast<RecordDecl>(anon->getParent());
2473 for (auto F = FieldParentRecordDecl->field_begin();
2474 F != FieldParentRecordDecl->field_end(); ++F) {
2475 const auto* RT = F->getType()->getAs<RecordType>();
2476 if (!RT)
2477 continue;
2478 if (anon == RT->getDecl()) {
2479 FD = *F;
2480 break;
2481 }
2482 }
2483 offset += C.toCharUnitsFromBits(C.getFieldOffset(FD)).getQuantity();
2484 }
2485 if (BaseCXXRD && BaseCXXRD != FieldParentRecordDecl->getCanonicalDecl()) {
2486 // FieldDecl FD belongs to some class C, but the base class BaseCXXRD is
2487 // not C. That means BaseCXXRD derives from C. Offset needs to be
2488 // calculated for Derived class
2489
2490 // Depth first Search is performed to the class that declares FD from
2491 // the base class
2492 std::vector<CXXRecordDecl*> stack;
2493 std::map<CXXRecordDecl*, CXXRecordDecl*> direction;
2494 stack.push_back(BaseCXXRD);
2495 while (!stack.empty()) {
2496 CXXRecordDecl* RD = stack.back();
2497 stack.pop_back();
2498 size_t num_bases = GetNumBases(RD);
2499 bool flag = false;
2500 for (size_t i = 0; i < num_bases; i++) {
2501 auto* CRD = unwrap<CXXRecordDecl>(GetBaseClass(RD, i));
2502 direction[CRD] = RD;
2503 if (CRD == FieldParentRecordDecl) {
2504 flag = true;
2505 break;
2506 }
2507 stack.push_back(CRD);
2508 }
2509 if (flag)
2510 break;
2511 }
2512 if (auto* RD = llvm::dyn_cast<CXXRecordDecl>(FieldParentRecordDecl)) {
2513 // add in the offsets for the (multi level) base classes
2514 RD = RD->getCanonicalDecl();
2515 while (BaseCXXRD != RD) {
2516 CXXRecordDecl* Parent = direction.at(RD);
2517 offset +=
2518 C.getASTRecordLayout(Parent).getBaseClassOffset(RD).getQuantity();
2519 RD = Parent;
2520 }
2521 } else {
2522 assert(false && "Unreachable");
2523 }
2524 }
2525 return offset;
2526 }
2527
2528 if (auto* VD = llvm::dyn_cast<VarDecl>(D)) {
2529 auto GD = GlobalDecl(VD);
2530 std::string mangledName;
2531 compat::maybeMangleDeclName(GD, mangledName);
2532 void* address = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
2533 mangledName.c_str());
2534
2535 if (!address)
2536 address = I.getAddressOfGlobal(GD);
2537 if (!address) {
2538 if (!VD->hasInit()) {
2540 getSema().InstantiateVariableDefinition(SourceLocation(), VD);
2541 VD = VD->getDefinition();
2542 }
2543 if (VD->hasInit() &&
2544 (VD->isConstexpr() || VD->getType().isConstQualified())) {
2545 if (const APValue* val = VD->evaluateValue()) {
2546 if (VD->getType()->isIntegralType(C)) {
2547 return (intptr_t)val->getInt().getRawData();
2548 }
2549 }
2550 }
2551 }
2552 if (!address) {
2553 auto Linkage = C.GetGVALinkageForVariable(VD);
2554 if (isDiscardableGVALinkage(Linkage))
2555 ForceCodeGen(VD, I);
2556 }
2557 auto VDAorErr = compat::getSymbolAddress(I, StringRef(mangledName));
2558 if (!VDAorErr) {
2559 llvm::logAllUnhandledErrors(VDAorErr.takeError(), llvm::errs(),
2560 "Failed to GetVariableOffset:");
2561 return 0;
2562 }
2563 return (intptr_t)jitTargetAddressToPointer<void*>(VDAorErr.get());
2564 }
2565
2566 return 0;
2567}
2568
2569intptr_t GetVariableOffset(ConstDeclRef var, ConstDeclRef parent) {
2570 INTEROP_TRACE(var, parent);
2571 // The internal overload may trigger JIT materialization — logically const.
2572 auto* D = const_cast<Decl*>(unwrap<Decl>(var));
2573 auto* RD = const_cast<CXXRecordDecl*>(
2574 llvm::dyn_cast_or_null<CXXRecordDecl>(unwrap<Decl>(parent)));
2575 return INTEROP_RETURN(GetVariableOffset(getInterp(), D, RD));
2576}
2577
2578// Check if the Access Specifier of the variable matches the provided value.
2579bool CheckVariableAccess(ConstDeclRef var, AccessSpecifier AS) {
2580 const auto* D = unwrap<Decl>(var);
2581 return D->getAccess() == AS;
2582}
2583
2584bool IsPublicVariable(ConstDeclRef var) {
2585 INTEROP_TRACE(var);
2586 return INTEROP_RETURN(CheckVariableAccess(var, AccessSpecifier::AS_public));
2587}
2588
2589bool IsProtectedVariable(ConstDeclRef var) {
2590 INTEROP_TRACE(var);
2591 return INTEROP_RETURN(
2592 CheckVariableAccess(var, AccessSpecifier::AS_protected));
2593}
2594
2595bool IsPrivateVariable(ConstDeclRef var) {
2596 INTEROP_TRACE(var);
2597 return INTEROP_RETURN(CheckVariableAccess(var, AccessSpecifier::AS_private));
2598}
2599
2600bool IsStaticVariable(ConstDeclRef var) {
2601 INTEROP_TRACE(var);
2602 const auto* D = unwrap<Decl>(var);
2603 if (llvm::isa_and_nonnull<VarDecl>(D)) {
2604 return INTEROP_RETURN(true);
2605 }
2606
2607 return INTEROP_RETURN(false);
2608}
2609
2610bool IsConstVariable(ConstDeclRef var) {
2611 INTEROP_TRACE(var);
2612 const auto* D = unwrap<clang::Decl>(var);
2613
2614 if (const auto* VD = llvm::dyn_cast_or_null<ValueDecl>(D)) {
2615 return INTEROP_RETURN(VD->getType().isConstQualified());
2616 }
2617
2618 return INTEROP_RETURN(false);
2619}
2620
2621bool IsRecordType(ConstTypeRef TyRef) {
2622 INTEROP_TRACE(TyRef);
2623 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2624 return INTEROP_RETURN(QT->isRecordType());
2625}
2626
2627bool IsPODType(ConstTypeRef TyRef) {
2628 INTEROP_TRACE(TyRef);
2629 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2630
2631 if (QT.isNull())
2632 return INTEROP_RETURN(false);
2633
2634 return INTEROP_RETURN(QT.isPODType(getASTContext()));
2635}
2636
2637bool IsIntegerType(ConstTypeRef TyRef, Signedness* s) {
2638 INTEROP_TRACE(TyRef, s);
2639 if (!TyRef)
2640 return INTEROP_RETURN(false);
2641 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2642 if (!QT->hasIntegerRepresentation())
2643 return INTEROP_RETURN(false);
2644 if (s) {
2645 *s = QT->hasSignedIntegerRepresentation() ? Signedness::kSigned
2646 : Signedness::kUnsigned;
2647 }
2648 return INTEROP_RETURN(true);
2649}
2650
2651bool IsFloatingType(ConstTypeRef TyRef) {
2652 INTEROP_TRACE(TyRef);
2653 if (!TyRef)
2654 return INTEROP_RETURN(false);
2655 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2656 return INTEROP_RETURN(QT->hasFloatingRepresentation());
2657}
2658
2659bool IsSameType(ConstTypeRef type_a, ConstTypeRef type_b) {
2660 INTEROP_TRACE(type_a, type_b);
2661 if (!type_a || !type_b)
2662 return INTEROP_RETURN(false);
2663 QualType QT1 = QualType::getFromOpaquePtr(type_a.data);
2664 QualType QT2 = QualType::getFromOpaquePtr(type_b.data);
2665 return INTEROP_RETURN(getASTContext().hasSameType(QT1, QT2));
2666}
2667
2668bool IsPointerType(ConstTypeRef TyRef) {
2669 INTEROP_TRACE(TyRef);
2670 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2671 return INTEROP_RETURN(QT->isPointerType());
2672}
2673
2674bool IsVoidPointerType(ConstTypeRef TyRef) {
2675 INTEROP_TRACE(TyRef);
2676 if (!TyRef)
2677 return INTEROP_RETURN(false);
2678 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2679 return INTEROP_RETURN(QT->isVoidPointerType());
2680}
2681
2682TypeRef GetPointeeType(ConstTypeRef TyRef) {
2683 INTEROP_TRACE(TyRef);
2684 if (!IsPointerType(TyRef))
2685 return INTEROP_RETURN(nullptr);
2686 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2687 return INTEROP_RETURN(QT->getPointeeType().getAsOpaquePtr());
2688}
2689
2690bool IsReferenceType(ConstTypeRef TyRef) {
2691 INTEROP_TRACE(TyRef);
2692 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2693 return INTEROP_RETURN(QT->isReferenceType());
2694}
2695
2696ValueKind GetValueKind(ConstTypeRef TyRef) {
2697 INTEROP_TRACE(TyRef);
2698 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2699 if (QT->isRValueReferenceType())
2700 return INTEROP_RETURN(ValueKind::RValue);
2701 if (QT->isLValueReferenceType())
2702 return INTEROP_RETURN(ValueKind::LValue);
2703 return INTEROP_RETURN(ValueKind::None);
2704}
2705
2706TypeRef GetPointerType(ConstTypeRef TyRef) {
2707 INTEROP_TRACE(TyRef);
2708 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2709 return INTEROP_RETURN(getASTContext().getPointerType(QT).getAsOpaquePtr());
2710}
2711
2712TypeRef GetReferencedType(ConstTypeRef TyRef, bool rvalue) {
2713 INTEROP_TRACE(TyRef, rvalue);
2714 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2715 if (rvalue)
2716 return INTEROP_RETURN(
2717 getASTContext().getRValueReferenceType(QT).getAsOpaquePtr());
2718 return INTEROP_RETURN(
2719 getASTContext().getLValueReferenceType(QT).getAsOpaquePtr());
2720}
2721
2722TypeRef GetNonReferenceType(ConstTypeRef TyRef) {
2723 INTEROP_TRACE(TyRef);
2724 if (!IsReferenceType(TyRef))
2725 return INTEROP_RETURN(nullptr);
2726 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2727 return INTEROP_RETURN(QT.getNonReferenceType().getAsOpaquePtr());
2728}
2729
2730TypeRef GetUnderlyingType(ConstTypeRef TyRef) {
2731 INTEROP_TRACE(TyRef);
2732 if (!TyRef)
2733 return INTEROP_RETURN(nullptr);
2734 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2735 QT = QT->getCanonicalTypeUnqualified();
2736
2737 // Recursively remove array dimensions
2738 while (QT->isArrayType())
2739 QT = QualType(QT->getArrayElementTypeNoTypeQual(), 0);
2740
2741 // Recursively reduce pointer depth till we are left with a pointerless
2742 // TyRef.
2743 for (auto PT = QT->getPointeeType(); !PT.isNull();
2744 PT = QT->getPointeeType()) {
2745 QT = PT;
2746 }
2747 QT = QT->getCanonicalTypeUnqualified();
2748 return INTEROP_RETURN(QT.getAsOpaquePtr());
2749}
2750
2751std::string GetTypeAsString(ConstTypeRef var) {
2752 INTEROP_TRACE(var);
2753 QualType QT = QualType::getFromOpaquePtr(var.data);
2754 PrintingPolicy Policy(getASTContext().getPrintingPolicy());
2755 Policy.Bool = true; // Print bool instead of _Bool.
2756 Policy.SuppressTagKeyword = true; // Do not print `class std::string`.
2757 Policy.Suppress_Elab = true;
2758 Policy.FullyQualifiedName = true;
2759 return INTEROP_RETURN(QT.getAsString(Policy));
2760}
2761
2762TypeRef GetCanonicalType(ConstTypeRef TyRef) {
2763 INTEROP_TRACE(TyRef);
2764 if (!TyRef)
2765 return INTEROP_RETURN(nullptr);
2766 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2767 return INTEROP_RETURN(QT.getCanonicalType().getAsOpaquePtr());
2768}
2769
2770bool HasTypeQualifier(ConstTypeRef TyRef, QualKind qual) {
2771 INTEROP_TRACE(TyRef, qual);
2772 if (!TyRef)
2773 return INTEROP_RETURN(false);
2774
2775 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2776 if (qual & QualKind::Const) {
2777 if (!QT.isConstQualified())
2778 return INTEROP_RETURN(false);
2779 }
2780 if (qual & QualKind::Volatile) {
2781 if (!QT.isVolatileQualified())
2782 return INTEROP_RETURN(false);
2783 }
2784 if (qual & QualKind::Restrict) {
2785 if (!QT.isRestrictQualified())
2786 return INTEROP_RETURN(false);
2787 }
2788 return INTEROP_RETURN(true);
2789}
2790
2791TypeRef RemoveTypeQualifier(ConstTypeRef TyRef, QualKind qual) {
2792 INTEROP_TRACE(TyRef, qual);
2793 if (!TyRef)
2794 return INTEROP_RETURN(nullptr);
2795
2796 auto QT = QualType(QualType::getFromOpaquePtr(TyRef.data));
2797 if (qual & QualKind::Const)
2798 QT.removeLocalConst();
2799 if (qual & QualKind::Volatile)
2800 QT.removeLocalVolatile();
2801 if (qual & QualKind::Restrict)
2802 QT.removeLocalRestrict();
2803 return INTEROP_RETURN(QT.getAsOpaquePtr());
2804}
2805
2806TypeRef AddTypeQualifier(ConstTypeRef TyRef, QualKind qual) {
2807 INTEROP_TRACE(TyRef, qual);
2808 if (!TyRef)
2809 return INTEROP_RETURN(nullptr);
2810
2811 auto QT = QualType(QualType::getFromOpaquePtr(TyRef.data));
2812 if (qual & QualKind::Const) {
2813 if (!QT.isConstQualified())
2814 QT.addConst();
2815 }
2816 if (qual & QualKind::Volatile) {
2817 if (!QT.isVolatileQualified())
2818 QT.addVolatile();
2819 }
2820 if (qual & QualKind::Restrict) {
2821 if (!QT.isRestrictQualified())
2822 QT.addRestrict();
2823 }
2824 return INTEROP_RETURN(QT.getAsOpaquePtr());
2825}
2826
2827// Registers all permutations of a word set
2828static void RegisterPerms(llvm::StringMap<QualType>& Map, QualType QT,
2829 llvm::SmallVectorImpl<llvm::StringRef>& Words) {
2830 std::sort(Words.begin(), Words.end());
2831 do {
2832 std::string Key;
2833 for (size_t i = 0; i < Words.size(); ++i) {
2834 if (i > 0)
2835 Key += ' ';
2836 Key += Words[i].str();
2837 }
2838 Map[Key] = QT;
2839 } while (std::next_permutation(Words.begin(), Words.end()));
2840}
2841ALLOW_ACCESS(ASTContext, Types, llvm::SmallVector<clang::Type*, 0>);
2842static void PopulateBuiltinMap(ASTContext& Context) {
2843 const PrintingPolicy Policy(Context.getLangOpts());
2844 auto& BuiltinMap = GetInterpreters().back().BuiltinMap;
2845 const auto& Types = ACCESS(Context, Types);
2846
2847 for (clang::Type* T : Types) {
2848 auto* BT = llvm::dyn_cast<BuiltinType>(T);
2849 if (!BT || BT->isPlaceholderType())
2850 continue;
2851
2852 QualType QT(BT, 0);
2853 std::string Name = QT.getAsString(Policy);
2854 if (Name.empty() || Name[0] == '<')
2855 continue;
2856
2857 // Initial entry (e.g., "int", "unsigned long")
2858 BuiltinMap[Name] = QT;
2859
2860 llvm::SmallVector<llvm::StringRef, 4> Words;
2861 llvm::StringRef(Name).split(Words, ' ', -1, false);
2862
2863 bool hasInt = false;
2864 bool hasSigned = false;
2865 bool hasUnsigned = false;
2866 bool hasChar = false;
2867 bool isModifiable = false;
2868
2869 for (auto W : Words) {
2870 if (W == "int")
2871 hasInt = true;
2872 else if (W == "signed")
2873 hasSigned = true;
2874 else if (W == "unsigned")
2875 hasUnsigned = true;
2876 else if (W == "char")
2877 hasChar = true;
2878
2879 if (W == "long" || W == "short" || hasInt)
2880 isModifiable = true;
2881 }
2882
2883 // Skip things like 'float' or 'double' that aren't combined
2884 if (!isModifiable && !hasUnsigned && !hasSigned)
2885 continue;
2886
2887 // Register base permutations (e.g., "long long" or "unsigned int")
2888 if (Words.size() > 1)
2889 RegisterPerms(BuiltinMap, QT, Words);
2890
2891 // Expansion: Add "int" suffix where missing (e.g., "short" -> "short int")
2892 if (!hasInt && !hasChar) {
2893 auto WithInt = Words;
2894 WithInt.push_back("int");
2895 RegisterPerms(BuiltinMap, QT, WithInt);
2896
2897 // If we are adding 'int', we should also try adding 'signed'
2898 // to cover cases like "short" -> "signed short int"
2899 if (!hasSigned && !hasUnsigned) {
2900 auto WithBoth = WithInt;
2901 WithBoth.push_back("signed");
2902 RegisterPerms(BuiltinMap, QT, WithBoth);
2903 }
2904 }
2905
2906 // Expansion: Add "signed" prefix
2907 // (e.g., "int" -> "signed int", "long" -> "signed long")
2908 if (!hasSigned && !hasUnsigned) {
2909 auto WithSigned = Words;
2910 WithSigned.push_back("signed");
2911 RegisterPerms(BuiltinMap, QT, WithSigned);
2912 }
2913 }
2914
2915 // Explicit global synonym
2916 BuiltinMap["signed"] = Context.IntTy;
2917 BuiltinMap["unsigned"] = Context.UnsignedIntTy;
2918}
2919static QualType findBuiltinType(llvm::StringRef typeName, ASTContext& Context) {
2920 llvm::StringMap<QualType>& BuiltinMap = GetInterpreters().back().BuiltinMap;
2921 if (BuiltinMap.empty())
2922 PopulateBuiltinMap(Context);
2923
2924 // Fast Lookup
2925 auto It = BuiltinMap.find(typeName);
2926 if (It != BuiltinMap.end())
2927 return It->second;
2928
2929 return QualType(); // Return null if not a builtin
2930}
2931static std::optional<QualType> GetTypeInternal(const Decl* D) {
2932 if (!D)
2933 return {};
2934 // Even though typedefs derive from TypeDecl, their getTypeForDecl()
2935 // returns a nullptr.
2936 if (const auto* TND = llvm::dyn_cast_or_null<TypedefNameDecl>(D))
2937 return TND->getUnderlyingType();
2938
2939 if (const auto* VD = dyn_cast<ValueDecl>(D))
2940 return VD->getType();
2941
2942 if (const auto* TD = llvm::dyn_cast_or_null<TypeDecl>(D))
2943 return compat::GetTypeFromDecl(TD);
2944
2945 return {};
2946}
2947
2948TypeRef GetType(const std::string& name, ConstDeclRef parent /*= nullptr*/) {
2949 INTEROP_TRACE(name, parent);
2950 QualType builtin = findBuiltinType(name, getASTContext());
2951 if (!builtin.isNull())
2952 return INTEROP_RETURN(builtin.getAsOpaquePtr());
2953
2954 return INTEROP_RETURN(GetTypeFromScope(GetNamed(name, parent)));
2955}
2956
2957TypeRef GetComplexType(ConstTypeRef TyRef) {
2958 INTEROP_TRACE(TyRef);
2959 QualType QT = QualType::getFromOpaquePtr(TyRef.data);
2960
2961 return INTEROP_RETURN(getASTContext().getComplexType(QT).getAsOpaquePtr());
2962}
2963
2964TypeRef GetTypeFromScope(ConstDeclRef DRef) {
2965 INTEROP_TRACE(DRef);
2966 if (!DRef)
2967 return INTEROP_RETURN(nullptr);
2968
2969 if (auto QT = GetTypeInternal(unwrap<Decl>(DRef)))
2970 return INTEROP_RETURN(QT->getAsOpaquePtr());
2971
2972 return INTEROP_RETURN(nullptr);
2973}
2974
2975// Internal functions that are not needed outside the library are
2976// encompassed in an anonymous namespace as follows.
2977namespace {
2978static unsigned long long gWrapperSerial = 0LL;
2979
2980enum EReferenceType { kNotReference, kLValueReference, kRValueReference };
2981
2982// Start of JitCall Helper Functions
2983
2984#define DEBUG_TYPE "jitcall"
2985
2986// FIXME: Use that routine throughout CallFunc's port in places such as
2987// make_narg_call.
2988inline void indent(std::ostringstream& buf, int indent_level) {
2989 static const std::string kIndentString(" ");
2990 for (int i = 0; i < indent_level; ++i)
2991 buf << kIndentString;
2992}
2993
2994void* compile_wrapper(compat::Interpreter& I, const std::string& wrapper_name,
2995 const std::string& wrapper,
2996 bool withAccessControl = true) {
2997 LLVM_DEBUG(dbgs() << "Compiling '" << wrapper_name << "'\n");
2998 return I.compileFunction(wrapper_name, wrapper, false /*ifUnique*/,
2999 withAccessControl);
3000}
3001
3002void get_type_as_string(QualType QT, std::string& type_name, ASTContext& C,
3003 PrintingPolicy Policy) {
3004 // TODO: Implement cling desugaring from utils::AST
3005 // cling::utils::Transform::GetPartiallyDesugaredType()
3006 // Desugar template type alias specializations (e.g. std::enable_if_t,
3007 // std::remove_cvref_t). Their printed form can carry expression-level
3008 // template arguments (variable-template references, SFINAE predicates)
3009 // that PrintingPolicy::FullyQualifiedName does not propagate into, so the
3010 // emitted text may reference identifiers like `is_constructible_v` without
3011 // the `std::` qualifier and fail to compile in the wrapper. Regular
3012 // typedefs (e.g. std::string) keep their sugared name.
3013 while (const auto* TST = QT->getAs<TemplateSpecializationType>()) {
3014 if (!TST->isTypeAlias())
3015 break;
3016 QT = TST->desugar();
3017 }
3018 if (!QT->isTypedefNameType() || QT->isBuiltinType())
3019 QT = QT.getDesugaredType(C);
3020 Policy.Suppress_Elab = true;
3021 Policy.SuppressTagKeyword = !QT->isEnumeralType();
3022 Policy.FullyQualifiedName = true;
3023 Policy.UsePreferredNames = false;
3024 QT.getAsStringInternal(type_name, Policy);
3025}
3026
3027static void GetDeclName(const clang::Decl* D, ASTContext& Context,
3028 std::string& name) {
3029 // Helper to extract a fully qualified name from a Decl
3030 PrintingPolicy Policy(Context.getPrintingPolicy());
3031 Policy.SuppressTagKeyword = true;
3032 Policy.SuppressUnwrittenScope = true;
3033 Policy.Print_Canonical_Types = true;
3034 if (const auto* TD = dyn_cast<TypeDecl>(D)) {
3035 // This is a class, struct, or union member.
3036 QualType QT;
3037 if (const auto* Typedef = dyn_cast<const TypedefDecl>(TD)) {
3038 // Handle the typedefs to anonymous types.
3039 QT = Typedef->getTypeSourceInfo()->getType();
3040 } else
3041 QT = compat::GetTypeFromDecl(TD);
3042 get_type_as_string(QT, name, Context, Policy);
3043 } else if (const auto* ND = dyn_cast<NamedDecl>(D)) {
3044 // This is a namespace member.
3045 raw_string_ostream stream(name);
3046 ND->getNameForDiagnostic(stream, Policy, /*Qualified=*/true);
3047 stream.flush();
3048 }
3049}
3050
3051void collect_type_info(const FunctionDecl* FD, QualType& QT,
3052 std::ostringstream& typedefbuf,
3053 std::ostringstream& callbuf, std::string& type_name,
3054 EReferenceType& refType, bool& isPointer,
3055 int indent_level, bool forArgument) {
3056 //
3057 // Collect information about the TyRef of a function parameter
3058 // needed for building the wrapper function.
3059 //
3060 ASTContext& C = FD->getASTContext();
3061 PrintingPolicy Policy(C.getPrintingPolicy());
3062 Policy.Suppress_Elab = true;
3063 refType = kNotReference;
3064 if (QT->isRecordType()) {
3065 if (forArgument) {
3066 get_type_as_string(QT, type_name, C, Policy);
3067 return;
3068 }
3069 if (auto* CXXRD = QT->getAsCXXRecordDecl()) {
3070 if (CXXRD->isLambda()) {
3071 std::string fn_name;
3072 llvm::raw_string_ostream stream(fn_name);
3073 Policy.FullyQualifiedName = true;
3074 Policy.SuppressUnwrittenScope = true;
3075 FD->getNameForDiagnostic(stream, Policy,
3076 /*Qualified=*/false);
3077 type_name = "__internal_CppInterOp::function<decltype(" + fn_name +
3078 ")>::result_type";
3079 return;
3080 }
3081 }
3082 }
3083 if (QT.getNonReferenceType()->isFunctionPointerType() ||
3084 QT.getNonReferenceType()->isFunctionProtoType()) {
3085 clang::QualType NRQT = QT.getNonReferenceType();
3086 std::string fp_typedef_name;
3087 {
3088 std::ostringstream nm;
3089 nm << "FP" << gWrapperSerial++;
3090 type_name = nm.str();
3091 raw_string_ostream OS(fp_typedef_name);
3092 NRQT.print(OS, Policy, type_name);
3093 OS.flush();
3094 }
3095
3096 indent(typedefbuf, indent_level);
3097
3098 typedefbuf << "typedef " << fp_typedef_name << ";\n";
3099
3100 if (QT->isRValueReferenceType())
3101 refType = kRValueReference;
3102 else
3103 refType = kLValueReference;
3104 return;
3105 } else if (QT->isMemberPointerType()) {
3106 std::string mp_typedef_name;
3107 {
3108 std::ostringstream nm;
3109 nm << "MP" << gWrapperSerial++;
3110 type_name = nm.str();
3111 raw_string_ostream OS(mp_typedef_name);
3112 QT.print(OS, Policy, type_name);
3113 OS.flush();
3114 }
3115
3116 indent(typedefbuf, indent_level);
3117
3118 typedefbuf << "typedef " << mp_typedef_name << ";\n";
3119 return;
3120 } else if (QT->isPointerType()) {
3121 isPointer = true;
3122 QT = cast<clang::PointerType>(QT.getCanonicalType())->getPointeeType();
3123 } else if (QT->isReferenceType()) {
3124 if (QT->isRValueReferenceType())
3125 refType = kRValueReference;
3126 else
3127 refType = kLValueReference;
3128 QT = cast<ReferenceType>(QT.getCanonicalType())->getPointeeType();
3129 }
3130 // Fall through for the array TyRef to deal with reference/pointer ro array
3131 // TyRef.
3132 if (QT->isArrayType()) {
3133 std::string ar_typedef_name;
3134 {
3135 std::ostringstream ar;
3136 ar << "AR" << gWrapperSerial++;
3137 type_name = ar.str();
3138 raw_string_ostream OS(ar_typedef_name);
3139 QT.print(OS, Policy, type_name);
3140 OS.flush();
3141 }
3142 indent(typedefbuf, indent_level);
3143 typedefbuf << "typedef " << ar_typedef_name << ";\n";
3144 return;
3145 }
3146 get_type_as_string(QT, type_name, C, Policy);
3147}
3148
3149void make_narg_ctor(const FunctionDecl* FD, const unsigned N,
3150 std::ostringstream& typedefbuf, std::ostringstream& callbuf,
3151 const std::string& class_name, int indent_level,
3152 bool array = false) {
3153 // Make a code string that follows this pattern:
3154 //
3155 // ClassName(args...)
3156 // OR
3157 // ClassName[nary] // array of objects
3158 //
3159
3160 if (array)
3161 callbuf << class_name << "[nary]";
3162 else
3163 callbuf << class_name;
3164
3165 // We cannot pass initialization parameters if we call array new
3166 if (N && !array) {
3167 callbuf << "(";
3168 for (unsigned i = 0U; i < N; ++i) {
3169 const ParmVarDecl* PVD = FD->getParamDecl(i);
3170 QualType Ty = PVD->getType();
3171 QualType QT = Ty.getCanonicalType();
3172 std::string type_name;
3173 EReferenceType refType = kNotReference;
3174 bool isPointer = false;
3175 collect_type_info(FD, QT, typedefbuf, callbuf, type_name, refType,
3176 isPointer, indent_level, true);
3177 if (i) {
3178 callbuf << ',';
3179 if (i % 2) {
3180 callbuf << ' ';
3181 } else {
3182 callbuf << "\n";
3183 indent(callbuf, indent_level);
3184 }
3185 }
3186 if (refType != kNotReference) {
3187 callbuf << "(" << type_name.c_str()
3188 << (refType == kLValueReference ? "&" : "&&") << ")*("
3189 << type_name.c_str() << "*)args[" << i << "]";
3190 } else if (isPointer) {
3191 callbuf << "*(" << type_name.c_str() << "**)args[" << i << "]";
3192 } else {
3193 callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
3194 }
3195 }
3196 callbuf << ")";
3197 }
3198 // This can be zero or default-initialized
3199 else if (const auto* CD = dyn_cast<CXXConstructorDecl>(FD);
3200 CD && CD->isDefaultConstructor() && !array) {
3201 callbuf << "()";
3202 }
3203}
3204
3205const DeclContext* get_non_transparent_decl_context(const FunctionDecl* FD) {
3206 const auto* DC = FD->getDeclContext();
3207 while (DC->isTransparentContext()) {
3208 DC = DC->getParent();
3209 assert(DC && "All transparent contexts should have a parent!");
3210 }
3211 return DC;
3212}
3213
3214void make_narg_call(const FunctionDecl* FD, const std::string& return_type,
3215 const unsigned N, std::ostringstream& typedefbuf,
3216 std::ostringstream& callbuf, const std::string& class_name,
3217 int indent_level) {
3218 //
3219 // Make a code string that follows this pattern:
3220 //
3221 // ((<class>*)obj)-><method>(*(<arg-i-TyRef>*)args[i], ...)
3222 //
3223
3224 // Sometimes it's necessary that we cast the function we want to call
3225 // first to its explicit function TyRef before calling it. This is supposed
3226 // to prevent that we accidentally ending up in a function that is not
3227 // the one we're supposed to call here (e.g. because the C++ function
3228 // lookup decides to take another function that better fits). This method
3229 // has some problems, e.g. when we call a function with default arguments
3230 // and we don't provide all arguments, we would fail with this pattern.
3231 // Same applies with member methods which seem to cause parse failures
3232 // even when we supply the object parameter. Therefore we only use it in
3233 // cases where we know it works and set this variable to true when we do.
3234
3235 // true if not a overloaded operators or the overloaded operator is call
3236 // operator
3237 bool op_flag = !FD->isOverloadedOperator() ||
3238 FD->getOverloadedOperator() == clang::OO_Call;
3239
3240 bool ShouldCastFunction = !isa<CXXMethodDecl>(FD) &&
3241 N == FD->getNumParams() && op_flag &&
3242 !FD->isTemplateInstantiation();
3243 if (ShouldCastFunction) {
3244 callbuf << "(";
3245 callbuf << "(";
3246 callbuf << return_type << " (&)";
3247 {
3248 callbuf << "(";
3249 for (unsigned i = 0U; i < N; ++i) {
3250 if (i) {
3251 callbuf << ',';
3252 if (i % 2) {
3253 callbuf << ' ';
3254 } else {
3255 callbuf << "\n";
3256 indent(callbuf, indent_level + 1);
3257 }
3258 }
3259 const ParmVarDecl* PVD = FD->getNonObjectParameter(i);
3260 QualType Ty = PVD->getType();
3261 QualType QT = Ty.getCanonicalType();
3262 std::string arg_type;
3263 ASTContext& C = FD->getASTContext();
3264 get_type_as_string(QT, arg_type, C, C.getPrintingPolicy());
3265 callbuf << arg_type;
3266 }
3267 if (FD->isVariadic())
3268 callbuf << ", ...";
3269 callbuf << ")";
3270 }
3271
3272 callbuf << ")";
3273 }
3274
3275 if (const auto* MD = dyn_cast<CXXMethodDecl>(FD)) {
3276 // This is a class, struct, or union member.
3277 // An rvalue-ref-qualified method must be called on an rvalue: bind the
3278 // receiver with static_cast<T&&>. Covers `f() &&` and `this T&&` (the
3279 // latter leaves getRefQualifier() == RQ_None).
3280 bool rvalue_ref = MD->getRefQualifier() == clang::RQ_RValue ||
3281 (MD->hasCXXExplicitFunctionObjectParameter() &&
3282 MD->getParamDecl(0)->getType()->isRValueReferenceType());
3283 if (rvalue_ref)
3284 callbuf << "static_cast<" << class_name << "&&>(*(" << class_name
3285 << "*)obj).";
3286 else if (MD->isConst())
3287 callbuf << "((const " << class_name << "*)obj)->";
3288 else
3289 callbuf << "((" << class_name << "*)obj)->";
3290
3291 if (op_flag)
3292 callbuf << class_name << "::";
3293 } else if (isa<NamedDecl>(get_non_transparent_decl_context(FD))) {
3294 // This is a namespace member.
3295 if (op_flag || N <= 1)
3296 callbuf << class_name << "::";
3297 }
3298 // callbuf << fMethod->Name() << "(";
3299 {
3300 std::string name;
3301 {
3302 std::string complete_name;
3303 llvm::raw_string_ostream stream(complete_name);
3304 PrintingPolicy PP = FD->getASTContext().getPrintingPolicy();
3305 PP.FullyQualifiedName = true;
3306 PP.SuppressUnwrittenScope = true;
3307 PP.Suppress_Elab = true;
3308 FD->getNameForDiagnostic(stream, PP,
3309 /*Qualified=*/false);
3310 name = complete_name;
3311
3312 // If a template has consecutive parameter packs, then it is impossible to
3313 // use the explicit name in the wrapper, since the TyRef deduction is what
3314 // determines the split of the packs. Instead, we'll revert to the
3315 // non-templated function name and hope that the TyRef casts in the
3316 // wrapper will suffice.
3317 std::string simple_name = FD->getNameAsString();
3318 if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) {
3319 const auto* FTDecl =
3320 llvm::dyn_cast<FunctionTemplateDecl>(FD->getPrimaryTemplate());
3321 if (FTDecl) {
3322 auto* templateParms = FTDecl->getTemplateParameters();
3323 int numPacks = 0;
3324 for (size_t iParam = 0, nParams = templateParms->size();
3325 iParam < nParams; ++iParam) {
3326 if (templateParms->getParam(iParam)->isTemplateParameterPack())
3327 numPacks += 1;
3328 else
3329 numPacks = 0;
3330 }
3331 if (numPacks > 1) {
3332 name = simple_name;
3333 }
3334 }
3335 }
3336 if (FD->isOverloadedOperator())
3337 name = simple_name;
3338 }
3339 if (op_flag || N <= 1)
3340 callbuf << name;
3341 }
3342 if (ShouldCastFunction)
3343 callbuf << ")";
3344
3345 callbuf << "(";
3346 for (unsigned i = 0U; i < N; ++i) {
3347 const ParmVarDecl* PVD = FD->getNonObjectParameter(i);
3348 QualType Ty = PVD->getType();
3349 QualType QT = Ty.getCanonicalType();
3350 std::string type_name;
3351 EReferenceType refType = kNotReference;
3352 bool isPointer = false;
3353 collect_type_info(FD, QT, typedefbuf, callbuf, type_name, refType,
3354 isPointer, indent_level, true);
3355
3356 if (i) {
3357 if (op_flag) {
3358 callbuf << ", ";
3359 } else {
3360 callbuf << ' '
3361 << clang::getOperatorSpelling(FD->getOverloadedOperator())
3362 << ' ';
3363 }
3364 }
3365
3366 CXXRecordDecl* rtdecl = QT->getAsCXXRecordDecl();
3367 if (refType != kNotReference) {
3368 callbuf << "(" << type_name.c_str()
3369 << (refType == kLValueReference ? "&" : "&&") << ")*("
3370 << type_name.c_str() << "*)args[" << i << "]";
3371 } else if (isPointer) {
3372 callbuf << "*(" << type_name.c_str() << "**)args[" << i << "]";
3373 } else if (rtdecl &&
3374 (rtdecl->hasTrivialCopyConstructor() &&
3375 !rtdecl->hasSimpleCopyConstructor()) &&
3376 rtdecl->hasMoveConstructor()) {
3377 // By-value construction; this may either copy or move, but there is no
3378 // information here in terms of intent. Thus, simply assume that the
3379 // intent is to move if there is no viable copy constructor (ie. if the
3380 // code would otherwise fail to even compile). There does not appear to be
3381 // a simple way of determining whether a viable copy constructor exists,
3382 // so check for the most common case: the trivial one, but not uniquely
3383 // available, while there is a move constructor.
3384
3385 // Move construction as needed for classes (note that this is
3386 // implicit). Emit `std::move`'s expansion directly rather than the
3387 // name: a cast to T&& is the definition of std::move for
3388 // non-reference T ([utility.swap]), and this avoids pulling
3389 // <utility> into the user's TU just to obtain the name. It also
3390 // sidesteps the `getSema().getStdNamespace()->lookup(...)` call,
3391 // which dereferences a nullptr when no `std::` has been parsed
3392 // yet in this interpreter's TU.
3393 callbuf << "static_cast<" << type_name.c_str() << "&&>(*("
3394 << type_name.c_str() << "*)args[" << i << "])";
3395 } else {
3396 // pointer falls back to non-pointer case; the argument preserves
3397 // the "pointerness" (i.e. doesn't reference the value).
3398 callbuf << "*(" << type_name.c_str() << "*)args[" << i << "]";
3399 }
3400 }
3401 callbuf << ")";
3402}
3403
3404void make_narg_ctor_with_return(const FunctionDecl* FD, const unsigned N,
3405 const std::string& class_name,
3406 std::ostringstream& buf, int indent_level) {
3407 // Make a code string that follows this pattern:
3408 //
3409 // Array new if nary has been passed, and nargs is 0 (must be default ctor)
3410 // if (nary) {
3411 // (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName[nary] :
3412 // new ClassName[nary];
3413 // }
3414 // else {
3415 // (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName(args...)
3416 // : new ClassName(args...);
3417 // }
3418 {
3419 std::ostringstream typedefbuf;
3420 std::ostringstream callbuf;
3421 //
3422 // Write the return value assignment part.
3423 //
3424 indent(callbuf, indent_level);
3425 const auto* CD = dyn_cast<CXXConstructorDecl>(FD);
3426
3427 // Activate this block only if array new is possible
3428 // if (nary) {
3429 // (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName[nary]
3430 // : new ClassName[nary];
3431 // }
3432 // else {
3433 if (CD->isDefaultConstructor()) {
3434 callbuf << "if (nary > 1) {\n";
3435 indent(callbuf, indent_level);
3436 callbuf << "(*(" << class_name << "**)ret) = ";
3437 callbuf << "(is_arena) ? new (*(" << class_name << "**)ret) ";
3438 make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
3439 true);
3440
3441 callbuf << ": new ";
3442 //
3443 // Write the actual expression.
3444 //
3445 make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level,
3446 true);
3447 //
3448 // End the new expression statement.
3449 //
3450 callbuf << ";\n";
3451 indent(callbuf, indent_level);
3452 callbuf << "}\n";
3453 callbuf << "else {\n";
3454 }
3455
3456 // Standard branch:
3457 // (*(ClassName**)ret) = (obj) ? new (*(ClassName**)ret) ClassName(args...)
3458 // : new ClassName(args...);
3459 indent(callbuf, indent_level);
3460 callbuf << "(*(" << class_name << "**)ret) = ";
3461 callbuf << "(is_arena) ? new (*(" << class_name << "**)ret) ";
3462 make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level);
3463
3464 callbuf << ": new ";
3465 //
3466 // Write the actual expression.
3467 //
3468 make_narg_ctor(FD, N, typedefbuf, callbuf, class_name, indent_level);
3469 //
3470 // End the new expression statement.
3471 //
3472 callbuf << ";\n";
3473 indent(callbuf, --indent_level);
3474 if (CD->isDefaultConstructor())
3475 callbuf << "}\n";
3476#if __has_feature(memory_sanitizer)
3477 // Outside the if/else so the array-new (nary > 1) and single-new
3478 // branches are both covered.
3479 indent(callbuf, indent_level);
3480 callbuf << "__msan_unpoison(*(void**)ret, sizeof(" << class_name
3481 << ") * (nary > 1 ? nary : 1));\n";
3482#endif
3483
3484 //
3485 // Output the whole new expression and return statement.
3486 //
3487 buf << typedefbuf.str() << callbuf.str();
3488 }
3489}
3490
3491void make_narg_call_with_return(compat::Interpreter& I, const FunctionDecl* FD,
3492 const unsigned N, const std::string& class_name,
3493 std::ostringstream& buf, int indent_level) {
3494 // Make a code string that follows this pattern:
3495 //
3496 // if (ret) {
3497 // new (ret) (return_type) ((class_name*)obj)->func(args...);
3498 // }
3499 // else {
3500 // (void)(((class_name*)obj)->func(args...));
3501 // }
3502 //
3503 if (const auto* CD = dyn_cast<CXXConstructorDecl>(FD)) {
3504 if (N <= 1 && llvm::isa<UsingShadowDecl>(FD)) {
3505 auto SpecMemKind = I.getCI()->getSema().getSpecialMember(CD);
3506 if ((N == 0 && SpecMemKind == CXXSpecialMemberKind::DefaultConstructor) ||
3507 (N == 1 && (SpecMemKind == CXXSpecialMemberKind::CopyConstructor ||
3508 SpecMemKind == CXXSpecialMemberKind::MoveConstructor))) {
3509 // Using declarations cannot inject special members; do not call
3510 // them as such. This might happen by using `Base(Base&, int = 12)`,
3511 // which is fine to be called as `Derived d(someBase, 42)` but not
3512 // as copy constructor of `Derived`.
3513 return;
3514 }
3515 }
3516 make_narg_ctor_with_return(FD, N, class_name, buf, indent_level);
3517 return;
3518 }
3519 QualType QT = FD->getReturnType();
3520 if (QT->isVoidType()) {
3521 std::ostringstream typedefbuf;
3522 std::ostringstream callbuf;
3523 indent(callbuf, indent_level);
3524 make_narg_call(FD, "void", N, typedefbuf, callbuf, class_name,
3525 indent_level);
3526 callbuf << ";\n";
3527 indent(callbuf, indent_level);
3528 callbuf << "return;\n";
3529 buf << typedefbuf.str() << callbuf.str();
3530 } else {
3531 indent(buf, indent_level);
3532
3533 std::string type_name;
3534 EReferenceType refType = kNotReference;
3535 bool isPointer = false;
3536
3537 std::ostringstream typedefbuf;
3538 std::ostringstream callbuf;
3539
3540 collect_type_info(FD, QT, typedefbuf, callbuf, type_name, refType,
3541 isPointer, indent_level, false);
3542
3543 buf << typedefbuf.str();
3544
3545 buf << "if (ret) {\n";
3546 ++indent_level;
3547 {
3548 //
3549 // Write the placement part of the placement new.
3550 //
3551 indent(callbuf, indent_level);
3552 callbuf << "new (ret) ";
3553 //
3554 // Write the TyRef part of the placement new.
3555 //
3556 callbuf << "(" << type_name.c_str();
3557 if (refType != kNotReference) {
3558 callbuf << "*) (&";
3559 type_name += "&";
3560 } else if (isPointer) {
3561 callbuf << "*) (";
3562 type_name += "*";
3563 } else {
3564 callbuf << ") (";
3565 }
3566 //
3567 // Write the actual function call.
3568 //
3569 make_narg_call(FD, type_name, N, typedefbuf, callbuf, class_name,
3570 indent_level);
3571 //
3572 // End the placement new.
3573 //
3574 callbuf << ");\n";
3575#if __has_feature(memory_sanitizer)
3576 indent(callbuf, indent_level);
3577 callbuf << "__msan_unpoison(ret, sizeof(" << type_name << "));\n";
3578#endif
3579 indent(callbuf, indent_level);
3580 callbuf << "return;\n";
3581 //
3582 // Output the whole placement new expression and return statement.
3583 //
3584 buf << typedefbuf.str() << callbuf.str();
3585 }
3586 --indent_level;
3587 indent(buf, indent_level);
3588 buf << "}\n";
3589 indent(buf, indent_level);
3590 buf << "else {\n";
3591 ++indent_level;
3592 {
3593 std::ostringstream typedefbuf;
3594 std::ostringstream callbuf;
3595 indent(callbuf, indent_level);
3596 callbuf << "(void)(";
3597 make_narg_call(FD, type_name, N, typedefbuf, callbuf, class_name,
3598 indent_level);
3599 callbuf << ");\n";
3600 indent(callbuf, indent_level);
3601 callbuf << "return;\n";
3602 buf << typedefbuf.str() << callbuf.str();
3603 }
3604 --indent_level;
3605 indent(buf, indent_level);
3606 buf << "}\n";
3607 }
3608}
3609
3610int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD,
3611 std::string& wrapper_name, std::string& wrapper) {
3612 assert(FD && "generate_wrapper called without a function decl!");
3613 ASTContext& Context = FD->getASTContext();
3614 //
3615 // Get the class or namespace name.
3616 //
3617 std::string class_name;
3618 const clang::DeclContext* DC = get_non_transparent_decl_context(FD);
3619 GetDeclName(cast<Decl>(DC), Context, class_name);
3620 //
3621 // Check to make sure that we can
3622 // instantiate and codegen this function.
3623 //
3624 bool needInstantiation = false;
3625 const FunctionDecl* Definition = 0;
3627 if (!FD->isDefined(Definition)) {
3628 FunctionDecl::TemplatedKind TK = FD->getTemplatedKind();
3629 switch (TK) {
3630 case FunctionDecl::TK_NonTemplate: {
3631 // Ordinary function, not a template specialization.
3632 // Note: This might be ok, the body might be defined
3633 // in a library, and all we have seen is the
3634 // header file.
3635 // llvm::errs() << "TClingCallFunc::make_wrapper" << ":" <<
3636 // "Cannot make wrapper for a function which is "
3637 // "declared but not defined!";
3638 // return 0;
3639 } break;
3640 case FunctionDecl::TK_FunctionTemplate: {
3641 // This decl is actually a function template,
3642 // not a function at all.
3643 llvm::errs() << "TClingCallFunc::make_wrapper"
3644 << ":"
3645 << "Cannot make wrapper for a function template!";
3646 return 0;
3647 } break;
3648 case FunctionDecl::TK_MemberSpecialization: {
3649 // This function is the result of instantiating an ordinary
3650 // member function of a class template, or of instantiating
3651 // an ordinary member function of a class member of a class
3652 // template, or of specializing a member function template
3653 // of a class template, or of specializing a member function
3654 // template of a class member of a class template.
3655 if (!FD->isTemplateInstantiation()) {
3656 // We are either TSK_Undeclared or
3657 // TSK_ExplicitSpecialization.
3658 // Note: This might be ok, the body might be defined
3659 // in a library, and all we have seen is the
3660 // header file.
3661 // llvm::errs() << "TClingCallFunc::make_wrapper" << ":" <<
3662 // "Cannot make wrapper for a function template "
3663 // "explicit specialization which is declared "
3664 // "but not defined!";
3665 // return 0;
3666 break;
3667 }
3668 const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern();
3669 if (!Pattern) {
3670 llvm::errs() << "TClingCallFunc::make_wrapper"
3671 << ":"
3672 << "Cannot make wrapper for a member function "
3673 "instantiation with no pattern!";
3674 return 0;
3675 }
3676 FunctionDecl::TemplatedKind PTK = Pattern->getTemplatedKind();
3677 TemplateSpecializationKind PTSK =
3678 Pattern->getTemplateSpecializationKind();
3679 if (
3680 // The pattern is an ordinary member function.
3681 (PTK == FunctionDecl::TK_NonTemplate) ||
3682 // The pattern is an explicit specialization, and
3683 // so is not a template.
3684 ((PTK != FunctionDecl::TK_FunctionTemplate) &&
3685 ((PTSK == TSK_Undeclared) ||
3686 (PTSK == TSK_ExplicitSpecialization)))) {
3687 // Note: This might be ok, the body might be defined
3688 // in a library, and all we have seen is the
3689 // header file.
3690 break;
3691 } else if (!Pattern->hasBody()) {
3692 llvm::errs() << "TClingCallFunc::make_wrapper"
3693 << ":"
3694 << "Cannot make wrapper for a member function "
3695 "instantiation with no body!";
3696 return 0;
3697 }
3698 if (FD->isImplicitlyInstantiable()) {
3699 needInstantiation = true;
3700 }
3701 } break;
3702 case FunctionDecl::TK_FunctionTemplateSpecialization: {
3703 // This function is the result of instantiating a function
3704 // template or possibly an explicit specialization of a
3705 // function template. Could be a namespace DRef function or a
3706 // member function.
3707 if (!FD->isTemplateInstantiation()) {
3708 // We are either TSK_Undeclared or
3709 // TSK_ExplicitSpecialization.
3710 // Note: This might be ok, the body might be defined
3711 // in a library, and all we have seen is the
3712 // header file.
3713 // llvm::errs() << "TClingCallFunc::make_wrapper" << ":" <<
3714 // "Cannot make wrapper for a function template "
3715 // "explicit specialization which is declared "
3716 // "but not defined!";
3717 // return 0;
3718 break;
3719 }
3720 const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern();
3721 if (!Pattern) {
3722 llvm::errs() << "TClingCallFunc::make_wrapper"
3723 << ":"
3724 << "Cannot make wrapper for a function template"
3725 "instantiation with no pattern!";
3726 return 0;
3727 }
3728 FunctionDecl::TemplatedKind PTK = Pattern->getTemplatedKind();
3729 TemplateSpecializationKind PTSK =
3730 Pattern->getTemplateSpecializationKind();
3731 if (
3732 // The pattern is an ordinary member function.
3733 (PTK == FunctionDecl::TK_NonTemplate) ||
3734 // The pattern is an explicit specialization, and
3735 // so is not a template.
3736 ((PTK != FunctionDecl::TK_FunctionTemplate) &&
3737 ((PTSK == TSK_Undeclared) ||
3738 (PTSK == TSK_ExplicitSpecialization)))) {
3739 // Note: This might be ok, the body might be defined
3740 // in a library, and all we have seen is the
3741 // header file.
3742 break;
3743 }
3744 if (!GetFunctionAddress(FD)) {
3745 if (!Pattern->hasBody()) {
3746 llvm::errs() << "TClingCallFunc::make_wrapper"
3747 << ":"
3748 << "Cannot make wrapper for a function template "
3749 << "instantiation with no body!";
3750 return 0;
3751 }
3752 if (FD->isImplicitlyInstantiable()) {
3753 needInstantiation = true;
3754 }
3755 }
3756 } break;
3757 case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
3758 // This function is the result of instantiating or
3759 // specializing a member function of a class template,
3760 // or a member function of a class member of a class template,
3761 // or a member function template of a class template, or a
3762 // member function template of a class member of a class
3763 // template where at least some part of the function is
3764 // dependent on a template argument.
3765 if (!FD->isTemplateInstantiation()) {
3766 // We are either TSK_Undeclared or
3767 // TSK_ExplicitSpecialization.
3768 // Note: This might be ok, the body might be defined
3769 // in a library, and all we have seen is the
3770 // header file.
3771 // llvm::errs() << "TClingCallFunc::make_wrapper" << ":" <<
3772 // "Cannot make wrapper for a dependent function "
3773 // "template explicit specialization which is declared "
3774 // "but not defined!";
3775 // return 0;
3776 break;
3777 }
3778 const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern();
3779 if (!Pattern) {
3780 llvm::errs() << "TClingCallFunc::make_wrapper"
3781 << ":"
3782 << "Cannot make wrapper for a dependent function template"
3783 "instantiation with no pattern!";
3784 return 0;
3785 }
3786 FunctionDecl::TemplatedKind PTK = Pattern->getTemplatedKind();
3787 TemplateSpecializationKind PTSK =
3788 Pattern->getTemplateSpecializationKind();
3789 if (
3790 // The pattern is an ordinary member function.
3791 (PTK == FunctionDecl::TK_NonTemplate) ||
3792 // The pattern is an explicit specialization, and
3793 // so is not a template.
3794 ((PTK != FunctionDecl::TK_FunctionTemplate) &&
3795 ((PTSK == TSK_Undeclared) ||
3796 (PTSK == TSK_ExplicitSpecialization)))) {
3797 // Note: This might be ok, the body might be defined
3798 // in a library, and all we have seen is the
3799 // header file.
3800 break;
3801 }
3802 if (!Pattern->hasBody()) {
3803 llvm::errs() << "TClingCallFunc::make_wrapper"
3804 << ":"
3805 << "Cannot make wrapper for a dependent function template"
3806 "instantiation with no body!";
3807 return 0;
3808 }
3809 if (FD->isImplicitlyInstantiable()) {
3810 needInstantiation = true;
3811 }
3812 } break;
3813 default: {
3814 // Will only happen if clang implementation changes.
3815 // Protect ourselves in case that happens.
3816 llvm::errs() << "TClingCallFunc::make_wrapper"
3817 << ":"
3818 << "Unhandled template kind!";
3819 return 0;
3820 } break;
3821 }
3822 // We do not set needInstantiation to true in these cases:
3823 //
3824 // isInvalidDecl()
3825 // TSK_Undeclared
3826 // TSK_ExplicitInstantiationDefinition
3827 // TSK_ExplicitSpecialization && !getClassScopeSpecializationPattern()
3828 // TSK_ExplicitInstantiationDeclaration &&
3829 // getTemplateInstantiationPattern() &&
3830 // PatternDecl->hasBody() &&
3831 // !PatternDecl->isInlined()
3832 //
3833 // Set it true in these cases:
3834 //
3835 // TSK_ImplicitInstantiation
3836 // TSK_ExplicitInstantiationDeclaration && (!getPatternDecl() ||
3837 // !PatternDecl->hasBody() || PatternDecl->isInlined())
3838 //
3839 }
3840 if (needInstantiation) {
3841 clang::FunctionDecl* FDmod = const_cast<clang::FunctionDecl*>(FD);
3843
3844 if (!FD->isDefined(Definition)) {
3845 llvm::errs() << "TClingCallFunc::make_wrapper"
3846 << ":"
3847 << "Failed to force template instantiation!";
3848 return 0;
3849 }
3850 }
3851 if (Definition) {
3852 FunctionDecl::TemplatedKind TK = Definition->getTemplatedKind();
3853 switch (TK) {
3854 case FunctionDecl::TK_NonTemplate: {
3855 // Ordinary function, not a template specialization.
3856 if (Definition->isDeleted()) {
3857 llvm::errs() << "TClingCallFunc::make_wrapper"
3858 << ":"
3859 << "Cannot make wrapper for a deleted function!";
3860 return 0;
3861 } else if (Definition->isLateTemplateParsed()) {
3862 llvm::errs() << "TClingCallFunc::make_wrapper"
3863 << ":"
3864 << "Cannot make wrapper for a late template parsed "
3865 "function!";
3866 return 0;
3867 }
3868 // else if (Definition->isDefaulted()) {
3869 // // Might not have a body, but we can still use it.
3870 //}
3871 // else {
3872 // // Has a body.
3873 //}
3874 } break;
3875 case FunctionDecl::TK_FunctionTemplate: {
3876 // This decl is actually a function template,
3877 // not a function at all.
3878 llvm::errs() << "TClingCallFunc::make_wrapper"
3879 << ":"
3880 << "Cannot make wrapper for a function template!";
3881 return 0;
3882 } break;
3883 case FunctionDecl::TK_MemberSpecialization: {
3884 // This function is the result of instantiating an ordinary
3885 // member function of a class template or of a member class
3886 // of a class template.
3887 if (Definition->isDeleted()) {
3888 llvm::errs() << "TClingCallFunc::make_wrapper"
3889 << ":"
3890 << "Cannot make wrapper for a deleted member function "
3891 "of a specialization!";
3892 return 0;
3893 } else if (Definition->isLateTemplateParsed()) {
3894 llvm::errs() << "TClingCallFunc::make_wrapper"
3895 << ":"
3896 << "Cannot make wrapper for a late template parsed "
3897 "member function of a specialization!";
3898 return 0;
3899 }
3900 // else if (Definition->isDefaulted()) {
3901 // // Might not have a body, but we can still use it.
3902 //}
3903 // else {
3904 // // Has a body.
3905 //}
3906 } break;
3907 case FunctionDecl::TK_FunctionTemplateSpecialization: {
3908 // This function is the result of instantiating a function
3909 // template or possibly an explicit specialization of a
3910 // function template. Could be a namespace DRef function or a
3911 // member function.
3912 if (Definition->isDeleted()) {
3913 llvm::errs() << "TClingCallFunc::make_wrapper"
3914 << ":"
3915 << "Cannot make wrapper for a deleted function "
3916 "template specialization!";
3917 return 0;
3918 } else if (Definition->isLateTemplateParsed()) {
3919 llvm::errs() << "TClingCallFunc::make_wrapper"
3920 << ":"
3921 << "Cannot make wrapper for a late template parsed "
3922 "function template specialization!";
3923 return 0;
3924 }
3925 // else if (Definition->isDefaulted()) {
3926 // // Might not have a body, but we can still use it.
3927 //}
3928 // else {
3929 // // Has a body.
3930 //}
3931 } break;
3932 case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
3933 // This function is the result of instantiating or
3934 // specializing a member function of a class template,
3935 // or a member function of a class member of a class template,
3936 // or a member function template of a class template, or a
3937 // member function template of a class member of a class
3938 // template where at least some part of the function is
3939 // dependent on a template argument.
3940 if (Definition->isDeleted()) {
3941 llvm::errs() << "TClingCallFunc::make_wrapper"
3942 << ":"
3943 << "Cannot make wrapper for a deleted dependent function "
3944 "template specialization!";
3945 return 0;
3946 } else if (Definition->isLateTemplateParsed()) {
3947 llvm::errs() << "TClingCallFunc::make_wrapper"
3948 << ":"
3949 << "Cannot make wrapper for a late template parsed "
3950 "dependent function template specialization!";
3951 return 0;
3952 }
3953 // else if (Definition->isDefaulted()) {
3954 // // Might not have a body, but we can still use it.
3955 //}
3956 // else {
3957 // // Has a body.
3958 //}
3959 } break;
3960 default: {
3961 // Will only happen if clang implementation changes.
3962 // Protect ourselves in case that happens.
3963 llvm::errs() << "TClingCallFunc::make_wrapper"
3964 << ":"
3965 << "Unhandled template kind!";
3966 return 0;
3967 } break;
3968 }
3969 }
3970 // A C++23 explicit object parameter is bound via the `obj->` receiver of the
3971 // emitted member call, not from the args[] array, so it is excluded from the
3972 // wrapper's argument arity (see make_narg_call).
3973 unsigned min_args = FD->getMinRequiredExplicitArguments();
3974 unsigned num_params = FD->getNumNonObjectParams();
3975 //
3976 // Make the wrapper name.
3977 //
3978 {
3979 std::ostringstream buf;
3980 buf << "__jc";
3981 // const auto* ND = dyn_cast<NamedDecl>(FD);
3982 // std::string mn;
3983 // fInterp->maybeMangleDeclName(ND, mn);
3984 // buf << '_' << mn;
3985 buf << '_' << gWrapperSerial++;
3986 wrapper_name = buf.str();
3987 }
3988 //
3989 // Write the wrapper code.
3990 // FIXME: this should be synthesized into the AST!
3991 //
3992 int indent_level = 0;
3993 std::ostringstream buf;
3994 buf << "#pragma clang diagnostic push\n"
3995 "#pragma clang diagnostic ignored \"-Wformat-security\"\n";
3996#if __has_feature(memory_sanitizer)
3997 // Declared (not #include'd) so the wrapper compiles with no need
3998 // for sanitizer headers in the JIT search path.
3999 buf << "extern \"C\" void __msan_unpoison(const volatile void*, "
4000 "unsigned long);\n";
4001#endif
4002 buf << "__attribute__((used)) "
4003 "__attribute__((annotate(\"__cling__ptrcheck(off)\")))\n"
4004 "extern \"C\" void ";
4005 buf << wrapper_name;
4006 if (Cpp::IsConstructor(wrap<ConstFuncRef>(FD))) {
4007 buf << "(void* ret, unsigned long nary, unsigned long nargs, void** args, "
4008 "void* is_arena)\n"
4009 "{\n";
4010 } else
4011 buf << "(void* obj, unsigned long nargs, void** args, void* ret)\n"
4012 "{\n";
4013
4014 ++indent_level;
4015 if (min_args == num_params) {
4016 // No parameters with defaults.
4017 make_narg_call_with_return(I, FD, num_params, class_name, buf,
4018 indent_level);
4019 } else {
4020 // We need one function call clause compiled for every
4021 // possible number of arguments per call.
4022 for (unsigned N = min_args; N <= num_params; ++N) {
4023 indent(buf, indent_level);
4024 buf << "if (nargs == " << N << ") {\n";
4025 ++indent_level;
4026 make_narg_call_with_return(I, FD, N, class_name, buf, indent_level);
4027 --indent_level;
4028 indent(buf, indent_level);
4029 buf << "}\n";
4030 }
4031 }
4032 --indent_level;
4033 buf << "}\n"
4034 "#pragma clang diagnostic pop";
4035 wrapper = buf.str();
4036 return 1;
4037}
4038
4039JitCall::GenericCall make_wrapper(compat::Interpreter& I,
4040 const FunctionDecl* FD) {
4041 auto& WrapperStore = getInterpInfo(&I).WrapperStore;
4042
4043 auto R = WrapperStore.find(FD);
4044 if (R != WrapperStore.end())
4045 return (JitCall::GenericCall)R->second;
4046
4047 std::string wrapper_name;
4048 std::string wrapper_code;
4049
4050 if (get_wrapper_code(I, FD, wrapper_name, wrapper_code) == 0)
4051 return 0;
4052
4053 // Log the wrapper source for the crash reproducer.
4054 if (auto* TI = CppInterOp::Tracing::TheTraceInfo) {
4055 std::string FuncName;
4056 llvm::raw_string_ostream FNS(FuncName);
4057 FD->getNameForDiagnostic(FNS, FD->getASTContext().getPrintingPolicy(),
4058 /*Qualified=*/true);
4059 TI->appendToLog(" // === Wrapper for " + FuncName + " ===");
4060 // Emit each line of the wrapper source as a comment.
4061 llvm::StringRef WC(wrapper_code);
4062 while (!WC.empty()) {
4063 auto [Line, Rest] = WC.split('\n');
4064 if (!Line.empty())
4065 TI->appendToLog((" // " + Line).str());
4066 WC = Rest;
4067 }
4068 TI->appendToLog(" // === End wrapper ===");
4069 }
4070
4071 //
4072 // Compile the wrapper code.
4073 //
4074 bool withAccessControl = true;
4075 // We should be able to call private default constructors.
4076 if (auto Ctor = dyn_cast<CXXConstructorDecl>(FD))
4077 withAccessControl = !Ctor->isDefaultConstructor();
4078 void* wrapper =
4079 compile_wrapper(I, wrapper_name, wrapper_code, withAccessControl);
4080 if (wrapper) {
4081 WrapperStore.insert(std::make_pair(FD, wrapper));
4082 } else {
4083 llvm::errs() << "TClingCallFunc::make_wrapper"
4084 << ":"
4085 << "Failed to compile\n"
4086 << "==== SOURCE BEGIN ====\n"
4087 << wrapper_code << "\n"
4088 << "==== SOURCE END ====\n";
4089 }
4090 LLVM_DEBUG(dbgs() << "Compiled '" << (wrapper ? "" : "un")
4091 << "successfully:\n"
4092 << wrapper_code << "'\n");
4093 return (JitCall::GenericCall)wrapper;
4094}
4095
4096// FIXME: Sink in the code duplication from get_wrapper_code.
4097static std::string PrepareStructorWrapper(const Decl* D,
4098 const char* wrapper_prefix,
4099 std::string& class_name) {
4100 ASTContext& Context = D->getASTContext();
4101 GetDeclName(D, Context, class_name);
4102
4103 //
4104 // Make the wrapper name.
4105 //
4106 std::string wrapper_name;
4107 {
4108 std::ostringstream buf;
4109 buf << wrapper_prefix;
4110 // const auto* ND = dyn_cast<NamedDecl>(FD);
4111 // string mn;
4112 // fInterp->maybeMangleDeclName(ND, mn);
4113 // buf << '_dtor_' << mn;
4114 buf << '_' << gWrapperSerial++;
4115 wrapper_name = buf.str();
4116 }
4117
4118 return wrapper_name;
4119}
4120
4121static JitCall::DestructorCall make_dtor_wrapper(compat::Interpreter& interp,
4122 const Decl* D) {
4123 // Make a code string that follows this pattern:
4124 //
4125 // void
4126 // unique_wrapper_ddd(void* obj, unsigned long nary, int withFree)
4127 // {
4128 // if (withFree) {
4129 // if (!nary) {
4130 // delete (ClassName*) obj;
4131 // }
4132 // else {
4133 // delete[] (ClassName*) obj;
4134 // }
4135 // }
4136 // else {
4137 // typedef ClassName DtorName;
4138 // if (!nary) {
4139 // ((ClassName*)obj)->~DtorName();
4140 // }
4141 // else {
4142 // for (unsigned long i = nary - 1; i > -1; --i) {
4143 // (((ClassName*)obj)+i)->~DtorName();
4144 // }
4145 // }
4146 // }
4147 // }
4148 //
4149 //--
4150
4151 auto& DtorWrapperStore = getInterpInfo(&interp).DtorWrapperStore;
4152
4153 auto I = DtorWrapperStore.find(D);
4154 if (I != DtorWrapperStore.end())
4155 return (JitCall::DestructorCall)I->second;
4156
4157 //
4158 // Make the wrapper name.
4159 //
4160 std::string class_name;
4161 std::string wrapper_name = PrepareStructorWrapper(D, "__dtor", class_name);
4162 //
4163 // Write the wrapper code.
4164 //
4165 int indent_level = 0;
4166 std::ostringstream buf;
4167#if CPPINTEROP_ASAN_BUILD
4168 // ASan-only: the ORC JIT's resolution of the delete-expression below
4169 // does not always route through libasan's operator-delete interposer
4170 // (observed for classes with an out-of-line destructor), leaving the
4171 // matching operator-new allocation live in LSan's shadow after the
4172 // real free. Call __lsan_ignore_object on the object first so LSan
4173 // treats the allocation as intentional. Real user-side leaks never
4174 // reach this wrapper and stay fully visible. Exercised by
4175 // FunctionReflection_GetFunctionCallWrapper in the unit tests;
4176 // removing this block makes that test report a leak under LSan CI.
4177 buf << "extern \"C\" void __lsan_ignore_object(const void*);\n";
4178#endif
4179 buf << "__attribute__((used)) ";
4180 buf << "extern \"C\" void ";
4181 buf << wrapper_name;
4182 buf << "(void* obj, unsigned long nary, int withFree)\n";
4183 buf << "{\n";
4184 // if (withFree) {
4185 // __lsan_ignore_object(obj); // ASan builds only
4186 // if (!nary) {
4187 // delete (ClassName*) obj;
4188 // }
4189 // else {
4190 // delete[] (ClassName*) obj;
4191 // }
4192 // }
4193 ++indent_level;
4194 indent(buf, indent_level);
4195 buf << "if (withFree) {\n";
4196 ++indent_level;
4197#if CPPINTEROP_ASAN_BUILD
4198 indent(buf, indent_level);
4199 buf << "__lsan_ignore_object(obj);\n";
4200#endif
4201 indent(buf, indent_level);
4202 buf << "if (!nary) {\n";
4203 ++indent_level;
4204 indent(buf, indent_level);
4205 buf << "delete (" << class_name << "*) obj;\n";
4206 --indent_level;
4207 indent(buf, indent_level);
4208 buf << "}\n";
4209 indent(buf, indent_level);
4210 buf << "else {\n";
4211 ++indent_level;
4212 indent(buf, indent_level);
4213 buf << "delete[] (" << class_name << "*) obj;\n";
4214 --indent_level;
4215 indent(buf, indent_level);
4216 buf << "}\n";
4217 --indent_level;
4218 indent(buf, indent_level);
4219 buf << "}\n";
4220 // else {
4221 // typedef ClassName Nm;
4222 // if (!nary) {
4223 // ((Nm*)obj)->~Nm();
4224 // }
4225 // else {
4226 // for (unsigned long i = nary - 1; i > -1; --i) {
4227 // (((Nm*)obj)+i)->~Nm();
4228 // }
4229 // }
4230 // }
4231 indent(buf, indent_level);
4232 buf << "else {\n";
4233 ++indent_level;
4234 indent(buf, indent_level);
4235 buf << "typedef " << class_name << " Nm;\n";
4236 buf << "if (!nary) {\n";
4237 ++indent_level;
4238 indent(buf, indent_level);
4239 buf << "((Nm*)obj)->~Nm();\n";
4240 --indent_level;
4241 indent(buf, indent_level);
4242 buf << "}\n";
4243 indent(buf, indent_level);
4244 buf << "else {\n";
4245 ++indent_level;
4246 indent(buf, indent_level);
4247 buf << "do {\n";
4248 ++indent_level;
4249 indent(buf, indent_level);
4250 buf << "(((Nm*)obj)+(--nary))->~Nm();\n";
4251 --indent_level;
4252 indent(buf, indent_level);
4253 buf << "} while (nary);\n";
4254 --indent_level;
4255 indent(buf, indent_level);
4256 buf << "}\n";
4257 --indent_level;
4258 indent(buf, indent_level);
4259 buf << "}\n";
4260 // End wrapper.
4261 --indent_level;
4262 buf << "}\n";
4263 // Done.
4264 std::string wrapper(buf.str());
4265 // fprintf(stderr, "%s\n", wrapper.c_str());
4266 //
4267 // Compile the wrapper code.
4268 //
4269 void* F = compile_wrapper(interp, wrapper_name, wrapper,
4270 /*withAccessControl=*/false);
4271 if (F) {
4272 DtorWrapperStore.insert(std::make_pair(D, F));
4273 } else {
4274 llvm::errs() << "make_dtor_wrapper"
4275 << "Failed to compile\n"
4276 << "==== SOURCE BEGIN ====\n"
4277 << wrapper << "\n ==== SOURCE END ====";
4278 }
4279 LLVM_DEBUG(dbgs() << "Compiled '" << (F ? "" : "un") << "successfully:\n"
4280 << wrapper << "'\n");
4281 return (JitCall::DestructorCall)F;
4282}
4283#undef DEBUG_TYPE
4284} // namespace
4285 // End of JitCall Helper Functions
4286
4287CPPINTEROP_API JitCall MakeFunctionCallable(InterpRef I, ConstFuncRef func) {
4288 INTEROP_TRACE(I, func);
4289 const auto* D = unwrap<clang::Decl>(func);
4290 if (!D)
4291 return INTEROP_RETURN(JitCall{});
4292
4293 auto* interp = unwrap<compat::Interpreter>(I);
4294
4295 // FIXME: Unify with make_wrapper.
4296 if (const auto* Dtor = dyn_cast<CXXDestructorDecl>(D)) {
4297 if (auto Wrapper = make_dtor_wrapper(*interp, Dtor->getParent()))
4298 return INTEROP_RETURN(
4299 JitCall(JitCall::kDestructorCall, Wrapper, wrap<ConstFuncRef>(Dtor)));
4300 // FIXME: else error we failed to compile the wrapper.
4301 return INTEROP_RETURN(JitCall{});
4302 }
4303
4304 if (const auto* Ctor = dyn_cast<CXXConstructorDecl>(D)) {
4305 if (auto Wrapper = make_wrapper(*interp, cast<FunctionDecl>(D)))
4306 return INTEROP_RETURN(JitCall(JitCall::kConstructorCall, Wrapper,
4307 wrap<ConstFuncRef>(Ctor)));
4308 // FIXME: else error we failed to compile the wrapper.
4309 return INTEROP_RETURN(JitCall{});
4310 }
4311
4312 if (auto Wrapper = make_wrapper(*interp, cast<FunctionDecl>(D))) {
4313 return INTEROP_RETURN(JitCall(JitCall::kGenericCall, Wrapper,
4314 wrap<ConstFuncRef>(cast<FunctionDecl>(D))));
4315 }
4316 // FIXME: else error we failed to compile the wrapper.
4317 return INTEROP_RETURN(JitCall{});
4318}
4319
4320CPPINTEROP_API JitCall MakeFunctionCallable(ConstFuncRef func) {
4321 INTEROP_TRACE(func);
4323}
4324
4325namespace {
4326#if !defined(CPPINTEROP_USE_CLING) && !defined(EMSCRIPTEN)
4327bool DefineAbsoluteSymbol(compat::Interpreter& I, const char* unmangled_name,
4328 uint64_t address) {
4329 using namespace llvm;
4330 using namespace llvm::orc;
4331
4332 llvm::orc::LLJIT& Jit = *compat::getExecutionEngine(I);
4333 JITDylib& DyLib = *Jit.getProcessSymbolsJITDylib().get();
4334
4335 // mangleAndIntern applies the target DataLayout's symbol prefix
4336 // (leading `_` on Mach-O, no-op on ELF) so the registered key
4337 // matches what the JIT computes when it lowers an IR symbol
4338 // reference for lookup. Plain ES.intern() bypasses the prefix and
4339 // silently breaks lookup on Mach-O.
4340 llvm::orc::SymbolMap InjectedSymbols{
4341 {Jit.mangleAndIntern(unmangled_name),
4342 ExecutorSymbolDef(ExecutorAddr(address), JITSymbolFlags::Exported)}};
4343
4344 if (Error Err = DyLib.define(absoluteSymbols(InjectedSymbols))) {
4345 logAllUnhandledErrors(std::move(Err), errs(),
4346 "DefineAbsoluteSymbol error: ");
4347 return true;
4348 }
4349 return false;
4350}
4351#endif
4352
4353static std::string MakeResourcesPath() {
4354 StringRef Dir;
4355#ifdef LLVM_BINARY_DIR
4356 Dir = LLVM_BINARY_DIR;
4357#else
4358 // Dir is bin/ or lib/, depending on where BinaryPath is.
4359 void* MainAddr = (void*)(intptr_t)GetExecutablePath;
4360 std::string BinaryPath = GetExecutablePath(/*Argv0=*/nullptr, MainAddr);
4361
4362 // build/tools/clang/unittests/Interpreter/Executable -> build/
4363 StringRef Dir = sys::path::parent_path(BinaryPath);
4364
4365 Dir = sys::path::parent_path(Dir);
4366 Dir = sys::path::parent_path(Dir);
4367 Dir = sys::path::parent_path(Dir);
4368 Dir = sys::path::parent_path(Dir);
4369 // Dir = sys::path::parent_path(Dir);
4370#endif // LLVM_BINARY_DIR
4371 llvm::SmallString<128> P(Dir);
4372 llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang",
4373 CLANG_VERSION_MAJOR_STRING);
4374 return std::string(P.str());
4375}
4376
4377void AddLibrarySearchPaths(const std::string& ResourceDir,
4379 // the resource-dir can be of the form
4380 // /prefix/lib/clang/XX or /prefix/lib/llvm-XX/lib/clang/XX
4381 // where XX represents version
4382 // the corresponing path we want to add are
4383 // /prefix/lib/clang/XX/lib, /prefix/lib/, and
4384 // /prefix/lib/llvm-XX/lib/clang/XX/lib, /prefix/lib/llvm-XX/lib/,
4385 // /prefix/lib/
4386 std::string path1 = ResourceDir + "/lib";
4387 I->getDynamicLibraryManager()->addSearchPath(path1, false, false);
4388 size_t pos = ResourceDir.rfind("/llvm-");
4389 if (pos != std::string::npos) {
4390 I->getDynamicLibraryManager()->addSearchPath(ResourceDir.substr(0, pos),
4391 false, false);
4392 }
4393 pos = ResourceDir.rfind("/clang");
4394 if (pos != std::string::npos) {
4395 I->getDynamicLibraryManager()->addSearchPath(ResourceDir.substr(0, pos),
4396 false, false);
4397 }
4398}
4399std::string ExtractArgument(const std::vector<const char*>& Args,
4400 const std::string& Arg) {
4401 size_t I = 0;
4402 for (auto i = Args.begin(); i != Args.end(); i++)
4403 if ((++I < Args.size()) && (*i == Arg))
4404 return *(++i);
4405 return "";
4406}
4407} // namespace
4408
4409InterpRef CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
4410 const std::vector<const char*>& GpuArgs /*={}*/) {
4411 INTEROP_TRACE(Args, GpuArgs);
4412 std::string MainExecutableName = sys::fs::getMainExecutable(nullptr, nullptr);
4413 // In some systems, CppInterOp cannot manually detect the correct resource.
4414 // Then the -resource-dir passed by the user is assumed to be the correct
4415 // location. Prioritising it over detecting it within CppInterOp. Extracting
4416 // the resource-dir from the arguments is required because we set the
4417 // necessary library search location explicitly below. Because by default,
4418 // linker flags are ignored in repl (issue #748)
4419 std::string ResourceDir = ExtractArgument(Args, "-resource-dir");
4420 if (ResourceDir.empty())
4421 ResourceDir = MakeResourcesPath();
4422 llvm::Triple T(llvm::sys::getProcessTriple());
4423 if ((!sys::fs::is_directory(ResourceDir)) &&
4424 (T.isOSDarwin() || T.isOSLinux()))
4425 ResourceDir = DetectResourceDir();
4426
4427 std::vector<const char*> ClingArgv = {"-std=c++14"};
4428 if (!ResourceDir.empty())
4429 ClingArgv.insert(ClingArgv.begin(), {"-resource-dir", ResourceDir.c_str()});
4430 ClingArgv.insert(ClingArgv.begin(), MainExecutableName.c_str());
4431#ifdef _WIN32
4432 // FIXME : Workaround Sema::PushDeclContext assert on windows
4433 ClingArgv.push_back("-fno-delayed-template-parsing");
4434#endif
4435#if __has_feature(memory_sanitizer)
4436 // Match the host stdlib (msan setup is libc++ end to end; the
4437 // in-process clang otherwise defaults to libstdc++ on Linux and
4438 // JIT'd `std::__cxx11::*` won't resolve against the host's
4439 // `std::__1::*`). User Args appended below can override.
4440 ClingArgv.push_back("-stdlib=libc++");
4441 // -stdlib=libc++ alone misses <install>/include/c++/v1: in-process
4442 // clang derives Driver::Dir from /proc/self/exe (= host binary),
4443 // not argv[0], so the force-include of `<new>` SIGSEGVs in
4444 // GenModule. Derive the include from -resource-dir, which IS the
4445 // cell. Gating on memory_sanitizer (not _LIBCPP_VERSION) keeps
4446 // this away from generic libc++ builds where the cell-derived
4447 // path may not be the libc++ the host actually uses.
4448 std::string LibcxxIncDir;
4449 if (!ResourceDir.empty()) {
4450 SmallString<256> P(ResourceDir);
4451 sys::path::remove_filename(P);
4452 sys::path::remove_filename(P);
4453 sys::path::remove_filename(P);
4454 sys::path::append(P, "include", "c++", "v1");
4455 if (sys::fs::is_directory(P)) {
4456 LibcxxIncDir = P.str().str();
4457 ClingArgv.push_back("-cxx-isystem");
4458 ClingArgv.push_back(LibcxxIncDir.c_str());
4459 }
4460 }
4461#endif
4462 ClingArgv.insert(ClingArgv.end(), Args.begin(), Args.end());
4463 // To keep the Interpreter creation interface between cling and clang-repl
4464 // to some extent compatible we should put Args and GpuArgs together. On the
4465 // receiving end we should check for -xcuda to know.
4466 if (!GpuArgs.empty()) {
4467 llvm::StringRef Arg0 = GpuArgs[0];
4468 Arg0 = Arg0.trim().ltrim('-');
4469 if (Arg0 != "cuda") {
4470 llvm::errs() << "[CreateInterpreter]: Make sure --cuda is passed as the"
4471 << " first argument of the GpuArgs\n";
4472 return INTEROP_RETURN(nullptr);
4473 }
4474 }
4475 ClingArgv.insert(ClingArgv.end(), GpuArgs.begin(), GpuArgs.end());
4476
4477 // Process externally passed arguments if present.
4478 std::vector<std::string> ExtraArgs;
4479 auto EnvOpt = llvm::sys::Process::GetEnv("CPPINTEROP_EXTRA_INTERPRETER_ARGS");
4480 if (EnvOpt) {
4481 StringRef Env(*EnvOpt);
4482 while (!Env.empty()) {
4483 StringRef Arg;
4484 std::tie(Arg, Env) = Env.split(' ');
4485 ExtraArgs.push_back(Arg.str());
4486 }
4487 }
4488 std::transform(ExtraArgs.begin(), ExtraArgs.end(),
4489 std::back_inserter(ClingArgv),
4490 [&](const std::string& str) { return str.c_str(); });
4491
4492 // Force global process initialization.
4493 (void)GetInterpreters();
4494
4495#ifdef CPPINTEROP_USE_CLING
4496 auto I = new compat::Interpreter(ClingArgv.size(), &ClingArgv[0]);
4497#else
4498 auto Interp =
4499 compat::Interpreter::create(static_cast<int>(ClingArgv.size()),
4500 ClingArgv.data(), nullptr, {}, nullptr, true);
4501 if (!Interp)
4502 return INTEROP_RETURN(nullptr);
4503 auto* I = Interp.release();
4504#endif
4505
4506 // Honor -mllvm.
4507 //
4508 // FIXME: Remove this, one day.
4509 // This should happen AFTER plugins have been loaded!
4510 const CompilerInstance* Clang = I->getCI();
4511 if (!Clang->getFrontendOpts().LLVMArgs.empty()) {
4512 unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size();
4513 auto Args = std::make_unique<const char*[]>(NumArgs + 2);
4514 Args[0] = "clang (LLVM option parsing)";
4515 for (unsigned i = 0; i != NumArgs; ++i)
4516 Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str();
4517 Args[NumArgs + 1] = nullptr;
4518 llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
4519 }
4520
4521 if (!T.isWasm())
4522 AddLibrarySearchPaths(ResourceDir, I);
4523
4524 if (GetLanguage(I) != InterpreterLanguage::C) {
4525 I->declare(R"(
4526 namespace __internal_CppInterOp {
4527 template <typename Signature>
4528 struct function;
4529 template <typename Res, typename... ArgTypes>
4530 struct function<Res(ArgTypes...)> {
4531 typedef Res result_type;
4532 };
4533 } // namespace __internal_CppInterOp
4534 )");
4535 }
4536
4537 RegisterInterpreter(I, /*Owned=*/true);
4538
4539// Define runtime symbols in the JIT dylib for clang-repl
4540#if !defined(CPPINTEROP_USE_CLING) && !defined(EMSCRIPTEN)
4541 DefineAbsoluteSymbol(*I, "__ci_newtag",
4542 reinterpret_cast<uint64_t>(&__ci_newtag));
4543// llvm >= 21 has this defined as a C symbol that does not require mangling
4544#if CLANG_VERSION_MAJOR >= 21
4545 DefineAbsoluteSymbol(
4546 *I, "__clang_Interpreter_SetValueWithAlloc",
4547 reinterpret_cast<uint64_t>(&__clang_Interpreter_SetValueWithAlloc));
4548#else
4549 // obtain mangled name
4550 auto* D =
4551 unwrap<Decl>(Cpp::GetNamed("__clang_Interpreter_SetValueWithAlloc"));
4552 if (auto* FD = llvm::dyn_cast_or_null<FunctionDecl>(D)) {
4553 auto GD = GlobalDecl(FD);
4554 std::string mangledName;
4555 compat::maybeMangleDeclName(GD, mangledName);
4556 DefineAbsoluteSymbol(
4557 *I, mangledName.c_str(),
4558 reinterpret_cast<uint64_t>(&__clang_Interpreter_SetValueWithAlloc));
4559 }
4560#endif
4561
4562 DefineAbsoluteSymbol(
4563 *I, "__clang_Interpreter_SetValueNoAlloc",
4564 reinterpret_cast<uint64_t>(&__clang_Interpreter_SetValueNoAlloc));
4565#endif
4566 return INTEROP_RETURN(I);
4567}
4568
4569InterpreterLanguage GetLanguage(InterpRef I /*=nullptr*/) {
4570 INTEROP_TRACE(I);
4571 compat::Interpreter* interp = &getInterp(I);
4572 const auto& LO = interp->getCI()->getLangOpts();
4573
4574 // CUDA and HIP reuse C++ language standards, so LangStd alone reports CXX.
4575 if (LO.CUDA)
4576 return INTEROP_RETURN(InterpreterLanguage::CUDA);
4577 if (LO.HIP)
4578 return INTEROP_RETURN(InterpreterLanguage::HIP);
4579
4580 auto standard = clang::LangStandard::getLangStandardForKind(LO.LangStd);
4581 auto lang = static_cast<InterpreterLanguage>(standard.getLanguage());
4582 assert(lang != InterpreterLanguage::Unknown && "Unknown language");
4583 assert(static_cast<unsigned char>(lang) <=
4584 static_cast<unsigned char>(InterpreterLanguage::HLSL) &&
4585 "Unhandled Language");
4586 return INTEROP_RETURN(lang);
4587}
4588
4589InterpreterLanguageStandard GetLanguageStandard(InterpRef I /*=nullptr*/) {
4590 INTEROP_TRACE(I);
4591 compat::Interpreter* interp = &getInterp(I);
4592 const auto& LO = interp->getCI()->getLangOpts();
4593 auto langStandard = static_cast<InterpreterLanguageStandard>(LO.LangStd);
4594 assert(langStandard != InterpreterLanguageStandard::lang_unspecified &&
4595 "Unspecified language standard");
4596 assert(static_cast<unsigned char>(langStandard) <=
4597 static_cast<unsigned char>(
4598 InterpreterLanguageStandard::lang_unspecified) &&
4599 "Unhandled language standard.");
4600 return INTEROP_RETURN(langStandard);
4601}
4602
4603void AddSearchPath(const char* dir, bool isUser, bool prepend) {
4604 INTEROP_TRACE(dir, isUser, prepend);
4605 getInterp().getDynamicLibraryManager()->addSearchPath(dir, isUser, prepend);
4606 return INTEROP_VOID_RETURN();
4607}
4608
4609const char* GetResourceDir() {
4610 INTEROP_TRACE();
4611 return INTEROP_RETURN(
4612 getInterp().getCI()->getHeaderSearchOpts().ResourceDir.c_str());
4613}
4614
4615///\returns 0 on success.
4616static bool exec(const char* cmd, std::vector<std::string>& outputs) {
4617#define DEBUG_TYPE "exec"
4618
4619 std::array<char, 256> buffer;
4620 struct file_deleter {
4621 void operator()(FILE* fp) { pclose(fp); }
4622 };
4623 std::unique_ptr<FILE, file_deleter> pipe{popen(cmd, "r")};
4624 LLVM_DEBUG(dbgs() << "Executing command '" << cmd << "'\n");
4625
4626 if (!pipe) {
4627 LLVM_DEBUG(dbgs() << "Execute failed!\n");
4628 perror("exec: ");
4629 return false;
4630 }
4631
4632 LLVM_DEBUG(dbgs() << "Execute returned:\n");
4633 while (fgets(buffer.data(), static_cast<int>(buffer.size()), pipe.get())) {
4634 LLVM_DEBUG(dbgs() << buffer.data());
4635 llvm::StringRef trimmed = buffer.data();
4636 outputs.push_back(trimmed.trim().str());
4637 }
4638
4639#undef DEBUG_TYPE
4640
4641 return true;
4642}
4643
4644std::string DetectResourceDir(const char* ClangBinaryName /* = clang */) {
4645 INTEROP_TRACE(ClangBinaryName);
4646 std::string cmd = std::string(ClangBinaryName) + " -print-resource-dir";
4647 std::vector<std::string> outs;
4648 exec(cmd.c_str(), outs);
4649 if (outs.empty() || outs.size() > 1)
4650 return INTEROP_RETURN("");
4651
4652 std::string detected_resource_dir = outs.back();
4653
4654 std::string version = CLANG_VERSION_MAJOR_STRING;
4655 // We need to check if the detected resource directory is compatible.
4656 if (llvm::sys::path::filename(detected_resource_dir) != version)
4657 return INTEROP_RETURN("");
4658
4659 return INTEROP_RETURN(detected_resource_dir);
4660}
4661
4662void DetectSystemCompilerIncludePaths(std::vector<std::string>& Paths,
4663 const char* CompilerName /*= "c++"*/) {
4664 INTEROP_TRACE(INTEROP_OUT(Paths), CompilerName);
4665 std::string cmd = "LC_ALL=C ";
4666 cmd += CompilerName;
4667 cmd += " -xc++ -E -v /dev/null 2>&1 | sed -n -e '/^.include/,${' -e '/^ "
4668 "\\/.*/p' -e '}'";
4669 std::vector<std::string> outs;
4670 exec(cmd.c_str(), Paths);
4671 return INTEROP_VOID_RETURN();
4672}
4673
4674void AddIncludePath(const char* dir) {
4675 INTEROP_TRACE(dir);
4677 return INTEROP_VOID_RETURN();
4678}
4679
4680void GetIncludePaths(std::vector<std::string>& IncludePaths, bool withSystem,
4681 bool withFlags) {
4682 INTEROP_TRACE(INTEROP_OUT(IncludePaths), withSystem, withFlags);
4683 llvm::SmallVector<std::string> paths(1);
4684 getInterp().GetIncludePaths(paths, withSystem, withFlags);
4685 for (auto& i : paths)
4686 IncludePaths.push_back(i);
4687 return INTEROP_VOID_RETURN();
4688}
4689
4690namespace {
4691class clangSilent {
4692public:
4693 clangSilent(clang::DiagnosticsEngine& diag) : fDiagEngine(diag) {
4694 fOldDiagValue = fDiagEngine.getSuppressAllDiagnostics();
4695 fDiagEngine.setSuppressAllDiagnostics(true);
4696 }
4697
4698 ~clangSilent() { fDiagEngine.setSuppressAllDiagnostics(fOldDiagValue); }
4699
4700protected:
4701 clang::DiagnosticsEngine& fDiagEngine;
4703};
4704} // namespace
4705
4706int Declare(compat::Interpreter& I, const char* code, bool silent) {
4707 // Trap diagnostics on both paths: I.declare's rc is 0 even when
4708 // Parse recovered from emitted errors, so callers need the trap to
4709 // distinguish "parsed cleanly" from "parsed with errors".
4710 clang::DiagnosticsEngine& Diag = I.getSema().getDiagnostics();
4711 clang::DiagnosticErrorTrap Trap(Diag);
4712 if (silent) {
4713 clangSilent diagSuppr(Diag);
4714 auto result = I.declare(code);
4715 if (Trap.hasErrorOccurred())
4716 return 1;
4717 return result;
4718 }
4719 auto result = I.declare(code);
4720 if (Trap.hasErrorOccurred())
4721 return 1;
4722 return result;
4723}
4724
4725int Declare(const char* code, bool silent) {
4726 INTEROP_TRACE(code, silent);
4727 return INTEROP_RETURN(Declare(getInterp(), code, silent));
4728}
4729
4730int Process(const char* code) {
4731 INTEROP_TRACE(code);
4732 return INTEROP_RETURN(getInterp().process(code));
4733}
4734
4735// Classify the QualType of a successfully-evaluated value into a
4736// Box::Kind. clang::Value's own ctor asserts on builtins the X-macro
4737// doesn't list (`__int128`, `_BitInt`, `_Float16`, ...), so by the time
4738// we get here QT is non-null and BT->getKind() is one of the enumerated
4739// arms. Records, pointers and references fall through to K_PtrOrObj.
4740// See memory/clang_value_wide_types_gap.md for the upstream follow-up
4741// that would broaden Value's coverage.
4742static Cpp::Box::Kind classifyByQualType(clang::QualType QT) {
4743 if (const auto* BT = QT->getAs<clang::BuiltinType>()) {
4744 switch (BT->getKind()) {
4745 case clang::BuiltinType::Bool:
4746 return Cpp::Box::K_Bool;
4747 case clang::BuiltinType::Char_S:
4748 return Cpp::Box::K_Char_S;
4749 case clang::BuiltinType::Char_U:
4750 // Platform-`unsigned`-char alias; share UChar storage so the
4751 // X-macro doesn't need a duplicate Box::Create<T> specialization.
4752 return Cpp::Box::K_UChar;
4753 case clang::BuiltinType::SChar:
4754 return Cpp::Box::K_SChar;
4755 case clang::BuiltinType::UChar:
4756 return Cpp::Box::K_UChar;
4757 case clang::BuiltinType::Short:
4758 return Cpp::Box::K_Short;
4759 case clang::BuiltinType::UShort:
4760 return Cpp::Box::K_UShort;
4761 case clang::BuiltinType::Int:
4762 return Cpp::Box::K_Int;
4763 case clang::BuiltinType::UInt:
4764 return Cpp::Box::K_UInt;
4765 case clang::BuiltinType::Long:
4766 return Cpp::Box::K_Long;
4767 case clang::BuiltinType::ULong:
4768 return Cpp::Box::K_ULong;
4769 case clang::BuiltinType::LongLong:
4770 return Cpp::Box::K_LongLong;
4771 case clang::BuiltinType::ULongLong:
4772 return Cpp::Box::K_ULongLong;
4773 case clang::BuiltinType::Float:
4774 return Cpp::Box::K_Float;
4775 case clang::BuiltinType::Double:
4776 return Cpp::Box::K_Double;
4777 case clang::BuiltinType::LongDouble:
4779 default:
4780 llvm_unreachable(
4781 "clang::Value asserts on builtins outside the X-macro set");
4782 }
4783 }
4784 return Cpp::Box::K_PtrOrObj;
4785}
4786
4787Box Evaluate(const char* code) {
4788 INTEROP_TRACE(code);
4789 compat::Value V;
4790 auto res = getInterp().evaluate(code, V);
4792 if (res != 0 || !V.hasValue())
4793 return INTEROP_RETURN(Box{});
4794
4795 clang::QualType QT = V.getType();
4796 void* qt = QT.getAsOpaquePtr();
4797 switch (classifyByQualType(QT)) {
4798#define X(TyRef, name) \
4799 case Cpp::Box::K_##name: \
4800 return INTEROP_RETURN( \
4801 Cpp::Box::Create<TyRef>(compat::convertTo<TyRef>(V), qt));
4803#undef X
4805 return INTEROP_RETURN(compat::MakeValueBox(V, qt));
4806 case Cpp::Box::K_Char_U:
4807 case Cpp::Box::K_Void:
4809 // classifyByQualType never produces these (Char_U folds to UChar;
4810 // Void/Unspecified can't reach a hasValue=true path).
4811 llvm_unreachable("Box::Kind not produced by classifyByQualType");
4812 }
4813 llvm_unreachable("classifyByQualType returned an unhandled Kind");
4814}
4815
4816std::string LookupLibrary(const char* lib_name) {
4817 INTEROP_TRACE(lib_name);
4818 return INTEROP_RETURN(
4819 getInterp().getDynamicLibraryManager()->lookupLibrary(lib_name));
4820}
4821
4822bool LoadLibrary(const char* lib_stem, bool lookup) {
4823 INTEROP_TRACE(lib_stem, lookup);
4825 getInterp().loadLibrary(lib_stem, lookup);
4826
4828}
4829
4830void UnloadLibrary(const char* lib_stem) {
4831 INTEROP_TRACE(lib_stem);
4833 return INTEROP_VOID_RETURN();
4834}
4835
4836std::string SearchLibrariesForSymbol(const char* mangled_name,
4837 bool search_system /*true*/) {
4838 INTEROP_TRACE(mangled_name, search_system);
4839 auto* DLM = getInterp().getDynamicLibraryManager();
4840 return INTEROP_RETURN(
4841 DLM->searchLibrariesForSymbol(mangled_name, search_system));
4842}
4843
4845 const char* linker_mangled_name,
4846 uint64_t address) {
4847 // FIXME: This approach is problematic since we could replace a symbol
4848 // whose address was already taken by clients.
4849 //
4850 // A safer approach would be to define our symbol replacements early in the
4851 // bootstrap process like:
4852 // auto J = LLJITBuilder().create();
4853 // if (!J)
4854 // return Err;
4855 //
4856 // if (Jupyter) {
4857 // llvm::orc::SymbolMap Overrides;
4858 // Overrides[J->mangleAndIntern("printf")] =
4859 // { ExecutorAddr::fromPtr(&printf), JITSymbolFlags::Exported };
4860 // Overrides[...] =
4861 // { ... };
4862 // if (auto Err =
4863 // J->getProcessSymbolsJITDylib().define(absoluteSymbols(std::move(Overrides)))
4864 // return Err;
4865 // }
4866
4867 // FIXME: If we still want to do symbol replacement we should use the
4868 // ReplacementManager which is available in llvm 18.
4869 using namespace llvm;
4870 using namespace llvm::orc;
4871
4872 auto Symbol = compat::getSymbolAddress(I, linker_mangled_name);
4873 llvm::orc::LLJIT& Jit = *compat::getExecutionEngine(I);
4874 llvm::orc::ExecutionSession& ES = Jit.getExecutionSession();
4875 JITDylib& DyLib = *Jit.getProcessSymbolsJITDylib().get();
4876
4877 if (Error Err = Symbol.takeError()) {
4878 logAllUnhandledErrors(std::move(Err), errs(),
4879 "[InsertOrReplaceJitSymbol] error: ");
4880#define DEBUG_TYPE "orc"
4881 LLVM_DEBUG(ES.dump(dbgs()));
4882#undef DEBUG_TYPE
4883 return true;
4884 }
4885
4886 // Nothing to define, we are redefining the same function.
4887 if (*Symbol && *Symbol == address) {
4888 errs() << "[InsertOrReplaceJitSymbol] warning: redefining '"
4889 << linker_mangled_name << "' with the same address\n";
4890 return true;
4891 }
4892
4893 // Let's inject it.
4894 llvm::orc::SymbolMap InjectedSymbols;
4895 auto& DL = compat::getExecutionEngine(I)->getDataLayout();
4896 char GlobalPrefix = DL.getGlobalPrefix();
4897 std::string tmp(linker_mangled_name);
4898 if (GlobalPrefix != '\0') {
4899 tmp = std::string(1, GlobalPrefix) + tmp;
4900 }
4901 auto Name = ES.intern(tmp);
4902 InjectedSymbols[Name] =
4903 ExecutorSymbolDef(ExecutorAddr(address), JITSymbolFlags::Exported);
4904
4905 // We want to replace a symbol with a custom provided one.
4906 if (Symbol && address)
4907 // The symbol be in the DyLib or in-process.
4908 if (auto Err = DyLib.remove({Name})) {
4909 logAllUnhandledErrors(std::move(Err), errs(),
4910 "[InsertOrReplaceJitSymbol] error: ");
4911 return true;
4912 }
4913
4914 if (Error Err = DyLib.define(absoluteSymbols(InjectedSymbols))) {
4915 logAllUnhandledErrors(std::move(Err), errs(),
4916 "[InsertOrReplaceJitSymbol] error: ");
4917 return true;
4918 }
4919
4920 return false;
4921}
4922
4923bool InsertOrReplaceJitSymbol(const char* linker_mangled_name,
4924 uint64_t address) {
4925 INTEROP_TRACE(linker_mangled_name, address);
4926 return INTEROP_RETURN(
4927 InsertOrReplaceJitSymbol(getInterp(), linker_mangled_name, address));
4928}
4929
4930std::string ObjToString(const char* TyRef, void* obj) {
4931 INTEROP_TRACE(TyRef, obj);
4932 return INTEROP_RETURN(getInterp().toString(TyRef, obj));
4933}
4934
4935static Decl* InstantiateTemplate(TemplateDecl* TemplateD,
4936 TemplateArgumentListInfo& TLI, Sema& S,
4937 bool instantiate_body) {
4938 // This is not right but we don't have a lot of options to choose from as a
4939 // template instantiation requires a valid source location.
4940 SourceLocation fakeLoc = GetValidSLoc(S);
4941 if (auto* FunctionTemplate = dyn_cast<FunctionTemplateDecl>(TemplateD)) {
4942 FunctionDecl* Specialization = nullptr;
4943 clang::sema::TemplateDeductionInfo Info(fakeLoc);
4944 TemplateDeductionResult Result =
4945 S.DeduceTemplateArguments(FunctionTemplate, &TLI, Specialization, Info,
4946 /*IsAddressOfFunction*/ true);
4947 if (Result != TemplateDeductionResult::Success) {
4948 // FIXME: Diagnose what happened.
4949 (void)Result;
4950 }
4951 if (instantiate_body)
4952 InstantiateFunctionDefinition(Specialization);
4953 return Specialization;
4954 }
4955
4956 if (auto* VarTemplate = dyn_cast<VarTemplateDecl>(TemplateD)) {
4957#if CLANG_VERSION_MAJOR < 22
4958 DeclResult R = S.CheckVarTemplateId(VarTemplate, fakeLoc, fakeLoc, TLI);
4959#else
4960 DeclResult R = S.CheckVarTemplateId(VarTemplate, fakeLoc, fakeLoc, TLI,
4961 /*SetWrittenArgs=*/true);
4962#endif
4963 if (R.isInvalid()) {
4964 // FIXME: Diagnose
4965 }
4966 return R.get();
4967 }
4968
4969 // This will instantiate tape<T> TyRef and return it.
4970 SourceLocation noLoc;
4971#if CLANG_VERSION_MAJOR < 22
4972 QualType TT = S.CheckTemplateIdType(TemplateName(TemplateD), noLoc, TLI);
4973#else
4974 QualType TT = S.CheckTemplateIdType(
4975 ElaboratedTypeKeyword::None, TemplateName(TemplateD), noLoc, TLI,
4976 /*Scope=*/nullptr, /*ForNestedNameSpecifier=*/false);
4977#endif
4978 if (TT.isNull())
4979 return nullptr;
4980
4981 // Perhaps we can extract this into a new interface.
4982 S.RequireCompleteType(fakeLoc, TT, diag::err_tentative_def_incomplete_type);
4983 return GetScopeFromType(TT);
4984
4985 // ASTContext &C = S.getASTContext();
4986 // // Get clad namespace and its identifier clad::.
4987 // CXXScopeSpec CSS;
4988 // CSS.Extend(C, GetCladNamespace(), noLoc, noLoc);
4989 // NestedNameSpecifier* NS = CSS.getScopeRep();
4990
4991 // // Create elaborated TyRef with namespace specifier,
4992 // // i.e. class<T> -> clad::class<T>
4993 // return C.getElaboratedType(ETK_None, NS, TT);
4994}
4995
4996Decl* InstantiateTemplate(TemplateDecl* TemplateD,
4997 ArrayRef<TemplateArgument> TemplateArgs, Sema& S,
4998 bool instantiate_body) {
4999 // Create a list of template arguments.
5000 TemplateArgumentListInfo TLI{};
5001 for (auto TA : TemplateArgs)
5002 TLI.addArgument(
5003 S.getTrivialTemplateArgumentLoc(TA, QualType(), SourceLocation()));
5004
5005 return InstantiateTemplate(TemplateD, TLI, S, instantiate_body);
5006}
5007
5009 const TemplateArgInfo* template_args,
5010 size_t template_args_size, bool instantiate_body) {
5011 auto& S = I.getSema();
5012 auto& C = S.getASTContext();
5013
5014 llvm::SmallVector<TemplateArgument> TemplateArgs;
5015 TemplateArgs.reserve(template_args_size);
5016 for (size_t i = 0; i < template_args_size; ++i) {
5017 QualType ArgTy = QualType::getFromOpaquePtr(template_args[i].m_Type);
5018 if (template_args[i].m_IntegralValue) {
5019 // We have a non-TyRef template parameter. Create an integral value from
5020 // the string representation.
5021 auto Res = llvm::APSInt(template_args[i].m_IntegralValue);
5022 Res = Res.extOrTrunc(C.getIntWidth(ArgTy));
5023 TemplateArgs.push_back(TemplateArgument(C, Res, ArgTy));
5024 } else {
5025 TemplateArgs.push_back(ArgTy);
5026 }
5027 }
5028
5029 auto* TmplD = unwrap<TemplateDecl>(tmpl);
5030 // We will create a new decl, push a transaction.
5032 return InstantiateTemplate(TmplD, TemplateArgs, S, instantiate_body);
5033}
5034
5035DeclRef InstantiateTemplate(DeclRef tmpl, const TemplateArgInfo* template_args,
5036 size_t template_args_size, bool instantiate_body) {
5037 INTEROP_TRACE(tmpl, template_args, template_args_size, instantiate_body);
5039 getInterp(), tmpl, template_args, template_args_size, instantiate_body));
5040}
5041
5042DeclRef InstantiateTemplate(DeclRef tmpl,
5043 const std::vector<TemplateArgInfo>& template_args,
5044 bool instantiate_body) {
5045 INTEROP_TRACE(tmpl, template_args, instantiate_body);
5046 // Forward to the static helper directly (not the deprecated public
5047 // overload) to avoid a nested INTEROP_TRACE.
5048 return INTEROP_RETURN(
5049 InstantiateTemplate(getInterp(), tmpl, template_args.data(),
5050 template_args.size(), instantiate_body));
5051}
5052
5053void GetClassTemplateArgs(ConstDeclRef templ_instance,
5054 std::vector<TemplateArgInfo>& args) {
5055 INTEROP_TRACE(templ_instance, INTEROP_OUT(args));
5056 const auto* CTSD = unwrap<ClassTemplateSpecializationDecl>(templ_instance);
5057 for (const auto& TA : CTSD->getTemplateArgs().asArray()) {
5058 // FIXME: Support cases with m_IntegralValue.
5059 args.push_back({TA.getAsType().getAsOpaquePtr()});
5060 }
5061 return INTEROP_VOID_RETURN();
5062}
5063
5064void GetClassTemplateInstantiationArgs(ConstDeclRef templ_instance,
5065 std::vector<TemplateArgInfo>& args) {
5066 INTEROP_TRACE(templ_instance, INTEROP_OUT(args));
5067 const auto* CTSD = unwrap<ClassTemplateSpecializationDecl>(templ_instance);
5068 for (const auto& TA : CTSD->getTemplateInstantiationArgs().asArray()) {
5069 switch (TA.getKind()) {
5070 default:
5071 assert(0 && "Not yet supported!");
5072 break;
5073 case TemplateArgument::Pack:
5074 for (auto SubTA : TA.pack_elements())
5075 args.push_back({SubTA.getAsType().getAsOpaquePtr()});
5076 break;
5077 case TemplateArgument::Integral:
5078 // FIXME: Support this case where the problem is where we provide the
5079 // storage for the m_IntegralValue.
5080 // llvm::APSInt Val = TA.getAsIntegral();
5081 // args.push_back({TA.getIntegralType(), TA.getAsIntegral()})
5082 // break;
5083 case TemplateArgument::Type:
5084 args.push_back({TA.getAsType().getAsOpaquePtr()});
5085 }
5086 }
5087 return INTEROP_VOID_RETURN();
5088}
5089
5090FuncRef InstantiateTemplateFunctionFromString(const char* function_template) {
5091 INTEROP_TRACE(function_template);
5092 // FIXME: Drop this interface and replace it with the proper overload
5093 // resolution handling and template instantiation selection.
5094
5095 // Try to force template instantiation and overload resolution.
5096 static unsigned long long var_count = 0;
5097 std::string id = "__Cppyy_GetMethTmpl_" + std::to_string(var_count++);
5098 std::string instance = "auto " + id + " = " + function_template + ";\n";
5099
5100 if (!Cpp::Declare(instance.c_str(), /*silent=*/false)) {
5101 auto* VD = unwrap<VarDecl>(Cpp::GetNamed(id, nullptr));
5102 DeclRefExpr* DRE = (DeclRefExpr*)VD->getInit()->IgnoreImpCasts();
5103 return INTEROP_RETURN(DRE->getDecl());
5104 }
5105 return INTEROP_RETURN(nullptr);
5106}
5107
5108void GetAllCppNames(ConstDeclRef DRef, std::set<std::string>& names) {
5109 INTEROP_TRACE(DRef, INTEROP_OUT(names));
5110 const auto* D = unwrap<clang::Decl>(DRef);
5111 clang::DeclContext* DC;
5112 clang::DeclContext::decl_iterator decl;
5113
5115
5116 if (const auto* TD = dyn_cast_or_null<TagDecl>(D)) {
5117 DC = clang::TagDecl::castToDeclContext(TD);
5118 decl = DC->decls_begin();
5119 decl++;
5120 } else if (const auto* ND = dyn_cast_or_null<NamespaceDecl>(D)) {
5121 DC = clang::NamespaceDecl::castToDeclContext(ND);
5122 decl = DC->decls_begin();
5123 } else if (const auto* TUD = dyn_cast_or_null<TranslationUnitDecl>(D)) {
5124 DC = clang::TranslationUnitDecl::castToDeclContext(TUD);
5125 decl = DC->decls_begin();
5126 } else {
5127 return INTEROP_VOID_RETURN();
5128 }
5129
5130 for (/* decl set above */; decl != DC->decls_end(); decl++) {
5131 if (const auto* ND = llvm::dyn_cast_or_null<NamedDecl>(*decl)) {
5132 names.insert(ND->getNameAsString());
5133 }
5134 }
5135 return INTEROP_VOID_RETURN();
5136}
5137
5138void GetEnums(ConstDeclRef DRef, std::vector<std::string>& Result) {
5139 INTEROP_TRACE(DRef, INTEROP_OUT(Result));
5140 // collectAllContexts is non-const but logically read-only here.
5141 auto* D = const_cast<clang::Decl*>(unwrap<clang::Decl>(DRef));
5142
5143 if (!llvm::isa_and_nonnull<clang::DeclContext>(D))
5144 return INTEROP_VOID_RETURN();
5145
5146 auto* DC = llvm::dyn_cast<clang::DeclContext>(D);
5147
5148 llvm::SmallVector<clang::DeclContext*, 4> DCs;
5149 DC->collectAllContexts(DCs);
5150
5151 // FIXME: We should use a lookup based approach instead of brute force
5152 for (auto* DC : DCs) {
5153 for (auto decl = DC->decls_begin(); decl != DC->decls_end(); decl++) {
5154 if (auto* ND = llvm::dyn_cast_or_null<EnumDecl>(*decl)) {
5155 Result.push_back(ND->getNameAsString());
5156 }
5157 }
5158 }
5159 return INTEROP_VOID_RETURN();
5160}
5161
5162// FIXME: On the CPyCppyy side the receiver is of TyRef
5163// vector<long int> instead of vector<size_t>
5164std::vector<long int> GetDimensions(ConstTypeRef TyRef) {
5165 INTEROP_TRACE(TyRef);
5166 QualType Qual = QualType::getFromOpaquePtr(TyRef.data);
5167 if (Qual.isNull())
5168 return INTEROP_RETURN(std::vector<long int>{});
5169 Qual = Qual.getCanonicalType();
5170 std::vector<long int> dims;
5171 if (Qual->isArrayType()) {
5172 const auto* ArrayType = dyn_cast<clang::ArrayType>(Qual.getTypePtr());
5173 while (ArrayType) {
5174 if (const auto* CAT = dyn_cast_or_null<ConstantArrayType>(ArrayType)) {
5175 llvm::APSInt Size(CAT->getSize());
5176 long int ArraySize = Size.getLimitedValue();
5177 dims.push_back(ArraySize);
5178 } else /* VariableArrayType, DependentSizedArrayType, IncompleteArrayType
5179 */
5180 {
5181 dims.push_back(DimensionValue::UNKNOWN_SIZE);
5182 }
5183 ArrayType = ArrayType->getElementType()->getAsArrayTypeUnsafe();
5184 }
5185 return INTEROP_RETURN(dims);
5186 }
5187 return INTEROP_RETURN(dims);
5188}
5189
5190bool IsTypeDerivedFrom(ConstTypeRef derived, ConstTypeRef base) {
5191 INTEROP_TRACE(derived, base);
5192 auto& S = getSema();
5193 auto fakeLoc = GetValidSLoc(S);
5194 auto derivedType = clang::QualType::getFromOpaquePtr(derived.data);
5195 auto baseType = clang::QualType::getFromOpaquePtr(base.data);
5196
5198 return INTEROP_RETURN(S.IsDerivedFrom(fakeLoc, derivedType, baseType));
5199}
5200
5201std::string GetFunctionArgDefault(ConstFuncRef func, size_t param_index) {
5202 INTEROP_TRACE(func, param_index);
5203 const auto* D = unwrap<clang::Decl>(func);
5204 const clang::ParmVarDecl* PI = nullptr;
5205
5206 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D))
5207 PI = FD->getNonObjectParameter(param_index);
5208
5209 else if (const auto* FD =
5210 llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
5211 PI = (FD->getTemplatedDecl())->getNonObjectParameter(param_index);
5212
5213 if (PI->hasDefaultArg()) {
5214 std::string Result;
5215 llvm::raw_string_ostream OS(Result);
5216 const Expr* DefaultArgExpr = nullptr;
5218 if (PI->hasUninstantiatedDefaultArg())
5219 DefaultArgExpr = PI->getUninstantiatedDefaultArg();
5220 else
5221 DefaultArgExpr = PI->getDefaultArg();
5222 DefaultArgExpr->printPretty(OS, nullptr, PrintingPolicy(LangOptions()));
5223
5224 // FIXME: Floats are printed in clang with the precision of their underlying
5225 // representation and not as written. This is a deficiency in the printing
5226 // mechanism of clang which we require extra work to mitigate. For example
5227 // float PI = 3.14 is printed as 3.1400000000000001
5228 if (PI->getType()->isFloatingType()) {
5229 if (!Result.empty() && Result.back() == '.')
5230 return INTEROP_RETURN(Result);
5231 auto DefaultArgValue = std::stod(Result);
5232 std::ostringstream oss;
5233 oss << DefaultArgValue;
5234 Result = oss.str();
5235 }
5236 return INTEROP_RETURN(Result);
5237 }
5238 return INTEROP_RETURN("");
5239}
5240
5241bool IsConstMethod(ConstFuncRef method) {
5242 INTEROP_TRACE(method);
5243 if (!method)
5244 return INTEROP_RETURN(false);
5245
5246 const auto* D = unwrap<clang::Decl>(method);
5247 if (const auto* func = dyn_cast<CXXMethodDecl>(D))
5248 return INTEROP_RETURN(func->getMethodQualifiers().hasConst());
5249
5250 return INTEROP_RETURN(false);
5251}
5252
5253std::string GetFunctionArgName(ConstFuncRef func, size_t param_index) {
5254 INTEROP_TRACE(func, param_index);
5255 const auto* D = unwrap<clang::Decl>(func);
5256 const clang::ParmVarDecl* PI = nullptr;
5257
5258 if (const auto* FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(D))
5259 PI = FD->getNonObjectParameter(param_index);
5260 else if (const auto* FD =
5261 llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(D))
5262 PI = (FD->getTemplatedDecl())->getNonObjectParameter(param_index);
5263
5264 return INTEROP_RETURN(PI->getNameAsString());
5265}
5266
5267std::string GetSpellingFromOperator(Operator Operator) {
5268 INTEROP_TRACE(Operator);
5269 return INTEROP_RETURN(
5270 clang::getOperatorSpelling((clang::OverloadedOperatorKind)Operator));
5271}
5272
5273Operator GetOperatorFromSpelling(const std::string& op) {
5274 INTEROP_TRACE(op);
5275#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
5276 if ((Spelling) == op) { \
5277 return INTEROP_RETURN((Operator)OO_##Name); \
5278 }
5279#include "clang/Basic/OperatorKinds.def"
5280 return INTEROP_RETURN(Operator::OP_None);
5281}
5282
5283OperatorArity GetOperatorArity(ConstFuncRef op) {
5284 INTEROP_TRACE(op);
5285 const auto* D = unwrap<Decl>(op);
5286 if (const auto* FD = llvm::dyn_cast<FunctionDecl>(D)) {
5287 if (FD->isOverloadedOperator()) {
5288 switch (FD->getOverloadedOperator()) {
5289#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
5290 case OO_##Name: \
5291 if ((Unary) && (Binary)) \
5292 return INTEROP_RETURN(kBoth); \
5293 if (Unary) \
5294 return INTEROP_RETURN(kUnary); \
5295 if (Binary) \
5296 return INTEROP_RETURN(kBinary); \
5297 break;
5298#include "clang/Basic/OperatorKinds.def"
5299 default:
5300 break;
5301 }
5302 }
5303 }
5304 return INTEROP_RETURN((OperatorArity)~0U);
5305}
5306
5307void GetOperator(ConstDeclRef DRef, Operator op,
5308 std::vector<FuncRef>& operators, OperatorArity kind) {
5309 INTEROP_TRACE(DRef, op, INTEROP_OUT(operators), kind);
5310 const auto* D = unwrap<Decl>(DRef);
5312 if (const auto* CXXRD = llvm::dyn_cast_or_null<CXXRecordDecl>(D)) {
5313 auto fn = [&operators, kind, op](const RecordDecl* RD) {
5314 ASTContext& C = RD->getASTContext();
5315 DeclContextLookupResult Result =
5316 RD->lookup(C.DeclarationNames.getCXXOperatorName(
5317 (clang::OverloadedOperatorKind)op));
5318 for (auto* i : Result) {
5319 if (kind & GetOperatorArity(i))
5320 operators.push_back(i);
5321 }
5322 return true;
5323 };
5324 fn(CXXRD);
5325 CXXRD->forallBases(fn);
5326 } else if (const auto* DC = llvm::dyn_cast_or_null<DeclContext>(D)) {
5327 ASTContext& C = getSema().getASTContext();
5328 DeclContextLookupResult Result =
5329 DC->lookup(C.DeclarationNames.getCXXOperatorName(
5330 (clang::OverloadedOperatorKind)op));
5331
5332 for (auto* i : Result) {
5333 if (kind & GetOperatorArity(i))
5334 operators.push_back(i);
5335 }
5336 }
5337 return INTEROP_VOID_RETURN();
5338}
5339
5340ObjectRef Allocate(DeclRef DRef, size_t count) {
5341 INTEROP_TRACE(DRef, count);
5342 return INTEROP_RETURN((ObjectRef)::operator new(Cpp::SizeOf(DRef) * count));
5343}
5344
5345void Deallocate(DeclRef DRef, ObjectRef address, size_t count) {
5346 INTEROP_TRACE(DRef, address, count);
5347 size_t bytes = Cpp::SizeOf(DRef) * count;
5348 ::operator delete(address.data, bytes);
5349 return INTEROP_VOID_RETURN();
5350}
5351
5352// FIXME: Add optional arguments to the operator new.
5353ObjectRef Construct(compat::Interpreter& interp, DeclRef DRef,
5354 void* arena /*=nullptr*/, size_t count /*=1UL*/) {
5355
5356 // DRef may be either a class or a specific constructor declaration.
5357 FuncRef ctorAsFunc = wrap<FuncRef>(DRef.data);
5358 if (!Cpp::IsConstructor(ctorAsFunc) && !Cpp::IsClass(DRef))
5359 return nullptr;
5360 if (Cpp::IsClass(DRef) && !HasDefaultConstructor(DRef))
5361 return nullptr;
5362
5363 FuncRef ctor = nullptr;
5364 if (Cpp::IsClass(DRef))
5365 ctor = Cpp::GetDefaultConstructor(DRef);
5366 else // a ctor
5367 ctor = ctorAsFunc;
5368
5369 if (JitCall JC = MakeFunctionCallable(&interp, ctor)) {
5370 // invoke the constructor (placement/heap) in one shot
5371 // flag is non-null for placement new, null for normal new
5372 void* is_arena = arena ? reinterpret_cast<void*>(1) : nullptr;
5373 void* result = arena;
5374 JC.InvokeConstructor(&result, count, /*args=*/{}, is_arena);
5375 return result;
5376 }
5377 return nullptr;
5378}
5379
5380ObjectRef Construct(DeclRef DRef, void* arena /*=nullptr*/,
5381 size_t count /*=1UL*/) {
5382 INTEROP_TRACE(DRef, arena, count);
5383 return INTEROP_RETURN(Construct(getInterp(), DRef, arena, count));
5384}
5385
5386bool Destruct(compat::Interpreter& interp, ObjectRef This, const Decl* Class,
5387 bool withFree, size_t nary) {
5388 if (auto wrapper = make_dtor_wrapper(interp, Class)) {
5389 (*wrapper)(This.data, nary, withFree);
5390 return true;
5391 }
5392 return false;
5393 // FIXME: Enable stronger diagnostics
5394}
5395
5396bool Destruct(ObjectRef This, DeclRef DRef, bool withFree /*=true*/,
5397 size_t count /*=0UL*/) {
5398 INTEROP_TRACE(This, DRef, withFree, count);
5399 const auto* Class = unwrap<Decl>(DRef);
5400 return INTEROP_RETURN(Destruct(getInterp(), This, Class, withFree, count));
5401}
5402
5404 FILE* m_TempFile = nullptr;
5405 int m_FD = -1;
5406 int m_DupFD = -1;
5407 bool m_OwnsFile = true;
5408
5409public:
5410#ifdef _MSC_VER
5411 StreamCaptureInfo(int FD)
5412 : m_TempFile{[]() {
5413 FILE* stream = nullptr;
5414 errno_t err;
5415 err = tmpfile_s(&stream);
5416 if (err)
5417 printf("Cannot create temporary file!\n");
5418 return stream;
5419 }()},
5420 m_FD(FD) {
5421#else
5422 StreamCaptureInfo(int FD) : m_FD(FD) {
5423#if !defined(CPPINTEROP_USE_CLING) && !defined(_WIN32)
5424 auto& I = getInterp();
5425 if (I.isOutOfProcess()) {
5426 // Use interpreter-managed redirection file for out-of-process
5427 // redirection. Since, we are using custom pipes instead of stdout, sterr,
5428 // it is kind of necessary to have this complication in StreamCaptureInfo.
5429
5430 // TODO(issues/733): Refactor the stream redirection
5431 FILE* redirected = I.getRedirectionFileForOutOfProcess(FD);
5432 if (redirected) {
5433 m_TempFile = redirected;
5434 m_OwnsFile = false;
5435 if (ftruncate(fileno(m_TempFile), 0) != 0)
5436 perror("ftruncate");
5437 if (lseek(fileno(m_TempFile), 0, SEEK_SET) == -1)
5438 perror("lseek");
5439 }
5440 } else {
5441 m_TempFile = tmpfile();
5442 }
5443#else
5444 m_TempFile = tmpfile();
5445#endif
5446#endif
5447
5448 if (!m_TempFile) {
5449 perror("StreamCaptureInfo: Unable to create temp file");
5450 return;
5451 }
5452
5453 m_DupFD = dup(FD);
5454
5455 // Flush now or can drop the buffer when dup2 is called with Fd later.
5456 // This seems only necessary when piping stdout or stderr, but do it
5457 // for ttys to avoid over complicated code for minimal benefit.
5458 ::fflush(FD == STDOUT_FILENO ? stdout : stderr);
5459 if (dup2(fileno(m_TempFile), FD) < 0)
5460 perror("StreamCaptureInfo:");
5461 }
5466
5468 assert(m_DupFD == -1 && "Captured output not used?");
5469 // Only close the temp file if we own it
5470 if (m_OwnsFile && m_TempFile)
5471 fclose(m_TempFile);
5472 }
5473
5474 std::string GetCapturedString() {
5475 assert(m_DupFD != -1 && "Multiple calls to GetCapturedString");
5476
5477 fflush(nullptr);
5478 if (dup2(m_DupFD, m_FD) < 0)
5479 perror("StreamCaptureInfo:");
5480 // Go to the end of the file.
5481 if (fseek(m_TempFile, 0L, SEEK_END) != 0)
5482 perror("StreamCaptureInfo:");
5483
5484 // Get the size of the file.
5485 long bufsize = ftell(m_TempFile);
5486 if (bufsize == -1) {
5487 perror("StreamCaptureInfo:");
5488 close(m_DupFD);
5489 m_DupFD = -1;
5490 return "";
5491 }
5492
5493 // Allocate our buffer to that size.
5494 std::unique_ptr<char[]> content(new char[bufsize + 1]);
5495
5496 // Go back to the start of the file.
5497 if (fseek(m_TempFile, 0L, SEEK_SET) != 0)
5498 perror("StreamCaptureInfo:");
5499
5500 // Read the entire file into memory.
5501 size_t newLen = fread(content.get(), sizeof(char), bufsize, m_TempFile);
5502 if (ferror(m_TempFile) != 0)
5503 fputs("Error reading file", stderr);
5504 else
5505 content[newLen++] = '\0'; // Just to be safe.
5506
5507 std::string result = content.get();
5508 close(m_DupFD);
5509 m_DupFD = -1;
5510#if !defined(_WIN32) && !defined(CPPINTEROP_USE_CLING)
5511 auto& I = getInterp();
5512 if (I.isOutOfProcess()) {
5513 int fd = fileno(m_TempFile);
5514 if (ftruncate(fd, 0) != 0)
5515 perror("ftruncate");
5516 if (lseek(fd, 0, SEEK_SET) == -1)
5517 perror("lseek");
5518 }
5519#endif
5520 return result;
5521 }
5522};
5523
5524static std::stack<StreamCaptureInfo>& GetRedirectionStack() {
5525 static std::stack<StreamCaptureInfo> sRedirectionStack;
5526 return sRedirectionStack;
5527}
5528
5529void BeginStdStreamCapture(CaptureStreamKind fd_kind) {
5530 INTEROP_TRACE(fd_kind);
5531 GetRedirectionStack().emplace((int)fd_kind);
5532 return INTEROP_VOID_RETURN();
5533}
5534
5535std::string EndStdStreamCapture() {
5536 INTEROP_TRACE();
5537 assert(GetRedirectionStack().size());
5539 std::string result = SCI.GetCapturedString();
5540 GetRedirectionStack().pop();
5541 return INTEROP_RETURN(result);
5542}
5543
5544void CodeComplete(std::vector<std::string>& Results, const char* code,
5545 unsigned complete_line /* = 1U */,
5546 unsigned complete_column /* = 1U */) {
5547 INTEROP_TRACE(INTEROP_OUT(Results), code, complete_line, complete_column);
5548 compat::codeComplete(Results, getInterp(), code, complete_line,
5549 complete_column);
5550 return INTEROP_VOID_RETURN();
5551}
5552
5553int Undo(unsigned N) {
5554 INTEROP_TRACE(N);
5556#ifdef CPPINTEROP_USE_CLING
5557 getInterp().unload(N);
5559#else
5560 return INTEROP_RETURN(getInterp().undo(N));
5561#endif
5562}
5563
5564} // namespace Cpp
#define CPP_BOX_BUILTIN_TYPES
Definition Box.h:79
#define clang_LookupResult_Found_Overloaded
#define clang_LookupResult_Not_Found
#define clang_LookupResult_Found
#define CPPINTEROP_API
bool fOldDiagValue
struct __clang_Interpreter_NewTag __ci_newtag
#define CPPINTEROP_MSAN_UNPOISON_VALUE(v)
clang::DiagnosticsEngine & fDiagEngine
void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,...)
void * __clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal, void *OpaqueType)
#define ACCESS(OBJECT, MEMBER)
Definition Sins.h:21
#define ALLOW_ACCESS(CLASS, MEMBER,...)
Definition Sins.h:9
#define INTEROP_TRACE(...)
Definition Tracing.h:853
#define INTEROP_RETURN(Val)
Definition Tracing.h:858
#define INTEROP_VOID_RETURN()
Definition Tracing.h:859
#define INTEROP_OUT(Var)
Definition Tracing.h:861
std::string writeToFile(const std::string &Version="")
Write the accumulated reproducer log to a file.
Definition Tracing.cpp:196
void unloadLibrary(llvm::StringRef libStem)
void addSearchPath(llvm::StringRef dir, bool isUser=true, bool prepend=false)
CppInterOp Interpreter.
llvm::Expected< clang::PartialTranslationUnit & > Parse(llvm::StringRef Code)
CompilationResult declare(const std::string &input, clang::PartialTranslationUnit **PTU=nullptr)
CompilationResult loadLibrary(const std::string &filename, bool lookup)
llvm::Error Execute(clang::PartialTranslationUnit &T)
static std::unique_ptr< Interpreter > create(int argc, const char *const *argv, const char *llvmdir=nullptr, const std::vector< std::shared_ptr< clang::ModuleFileExtension > > &moduleExtensions={}, void *extraLibHandle=nullptr, bool noRuntime=true)
const DynamicLibraryManager * getDynamicLibraryManager() const
void AddIncludePath(llvm::StringRef PathsStr)
Adds a single include path (-I).
const clang::CompilerInstance * getCI() const
void * getAddressOfGlobal(const clang::GlobalDecl &GD) const
CompilationResult
Describes the return result of the different routines that do the incremental compilation.
CompilationResult evaluate(const std::string &input, clang::Value &V)
clang::Sema & getSema() const
void GetIncludePaths(llvm::SmallVectorImpl< std::string > &incpaths, bool withSystem, bool withFlags) const
Get the current include paths that are used.
void * compileFunction(llvm::StringRef name, llvm::StringRef code, bool ifUnique, bool withAccessControl)
Definition Box.h:96
Kind
Definition Box.h:99
@ K_PtrOrObj
Definition Box.h:105
@ K_Char_S
Definition Box.h:101
@ K_Double
Definition Box.h:101
@ K_LongLong
Definition Box.h:101
@ K_Char_U
Definition Box.h:103
@ K_Short
Definition Box.h:101
@ K_Long
Definition Box.h:101
@ K_SChar
Definition Box.h:101
@ K_Unspecified
Definition Box.h:106
@ K_UInt
Definition Box.h:101
@ K_Int
Definition Box.h:101
@ K_LongDouble
Definition Box.h:101
@ K_Float
Definition Box.h:101
@ K_Bool
Definition Box.h:101
@ K_ULongLong
Definition Box.h:101
@ K_UShort
Definition Box.h:101
@ K_UChar
Definition Box.h:101
@ K_ULong
Definition Box.h:101
@ K_Void
Definition Box.h:104
StreamCaptureInfo(const StreamCaptureInfo &)=delete
StreamCaptureInfo & operator=(const StreamCaptureInfo &)=delete
StreamCaptureInfo & operator=(StreamCaptureInfo &&)=delete
std::string GetCapturedString()
StreamCaptureInfo(StreamCaptureInfo &&)=delete
void InitTracing()
Activate tracing.
Definition Tracing.cpp:48
TraceInfo * TheTraceInfo
Process-global tracer pointer.
Definition Tracing.cpp:46
void Named(clang::Sema *S, clang::LookupResult &R, const clang::DeclContext *Within=nullptr)
static constexpr int kVTableOverlayPrefixSize
Definition CppInterOp.h:51
Definition Box.h:70
bool IsPODType(ConstTypeRef TyRef)
void BeginStdStreamCapture(CaptureStreamKind fd_kind)
bool IsSameType(ConstTypeRef type_a, ConstTypeRef type_b)
DeclRef GetUnderlyingScope(ConstDeclRef DRef)
bool DeleteInterpreter(InterpRef I)
void GetEnums(ConstDeclRef DRef, std::vector< std::string > &Result)
void InstallDiagConsumer(InterpreterInfo *II)
Wire CppInterOp's DiagnosticConsumer into the interpreter's DiagnosticsEngine so parser/sema diagnost...
TypeRef GetCanonicalType(ConstTypeRef TyRef)
static bool isSmartPointer(const RecordType *RT)
bool IsComplete(ConstDeclRef DRef)
void UseExternalInterpreter(InterpRef I)
InterpreterLanguageStandard GetLanguageStandard(InterpRef I)
std::vector< FuncRef > GetFunctionsUsingName(ConstDeclRef DRef, const std::string &name)
void CppInterOpTraceJitCallInvokeImpl(const JitCall *JC, void *result, void **args, std::size_t nargs, void *self)
std::string GetTypeAsString(ConstTypeRef var)
bool IsProtectedMethod(ConstFuncRef method)
DeclRef GetScope(const std::string &name, ConstDeclRef parent)
TypeRef RemoveTypeQualifier(ConstTypeRef TyRef, QualKind qual)
static Decl * GetScopeFromType(QualType QT)
int64_t GetBaseClassOffset(ConstDeclRef derived, ConstDeclRef base)
void GetAllCppNames(ConstDeclRef DRef, std::set< std::string > &names)
bool IsRecordType(ConstTypeRef TyRef)
static VTableOverlay * applyVTableOverlay(void *inst, int total_method_slots, const int *slots, void *const *fns, std::size_t n, std::size_t n_extra_prefix_slots)
bool CheckVariableAccess(ConstDeclRef var, AccessSpecifier AS)
ValueKind GetValueKind(ConstTypeRef TyRef)
std::string GetFunctionArgDefault(ConstFuncRef func, size_t param_index)
std::string ObjToString(const char *TyRef, void *obj)
Operator GetOperatorFromSpelling(const std::string &op)
TypeRef GetTypeFromScope(ConstDeclRef DRef)
std::vector< DeclRef > GetEnumConstants(ConstDeclRef DRef)
bool IsVoidPointerType(ConstTypeRef TyRef)
FuncRef GetDestructor(ConstDeclRef DRef)
InterpreterInfo * GetInterpInfo(InterpRef I)
Resolve an InterpRef to the impl-side struct.
bool IsDestructor(ConstFuncRef method)
std::string GetSpellingFromOperator(Operator Operator)
TypeRef GetIntegerTypeFromEnumType(ConstTypeRef enum_type)
bool IsEnumType(ConstTypeRef TyRef)
FuncRef InstantiateTemplateFunctionFromString(const char *function_template)
bool IsLambdaClass(ConstTypeRef TyRef)
void DetectSystemCompilerIncludePaths(std::vector< std::string > &Paths, const char *CompilerName)
DeclRef GetParentScope(ConstDeclRef DRef)
bool HasTypeQualifier(ConstTypeRef TyRef, QualKind qual)
std::vector< DeclRef > GetUsingNamespaces(ConstDeclRef DRef)
TypeRef GetPointeeType(ConstTypeRef TyRef)
InterpRef CreateInterpreter(const std::vector< const char * > &Args, const std::vector< const char * > &GpuArgs)
void CodeComplete(std::vector< std::string > &Results, const char *code, unsigned complete_line, unsigned complete_column)
size_t GetFunctionRequiredArgs(ConstFuncRef func)
DeclRef GetScopeFromCompleteName(const std::string &name)
std::string GetQualifiedName(ConstDeclRef DRef)
bool IsPrivateVariable(ConstDeclRef var)
ObjectRef Construct(compat::Interpreter &interp, DeclRef DRef, void *arena, size_t count)
bool IsTemplateSpecialization(ConstDeclRef DRef)
bool ActivateInterpreter(InterpRef I)
bool IsEnumConstant(ConstDeclRef DRef)
bool InsertOrReplaceJitSymbol(compat::Interpreter &I, const char *linker_mangled_name, uint64_t address)
bool Destruct(compat::Interpreter &interp, ObjectRef This, const Decl *Class, bool withFree, size_t nary)
OperatorArity GetOperatorArity(ConstFuncRef op)
bool IsVariable(ConstDeclRef DRef)
bool HasDefaultConstructor(ConstDeclRef DRef)
size_t GetSizeOfType(ConstTypeRef TyRef)
bool IsConstructor(ConstFuncRef method)
std::string Demangle(const std::string &mangled_name)
TypeRef GetFunctionReturnType(ConstFuncRef func)
void GetIncludePaths(std::vector< std::string > &IncludePaths, bool withSystem, bool withFlags)
size_t SizeOf(ConstDeclRef DRef)
static Decl * InstantiateTemplate(TemplateDecl *TemplateD, TemplateArgumentListInfo &TLI, Sema &S, bool instantiate_body)
bool ExistsFunctionTemplate(const std::string &name, ConstDeclRef parent)
constexpr int kMinVTableMethodSlots
void EnableDebugOutput(bool value)
std::string EndStdStreamCapture()
static void RegisterInterpreter(compat::Interpreter *I, bool Owned)
bool GetClassTemplatedMethods(const std::string &name, ConstDeclRef parent, std::vector< FuncRef > &funcs)
static QualType findBuiltinType(llvm::StringRef typeName, ASTContext &Context)
Box Evaluate(const char *code)
void AddIncludePath(const char *dir)
static void GetClassDecls(ConstDeclRef DRef, std::vector< HandleType > &methods)
bool IsVirtualMethod(ConstFuncRef method)
constexpr int kABIPrefixSize
std::string DetectResourceDir(const char *ClangBinaryName)
static void RegisterPerms(llvm::StringMap< QualType > &Map, QualType QT, llvm::SmallVectorImpl< llvm::StringRef > &Words)
bool IsStaticVariable(ConstDeclRef var)
std::string GetFunctionSignature(ConstFuncRef func)
const char * GetResourceDir()
bool IsPublicVariable(ConstDeclRef var)
TypeRef AddTypeQualifier(ConstTypeRef TyRef, QualKind qual)
void * GetFunctionAddress(const char *mangled_name)
DeclRef GetNamed(const std::string &name, ConstDeclRef parent)
static DeclarationName getCXXOperatorDeclName(ASTContext &Ctx, llvm::StringRef name)
static InterpreterInfo & getInterpInfo(compat::Interpreter *I=nullptr)
std::string GetName(ConstDeclRef DRef)
void DestroyVTableOverlay(VTableOverlay *overlay)
static void DefaultProcessCrashHandler(void *)
constexpr int kDeletingDtorSlot
void GetClassTemplateArgs(ConstDeclRef templ_instance, std::vector< TemplateArgInfo > &args)
std::string GetCompleteName(ConstDeclRef DRef)
TypeRef GetVariableType(ConstDeclRef var)
std::string GetDoxygenComment(ConstDeclRef DRef, bool strip_comment_markers)
bool IsReferenceType(ConstTypeRef TyRef)
static void ForceCodeGen(Decl *D, compat::Interpreter &I)
static std::deque< InterpreterInfo > & GetInterpreters(bool SetCrashHandler=true)
TypeRef GetEnumConstantType(ConstDeclRef DRef)
DeclRef GetBaseClass(ConstDeclRef DRef, size_t ibase)
static void InstantiateFunctionDefinition(Decl *D)
bool IsFunction(ConstDeclRef DRef)
bool IsConstMethod(ConstFuncRef method)
TypeRef GetNonReferenceType(ConstTypeRef TyRef)
DeclRef LookupDatamember(const std::string &name, ConstDeclRef parent)
static bool exec(const char *cmd, std::vector< std::string > &outputs)
std::string GetFunctionArgName(ConstFuncRef func, size_t param_index)
int Declare(compat::Interpreter &I, const char *code, bool silent)
void UnloadLibrary(const char *lib_stem)
bool IsStaticMethod(ConstFuncRef method)
void Deallocate(DeclRef DRef, ObjectRef address, size_t count)
bool IsNamespace(ConstDeclRef DRef)
InterpreterLanguage GetLanguage(InterpRef I)
bool IsTemplatedFunction(ConstFuncRef func)
bool IsClassPolymorphic(ConstDeclRef DRef)
void GetClassTemplateInstantiationArgs(ConstDeclRef templ_instance, std::vector< TemplateArgInfo > &args)
static const clang::Decl * GetUnderlyingScopeImpl(const clang::Decl *D)
static std::optional< QualType > GetTypeInternal(const Decl *D)
bool CheckMethodAccess(ConstFuncRef method, AccessSpecifier AS)
void GetClassMethods(ConstDeclRef DRef, std::vector< FuncRef > &methods)
bool IsFunctionDeleted(ConstFuncRef function)
static clang::Sema & getSema()
bool IsTemplate(ConstDeclRef DRef)
void DumpScope(ConstDeclRef DRef)
TypeRef GetComplexType(ConstTypeRef TyRef)
void CppInterOpTraceJitCallInvokeReturnImpl(const JitCall *JC, void *result)
bool IsPrivateMethod(ConstFuncRef method)
std::string GetBuildInfo()
static int virtualMethodSlot(ConstFuncRef method)
static bool hasComplexVTableLayout(const CXXRecordDecl *RD)
TypeRef GetIntegerTypeFromEnumScope(ConstDeclRef DRef)
static Cpp::Box::Kind classifyByQualType(clang::QualType QT)
static clang::ASTContext & getASTContext()
bool IsEnumScope(ConstDeclRef DRef)
TypeRef GetType(const std::string &name, ConstDeclRef parent)
bool IsTemplateParmType(ConstTypeRef TyRef)
JitCall MakeFunctionCallable(InterpRef I, ConstFuncRef func)
bool IsMethod(ConstFuncRef method)
static SourceLocation GetValidSLoc(Sema &semaRef)
int Process(const char *code)
bool IsTypeDerivedFrom(ConstTypeRef derived, ConstTypeRef base)
void GetDatamembers(DeclRef DRef, std::vector< DeclRef > &datamembers)
void GetFnTypeSignature(ConstTypeRef fn_type, std::vector< TypeRef > &sig)
bool IsAggregate(ConstDeclRef DRef)
ObjectRef Allocate(DeclRef DRef, size_t count)
bool IsFunctionPointerType(ConstTypeRef TyRef)
TypeRef GetFunctionArgType(ConstFuncRef func, size_t iarg)
intptr_t GetVariableOffset(compat::Interpreter &I, Decl *D, CXXRecordDecl *BaseCXXRD)
TypeRef GetUnderlyingType(ConstTypeRef TyRef)
static int vtableMethodSlotCount(ConstDeclRef DRef)
bool IsSmartPtrType(ConstTypeRef TyRef)
std::string GetQualifiedCompleteName(ConstDeclRef DRef)
void AddSearchPath(const char *dir, bool isUser, bool prepend)
TypeRef GetPointerType(ConstTypeRef TyRef)
size_t GetFunctionNumArgs(ConstFuncRef func)
static void PopulateBuiltinMap(ASTContext &Context)
bool IsDebugOutputEnabled()
bool IsFloatingType(ConstTypeRef TyRef)
TypeRef GetReferencedType(ConstTypeRef TyRef, bool rvalue)
bool IsBuiltin(ConstTypeRef TyRef)
size_t GetNumBases(ConstDeclRef DRef)
static std::string GetCompleteNameImpl(ConstDeclRef DRef, bool qualified)
bool IsClass(ConstDeclRef DRef)
std::vector< long int > GetDimensions(ConstTypeRef TyRef)
bool IsPublicMethod(ConstFuncRef method)
DeclRef GetGlobalScope()
void LookupConstructors(const std::string &name, ConstDeclRef parent, std::vector< FuncRef > &funcs)
FuncRef GetDefaultConstructor(compat::Interpreter &interp, DeclRef DRef)
bool IsIntegerType(ConstTypeRef TyRef, Signedness *s)
bool IsAbstract(ConstDeclRef DRef)
void cppinteropVTableOverlayDtorWrapper(void *self)
void CppInterOpTraceJitCallInvokeDestructorImpl(const JitCall *JC, void *object, unsigned long nary, int withFree)
void GetStaticDatamembers(ConstDeclRef DRef, std::vector< DeclRef > &datamembers)
bool IsPointerType(ConstTypeRef TyRef)
std::string SearchLibrariesForSymbol(const char *mangled_name, bool search_system)
FuncRef BestOverloadFunctionMatch(const std::vector< FuncRef > &candidates, const std::vector< TemplateArgInfo > &explicit_types, const std::vector< TemplateArgInfo > &arg_types)
void GetOperator(ConstDeclRef DRef, Operator op, std::vector< FuncRef > &operators, OperatorArity kind)
bool LoadLibrary(const char *lib_stem, bool lookup)
bool IsSubclass(ConstDeclRef derived, ConstDeclRef base)
void GetEnumConstantDatamembers(ConstDeclRef DRef, std::vector< DeclRef > &datamembers, bool include_enum_class)
static bool SkipShutDown
Set by UseExternalInterpreter to suppress llvm_shutdown at process exit – the client owns LLVM in tha...
VTableOverlay * MakeVTableOverlay(void *inst, ConstDeclRef base, const ConstFuncRef *methods, void *const *overlay_fns, std::size_t n_overlays, std::size_t n_extra_prefix_slots, VTableOverlayDtorHook on_destroy, void *cleanup_data)
static unsigned ComputeBaseOffset(const ASTContext &Context, const CXXRecordDecl *DerivedRD, const CXXBasePath &Path)
InterpRef GetInterpreter()
static std::stack< StreamCaptureInfo > & GetRedirectionStack()
bool IsExplicit(ConstFuncRef method)
size_t GetEnumConstantValue(ConstDeclRef DRef)
std::string GetVersion()
static compat::Interpreter & getInterp(InterpRef I=nullptr)
std::string LookupLibrary(const char *lib_name)
bool IsProtectedVariable(ConstDeclRef var)
bool IsConstVariable(ConstDeclRef var)
void GetFunctionTemplatedDecls(ConstDeclRef DRef, std::vector< FuncRef > &methods)
bool IsFunctionProtoType(ConstTypeRef TyRef)
bool IsTypedefed(ConstDeclRef DRef)
clang::QualType GetTypeFromDecl(const clang::TypeDecl *TD)
void InstantiateClassTemplateSpecialization(Interpreter &interp, clang::ClassTemplateSpecializationDecl *CTSD)
clang::Value Value
void maybeMangleDeclName(const clang::GlobalDecl &GD, std::string &mangledName)
CppInternal::Interpreter Interpreter
void codeComplete(std::vector< std::string > &Results, clang::Interpreter &I, const char *code, unsigned complete_line=1U, unsigned complete_column=1U)
llvm::orc::LLJIT * getExecutionEngine(clang::Interpreter &I)
Cpp::Box MakeValueBox(const Value &V, void *qt) noexcept
Wrap a compat::Value into a refcount-shared K_PtrOrObj Cpp::Box.
llvm::Expected< llvm::JITTargetAddress > getSymbolAddress(clang::Interpreter &I, llvm::StringRef IRName)
Definition Paths.h:18
std::map< const clang::FunctionDecl *, void * > WrapperStore
compat::Interpreter * Interpreter
std::map< const clang::Decl *, void * > DtorWrapperStore
RAII guard whose dtor calls llvm_shutdown for the owned-interpreter case.
VTableOverlay & operator=(const VTableOverlay &)=delete
static void ** ReadVPtr(void *inst)
VTableOverlay ** hidden_slot() const
VTableOverlayDtorHook cleanup
static void WriteVPtr(void *inst, void **new_vptr)
void(* orig_dtor)(void *)
std::size_t n_extra_prefix_slots
VTableOverlay(void **block, void **orig_vptr, void *inst, std::size_t n_extra)
static To BitCastFn(From f) noexcept
void ** address_point() const
VTableOverlay(const VTableOverlay &)=delete
Holds information for instantiating a template.