https://github.com/xingxue-ibm updated https://github.com/llvm/llvm-project/pull/209280
>From 6b69974ca040d85a14a898c242f60c425b190c49 Mon Sep 17 00:00:00 2001 From: Xing Xue <[email protected]> Date: Mon, 13 Jul 2026 15:04:04 -0400 Subject: [PATCH 1/5] Update the unwinder to accommodate AIX changes required for LLU (Live Library Update). --- libcxxabi/test/aix_unwind_vapi.pass.cpp | 66 +++++++++++++++++ libunwind/src/UnwindCursor.hpp | 98 ++++++++++++++++++++++++- 2 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 libcxxabi/test/aix_unwind_vapi.pass.cpp diff --git a/libcxxabi/test/aix_unwind_vapi.pass.cpp b/libcxxabi/test/aix_unwind_vapi.pass.cpp new file mode 100644 index 0000000000000..bafb02f366ab4 --- /dev/null +++ b/libcxxabi/test/aix_unwind_vapi.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Test unwinding through a frame whose return address points to the VAPI +// glue for the Live Library Update feature. + +// REQUIRES: target={{.+}}-aix{{.*}} + +#include <stdlib.h> +#include <stdio.h> + +// VAPI glue addresses +constexpr uintptr_t vapi_glue_addr_ext_32 = 0x8B80; +constexpr uintptr_t vapi_addr_64 = 0x8e00; +constexpr uintptr_t vapi_size_64 = 0x0200; +constexpr uintptr_t vapi_glue_addr_begin = vapi_glue_addr_ext_32; // Start address in 32-bit +constexpr uintptr_t vapi_glue_addr_end = vapi_addr_64 + vapi_size_64; // End address in 64-bit + +struct FunctionDescriptor { + uintptr_t entry; + uintptr_t toc; + uintptr_t env; +}; + +struct Tracker { + const char* name; + Tracker(const char* n) : name(n) { printf("Construct %s\n", name); } + ~Tracker() { printf("Destruct %s\n", name); } +}; + +int comp(const void*, const void*) { + printf("comp()\n"); + throw 42; +} + +static void do_search() { + Tracker t("do_search-local"); + char buf[1]; + char key = 0; + printf("calling bsearch()\n"); + // bsearch uses VAPI and sets the return address to the VAPI glue when LLU + // is on. + bsearch(&key, buf, 1, 1, comp); + printf("after bsearch\n"); +} + +int main() { + FunctionDescriptor* fd = reinterpret_cast<FunctionDescriptor*>(bsearch); + + if (vapi_glue_addr_begin <= fd->entry && fd->entry < vapi_glue_addr_end) { + printf("!!! Live Library Update is enabled !!!\n"); + } else { + printf("!!! Live Library Update is NOT enabled !!!\n"); + } + + try { + do_search(); + } catch (...) { + printf("caught ...\n"); + } +} diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index ff92c9e0a844a..f59384af81b5e 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -1363,6 +1363,10 @@ class UnwindCursor : public AbstractUnwindCursor { reinterpret_cast<tbtable *>(_info.unwind_info), _registers, _isSignalFrame); } + bool isKnownVapiNotActive() const { return _isKnownVapiNotActive; } + void setIsKnownVapiNotActive(bool val) { _isKnownVapiNotActive = val; } + static pint_t getVAPILR(); + #endif // defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) A &_addressSpace; @@ -1377,13 +1381,15 @@ class UnwindCursor : public AbstractUnwindCursor { #ifdef _LIBUNWIND_TRACE_RET_INJECT uint32_t _walkedFrames; #endif +#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + bool _isKnownVapiNotActive; +#endif }; - template <typename A, typename R> UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as) : _addressSpace(as), _registers(context), _unwindInfoMissing(false), - _isSignalFrame(false) { + _isSignalFrame(false), _isKnownVapiNotActive(false) { static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit), "UnwindCursor<> does not fit in unw_cursor_t"); static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)), @@ -1393,13 +1399,13 @@ UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as) template <typename A, typename R> UnwindCursor<A, R>::UnwindCursor(A &as, void *) - : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) { + : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false), + _isKnownVapiNotActive(false) { memset(static_cast<void *>(&_info), 0, sizeof(_info)); // FIXME // fill in _registers from thread arg } - template <typename A, typename R> bool UnwindCursor<A, R>::validReg(int regNum) { return _registers.validRegister(regNum); @@ -1469,6 +1475,30 @@ template <typename A, typename R> void UnwindCursor<A, R>::jumpto() { static constexpr size_t _EXTRA_LIBUNWIND_FRAMES_WALKED = 5 - 1; _registers.returnto(_walkedFrames + _EXTRA_LIBUNWIND_FRAMES_WALKED); #else +#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + if (isKnownVapiNotActive()) { + // If the current frame is known VAPI not active , execute the VAPI return + // glue to clear the VAPI control block. The VAPI return glue is used by + // AIX longjmp based on the VAPI active status recorded by setjmp in the + // jmp_buf, which means that the VAPI return glue can be called solely on + // the basis of the VAPI active status of the target context. + + // VAPI return glue address is the VAPI glue address - 4. +#ifdef __64BIT__ + constexpr pint_t VAPIReturnGlue = 0x8e40 - 4; +#else + constexpr pint_t VAPIReturnGlue = 0x8c40 - 4; +#endif + + _LIBUNWIND_TRACE_UNWINDING("VAPI: executing return glue %p\n", + reinterpret_cast<void *>(VAPIReturnGlue)); + register auto *registers __asm__("r30") = &_registers; + __asm__ __volatile__("bla %[retglue]" + : "+r"(registers) + : [retglue] "i"(VAPIReturnGlue)); + registers->jumpto(); + } +#endif // defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) _registers.jumpto(); #endif } @@ -2459,6 +2489,45 @@ bool UnwindCursor<A, R>::getInfoFromTBTable(pint_t pc, R ®isters) { return true; } +// VAPI glue addresses +constexpr uintptr_t vapi_glue_addr_ext_32 = 0x8B80; +constexpr uintptr_t vapi_addr_64 = 0x8e00; +constexpr uintptr_t vapi_size_64 = 0x0200; +constexpr uintptr_t vapi_glue_addr_begin = + vapi_glue_addr_ext_32; // Start address in 32-bit +constexpr uintptr_t vapi_glue_addr_end = + vapi_addr_64 + vapi_size_64; // End address in 64-bit + +#ifdef __64BIT__ +constexpr uintptr_t VAPI_CB_SIZE = 256; +constexpr uintptr_t TLS_POINTER_OFFSET = 30 * 1024; +constexpr uintptr_t TLSCB_BASE_SIZE = 256; + +static __inline__ __attribute__((__always_inline__)) char *tptr(void) { + char *result; + __asm__("mr %0, 13" : "=r"(result)); + return result; +} +#else // 32-bit +constexpr uintptr_t VAPI_CB_SIZE = 128; +constexpr uintptr_t TLS_POINTER_OFFSET = 31 * 1024; +constexpr uintptr_t TLSCB_BASE_SIZE = 128; + +static __inline__ __attribute__((__always_inline__)) char *tptr(void) { + char *result; + __asm__("mfspr %0, 259" : "=r"(result)); + return result; +} +#endif + +constexpr int VAPI_CB_OFFSET = + TLS_POINTER_OFFSET + VAPI_CB_SIZE + TLSCB_BASE_SIZE; + +template <typename A, typename R> +typename UnwindCursor<A, R>::pint_t UnwindCursor<A, R>::getVAPILR() { + return *reinterpret_cast<pint_t *>(tptr() - VAPI_CB_OFFSET + 8); +} + // Step back up the stack following the frame back link. template <typename A, typename R> int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable, @@ -2579,6 +2648,17 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable, } else { // Otherwise, use the LR value in the stack link area. returnAddress = reinterpret_cast<pint_t *>(lastStack)[2]; + + if (vapi_glue_addr_begin <= returnAddress && + returnAddress < vapi_glue_addr_end) { + _LIBUNWIND_TRACE_UNWINDING( + "The return address=%p is within the range of VAPI address, ", + reinterpret_cast<void *>(returnAddress)); + setIsKnownVapiNotActive(true); + returnAddress = getVAPILR(); + _LIBUNWIND_TRACE_UNWINDING("return address=%p from VAPI\n", + reinterpret_cast<void *>(returnAddress)); + } } // Reset LR in the current context. @@ -2709,6 +2789,16 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable, // Return address is the address after call site instruction. pint_t nextReturnAddress = reinterpret_cast<pint_t *>(nextStack)[2]; + if (vapi_glue_addr_begin <= nextReturnAddress && + nextReturnAddress < vapi_glue_addr_end) { + _LIBUNWIND_TRACE_UNWINDING( + "The next return address=%p is within the range of VAPI address, ", + reinterpret_cast<void *>(nextReturnAddress)); + nextReturnAddress = getVAPILR(); + _LIBUNWIND_TRACE_UNWINDING("the next return address=%p from VAPI\n", + reinterpret_cast<void *>(nextReturnAddress)); + } + if (nextReturnAddress > 0x01 && nextReturnAddress < 0x10000) { _LIBUNWIND_TRACE_UNWINDING("The next is a signal handler frame: " "nextStack=%p, next return address=%p\n", >From 578ab2193990e1954f302654d3f17fa40e639f0e Mon Sep 17 00:00:00 2001 From: Xing Xue <[email protected]> Date: Mon, 13 Jul 2026 15:47:23 -0400 Subject: [PATCH 2/5] Guard _isKnownVapiNotActive(false) initializers with #if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND). --- libunwind/src/UnwindCursor.hpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index f59384af81b5e..7b400964defc8 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -1389,7 +1389,11 @@ class UnwindCursor : public AbstractUnwindCursor { template <typename A, typename R> UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as) : _addressSpace(as), _registers(context), _unwindInfoMissing(false), - _isSignalFrame(false), _isKnownVapiNotActive(false) { + _isSignalFrame(false) +#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + , _isKnownVapiNotActive(false) +#endif + { static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit), "UnwindCursor<> does not fit in unw_cursor_t"); static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)), @@ -1399,8 +1403,11 @@ UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as) template <typename A, typename R> UnwindCursor<A, R>::UnwindCursor(A &as, void *) - : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false), - _isKnownVapiNotActive(false) { + : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) +#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + , _isKnownVapiNotActive(false) +#endif + { memset(static_cast<void *>(&_info), 0, sizeof(_info)); // FIXME // fill in _registers from thread arg >From 6b571a1a2099194a52e7db94c4fcd9adf5b39bde Mon Sep 17 00:00:00 2001 From: Xing Xue <[email protected]> Date: Mon, 13 Jul 2026 18:18:53 -0400 Subject: [PATCH 3/5] Address comments and fix formatting. - correct variable types - add a comment for TODO --- libcxxabi/test/aix_unwind_vapi.pass.cpp | 66 ------------------------- libunwind/src/UnwindCursor.hpp | 37 ++++++++------ 2 files changed, 21 insertions(+), 82 deletions(-) delete mode 100644 libcxxabi/test/aix_unwind_vapi.pass.cpp diff --git a/libcxxabi/test/aix_unwind_vapi.pass.cpp b/libcxxabi/test/aix_unwind_vapi.pass.cpp deleted file mode 100644 index bafb02f366ab4..0000000000000 --- a/libcxxabi/test/aix_unwind_vapi.pass.cpp +++ /dev/null @@ -1,66 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// Test unwinding through a frame whose return address points to the VAPI -// glue for the Live Library Update feature. - -// REQUIRES: target={{.+}}-aix{{.*}} - -#include <stdlib.h> -#include <stdio.h> - -// VAPI glue addresses -constexpr uintptr_t vapi_glue_addr_ext_32 = 0x8B80; -constexpr uintptr_t vapi_addr_64 = 0x8e00; -constexpr uintptr_t vapi_size_64 = 0x0200; -constexpr uintptr_t vapi_glue_addr_begin = vapi_glue_addr_ext_32; // Start address in 32-bit -constexpr uintptr_t vapi_glue_addr_end = vapi_addr_64 + vapi_size_64; // End address in 64-bit - -struct FunctionDescriptor { - uintptr_t entry; - uintptr_t toc; - uintptr_t env; -}; - -struct Tracker { - const char* name; - Tracker(const char* n) : name(n) { printf("Construct %s\n", name); } - ~Tracker() { printf("Destruct %s\n", name); } -}; - -int comp(const void*, const void*) { - printf("comp()\n"); - throw 42; -} - -static void do_search() { - Tracker t("do_search-local"); - char buf[1]; - char key = 0; - printf("calling bsearch()\n"); - // bsearch uses VAPI and sets the return address to the VAPI glue when LLU - // is on. - bsearch(&key, buf, 1, 1, comp); - printf("after bsearch\n"); -} - -int main() { - FunctionDescriptor* fd = reinterpret_cast<FunctionDescriptor*>(bsearch); - - if (vapi_glue_addr_begin <= fd->entry && fd->entry < vapi_glue_addr_end) { - printf("!!! Live Library Update is enabled !!!\n"); - } else { - printf("!!! Live Library Update is NOT enabled !!!\n"); - } - - try { - do_search(); - } catch (...) { - printf("caught ...\n"); - } -} diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index 7b400964defc8..1f147dc4e920e 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -1382,6 +1382,9 @@ class UnwindCursor : public AbstractUnwindCursor { uint32_t _walkedFrames; #endif #if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) + // TODO: this will need to be recorded in the unw_context_t by unw_getcontext + // to support cases where the cursor is retrieved prior to invocation of the + // Virtual API. bool _isKnownVapiNotActive; #endif }; @@ -1391,9 +1394,10 @@ UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as) : _addressSpace(as), _registers(context), _unwindInfoMissing(false), _isSignalFrame(false) #if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) - , _isKnownVapiNotActive(false) + , + _isKnownVapiNotActive(false) #endif - { +{ static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit), "UnwindCursor<> does not fit in unw_cursor_t"); static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)), @@ -1405,9 +1409,10 @@ template <typename A, typename R> UnwindCursor<A, R>::UnwindCursor(A &as, void *) : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) #if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) - , _isKnownVapiNotActive(false) + , + _isKnownVapiNotActive(false) #endif - { +{ memset(static_cast<void *>(&_info), 0, sizeof(_info)); // FIXME // fill in _registers from thread arg @@ -1484,7 +1489,7 @@ template <typename A, typename R> void UnwindCursor<A, R>::jumpto() { #else #if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND) if (isKnownVapiNotActive()) { - // If the current frame is known VAPI not active , execute the VAPI return + // If the current frame is known VAPI not active, execute the VAPI return // glue to clear the VAPI control block. The VAPI return glue is used by // AIX longjmp based on the VAPI active status recorded by setjmp in the // jmp_buf, which means that the VAPI return glue can be called solely on @@ -2497,18 +2502,18 @@ bool UnwindCursor<A, R>::getInfoFromTBTable(pint_t pc, R ®isters) { } // VAPI glue addresses -constexpr uintptr_t vapi_glue_addr_ext_32 = 0x8B80; +constexpr uintptr_t vapi_glue_addr_ext_32 = 0x8b80; constexpr uintptr_t vapi_addr_64 = 0x8e00; -constexpr uintptr_t vapi_size_64 = 0x0200; +constexpr size_t vapi_size_64 = 0x0200; constexpr uintptr_t vapi_glue_addr_begin = vapi_glue_addr_ext_32; // Start address in 32-bit constexpr uintptr_t vapi_glue_addr_end = vapi_addr_64 + vapi_size_64; // End address in 64-bit #ifdef __64BIT__ -constexpr uintptr_t VAPI_CB_SIZE = 256; -constexpr uintptr_t TLS_POINTER_OFFSET = 30 * 1024; -constexpr uintptr_t TLSCB_BASE_SIZE = 256; +constexpr size_t VAPI_CB_SIZE = 256; +constexpr ptrdiff_t TLS_POINTER_OFFSET = 30 * 1024; +constexpr size_t TLSCB_BASE_SIZE = 256; static __inline__ __attribute__((__always_inline__)) char *tptr(void) { char *result; @@ -2516,9 +2521,9 @@ static __inline__ __attribute__((__always_inline__)) char *tptr(void) { return result; } #else // 32-bit -constexpr uintptr_t VAPI_CB_SIZE = 128; -constexpr uintptr_t TLS_POINTER_OFFSET = 31 * 1024; -constexpr uintptr_t TLSCB_BASE_SIZE = 128; +constexpr size_t VAPI_CB_SIZE = 128; +constexpr ptrdiff_t TLS_POINTER_OFFSET = 31 * 1024; +constexpr size_t TLSCB_BASE_SIZE = 128; static __inline__ __attribute__((__always_inline__)) char *tptr(void) { char *result; @@ -2527,7 +2532,7 @@ static __inline__ __attribute__((__always_inline__)) char *tptr(void) { } #endif -constexpr int VAPI_CB_OFFSET = +constexpr ptrdiff_t VAPI_CB_OFFSET = TLS_POINTER_OFFSET + VAPI_CB_SIZE + TLSCB_BASE_SIZE; template <typename A, typename R> @@ -2659,7 +2664,7 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable, if (vapi_glue_addr_begin <= returnAddress && returnAddress < vapi_glue_addr_end) { _LIBUNWIND_TRACE_UNWINDING( - "The return address=%p is within the range of VAPI address, ", + "The return address=%p is within the range of VAPI address;", reinterpret_cast<void *>(returnAddress)); setIsKnownVapiNotActive(true); returnAddress = getVAPILR(); @@ -2799,7 +2804,7 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable, if (vapi_glue_addr_begin <= nextReturnAddress && nextReturnAddress < vapi_glue_addr_end) { _LIBUNWIND_TRACE_UNWINDING( - "The next return address=%p is within the range of VAPI address, ", + "The next return address=%p is within the range of VAPI address;", reinterpret_cast<void *>(nextReturnAddress)); nextReturnAddress = getVAPILR(); _LIBUNWIND_TRACE_UNWINDING("the next return address=%p from VAPI\n", >From cceca093ab4e38ce33b6fe7457158c52b8688ee4 Mon Sep 17 00:00:00 2001 From: Xing Xue <[email protected]> Date: Wed, 15 Jul 2026 10:50:09 -0400 Subject: [PATCH 4/5] If the return address in a signal handling trampoline frame is a VAPI glue return address, set isKnownVapiNotActive flag to true. --- libunwind/src/UnwindCursor.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index 1f147dc4e920e..03ea96b2e4451 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -2592,6 +2592,16 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable, _LIBUNWIND_TRACE_UNWINDING("Possible signal handler frame: lastStack=%p", reinterpret_cast<void *>(lastStack)); + pint_t returnAddressInStack = reinterpret_cast<pint_t *>(lastStack)[2]; + if (vapi_glue_addr_begin <= returnAddressInStack && + returnAddressInStack < vapi_glue_addr_end) { + _LIBUNWIND_TRACE_UNWINDING( + "The return address in stack %p is within the range of VAPI address," + " set isKnownVapiNotActive to true\n", + reinterpret_cast<void *>(returnAddressInStack)); + setIsKnownVapiNotActive(true); + } + sigcontext *sigContext = reinterpret_cast<sigcontext *>( reinterpret_cast<char *>(lastStack) + STKMINALIGN); returnAddress = sigContext->sc_jmpbuf.jmp_context.iar; >From f2a6772a578c51da6ea39fc2bf7483bf331ae3d4 Mon Sep 17 00:00:00 2001 From: Xing Xue <[email protected]> Date: Thu, 16 Jul 2026 06:40:35 -0400 Subject: [PATCH 5/5] Apply suggestion: ',' -> ';'. Co-authored-by: Hubert Tong <[email protected]> --- libunwind/src/UnwindCursor.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index 03ea96b2e4451..537dbd83f4f74 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -2596,7 +2596,7 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable, if (vapi_glue_addr_begin <= returnAddressInStack && returnAddressInStack < vapi_glue_addr_end) { _LIBUNWIND_TRACE_UNWINDING( - "The return address in stack %p is within the range of VAPI address," + "The return address in stack %p is within the range of VAPI address;" " set isKnownVapiNotActive to true\n", reinterpret_cast<void *>(returnAddressInStack)); setIsKnownVapiNotActive(true); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
