r292615 - [Sema] Improve the error diagnostic for dot destructor calls on pointer objects
Alex Lorenz via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 20 07:38:58 PST 2017
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 '->'}}
+}
+}
More information about the cfe-commits
mailing list