From: David Blaikie Date: Thu, 8 Dec 2011 16:13:53 +0000 (+0000) Subject: Decltype in non-pseudo (& non-dependent) dtor calls. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=53a75c07dbe79b3dd5dd88a0378aefa18f793083;p=clang Decltype in non-pseudo (& non-dependent) dtor calls. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146155 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 89e7662f03..3133f708ee 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3020,6 +3020,8 @@ public: ParsedType ObjectType, bool EnteringContext); + ParsedType getDestructorType(const DeclSpec& DS, ParsedType ObjectType); + // Checks that reinterpret casts don't have undefined behavior. void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, bool IsDereference, SourceRange Range); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 79d2ec21ab..182f2f080d 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1966,6 +1966,16 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // Parse the '~'. SourceLocation TildeLoc = ConsumeToken(); + + if (SS.isEmpty() && Tok.is(tok::kw_decltype)) { + DeclSpec DS(AttrFactory); + SourceLocation EndLoc = ParseDecltypeSpecifier(DS); + if (ParsedType Type = Actions.getDestructorType(DS, ObjectType)) { + Result.setDestructorName(TildeLoc, Type, EndLoc); + return false; + } + return true; + } // Parse the class-name. if (Tok.isNot(tok::identifier)) { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 06837fef84..af297840c3 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -265,6 +265,22 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, return ParsedType(); } +ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) { + if (DS.getTypeSpecType() == DeclSpec::TST_error) + return ParsedType(); + assert(DS.getTypeSpecType() == DeclSpec::TST_decltype + && "only get destructor types from declspecs"); + QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + QualType SearchType = GetTypeFromParser(ObjectType); + if (SearchType->isDependentType() || Context.hasSameUnqualifiedType(SearchType, T)) { + return ParsedType::make(T); + } + + Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch) + << T << SearchType; + return ParsedType(); +} + /// \brief Build a C++ typeid expression with a type operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, diff --git a/test/CXX/special/class.dtor/p10-0x.cpp b/test/CXX/special/class.dtor/p10-0x.cpp new file mode 100644 index 0000000000..121624e7e2 --- /dev/null +++ b/test/CXX/special/class.dtor/p10-0x.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s + +// PR10127/N3031 +struct A { ~A(); }; +struct B {}; +template +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}} + + 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) { + 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}} + x->~decltype(B())(); // expected-error{{destructor type 'decltype(B())' (aka 'B') 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}} + // 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}} +}