summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Lorenz <arphaman@gmail.com>2017-01-20 15:38:58 +0000
committerAlex Lorenz <arphaman@gmail.com>2017-01-20 15:38:58 +0000
commit56fb6fef50070d92d3137bcf912580f607e465b8 (patch)
treecd2e93513cebbef16d9e24a647a487f030f83a53
parent94b999b9df15661742fdce96e14ea694f3b8f9a5 (diff)
downloadbcm5719-llvm-56fb6fef50070d92d3137bcf912580f607e465b8.tar.gz
bcm5719-llvm-56fb6fef50070d92d3137bcf912580f607e465b8.zip
[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 llvm-svn: 292615
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp56
-rw-r--r--clang/test/CXX/special/class.dtor/p10-0x.cpp2
-rw-r--r--clang/test/FixIt/fixit.cpp11
-rw-r--r--clang/test/FixIt/no-fixit.cpp12
-rw-r--r--clang/test/SemaCXX/pseudo-destructors.cpp23
5 files changed, 94 insertions, 10 deletions
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 191bb28df46..2bf1c739395 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -6403,6 +6403,23 @@ static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base,
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::BuildPseudoDestructorExpr(Expr *Base,
= 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()) {
diff --git a/clang/test/CXX/special/class.dtor/p10-0x.cpp b/clang/test/CXX/special/class.dtor/p10-0x.cpp
index 3b8a0ad4d6a..3be0a98d47d 100644
--- a/clang/test/CXX/special/class.dtor/p10-0x.cpp
+++ b/clang/test/CXX/special/class.dtor/p10-0x.cpp
@@ -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}}
}
diff --git a/clang/test/FixIt/fixit.cpp b/clang/test/FixIt/fixit.cpp
index c43aac98623..0b7fc626ff8 100644
--- a/clang/test/FixIt/fixit.cpp
+++ b/clang/test/FixIt/fixit.cpp
@@ -409,3 +409,14 @@ const const_zero_init czi; // expected-error {{default initialization of an obje
// 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}:"->"
+
+}
diff --git a/clang/test/FixIt/no-fixit.cpp b/clang/test/FixIt/no-fixit.cpp
index 7e8e1fbbb07..2dad28d3579 100644
--- a/clang/test/FixIt/no-fixit.cpp
+++ b/clang/test/FixIt/no-fixit.cpp
@@ -11,3 +11,15 @@ struct {
(void)&i;
}
} x;
+
+namespace dotPointerDestructor {
+
+struct Bar {
+ ~Bar() = delete;
+};
+
+void bar(Bar *o) {
+ o.~Bar(); // no fixit
+}
+
+}
diff --git a/clang/test/SemaCXX/pseudo-destructors.cpp b/clang/test/SemaCXX/pseudo-destructors.cpp
index 45f1eafba10..bc0d7b2c835 100644
--- a/clang/test/SemaCXX/pseudo-destructors.cpp
+++ b/clang/test/SemaCXX/pseudo-destructors.cpp
@@ -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 '->'}}
+}
+}
OpenPOWER on IntegriCloud