Skip to content

Commit 4f9e6ba

Browse files
authored
[clang][bytecode] Fix calling operator new with nothrow/align parameter (#144271)
Discard all the parameters we don't care about.
1 parent 4ea616d commit 4f9e6ba

File tree

2 files changed

+35
-7
lines changed

2 files changed

+35
-7
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,6 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
14231423
// Walk up the call stack to find the appropriate caller and get the
14241424
// element type from it.
14251425
auto [NewCall, ElemType] = S.getStdAllocatorCaller("allocate");
1426-
APSInt Bytes = popToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(0)));
14271426

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

1441+
// We only care about the first parameter (the size), so discard all the
1442+
// others.
1443+
{
1444+
unsigned NumArgs = Call->getNumArgs();
1445+
assert(NumArgs >= 1);
1446+
1447+
// The std::nothrow_t arg never gets put on the stack.
1448+
if (Call->getArg(NumArgs - 1)->getType()->isNothrowT())
1449+
--NumArgs;
1450+
auto Args = llvm::ArrayRef(Call->getArgs(), Call->getNumArgs());
1451+
// First arg is needed.
1452+
Args = Args.drop_front();
1453+
1454+
// Discard the rest.
1455+
for (const Expr *Arg : Args)
1456+
discard(S.Stk, *S.getContext().classify(Arg));
1457+
}
1458+
1459+
APSInt Bytes = popToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(0)));
14421460
CharUnits ElemSize = S.getASTContext().getTypeSizeInChars(ElemType);
14431461
assert(!ElemSize.isZero());
14441462
// Divide the number of bytes by sizeof(ElemType), so we get the number of

clang/test/AST/ByteCode/new-delete.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s
2-
// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s
3-
// RUN: %clang_cc1 -triple=i686-linux-gnu -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s
4-
// RUN: %clang_cc1 -verify=ref,both %s
5-
// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s
6-
// RUN: %clang_cc1 -triple=i686-linux-gnu -std=c++20 -verify=ref,both %s
1+
// RUN: %clang_cc1 -verify=expected,both -fexperimental-new-constant-interpreter %s
2+
// RUN: %clang_cc1 -std=c++20 -verify=expected,both -fexperimental-new-constant-interpreter %s
3+
// RUN: %clang_cc1 -std=c++20 -verify=expected,both -triple=i686-linux-gnu -fexperimental-new-constant-interpreter %s
4+
// RUN: %clang_cc1 -verify=ref,both %s
5+
// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s
6+
// RUN: %clang_cc1 -std=c++20 -verify=ref,both -triple=i686-linux-gnu %s
77

88
#if __cplusplus >= 202002L
99

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

1015+
namespace OpNewNothrow {
1016+
constexpr int f() {
1017+
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'}}
1018+
operator delete(v, std::align_val_t(2), std::nothrow);
1019+
return 1;
1020+
}
1021+
static_assert(f()); // both-error {{not an integral constant expression}} \
1022+
// both-note {{in call to}}
1023+
}
1024+
10151025
#else
10161026
/// Make sure we reject this prior to C++20
10171027
constexpr int a() { // both-error {{never produces a constant expression}}

0 commit comments

Comments
 (0)