Support decltype in pseudo destructors and dependent destructor calls.
Reviewed by Eli Friedman.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146738 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 88b3f59..0b08526 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -3250,6 +3250,13 @@
UnqualifiedId &SecondTypeName,
bool HasTrailingLParen);
+ ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation TildeLoc,
+ const DeclSpec& DS,
+ bool HasTrailingLParen);
+
/// MaybeCreateExprWithCleanups - If the current full-expression
/// requires any cleanups, surround it with a ExprWithCleanups node.
/// Otherwise, just returns the passed-in expression.
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 182f2f0..2e0b6a5 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -1019,6 +1019,17 @@
// Parse the tilde.
assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail");
SourceLocation TildeLoc = ConsumeToken();
+
+ if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid() && SS.isEmpty()) {
+ DeclSpec DS(AttrFactory);
+ SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
+ if (DS.getTypeSpecType() == TST_error)
+ return ExprError();
+ return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc,
+ OpKind, TildeLoc, DS,
+ Tok.is(tok::l_paren));
+ }
+
if (!Tok.is(tok::identifier)) {
Diag(Tok, diag::err_destructor_tilde_identifier);
return ExprError();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index e7e6b89..eaa330b 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -28,6 +28,7 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "TypeLocBuilder.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -4313,6 +4314,30 @@
/*RPLoc*/ ExpectedLParenLoc);
}
+static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *Base,
+ tok::TokenKind& OpKind, SourceLocation OpLoc) {
+ // C++ [expr.pseudo]p2:
+ // The left-hand side of the dot operator shall be of scalar type. The
+ // left-hand side of the arrow operator shall be of pointer to scalar type.
+ // This scalar type is the object type.
+ if (OpKind == tok::arrow) {
+ if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
+ ObjectType = Ptr->getPointeeType();
+ } else if (!Base->isTypeDependent()) {
+ // The user wrote "p->" when she probably meant "p."; fix it.
+ S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+ << ObjectType << true
+ << FixItHint::CreateReplacement(OpLoc, ".");
+ if (S.isSFINAEContext())
+ return true;
+
+ OpKind = tok::period;
+ }
+ }
+
+ return false;
+}
+
ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
@@ -4324,25 +4349,9 @@
bool HasTrailingLParen) {
TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();
- // C++ [expr.pseudo]p2:
- // The left-hand side of the dot operator shall be of scalar type. The
- // left-hand side of the arrow operator shall be of pointer to scalar type.
- // This scalar type is the object type.
QualType ObjectType = Base->getType();
- if (OpKind == tok::arrow) {
- if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
- ObjectType = Ptr->getPointeeType();
- } else if (!Base->isTypeDependent()) {
- // The user wrote "p->" when she probably meant "p."; fix it.
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << ObjectType << true
- << FixItHint::CreateReplacement(OpLoc, ".");
- if (isSFINAEContext())
- return ExprError();
-
- OpKind = tok::period;
- }
- }
+ if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
+ return ExprError();
if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) {
Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
@@ -4442,25 +4451,9 @@
SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
"Invalid second type name in pseudo-destructor");
- // C++ [expr.pseudo]p2:
- // The left-hand side of the dot operator shall be of scalar type. The
- // left-hand side of the arrow operator shall be of pointer to scalar type.
- // This scalar type is the object type.
QualType ObjectType = Base->getType();
- if (OpKind == tok::arrow) {
- if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
- ObjectType = Ptr->getPointeeType();
- } else if (!ObjectType->isDependentType()) {
- // The user wrote "p->" when she probably meant "p."; fix it.
- Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
- << ObjectType << true
- << FixItHint::CreateReplacement(OpLoc, ".");
- if (isSFINAEContext())
- return ExprError();
-
- OpKind = tok::period;
- }
- }
+ if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
+ return ExprError();
// Compute the object type that we should use for name lookup purposes. Only
// record types and dependent types matter.
@@ -4580,6 +4573,30 @@
Destructed, HasTrailingLParen);
}
+ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation TildeLoc,
+ const DeclSpec& DS,
+ bool HasTrailingLParen) {
+
+ QualType ObjectType = Base->getType();
+ if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
+ return ExprError();
+
+ QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+
+ TypeLocBuilder TLB;
+ DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
+ DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc());
+ TypeSourceInfo *DestructedTypeInfo = TLB.getTypeSourceInfo(Context, T);
+ PseudoDestructorTypeStorage Destructed(DestructedTypeInfo);
+
+ return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, CXXScopeSpec(),
+ 0, SourceLocation(), TildeLoc,
+ Destructed, HasTrailingLParen);
+}
+
ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
CXXMethodDecl *Method,
bool HadMultipleCandidates) {
diff --git a/test/CXX/special/class.dtor/p10-0x.cpp b/test/CXX/special/class.dtor/p10-0x.cpp
index 7f0c070..e10afb5 100644
--- a/test/CXX/special/class.dtor/p10-0x.cpp
+++ b/test/CXX/special/class.dtor/p10-0x.cpp
@@ -5,16 +5,18 @@
struct B {};
template<typename T>
void b(const T *x, const A *y) {
- // FIXME: this parses as a pseudo destructor call which doesn't have decltype support yet
- x->~decltype(T())(); // expected-error{{expected a class name after '~' to name a destructor}}
+ x->~decltype(T())();
+ x->~decltype(*x)(); // expected-error{{the type of object expression ('const int') does not match the type being destroyed ('decltype(*x)' (aka 'const int &')) in pseudo-destructor expression}} \
+ expected-error{{no member named '~const struct A &' in 'A'}}
+ x->~decltype(int())(); // expected-error{{no member named '~int' in 'A'}}
y->~decltype(*y)(); // expected-error{{destructor type 'decltype(*y)' (aka 'const A &') in object destruction expression does not match the type 'const A' of the object being destroyed}}
y->~decltype(T())(); // expected-error{{destructor type 'decltype(T())' in object destruction expression does not match the type 'const A' of the object being destroyed}}
y->~decltype(A())();
}
-template void b(const int*, const A*);
-template void b(const A*,const A*);
-void a(const A *x) {
+template void b(const int*, const A*); // expected-note{{in instantiation of function template specialization 'b<int>' requested here}}
+template void b(const A*,const A*); // expected-note{{in instantiation of function template specialization 'b<A>' requested here}}
+void a(const A *x, int i, int *pi) {
x->~decltype(A())();
x->~decltype(*x)(); // expected-error{{destructor type 'decltype(*x)' (aka 'const A &') in object destruction expression does not match the type 'const A' of the object being destroyed}}
x->~decltype()(); // expected-error{{expected expression}}
@@ -23,4 +25,15 @@
// this last one could be better, mentioning that the nested-name-specifier could be removed or a type name after the ~
x->::A::~decltype(*x)(); // expected-error{{expected a class name after '~' to name a destructor}}
y->~decltype(A())(); // expected-error{{use of undeclared identifier 'y'}}
+
+ typedef int *intp;
+ i->~decltype(int())(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}}
+ i.~decltype(int())();
+ i->~decltype(intp())(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}} \
+ 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(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/test/SemaCXX/pseudo-destructors.cpp b/test/SemaCXX/pseudo-destructors.cpp
index bd39848..a8f6683 100644
--- a/test/SemaCXX/pseudo-destructors.cpp
+++ b/test/SemaCXX/pseudo-destructors.cpp
@@ -19,7 +19,7 @@
cvt->T::~T(); // no-warning
}
-void f(A* a, Foo *f, int *i, double *d) {
+void f(A* a, Foo *f, int *i, double *d, int ii) {
a->~A();
a->A::~A();
@@ -46,6 +46,9 @@
i->N::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('Double' (aka 'double')) in pseudo-destructor expression}}
+ ii->~Integer(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}}
+ ii.~Integer();
+
cv_test(a);
cv_test(f);
cv_test(i);