Skip to content

Commit a0f0a5f

Browse files
committed
[clang][bytecode] Allow placement-new in std function pre-C++26
1 parent b30b9eb commit a0f0a5f

File tree

7 files changed

+85
-4
lines changed

7 files changed

+85
-4
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3116,8 +3116,7 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
31163116
if (!this->discard(Arg1))
31173117
return false;
31183118
IsNoThrow = true;
3119-
} else if (Ctx.getLangOpts().CPlusPlus26 &&
3120-
OperatorNew->isReservedGlobalPlacementOperator()) {
3119+
} else if (OperatorNew->isReservedGlobalPlacementOperator()) {
31213120
// If we have a placement-new destination, we'll later use that instead
31223121
// of allocating.
31233122
PlacementDest = Arg1;

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,13 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
12931293
if (!CheckStore(S, OpPC, Ptr))
12941294
return false;
12951295

1296+
if (!InvalidNewDeleteExpr(S, OpPC, E))
1297+
return false;
1298+
1299+
// Assume proper types in std functions.
1300+
if (S.Current->isStdFunction())
1301+
return true;
1302+
12961303
const auto *NewExpr = cast<CXXNewExpr>(E);
12971304
QualType StorageType = Ptr.getType();
12981305

@@ -1334,10 +1341,16 @@ bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) {
13341341
assert(E);
13351342
const auto &Loc = S.Current->getSource(OpPC);
13361343

1344+
if (S.getLangOpts().CPlusPlus26)
1345+
return true;
1346+
13371347
if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {
13381348
const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();
13391349

13401350
if (!S.getLangOpts().CPlusPlus26 && NewExpr->getNumPlacementArgs() > 0) {
1351+
// This is allowed pre-C++26, but only an std function.
1352+
if (S.Current->isStdFunction())
1353+
return true;
13411354
S.FFDiag(Loc, diag::note_constexpr_new_placement)
13421355
<< /*C++26 feature*/ 1 << E->getSourceRange();
13431356
} else if (NewExpr->getNumPlacementArgs() == 1 &&

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,8 +1345,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
13451345
assert(!ElemT);
13461346
// Structs etc.
13471347
const Descriptor *Desc = S.P.createDescriptor(
1348-
Call, ElemType.getTypePtr(),
1349-
NumElems.ule(1) ? std::nullopt : Descriptor::InlineDescMD,
1348+
Call, ElemType.getTypePtr(), Descriptor::InlineDescMD,
13501349
/*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false,
13511350
/*Init=*/nullptr);
13521351

clang/lib/AST/ByteCode/InterpFrame.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,13 @@ SourceRange InterpFrame::getRange(CodePtr PC) const {
257257

258258
return S.getRange(Func, PC);
259259
}
260+
261+
bool InterpFrame::isStdFunction() const {
262+
if (!Func)
263+
return false;
264+
for (const DeclContext *DC = Func->getDecl(); DC; DC = DC->getParent())
265+
if (DC->isStdNamespace())
266+
return true;
267+
268+
return false;
269+
}

clang/lib/AST/ByteCode/InterpFrame.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ class InterpFrame final : public Frame {
117117

118118
unsigned getDepth() const { return Depth; }
119119

120+
bool isStdFunction() const;
121+
120122
void dump() const { dump(llvm::errs(), 0); }
121123
void dump(llvm::raw_ostream &OS, unsigned Indent = 0) const;
122124

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,10 @@ namespace std {
594594
// both-note {{used to delete a null pointer}}
595595
}
596596
};
597+
template<typename T, typename ...Args>
598+
constexpr void construct_at(void *p, Args &&...args) { // #construct
599+
new (p) T((Args&&)args...);
600+
}
597601
}
598602

599603
/// Specialization for float, using operator new/delete.
@@ -762,6 +766,16 @@ namespace Placement {
762766
}
763767
static_assert(ok1()); // both-error {{not an integral constant expression}} \
764768
// both-note {{in call to}}
769+
770+
/// placement-new should be supported before C++26 in std functions.
771+
constexpr int ok2() {
772+
int *I = new int;
773+
std::construct_at<int>(I);
774+
int r = *I;
775+
delete I;
776+
return r;
777+
}
778+
static_assert(ok2()== 0);
765779
}
766780

767781
#else

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@
33

44
namespace std {
55
using size_t = decltype(sizeof(0));
6+
template<typename T> struct allocator {
7+
constexpr T *allocate(size_t N) {
8+
return (T*)operator new(sizeof(T) * N);
9+
}
10+
constexpr void deallocate(void *p) {
11+
operator delete(p);
12+
}
13+
};
14+
template<typename T, typename ...Args>
15+
constexpr void construct_at(void *p, Args &&...args) {
16+
new (p) T((Args&&)args...); // both-note {{in call to}}
17+
}
618
}
719

820
void *operator new(std::size_t, void *p) { return p; }
@@ -217,3 +229,35 @@ namespace records {
217229
}
218230
static_assert(foo() == 0);
219231
}
232+
233+
namespace ConstructAt {
234+
struct S {
235+
int a = 10;
236+
float b = 1.0;
237+
};
238+
239+
constexpr bool ok1() {
240+
S s;
241+
242+
std::construct_at<S>(&s);
243+
return s.a == 10 && s.b == 1.0;
244+
}
245+
static_assert(ok1());
246+
247+
struct S2 {
248+
constexpr S2() {
249+
(void)(1/0); // both-note {{division by zero}} \
250+
// both-warning {{division by zero is undefined}}
251+
}
252+
};
253+
254+
constexpr bool ctorFail() { //
255+
S2 *s = std::allocator<S2>().allocate(1);
256+
std::construct_at<S2>(s); // both-note {{in call to}}
257+
258+
return true;
259+
}
260+
static_assert(ctorFail()); // both-error {{not an integral constant expression}} \
261+
// both-note {{in call to 'ctorFail()'}}
262+
263+
}

0 commit comments

Comments
 (0)