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
20 changes: 19 additions & 1 deletion clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1423,7 +1423,6 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
// Walk up the call stack to find the appropriate caller and get the
// element type from it.
auto [NewCall, ElemType] = S.getStdAllocatorCaller("allocate");
APSInt Bytes = popToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(0)));

if (ElemType.isNull()) {
S.FFDiag(Call, S.getLangOpts().CPlusPlus20
Expand All @@ -1439,6 +1438,25 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
return false;
}

// We only care about the first parameter (the size), so discard all the
// others.
{
unsigned NumArgs = Call->getNumArgs();
assert(NumArgs >= 1);

// The std::nothrow_t arg never gets put on the stack.
if (Call->getArg(NumArgs - 1)->getType()->isNothrowT())
--NumArgs;
auto Args = llvm::ArrayRef(Call->getArgs(), Call->getNumArgs());
// First arg is needed.
Args = Args.drop_front();

// Discard the rest.
for (const Expr *Arg : Args)
discard(S.Stk, *S.getContext().classify(Arg));
}

APSInt Bytes = popToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(0)));
CharUnits ElemSize = S.getASTContext().getTypeSizeInChars(ElemType);
assert(!ElemSize.isZero());
// Divide the number of bytes by sizeof(ElemType), so we get the number of
Expand Down
22 changes: 16 additions & 6 deletions clang/test/AST/ByteCode/new-delete.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s
// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s
// RUN: %clang_cc1 -triple=i686-linux-gnu -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s
// RUN: %clang_cc1 -verify=ref,both %s
// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s
// RUN: %clang_cc1 -triple=i686-linux-gnu -std=c++20 -verify=ref,both %s
// RUN: %clang_cc1 -verify=expected,both -fexperimental-new-constant-interpreter %s
// RUN: %clang_cc1 -std=c++20 -verify=expected,both -fexperimental-new-constant-interpreter %s
// RUN: %clang_cc1 -std=c++20 -verify=expected,both -triple=i686-linux-gnu -fexperimental-new-constant-interpreter %s
// RUN: %clang_cc1 -verify=ref,both %s
// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s
// RUN: %clang_cc1 -std=c++20 -verify=ref,both -triple=i686-linux-gnu %s

#if __cplusplus >= 202002L

Expand Down Expand Up @@ -1012,6 +1012,16 @@ constexpr int no_deallocate_nonalloc = (std::allocator<int>().deallocate((int*)&
// both-note {{in call}} \
// both-note {{declared here}}

namespace OpNewNothrow {
constexpr int f() {
int *v = (int*)operator new(sizeof(int), std::align_val_t(2), std::nothrow); // both-note {{cannot allocate untyped memory in a constant expression; use 'std::allocator<T>::allocate' to allocate memory of type 'T'}}
operator delete(v, std::align_val_t(2), std::nothrow);
return 1;
}
static_assert(f()); // 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}}
Expand Down
Loading