[clang] 9dbb088 - Perform lvalue conversions on the left of a pseudo-destructor call 'p->~T()'.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 14 22:09:13 PDT 2020


Author: Richard Smith
Date: 2020-10-14T22:09:01-07:00
New Revision: 9dbb0886ea799061baf79d4dce3203524a8468cc

URL: https://github.com/llvm/llvm-project/commit/9dbb0886ea799061baf79d4dce3203524a8468cc
DIFF: https://github.com/llvm/llvm-project/commit/9dbb0886ea799061baf79d4dce3203524a8468cc.diff

LOG: Perform lvalue conversions on the left of a pseudo-destructor call 'p->~T()'.

Previously we failed to convert 'p' from array/function to pointer type,
and to represent the load of 'p' in the AST. The latter causes problems
for constant evaluation.

Added: 
    

Modified: 
    clang/lib/Sema/SemaExprCXX.cpp
    clang/test/SemaCXX/constant-expression-cxx2a.cpp
    clang/test/SemaCXX/pseudo-destructors.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index d39820fb483d..8d5dccc19726 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -7249,8 +7249,8 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
   return Base;
 }
 
-static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base,
-                   tok::TokenKind& OpKind, SourceLocation OpLoc) {
+static bool CheckArrow(Sema &S, QualType &ObjectType, Expr *&Base,
+                       tok::TokenKind &OpKind, SourceLocation OpLoc) {
   if (Base->hasPlaceholderType()) {
     ExprResult result = S.CheckPlaceholderExpr(Base);
     if (result.isInvalid()) return true;
@@ -7265,6 +7265,18 @@ static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base,
   // Note that this is rather 
diff erent from the normal handling for the
   // arrow operator.
   if (OpKind == tok::arrow) {
+    // The operator requires a prvalue, so perform lvalue conversions.
+    // Only do this if we might plausibly end with a pointer, as otherwise
+    // this was likely to be intended to be a '.'.
+    if (ObjectType->isPointerType() || ObjectType->isArrayType() ||
+        ObjectType->isFunctionType()) {
+      ExprResult BaseResult = S.DefaultFunctionArrayLvalueConversion(Base);
+      if (BaseResult.isInvalid())
+        return true;
+      Base = BaseResult.get();
+      ObjectType = Base->getType();
+    }
+
     if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
       ObjectType = Ptr->getPointeeType();
     } else if (!Base->isTypeDependent()) {

diff  --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index 2aea2577d972..4adadc9988ab 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -1061,9 +1061,10 @@ namespace memory_leaks {
   static_assert(h({new bool(true)})); // ok
 }
 
-void *operator new(std::size_t, void*);
+constexpr void *operator new(std::size_t, void *p) { return p; }
 namespace std {
   template<typename T> constexpr T *construct(T *p) { return new (p) T; }
+  template<typename T> constexpr void destroy(T *p) { p->~T(); }
 }
 
 namespace dtor_call {
@@ -1428,3 +1429,11 @@ namespace PR47805 {
   constexpr bool g(B b) { return &b == b.p; }
   static_assert(g({}));
 }
+
+constexpr bool destroy_at_test() {
+  int n = 0;
+  std::destroy(&n);
+  std::construct(&n);
+  return true;
+}
+static_assert(destroy_at_test());

diff  --git a/clang/test/SemaCXX/pseudo-destructors.cpp b/clang/test/SemaCXX/pseudo-destructors.cpp
index 7a5c540794e2..f214f5226ee2 100644
--- a/clang/test/SemaCXX/pseudo-destructors.cpp
+++ b/clang/test/SemaCXX/pseudo-destructors.cpp
@@ -183,3 +183,14 @@ namespace TwoPhaseLookup {
     template<typename T> void f6(int *p) { p->TemplateNamesNonTemplate::C::~C<int>(); } // expected-error {{'C' does not refer to a template}}
   }
 }
+
+void destroy_array_element() {
+  int arr[5];
+  using T = int;
+  arr->~T(); // ok, destroy arr[0].
+}
+
+void destroy_function() {
+  using T = void();
+  destroy_function->~T(); // expected-error {{object expression of non-scalar type 'void ()' cannot be used in a pseudo-destructor expression}}
+}


        


More information about the cfe-commits mailing list