Author: arphaman Date: Fri Jan 20 09:38:58 2017 New Revision: 292615 URL: http://llvm.org/viewvc/llvm-project?rev=292615&view=rev Log: [Sema] Improve the error diagnostic for dot destructor calls on pointer objects
This commit improves the mismatched destructor type error by detecting when the destructor call has used a '.' instead of a '->' on a pointer to the destructed type. The diagnostic now suggests to use '->' instead of '.', and adds a fixit where appropriate. rdar://28766702 Differential Revision: https://reviews.llvm.org/D25817 Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/test/CXX/special/class.dtor/p10-0x.cpp cfe/trunk/test/FixIt/fixit.cpp cfe/trunk/test/FixIt/no-fixit.cpp cfe/trunk/test/SemaCXX/pseudo-destructors.cpp Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=292615&r1=292614&r2=292615&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Jan 20 09:38:58 2017 @@ -6403,6 +6403,23 @@ static bool CheckArrow(Sema& S, QualType return false; } +/// \brief Check if it's ok to try and recover dot pseudo destructor calls on +/// pointer objects. +static bool +canRecoverDotPseudoDestructorCallsOnPointerObjects(Sema &SemaRef, + QualType DestructedType) { + // If this is a record type, check if its destructor is callable. + if (auto *RD = DestructedType->getAsCXXRecordDecl()) { + if (CXXDestructorDecl *D = SemaRef.LookupDestructor(RD)) + return SemaRef.CanUseDecl(D, /*TreatUnavailableAsInvalid=*/false); + return false; + } + + // Otherwise, check if it's a type for which it's valid to use a pseudo-dtor. + return DestructedType->isDependentType() || DestructedType->isScalarType() || + DestructedType->isVectorType(); +} + ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, @@ -6437,15 +6454,36 @@ ExprResult Sema::BuildPseudoDestructorEx = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) { if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { - Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) - << ObjectType << DestructedType << Base->getSourceRange() - << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); - - // Recover by setting the destructed type to the object type. - DestructedType = ObjectType; - DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, - DestructedTypeStart); - Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); + // Detect dot pseudo destructor calls on pointer objects, e.g.: + // Foo *foo; + // foo.~Foo(); + if (OpKind == tok::period && ObjectType->isPointerType() && + Context.hasSameUnqualifiedType(DestructedType, + ObjectType->getPointeeType())) { + auto Diagnostic = + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << ObjectType << /*IsArrow=*/0 << Base->getSourceRange(); + + // Issue a fixit only when the destructor is valid. + if (canRecoverDotPseudoDestructorCallsOnPointerObjects( + *this, DestructedType)) + Diagnostic << FixItHint::CreateReplacement(OpLoc, "->"); + + // Recover by setting the object type to the destructed type and the + // operator to '->'. + ObjectType = DestructedType; + OpKind = tok::arrow; + } else { + Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) + << ObjectType << DestructedType << Base->getSourceRange() + << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); + + // Recover by setting the destructed type to the object type. + DestructedType = ObjectType; + DestructedTypeInfo = + Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart); + Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); + } } else if (DestructedType.getObjCLifetime() != ObjectType.getObjCLifetime()) { Modified: cfe/trunk/test/CXX/special/class.dtor/p10-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.dtor/p10-0x.cpp?rev=292615&r1=292614&r2=292615&view=diff ============================================================================== --- cfe/trunk/test/CXX/special/class.dtor/p10-0x.cpp (original) +++ cfe/trunk/test/CXX/special/class.dtor/p10-0x.cpp Fri Jan 20 09:38:58 2017 @@ -33,7 +33,7 @@ void a(const A *x, int i, int *pi) { expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}} i.~decltype(intp())(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}} pi->~decltype(int())(); - pi.~decltype(int())(); // expected-error{{the type of object expression ('int *') does not match the type being destroyed ('decltype(int())' (aka 'int')) in pseudo-destructor expression}} + pi.~decltype(int())(); // expected-error{{member reference type 'int *' is a pointer; did you mean to use '->'?}} pi.~decltype(intp())(); pi->~decltype(intp())(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}} } Modified: cfe/trunk/test/FixIt/fixit.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit.cpp?rev=292615&r1=292614&r2=292615&view=diff ============================================================================== --- cfe/trunk/test/FixIt/fixit.cpp (original) +++ cfe/trunk/test/FixIt/fixit.cpp Fri Jan 20 09:38:58 2017 @@ -409,3 +409,14 @@ const const_zero_init czi; // expected-e // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:26-[[@LINE-1]]:26}:"{}" int use_czi = czi.a; +namespace dotPointerDestructor { + +struct Bar { + ~Bar(); +}; + +void bar(Bar *o) { + o.~Bar(); // expected-error {{member reference type 'dotPointerDestructor::Bar *' is a pointer; did you mean to use '->'}} +} // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:5}:"->" + +} Modified: cfe/trunk/test/FixIt/no-fixit.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/no-fixit.cpp?rev=292615&r1=292614&r2=292615&view=diff ============================================================================== --- cfe/trunk/test/FixIt/no-fixit.cpp (original) +++ cfe/trunk/test/FixIt/no-fixit.cpp Fri Jan 20 09:38:58 2017 @@ -11,3 +11,15 @@ struct { (void)&i; } } x; + +namespace dotPointerDestructor { + +struct Bar { + ~Bar() = delete; +}; + +void bar(Bar *o) { + o.~Bar(); // no fixit +} + +} Modified: cfe/trunk/test/SemaCXX/pseudo-destructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/pseudo-destructors.cpp?rev=292615&r1=292614&r2=292615&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/pseudo-destructors.cpp (original) +++ cfe/trunk/test/SemaCXX/pseudo-destructors.cpp Fri Jan 20 09:38:58 2017 @@ -89,3 +89,26 @@ template<typename T> using Id = T; void AliasTemplate(int *p) { p->~Id<int>(); } + +namespace dotPointerAccess { +struct Base { + virtual ~Base() {} +}; + +struct Derived : Base { + ~Derived() {} +}; + +void test() { + Derived d; + static_cast<Base *>(&d).~Base(); // expected-error {{member reference type 'dotPointerAccess::Base *' is a pointer; did you mean to use '->'}} + d->~Derived(); // expected-error {{member reference type 'dotPointerAccess::Derived' is not a pointer; did you mean to use '.'}} +} + +typedef Derived *Foo; + +void test2(Foo d) { + d.~Foo(); // This is ok + d.~Derived(); // expected-error {{member reference type 'Foo' (aka 'dotPointerAccess::Derived *') is a pointer; did you mean to use '->'}} +} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits