Index: lib/Parse/ParseExprCXX.cpp =================================================================== --- lib/Parse/ParseExprCXX.cpp +++ lib/Parse/ParseExprCXX.cpp @@ -2439,6 +2439,18 @@ if (SS.isEmpty() && Tok.is(tok::kw_decltype)) { DeclSpec DS(AttrFactory); SourceLocation EndLoc = ParseDecltypeSpecifier(DS); + + // There are two cases to consider with ~decltype(expr): + // - If a base object isn't present, the '~' will not refer to a + // destructor but instead a unary complement. + // - If a base object is present, it will perform member access on the + // destructor. + // + // Since we are parsing a destructor, we must have a base object. + if (!ObjectType) { + Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_tilde_identifier); + return true; + } if (ParsedType Type = Actions.getDestructorType(DS, ObjectType)) { Result.setDestructorName(TildeLoc, Type, EndLoc); return false; Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -319,7 +319,8 @@ } ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) { - if (DS.getTypeSpecType() == DeclSpec::TST_error || !ObjectType) + assert(ObjectType && "expected an object type!"); + if (DS.getTypeSpecType() == DeclSpec::TST_error) return ParsedType(); assert(DS.getTypeSpecType() == DeclSpec::TST_decltype && "only get destructor types from declspecs"); Index: test/CXX/special/class.dtor/p10-0x.cpp =================================================================== --- test/CXX/special/class.dtor/p10-0x.cpp +++ test/CXX/special/class.dtor/p10-0x.cpp @@ -24,8 +24,8 @@ 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}} - y->~decltype(A())(); // expected-error{{use of undeclared identifier 'y'}} - + y->~decltype(A())(); // expected-error{{use of undeclared identifier 'y'}} \ + // expected-error{{expected a class name after '~' to name a destructor}} typedef int *intp; i->~decltype(int())(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}} i.~decltype(int())(); @@ -37,3 +37,17 @@ 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}} } + +namespace PR20378 { +struct S; + +S *f(); + +struct S { + static S g(); + void h() { this->~decltype(g())(); } + void i() { ~decltype(g())(); } // expected-error{{invalid argument type 'decltype(g())' (aka 'PR20378::S') to unary expression}} + ~decltype(*f()); // expected-error{{expected a class name after '~' to name a destructor}} + ~decltype(0) {} // expected-error{{expected a class name after '~' to name a destructor}} +}; +}