Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5146,7 +5146,8 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
if (!this->emitCheckPseudoDtor(E))
return false;
const Expr *Base = PD->getBase();
if (!Base->isGLValue())
// E.g. `using T = int; 0.~T();`.
if (OptPrimType BaseT = classify(Base); !BaseT || BaseT != PT_Ptr)
return this->discard(Base);
if (!this->visit(Base))
return false;
Expand Down
43 changes: 43 additions & 0 deletions clang/test/AST/ByteCode/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,27 @@
#error "huh?"
#endif


inline constexpr void* operator new(__SIZE_TYPE__, void* p) noexcept { return p; }
namespace std {
using size_t = decltype(sizeof(0));
template<typename T> struct allocator {
constexpr T *allocate(size_t N) {
return (T*)__builtin_operator_new(sizeof(T) * N); // #alloc
}
constexpr void deallocate(void *p, __SIZE_TYPE__) {
__builtin_operator_delete(p);
}
};
template<typename T, typename... Args>
constexpr T* construct_at(T* p, Args&&... args) { return ::new((void*)p) T(static_cast<Args&&>(args)...); }

template<typename T>
constexpr void destroy_at(T* p) {
p->~T();
}
}

extern "C" {
typedef decltype(sizeof(int)) size_t;
extern size_t wcslen(const wchar_t *p);
Expand Down Expand Up @@ -1767,6 +1788,28 @@ namespace WithinLifetime {
}
} xstd; // both-error {{is not a constant expression}} \
// both-note {{in call to}}

consteval bool test_dynamic(bool read_after_deallocate) {
std::allocator<int> a;
int* p = a.allocate(1);
// a.allocate starts the lifetime of an array,
// the complete object of *p has started its lifetime
if (__builtin_is_within_lifetime(p))
return false;
std::construct_at(p);
if (!__builtin_is_within_lifetime(p))
return false;
std::destroy_at(p);
if (__builtin_is_within_lifetime(p))
return false;
a.deallocate(p, 1);
if (read_after_deallocate)
__builtin_is_within_lifetime(p); // both-note {{read of heap allocated object that has been deleted}}
return true;
}
static_assert(test_dynamic(false));
static_assert(test_dynamic(true)); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
}

#ifdef __SIZEOF_INT128__
Expand Down