Skip to content

Commit 886adf8

Browse files
authored
[clang][ExprConst] Let diagnostics point to std::allocator calls (#123744)
Instead of the underlying operator new calls. This fixes a longstanding FIXME comment in cxx2a-constexpr-dynalloc.cpp.
1 parent ddd2f57 commit 886adf8

File tree

3 files changed

+11
-9
lines changed

3 files changed

+11
-9
lines changed

clang/lib/AST/ExprConstant.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,7 @@ namespace {
11361136
struct StdAllocatorCaller {
11371137
unsigned FrameIndex;
11381138
QualType ElemType;
1139+
const Expr *Call;
11391140
explicit operator bool() const { return FrameIndex != 0; };
11401141
};
11411142

@@ -1159,7 +1160,7 @@ namespace {
11591160
if (CTSD->isInStdNamespace() && ClassII &&
11601161
ClassII->isStr("allocator") && TAL.size() >= 1 &&
11611162
TAL[0].getKind() == TemplateArgument::Type)
1162-
return {Call->Index, TAL[0].getAsType()};
1163+
return {Call->Index, TAL[0].getAsType(), Call->CallExpr};
11631164
}
11641165

11651166
return {};
@@ -7113,7 +7114,7 @@ static bool HandleOperatorNewCall(EvalInfo &Info, const CallExpr *E,
71137114

71147115
QualType AllocType = Info.Ctx.getConstantArrayType(
71157116
ElemType, Size, nullptr, ArraySizeModifier::Normal, 0);
7116-
APValue *Val = Info.createHeapAlloc(E, AllocType, Result);
7117+
APValue *Val = Info.createHeapAlloc(Caller.Call, AllocType, Result);
71177118
*Val = APValue(APValue::UninitArray(), 0, Size.getZExtValue());
71187119
Result.addArray(Info, E, cast<ConstantArrayType>(AllocType));
71197120
return true;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,7 +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); // both-note 2{{allocation performed here}} \
605+
return (T*)__builtin_operator_new(sizeof(T) * N); // expected-note 2{{allocation performed here}} \
606606
// #alloc
607607
}
608608
constexpr void deallocate(void *p) {
@@ -641,7 +641,7 @@ namespace OperatorNewDelete {
641641
p = new int[1]; // both-note {{heap allocation performed here}}
642642
break;
643643
case 2:
644-
p = std::allocator<int>().allocate(1);
644+
p = std::allocator<int>().allocate(1); // ref-note 2{{heap allocation performed here}}
645645
break;
646646
}
647647
switch (dealloc_kind) {

clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ static_assert(alloc_from_user_code()); // expected-error {{constant expression}}
1212

1313
namespace std {
1414
using size_t = decltype(sizeof(0));
15-
// FIXME: It would be preferable to point these notes at the location of the call to allocator<...>::[de]allocate instead
1615
template<typename T> struct allocator {
1716
constexpr T *allocate(size_t N) {
18-
return (T*)NEW(sizeof(T) * N); // expected-note 3{{heap allocation}} expected-note {{not deallocated}}
17+
return (T*)NEW(sizeof(T) * N);
1918
}
2019
constexpr void deallocate(void *p) {
2120
DELETE(p); // #dealloc expected-note 2{{'std::allocator<...>::deallocate' used to delete pointer to object allocated with 'new'}}
@@ -59,7 +58,7 @@ constexpr bool mismatched(int alloc_kind, int dealloc_kind) {
5958
p = new int[1]; // expected-note {{heap allocation}}
6059
break;
6160
case 2:
62-
p = std::allocator<int>().allocate(1);
61+
p = std::allocator<int>().allocate(1); // expected-note 2{{heap allocation}}
6362
break;
6463
}
6564
switch (dealloc_kind) {
@@ -81,8 +80,10 @@ static_assert(mismatched(2, 0)); // expected-error {{constant expression}} expec
8180
static_assert(mismatched(2, 1)); // expected-error {{constant expression}} expected-note {{in call}}
8281
static_assert(mismatched(2, 2));
8382

84-
constexpr int *escape = std::allocator<int>().allocate(3); // expected-error {{constant expression}} expected-note {{pointer to subobject of heap-allocated}}
85-
constexpr int leak = (std::allocator<int>().allocate(3), 0); // expected-error {{constant expression}}
83+
constexpr int *escape = std::allocator<int>().allocate(3); // expected-error {{constant expression}} expected-note {{pointer to subobject of heap-allocated}} \
84+
// expected-note {{heap allocation performed here}}
85+
constexpr int leak = (std::allocator<int>().allocate(3), 0); // expected-error {{constant expression}} \
86+
// expected-note {{not deallocated}}
8687
constexpr int no_lifetime_start = (*std::allocator<int>().allocate(1) = 1); // expected-error {{constant expression}} expected-note {{assignment to object outside its lifetime}}
8788
constexpr int no_deallocate_nullptr = (std::allocator<int>().deallocate(nullptr), 1); // expected-error {{constant expression}} expected-note {{in call}}
8889
// expected-note@#dealloc {{'std::allocator<...>::deallocate' used to delete a null pointer}}

0 commit comments

Comments
 (0)