https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/136141
This is only permitted in a std::allocator::deallocate frame. >From 4774ba70d70a33cde681ab8daba7f7429e131ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Thu, 17 Apr 2025 15:44:49 +0200 Subject: [PATCH] [clang][bytecode] Check if operator delete calls are in the right frame This is only permitted in a std::allocator::deallocate frame. --- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 35 ++++++++++++++++++++++++ clang/test/AST/ByteCode/new-delete.cpp | 12 ++++++++ 2 files changed, 47 insertions(+) diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 31d97d9060142..34553301ef630 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -1651,6 +1651,41 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC, const Expr *Source = nullptr; const Block *BlockToDelete = nullptr; + if (S.checkingPotentialConstantExpression()) + return false; + + // This is permitted only within a call to std::allocator<T>::deallocate. + bool DeallocateFrameFound = false; + for (const InterpFrame *F = Frame; F; F = F->Caller) { + const Function *Func = F->getFunction(); + if (!Func) + continue; + const auto *MD = dyn_cast_if_present<CXXMethodDecl>(Func->getDecl()); + if (!MD) + continue; + const IdentifierInfo *FnII = MD->getIdentifier(); + if (!FnII || !FnII->isStr("deallocate")) + continue; + + const auto *CTSD = + dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent()); + if (!CTSD) + continue; + + const IdentifierInfo *ClassII = CTSD->getIdentifier(); + const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); + if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") && + TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) { + DeallocateFrameFound = true; + break; + } + } + + if (!DeallocateFrameFound) { + S.FFDiag(Call); + return true; + } + { const Pointer &Ptr = S.Stk.peek<Pointer>(); diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp index 5ddd7070f6710..e1b81e9a7963e 100644 --- a/clang/test/AST/ByteCode/new-delete.cpp +++ b/clang/test/AST/ByteCode/new-delete.cpp @@ -992,6 +992,18 @@ namespace ZeroSizeSub { // both-note {{in call to}} } +namespace WrongFrame { + constexpr int foo() { + int *p = nullptr; + __builtin_operator_delete(p); // both-note {{subexpression not valid in a constant expression}} + + return 1; + } + static_assert(foo()); // both-error {{not an integral constant expression}} \ + // both-note {{in call to}} + +} + #else /// Make sure we reject this prior to C++20 constexpr int a() { // both-error {{never produces a constant expression}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits