Skip to content

Commit e6030d3

Browse files
authored
[clang][bytecode] Use std::allocator calls for Descriptor source (llvm#123900)
... for the dynamic blocks created for operator new calls. This way we get the type of memory allocated right. As a side-effect, the diagnostics now point to the std::allocator calls, which is an improvement.
1 parent 9bb3c62 commit e6030d3

File tree

3 files changed

+36
-9
lines changed

3 files changed

+36
-9
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -873,13 +873,17 @@ bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,
873873

874874
bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
875875
const Pointer &Ptr) {
876-
// The two sources we currently allow are new expressions and
877-
// __builtin_operator_new calls.
876+
// Regular new type(...) call.
878877
if (isa_and_nonnull<CXXNewExpr>(Source))
879878
return true;
880-
if (const CallExpr *CE = dyn_cast_if_present<CallExpr>(Source);
879+
// operator new.
880+
if (const auto *CE = dyn_cast_if_present<CallExpr>(Source);
881881
CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new)
882882
return true;
883+
// std::allocator.allocate() call
884+
if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(Source);
885+
MCE && MCE->getMethodDecl()->getIdentifier()->isStr("allocate"))
886+
return true;
883887

884888
// Whatever this is, we didn't heap allocate it.
885889
const SourceInfo &Loc = S.Current->getSource(OpPC);
@@ -1489,7 +1493,8 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
14891493
const auto *NewExpr = cast<CXXNewExpr>(E);
14901494
QualType StorageType = Ptr.getType();
14911495

1492-
if (isa_and_nonnull<CXXNewExpr>(Ptr.getFieldDesc()->asExpr()) &&
1496+
if ((isa_and_nonnull<CXXNewExpr>(Ptr.getFieldDesc()->asExpr()) ||
1497+
isa_and_nonnull<CXXMemberCallExpr>(Ptr.getFieldDesc()->asExpr())) &&
14931498
StorageType->isPointerType()) {
14941499
// FIXME: Are there other cases where this is a problem?
14951500
StorageType = StorageType->getPointeeType();

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,6 +1584,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
15841584
// Walk up the call stack to find the appropriate caller and get the
15851585
// element type from it.
15861586
QualType ElemType;
1587+
const CallExpr *NewCall = nullptr;
15871588

15881589
for (const InterpFrame *F = Frame; F; F = F->Caller) {
15891590
const Function *Func = F->getFunction();
@@ -1606,6 +1607,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
16061607
if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
16071608
TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) {
16081609
ElemType = TAL[0].getAsType();
1610+
NewCall = cast<CallExpr>(F->Caller->getExpr(F->getRetPC()));
16091611
break;
16101612
}
16111613
}
@@ -1616,6 +1618,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
16161618
: diag::note_constexpr_new);
16171619
return false;
16181620
}
1621+
assert(NewCall);
16191622

16201623
if (ElemType->isIncompleteType() || ElemType->isFunctionType()) {
16211624
S.FFDiag(Call, diag::note_constexpr_new_not_complete_object_type)
@@ -1654,7 +1657,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
16541657
if (ElemT) {
16551658
if (NumElems.ule(1)) {
16561659
const Descriptor *Desc =
1657-
S.P.createDescriptor(Call, *ElemT, Descriptor::InlineDescMD,
1660+
S.P.createDescriptor(NewCall, *ElemT, Descriptor::InlineDescMD,
16581661
/*IsConst=*/false, /*IsTemporary=*/false,
16591662
/*IsMutable=*/false);
16601663
Block *B = Allocator.allocate(Desc, S.getContext().getEvalID(),
@@ -1667,7 +1670,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
16671670
assert(NumElems.ugt(1));
16681671

16691672
Block *B =
1670-
Allocator.allocate(Call, *ElemT, NumElems.getZExtValue(),
1673+
Allocator.allocate(NewCall, *ElemT, NumElems.getZExtValue(),
16711674
S.Ctx.getEvalID(), DynamicAllocator::Form::Operator);
16721675
assert(B);
16731676
S.Stk.push<Pointer>(B);

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

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -602,8 +602,7 @@ namespace std {
602602
using size_t = decltype(sizeof(0));
603603
template<typename T> struct allocator {
604604
constexpr T *allocate(size_t N) {
605-
return (T*)__builtin_operator_new(sizeof(T) * N); // expected-note 2{{allocation performed here}} \
606-
// #alloc
605+
return (T*)__builtin_operator_new(sizeof(T) * N); // #alloc
607606
}
608607
constexpr void deallocate(void *p) {
609608
__builtin_operator_delete(p); // both-note 2{{std::allocator<...>::deallocate' used to delete pointer to object allocated with 'new'}} \
@@ -641,7 +640,7 @@ namespace OperatorNewDelete {
641640
p = new int[1]; // both-note {{heap allocation performed here}}
642641
break;
643642
case 2:
644-
p = std::allocator<int>().allocate(1); // ref-note 2{{heap allocation performed here}}
643+
p = std::allocator<int>().allocate(1); // both-note 2{{heap allocation performed here}}
645644
break;
646645
}
647646
switch (dealloc_kind) {
@@ -838,6 +837,26 @@ namespace ToplevelScopeInTemplateArg {
838837
}
839838
}
840839

840+
template <typename T>
841+
struct SS {
842+
constexpr SS(unsigned long long N)
843+
: data(nullptr){
844+
data = alloc.allocate(N); // #call
845+
for(std::size_t i = 0; i < N; i ++)
846+
std::construct_at<T>(data + i, i); // #construct_call
847+
}
848+
constexpr T operator[](std::size_t i) const {
849+
return data[i];
850+
}
851+
852+
constexpr ~SS() {
853+
alloc.deallocate(data);
854+
}
855+
std::allocator<T> alloc;
856+
T* data;
857+
};
858+
constexpr unsigned short ssmall = SS<unsigned short>(100)[42];
859+
841860
#else
842861
/// Make sure we reject this prior to C++20
843862
constexpr int a() { // both-error {{never produces a constant expression}}

0 commit comments

Comments
 (0)