зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
6b65d4a9cc
Коммит
91ec7894ec
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче