forked from OSchip/llvm-project
Support decltype in pseudo destructors and dependent destructor calls.
Reviewed by Eli Friedman. llvm-svn: 146738
This commit is contained in:
parent
21c2484454
commit
1d578782fa
|
@ -3250,6 +3250,13 @@ public:
|
||||||
UnqualifiedId &SecondTypeName,
|
UnqualifiedId &SecondTypeName,
|
||||||
bool HasTrailingLParen);
|
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
|
/// MaybeCreateExprWithCleanups - If the current full-expression
|
||||||
/// requires any cleanups, surround it with a ExprWithCleanups node.
|
/// requires any cleanups, surround it with a ExprWithCleanups node.
|
||||||
/// Otherwise, just returns the passed-in expression.
|
/// Otherwise, just returns the passed-in expression.
|
||||||
|
|
|
@ -1019,6 +1019,17 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
|
||||||
// Parse the tilde.
|
// Parse the tilde.
|
||||||
assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail");
|
assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail");
|
||||||
SourceLocation TildeLoc = ConsumeToken();
|
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)) {
|
if (!Tok.is(tok::identifier)) {
|
||||||
Diag(Tok, diag::err_destructor_tilde_identifier);
|
Diag(Tok, diag::err_destructor_tilde_identifier);
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "clang/Basic/PartialDiagnostic.h"
|
#include "clang/Basic/PartialDiagnostic.h"
|
||||||
#include "clang/Basic/TargetInfo.h"
|
#include "clang/Basic/TargetInfo.h"
|
||||||
#include "clang/Lex/Preprocessor.h"
|
#include "clang/Lex/Preprocessor.h"
|
||||||
|
#include "TypeLocBuilder.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
@ -4313,6 +4314,30 @@ ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
|
||||||
/*RPLoc*/ ExpectedLParenLoc);
|
/*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,
|
ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
|
||||||
SourceLocation OpLoc,
|
SourceLocation OpLoc,
|
||||||
tok::TokenKind OpKind,
|
tok::TokenKind OpKind,
|
||||||
|
@ -4324,25 +4349,9 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
|
||||||
bool HasTrailingLParen) {
|
bool HasTrailingLParen) {
|
||||||
TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();
|
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();
|
QualType ObjectType = Base->getType();
|
||||||
if (OpKind == tok::arrow) {
|
if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
|
||||||
if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
|
return ExprError();
|
||||||
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 (!ObjectType->isDependentType() && !ObjectType->isScalarType()) {
|
if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) {
|
||||||
Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
|
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) &&
|
SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
|
||||||
"Invalid second type name in pseudo-destructor");
|
"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();
|
QualType ObjectType = Base->getType();
|
||||||
if (OpKind == tok::arrow) {
|
if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
|
||||||
if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
|
return ExprError();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the object type that we should use for name lookup purposes. Only
|
// Compute the object type that we should use for name lookup purposes. Only
|
||||||
// record types and dependent types matter.
|
// record types and dependent types matter.
|
||||||
|
@ -4580,6 +4573,30 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
|
||||||
Destructed, HasTrailingLParen);
|
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,
|
ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
|
||||||
CXXMethodDecl *Method,
|
CXXMethodDecl *Method,
|
||||||
bool HadMultipleCandidates) {
|
bool HadMultipleCandidates) {
|
||||||
|
|
|
@ -5,16 +5,18 @@ struct A { ~A(); };
|
||||||
struct B {};
|
struct B {};
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void b(const T *x, const A *y) {
|
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())();
|
||||||
x->~decltype(T())(); // expected-error{{expected a class name after '~' to name a destructor}}
|
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(*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(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())();
|
y->~decltype(A())();
|
||||||
}
|
}
|
||||||
template void b(const int*, const A*);
|
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*);
|
template void b(const A*,const A*); // expected-note{{in instantiation of function template specialization 'b<A>' requested here}}
|
||||||
void a(const A *x) {
|
void a(const A *x, int i, int *pi) {
|
||||||
x->~decltype(A())();
|
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(*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}}
|
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 ~
|
// 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}}
|
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'}}
|
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
|
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->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->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}}
|
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(a);
|
||||||
cv_test(f);
|
cv_test(f);
|
||||||
cv_test(i);
|
cv_test(i);
|
||||||
|
|
Loading…
Reference in New Issue