forked from OSchip/llvm-project
DR1753: Don't permit x.NS::~T() as a pseudo-destructor name.
When used as qualified names, pseudo-destructors are always named as if they were members of the type, never as members of the namespace enclosing the type.
This commit is contained in:
parent
ef7f3af760
commit
04f131da0b
|
@ -418,8 +418,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
}
|
||||
|
||||
if (Next.is(tok::coloncolon)) {
|
||||
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) &&
|
||||
!Actions.isNonTypeNestedNameSpecifier(getCurScope(), SS, IdInfo)) {
|
||||
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
|
||||
*MayBePseudoDestructor = true;
|
||||
return false;
|
||||
}
|
||||
|
@ -548,7 +547,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
// Even if we didn't see any pieces of a nested-name-specifier, we
|
||||
// still check whether there is a tilde in this position, which
|
||||
// indicates a potential pseudo-destructor.
|
||||
if (CheckForDestructor && Tok.is(tok::tilde))
|
||||
if (CheckForDestructor && !HasScopeSpecifier && Tok.is(tok::tilde))
|
||||
*MayBePseudoDestructor = true;
|
||||
|
||||
return false;
|
||||
|
@ -1689,31 +1688,42 @@ ExprResult Parser::ParseCXXUuidof() {
|
|||
|
||||
/// Parse a C++ pseudo-destructor expression after the base,
|
||||
/// . or -> operator, and nested-name-specifier have already been
|
||||
/// parsed.
|
||||
/// parsed. We're handling this fragment of the grammar:
|
||||
///
|
||||
/// postfix-expression: [C++ 5.2]
|
||||
/// postfix-expression . pseudo-destructor-name
|
||||
/// postfix-expression -> pseudo-destructor-name
|
||||
/// postfix-expression: [C++2a expr.post]
|
||||
/// postfix-expression . template[opt] id-expression
|
||||
/// postfix-expression -> template[opt] id-expression
|
||||
///
|
||||
/// pseudo-destructor-name:
|
||||
/// ::[opt] nested-name-specifier[opt] type-name :: ~type-name
|
||||
/// ::[opt] nested-name-specifier template simple-template-id ::
|
||||
/// ~type-name
|
||||
/// ::[opt] nested-name-specifier[opt] ~type-name
|
||||
/// id-expression:
|
||||
/// qualified-id
|
||||
/// unqualified-id
|
||||
///
|
||||
/// qualified-id:
|
||||
/// nested-name-specifier template[opt] unqualified-id
|
||||
///
|
||||
/// nested-name-specifier:
|
||||
/// type-name ::
|
||||
/// decltype-specifier :: FIXME: not implemented, but probably only
|
||||
/// allowed in C++ grammar by accident
|
||||
/// nested-name-specifier identifier ::
|
||||
/// nested-name-specifier template[opt] simple-template-id ::
|
||||
/// [...]
|
||||
///
|
||||
/// unqualified-id:
|
||||
/// ~ type-name
|
||||
/// ~ decltype-specifier
|
||||
/// [...]
|
||||
///
|
||||
/// ... where the all but the last component of the nested-name-specifier
|
||||
/// has already been parsed, and the base expression is not of a non-dependent
|
||||
/// class type.
|
||||
ExprResult
|
||||
Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
CXXScopeSpec &SS,
|
||||
ParsedType ObjectType) {
|
||||
// We're parsing either a pseudo-destructor-name or a dependent
|
||||
// member access that has the same form as a
|
||||
// pseudo-destructor-name. We parse both in the same way and let
|
||||
// the action model sort them out.
|
||||
//
|
||||
// Note that the ::[opt] nested-name-specifier[opt] has already
|
||||
// been parsed, and if there was a simple-template-id, it has
|
||||
// been coalesced into a template-id annotation token.
|
||||
// If the last component of the (optional) nested-name-specifier is
|
||||
// template[opt] simple-template-id, it has already been annotated.
|
||||
UnqualifiedId FirstTypeName;
|
||||
SourceLocation CCLoc;
|
||||
if (Tok.is(tok::identifier)) {
|
||||
|
@ -1722,14 +1732,13 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
|
|||
assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
|
||||
CCLoc = ConsumeToken();
|
||||
} else if (Tok.is(tok::annot_template_id)) {
|
||||
// FIXME: retrieve TemplateKWLoc from template-id annotation and
|
||||
// store it in the pseudo-dtor node (to be used when instantiating it).
|
||||
FirstTypeName.setTemplateId(
|
||||
(TemplateIdAnnotation *)Tok.getAnnotationValue());
|
||||
ConsumeAnnotationToken();
|
||||
assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
|
||||
CCLoc = ConsumeToken();
|
||||
} else {
|
||||
assert(SS.isEmpty() && "missing last component of nested name specifier");
|
||||
FirstTypeName.setIdentifier(nullptr, SourceLocation());
|
||||
}
|
||||
|
||||
|
@ -1737,7 +1746,7 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc,
|
|||
assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail");
|
||||
SourceLocation TildeLoc = ConsumeToken();
|
||||
|
||||
if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid() && SS.isEmpty()) {
|
||||
if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid()) {
|
||||
DeclSpec DS(AttrFactory);
|
||||
ParseDecltypeSpecifier(DS);
|
||||
if (DS.getTypeSpecType() == TST_error)
|
||||
|
|
|
@ -3,10 +3,6 @@
|
|||
// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
||||
// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
|
||||
namespace dr1715 { // dr1715: 3.9
|
||||
#if __cplusplus >= 201103L
|
||||
struct B {
|
||||
|
@ -47,6 +43,32 @@ S s(q); // expected-note {{instantiation of}}
|
|||
#endif
|
||||
}
|
||||
|
||||
namespace dr1753 { // dr1753: 11
|
||||
typedef int T;
|
||||
struct A { typedef int T; };
|
||||
namespace B { typedef int T; }
|
||||
|
||||
void f(T n) {
|
||||
n.~T();
|
||||
n.T::~T();
|
||||
|
||||
n.dr1753::~T(); // expected-error {{'dr1753' does not refer to a type name in pseudo-destructor}}
|
||||
n.dr1753::T::~T();
|
||||
|
||||
n.A::~T(); // expected-error {{the type of object expression ('dr1753::T' (aka 'int')) does not match the type being destroyed ('dr1753::A') in pseudo-destructor expression}}
|
||||
n.A::T::~T();
|
||||
|
||||
n.B::~T(); // expected-error {{'B' does not refer to a type name in pseudo-destructor expression}}
|
||||
n.B::T::~T();
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
n.decltype(n)::~T(); // expected-error {{not a class, namespace, or enumeration}}
|
||||
n.T::~decltype(n)(); // expected-error {{expected a class name after '~'}}
|
||||
n.~decltype(n)(); // OK
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
namespace dr1756 { // dr1756: 3.7
|
||||
#if __cplusplus >= 201103L
|
||||
// Direct-list-initialization of a non-class object
|
||||
|
|
|
@ -33,17 +33,21 @@ void f(A* a, Foo *f, int *i, double *d, int ii) {
|
|||
|
||||
g().~Bar(); // expected-error{{non-scalar}}
|
||||
|
||||
f->::~Bar();
|
||||
f->::~Bar(); // expected-error {{not a structure or union}}
|
||||
f->::Bar::~Bar();
|
||||
f->N::~Wibble(); // expected-error{{'N' does not refer to a type}} expected-error{{'Wibble' does not refer to a type}}
|
||||
|
||||
f->::~Bar(17, 42); // expected-error{{cannot have any arguments}}
|
||||
f->Bar::~Bar(17, 42); // expected-error{{cannot have any arguments}}
|
||||
|
||||
i->~Integer();
|
||||
i->Integer::~Integer();
|
||||
i->N::~OtherInteger();
|
||||
i->N::~OtherInteger(); // expected-error{{'N' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
|
||||
// expected-error@-1{{'OtherInteger' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
|
||||
i->N::OtherInteger::~OtherInteger();
|
||||
i->N::OtherInteger::~OtherInteger();
|
||||
i->N::OtherInteger::~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->N::~Integer(); // expected-error{{'N' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
|
||||
i->N::OtherInteger::~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; did you mean to use '.'?}}
|
||||
|
|
|
@ -10333,7 +10333,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="https://wg21.link/cwg1753">1753</a></td>
|
||||
<td>CD4</td>
|
||||
<td><I>decltype-specifier</I> in <I>nested-name-specifier</I> of destructor</td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="unreleased" align="center">Clang 11</td>
|
||||
</tr>
|
||||
<tr id="1754">
|
||||
<td><a href="https://wg21.link/cwg1754">1754</a></td>
|
||||
|
|
Loading…
Reference in New Issue