Skip to content

Commit 842efb6

Browse files
SC llvm teamSC llvm team
authored andcommitted
Merged main:e0bd8d3485075d24ecff2b4f5d9e2117853bd08b into amd-gfx:44ce984e8f2a
Local branch amd-gfx 44ce984 Merged main:cff753f8768ff3a7afbc27adaf318ebbf419dcfa into amd-gfx:d87172722360 Remote branch main e0bd8d3 [SLP] Better way to filter target-specific tests (llvm#106720)
2 parents 44ce984 + e0bd8d3 commit 842efb6

40 files changed

+2796
-93
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3097,12 +3097,11 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
30973097
QualType ElementType = E->getAllocatedType();
30983098
std::optional<PrimType> ElemT = classify(ElementType);
30993099
unsigned PlacementArgs = E->getNumPlacementArgs();
3100+
const FunctionDecl *OperatorNew = E->getOperatorNew();
3101+
const Expr *PlacementDest = nullptr;
31003102
bool IsNoThrow = false;
31013103

3102-
// FIXME: Better diagnostic. diag::note_constexpr_new_placement
31033104
if (PlacementArgs != 0) {
3104-
// The only new-placement list we support is of the form (std::nothrow).
3105-
//
31063105
// FIXME: There is no restriction on this, but it's not clear that any
31073106
// other form makes any sense. We get here for cases such as:
31083107
//
@@ -3111,27 +3110,43 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
31113110
// (which should presumably be valid only if N is a multiple of
31123111
// alignof(int), and in any case can't be deallocated unless N is
31133112
// alignof(X) and X has new-extended alignment).
3114-
if (PlacementArgs != 1 || !E->getPlacementArg(0)->getType()->isNothrowT())
3115-
return this->emitInvalid(E);
3113+
if (PlacementArgs == 1) {
3114+
const Expr *Arg1 = E->getPlacementArg(0);
3115+
if (Arg1->getType()->isNothrowT()) {
3116+
if (!this->discard(Arg1))
3117+
return false;
3118+
IsNoThrow = true;
3119+
} else if (Ctx.getLangOpts().CPlusPlus26 &&
3120+
OperatorNew->isReservedGlobalPlacementOperator()) {
3121+
// If we have a placement-new destination, we'll later use that instead
3122+
// of allocating.
3123+
PlacementDest = Arg1;
3124+
} else {
3125+
return this->emitInvalidNewDeleteExpr(E, E);
3126+
}
31163127

3117-
if (!this->discard(E->getPlacementArg(0)))
3118-
return false;
3119-
IsNoThrow = true;
3128+
} else {
3129+
return this->emitInvalid(E);
3130+
}
3131+
} else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
3132+
return this->emitInvalidNewDeleteExpr(E, E);
31203133
}
31213134

31223135
const Descriptor *Desc;
3123-
if (ElemT) {
3124-
if (E->isArray())
3125-
Desc = nullptr; // We're not going to use it in this case.
3126-
else
3127-
Desc = P.createDescriptor(E, *ElemT, Descriptor::InlineDescMD,
3128-
/*IsConst=*/false, /*IsTemporary=*/false,
3129-
/*IsMutable=*/false);
3130-
} else {
3131-
Desc = P.createDescriptor(
3132-
E, ElementType.getTypePtr(),
3133-
E->isArray() ? std::nullopt : Descriptor::InlineDescMD,
3134-
/*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false, Init);
3136+
if (!PlacementDest) {
3137+
if (ElemT) {
3138+
if (E->isArray())
3139+
Desc = nullptr; // We're not going to use it in this case.
3140+
else
3141+
Desc = P.createDescriptor(E, *ElemT, Descriptor::InlineDescMD,
3142+
/*IsConst=*/false, /*IsTemporary=*/false,
3143+
/*IsMutable=*/false);
3144+
} else {
3145+
Desc = P.createDescriptor(
3146+
E, ElementType.getTypePtr(),
3147+
E->isArray() ? std::nullopt : Descriptor::InlineDescMD,
3148+
/*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false, Init);
3149+
}
31353150
}
31363151

31373152
if (E->isArray()) {
@@ -3148,26 +3163,42 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
31483163

31493164
PrimType SizeT = classifyPrim(Stripped->getType());
31503165

3151-
if (!this->visit(Stripped))
3152-
return false;
3153-
3154-
if (ElemT) {
3155-
// N primitive elements.
3156-
if (!this->emitAllocN(SizeT, *ElemT, E, IsNoThrow, E))
3166+
if (PlacementDest) {
3167+
if (!this->visit(PlacementDest))
3168+
return false;
3169+
if (!this->visit(Stripped))
3170+
return false;
3171+
if (!this->emitCheckNewTypeMismatchArray(SizeT, E, E))
31573172
return false;
31583173
} else {
3159-
// N Composite elements.
3160-
if (!this->emitAllocCN(SizeT, Desc, IsNoThrow, E))
3174+
if (!this->visit(Stripped))
31613175
return false;
3176+
3177+
if (ElemT) {
3178+
// N primitive elements.
3179+
if (!this->emitAllocN(SizeT, *ElemT, E, IsNoThrow, E))
3180+
return false;
3181+
} else {
3182+
// N Composite elements.
3183+
if (!this->emitAllocCN(SizeT, Desc, IsNoThrow, E))
3184+
return false;
3185+
}
31623186
}
31633187

31643188
if (Init && !this->visitInitializer(Init))
31653189
return false;
31663190

31673191
} else {
3168-
// Allocate just one element.
3169-
if (!this->emitAlloc(Desc, E))
3170-
return false;
3192+
if (PlacementDest) {
3193+
if (!this->visit(PlacementDest))
3194+
return false;
3195+
if (!this->emitCheckNewTypeMismatch(E, E))
3196+
return false;
3197+
} else {
3198+
// Allocate just one element.
3199+
if (!this->emitAlloc(Desc, E))
3200+
return false;
3201+
}
31713202

31723203
if (Init) {
31733204
if (ElemT) {
@@ -3194,6 +3225,11 @@ template <class Emitter>
31943225
bool Compiler<Emitter>::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
31953226
const Expr *Arg = E->getArgument();
31963227

3228+
const FunctionDecl *OperatorDelete = E->getOperatorDelete();
3229+
3230+
if (!OperatorDelete->isReplaceableGlobalAllocationFunction())
3231+
return this->emitInvalidNewDeleteExpr(E, E);
3232+
31973233
// Arg must be an lvalue.
31983234
if (!this->visit(Arg))
31993235
return false;

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,80 @@ bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
12861286
return Call(S, OpPC, F, VarArgSize);
12871287
}
12881288

1289+
bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
1290+
std::optional<uint64_t> ArraySize) {
1291+
const Pointer &Ptr = S.Stk.peek<Pointer>();
1292+
1293+
if (!CheckStore(S, OpPC, Ptr))
1294+
return false;
1295+
1296+
const auto *NewExpr = cast<CXXNewExpr>(E);
1297+
QualType StorageType = Ptr.getType();
1298+
1299+
if (isa_and_nonnull<CXXNewExpr>(Ptr.getFieldDesc()->asExpr())) {
1300+
// FIXME: Are there other cases where this is a problem?
1301+
StorageType = StorageType->getPointeeType();
1302+
}
1303+
1304+
const ASTContext &ASTCtx = S.getASTContext();
1305+
QualType AllocType;
1306+
if (ArraySize) {
1307+
AllocType = ASTCtx.getConstantArrayType(
1308+
NewExpr->getAllocatedType(),
1309+
APInt(64, static_cast<uint64_t>(*ArraySize), false), nullptr,
1310+
ArraySizeModifier::Normal, 0);
1311+
} else {
1312+
AllocType = NewExpr->getAllocatedType();
1313+
}
1314+
1315+
unsigned StorageSize = 1;
1316+
unsigned AllocSize = 1;
1317+
if (const auto *CAT = dyn_cast<ConstantArrayType>(AllocType))
1318+
AllocSize = CAT->getZExtSize();
1319+
if (const auto *CAT = dyn_cast<ConstantArrayType>(StorageType))
1320+
StorageSize = CAT->getZExtSize();
1321+
1322+
if (AllocSize > StorageSize ||
1323+
!ASTCtx.hasSimilarType(ASTCtx.getBaseElementType(AllocType),
1324+
ASTCtx.getBaseElementType(StorageType))) {
1325+
S.FFDiag(S.Current->getLocation(OpPC),
1326+
diag::note_constexpr_placement_new_wrong_type)
1327+
<< StorageType << AllocType;
1328+
return false;
1329+
}
1330+
return true;
1331+
}
1332+
1333+
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) {
1334+
assert(E);
1335+
const auto &Loc = S.Current->getSource(OpPC);
1336+
1337+
if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {
1338+
const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();
1339+
1340+
if (!S.getLangOpts().CPlusPlus26 && NewExpr->getNumPlacementArgs() > 0) {
1341+
S.FFDiag(Loc, diag::note_constexpr_new_placement)
1342+
<< /*C++26 feature*/ 1 << E->getSourceRange();
1343+
} else if (NewExpr->getNumPlacementArgs() == 1 &&
1344+
!OperatorNew->isReservedGlobalPlacementOperator()) {
1345+
S.FFDiag(Loc, diag::note_constexpr_new_placement)
1346+
<< /*Unsupported*/ 0 << E->getSourceRange();
1347+
} else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
1348+
S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable)
1349+
<< isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
1350+
}
1351+
} else {
1352+
const auto *DeleteExpr = cast<CXXDeleteExpr>(E);
1353+
const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();
1354+
if (!OperatorDelete->isReplaceableGlobalAllocationFunction()) {
1355+
S.FFDiag(Loc, diag::note_constexpr_new_non_replaceable)
1356+
<< isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;
1357+
}
1358+
}
1359+
1360+
return false;
1361+
}
1362+
12891363
bool Interpret(InterpState &S, APValue &Result) {
12901364
// The current stack frame when we started Interpret().
12911365
// This is being used by the ops to determine wheter

clang/lib/AST/ByteCode/Interp.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2947,6 +2947,17 @@ static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
29472947
return true;
29482948
}
29492949

2950+
/// Check if the initializer and storage types of a placement-new expression
2951+
/// match.
2952+
bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
2953+
std::optional<uint64_t> ArraySize = std::nullopt);
2954+
2955+
template <PrimType Name, class T = typename PrimConv<Name>::T>
2956+
bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {
2957+
const auto &Size = S.Stk.pop<T>();
2958+
return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));
2959+
}
2960+
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
29502961
//===----------------------------------------------------------------------===//
29512962
// Read opcode arguments
29522963
//===----------------------------------------------------------------------===//

clang/lib/AST/ByteCode/Opcodes.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,4 +787,18 @@ def Free : Opcode {
787787
let Args = [ArgBool];
788788
}
789789

790+
def CheckNewTypeMismatch : Opcode {
791+
let Args = [ArgExpr];
792+
}
793+
794+
def InvalidNewDeleteExpr : Opcode {
795+
let Args = [ArgExpr];
796+
}
797+
798+
def CheckNewTypeMismatchArray : Opcode {
799+
let Types = [IntegerTypeClass];
800+
let Args = [ArgExpr];
801+
let HasGroup = 1;
802+
}
803+
790804
def IsConstantContext: Opcode;

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

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -241,12 +241,10 @@ namespace std {
241241

242242

243243

244-
/// FIXME: The new interpreter produces the wrong diagnostic.
245244
namespace PlacementNew {
246245
constexpr int foo() { // both-error {{never produces a constant expression}}
247246
char c[sizeof(int)];
248-
new (c) int{12}; // ref-note {{this placement new expression is not supported in constant expressions before C++2c}} \
249-
// expected-note {{subexpression not valid in a constant expression}}
247+
new (c) int{12}; // both-note {{this placement new expression is not supported in constant expressions before C++2c}}
250248
return 0;
251249
}
252250
}
@@ -305,41 +303,38 @@ namespace placement_new_delete {
305303
}
306304
static_assert(ok());
307305

308-
/// FIXME: Diagnosting placement new.
309306
constexpr bool bad(int which) {
310307
switch (which) {
311308
case 0:
312-
delete new (placement_new_arg{}) int; // ref-note {{this placement new expression is not supported in constant expressions}} \
313-
// expected-note {{subexpression not valid in a constant expression}}
309+
delete new (placement_new_arg{}) int; // both-note {{this placement new expression is not supported in constant expressions}}
314310
break;
315311

316312
case 1:
317-
delete new ClassSpecificNew; // ref-note {{call to class-specific 'operator new'}}
313+
delete new ClassSpecificNew; // both-note {{call to class-specific 'operator new'}}
318314
break;
319315

320316
case 2:
321-
delete new ClassSpecificDelete; // ref-note {{call to class-specific 'operator delete'}}
317+
delete new ClassSpecificDelete; // both-note {{call to class-specific 'operator delete'}}
322318
break;
323319

324320
case 3:
325-
delete new DestroyingDelete; // ref-note {{call to class-specific 'operator delete'}}
321+
delete new DestroyingDelete; // both-note {{call to class-specific 'operator delete'}}
326322
break;
327323

328324
case 4:
329325
// FIXME: This technically follows the standard's rules, but it seems
330326
// unreasonable to expect implementations to support this.
331-
delete new (std::align_val_t{64}) Overaligned; // ref-note {{this placement new expression is not supported in constant expressions}} \
332-
// expected-note {{subexpression not valid in a constant expression}}
327+
delete new (std::align_val_t{64}) Overaligned; // both-note {{this placement new expression is not supported in constant expressions}}
333328
break;
334329
}
335330

336331
return true;
337332
}
338333
static_assert(bad(0)); // both-error {{constant expression}} \
339334
// both-note {{in call}}
340-
static_assert(bad(1)); // ref-error {{constant expression}} ref-note {{in call}}
341-
static_assert(bad(2)); // ref-error {{constant expression}} ref-note {{in call}}
342-
static_assert(bad(3)); // ref-error {{constant expression}} ref-note {{in call}}
335+
static_assert(bad(1)); // both-error {{constant expression}} both-note {{in call}}
336+
static_assert(bad(2)); // both-error {{constant expression}} both-note {{in call}}
337+
static_assert(bad(3)); // both-error {{constant expression}} both-note {{in call}}
343338
static_assert(bad(4)); // both-error {{constant expression}} \
344339
// both-note {{in call}}
345340
}
@@ -586,7 +581,6 @@ constexpr void use_after_free_2() { // both-error {{never produces a constant ex
586581
p->f(); // both-note {{member call on heap allocated object that has been deleted}}
587582
}
588583

589-
590584
/// std::allocator definition
591585
namespace std {
592586
using size_t = decltype(sizeof(0));
@@ -758,6 +752,18 @@ namespace Limits {
758752
#endif
759753
}
760754

755+
/// Just test that we reject placement-new expressions before C++2c.
756+
/// Tests for successful expressions are in placement-new.cpp
757+
namespace Placement {
758+
consteval auto ok1() { // both-error {{never produces a constant expression}}
759+
bool b;
760+
new (&b) bool(true); // both-note 2{{this placement new expression is not supported in constant expressions before C++2c}}
761+
return b;
762+
}
763+
static_assert(ok1()); // both-error {{not an integral constant expression}} \
764+
// both-note {{in call to}}
765+
}
766+
761767
#else
762768
/// Make sure we reject this prior to C++20
763769
constexpr int a() { // both-error {{never produces a constant expression}}

0 commit comments

Comments
 (0)