diff options
author | David Blaikie <dblaikie@gmail.com> | 2011-12-16 16:03:09 +0000 |
---|---|---|
committer | David Blaikie <dblaikie@gmail.com> | 2011-12-16 16:03:09 +0000 |
commit | 91ec7894ec186dd36f509682f00486c98d8228ed (patch) | |
tree | cd1be2e88bce92c22296a1293f3de6e570deadad | |
parent | 6b65d4a9cc5aed96a7f1a36e75dd9c4adb164e0b (diff) |
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
-rw-r--r-- | include/clang/Sema/Sema.h | 7 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 83 | ||||
-rw-r--r-- | test/CXX/special/class.dtor/p10-0x.cpp | 23 | ||||
-rw-r--r-- | test/SemaCXX/pseudo-destructors.cpp | 5 |
5 files changed, 90 insertions, 39 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 88b3f595b2..0b08526d98 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3250,6 +3250,13 @@ public: 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 182f2f080d..2e0b6a55d5 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1019,6 +1019,17 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, // 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 e7e6b892e5..eaa330b183 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,37 +4314,45 @@ ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, /*RPLoc*/ ExpectedLParenLoc); } -ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - const CXXScopeSpec &SS, - TypeSourceInfo *ScopeTypeInfo, - SourceLocation CCLoc, - SourceLocation TildeLoc, - PseudoDestructorTypeStorage Destructed, - bool HasTrailingLParen) { - TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo(); - +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. - 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) + S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << ObjectType << true << FixItHint::CreateReplacement(OpLoc, "."); - if (isSFINAEContext()) - return ExprError(); + if (S.isSFINAEContext()) + return true; OpKind = tok::period; } } + return false; +} + +ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + TypeSourceInfo *ScopeTypeInfo, + SourceLocation CCLoc, + SourceLocation TildeLoc, + PseudoDestructorTypeStorage Destructed, + bool HasTrailingLParen) { + TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo(); + + QualType ObjectType = Base->getType(); + if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) + return ExprError(); + if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) { Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) << ObjectType << Base->getSourceRange(); @@ -4442,25 +4451,9 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, 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 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, 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 7f0c07011e..e10afb52e2 100644 --- a/test/CXX/special/class.dtor/p10-0x.cpp +++ b/test/CXX/special/class.dtor/p10-0x.cpp @@ -5,16 +5,18 @@ struct A { ~A(); }; 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 @@ void a(const A *x) { // 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 bd39848175..a8f6683ced 100644 --- a/test/SemaCXX/pseudo-destructors.cpp +++ b/test/SemaCXX/pseudo-destructors.cpp @@ -19,7 +19,7 @@ void cv_test(const volatile T* cvt) { 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 @@ void f(A* a, Foo *f, int *i, double *d) { 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); |