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}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits