[clang] a892b00 - PR49465: Disallow constant evaluation of a call to operator delete(nullptr).
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 9 15:06:18 PST 2021
Author: Richard Smith
Date: 2021-03-09T15:06:06-08:00
New Revision: a892b0015ed6af5945d06e87ca5da1ad8be7ad29
URL: https://github.com/llvm/llvm-project/commit/a892b0015ed6af5945d06e87ca5da1ad8be7ad29
DIFF: https://github.com/llvm/llvm-project/commit/a892b0015ed6af5945d06e87ca5da1ad8be7ad29.diff
LOG: PR49465: Disallow constant evaluation of a call to operator delete(nullptr).
The only time we would consider allowing this is inside a call to
std::allocator<T>::deallocate, whose contract does not permit deletion
of null pointers.
Added:
Modified:
clang/include/clang/Basic/DiagnosticASTKinds.td
clang/lib/AST/ExprConstant.cpp
clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index f6b936f5ccd9..496d86ee2fe7 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -349,6 +349,8 @@ def note_constexpr_new_delete_mismatch : Note<
"used to delete pointer to "
"%select{array object of type %2|non-array object of type %2|"
"object allocated with 'new'}0}1">;
+def note_constexpr_deallocate_null : Note<
+ "'std::allocator<...>::deallocate' used to delete a null pointer">;
def note_constexpr_delete_subobject : Note<
"delete of pointer%select{ to subobject|}1 '%0' "
"%select{|that does not point to complete object}1">;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index ae7131eae01d..4213beb915af 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6712,9 +6712,12 @@ bool HandleOperatorDeleteCall(EvalInfo &Info, const CallExpr *E) {
if (Pointer.Designator.Invalid)
return false;
- // Deleting a null pointer has no effect.
- if (Pointer.isNullPointer())
+ // Deleting a null pointer would have no effect, but it's not permitted by
+ // std::allocator<T>::deallocate's contract.
+ if (Pointer.isNullPointer()) {
+ Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_deallocate_null);
return true;
+ }
if (!CheckDeleteKind(Info, E, Pointer, DynAlloc::StdAllocator))
return false;
diff --git a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
index 097ca00640e9..f37ebc9f6365 100644
--- a/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
+++ b/clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp
@@ -17,7 +17,7 @@ namespace std {
return (T*)NEW(sizeof(T) * N); // expected-note 3{{heap allocation}} expected-note {{not deallocated}}
}
constexpr void deallocate(void *p) {
- DELETE(p); // expected-note 2{{'std::allocator<...>::deallocate' used to delete pointer to object allocated with 'new'}}
+ DELETE(p); // #dealloc expected-note 2{{'std::allocator<...>::deallocate' used to delete pointer to object allocated with 'new'}}
}
};
}
@@ -83,6 +83,11 @@ static_assert(mismatched(2, 2));
constexpr int *escape = std::allocator<int>().allocate(3); // expected-error {{constant expression}} expected-note {{pointer to subobject of heap-allocated}}
constexpr int leak = (std::allocator<int>().allocate(3), 0); // expected-error {{constant expression}}
constexpr int no_lifetime_start = (*std::allocator<int>().allocate(1) = 1); // expected-error {{constant expression}} expected-note {{assignment to object outside its lifetime}}
+constexpr int no_deallocate_nullptr = (std::allocator<int>().deallocate(nullptr), 1); // expected-error {{constant expression}} expected-note {{in call}}
+// expected-note@#dealloc {{'std::allocator<...>::deallocate' used to delete a null pointer}}
+constexpr int no_deallocate_nonalloc = (std::allocator<int>().deallocate((int*)&no_deallocate_nonalloc), 1); // expected-error {{constant expression}} expected-note {{in call}}
+// expected-note@#dealloc {{delete of pointer '&no_deallocate_nonalloc' that does not point to a heap-allocated object}}
+// expected-note at -2 {{declared here}}
void *operator new(std::size_t, void *p) { return p; }
constexpr bool no_placement_new_in_user_code() { // expected-error {{never produces a constant expression}}
More information about the cfe-commits
mailing list