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
This commit is contained in:
David Blaikie 2011-12-16 16:03:09 +00:00
Родитель 6b65d4a9cc
Коммит 91ec7894ec
5 изменённых файлов: 93 добавлений и 42 удалений

Просмотреть файл

@ -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.

Просмотреть файл

@ -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();

Просмотреть файл

@ -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 @@ ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
/*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 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
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 @@ 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) {

Просмотреть файл

@ -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}}
}

Просмотреть файл

@ -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);