forked from OSchip/llvm-project
Rework parsing of pseudo-destructor expressions and explicit
destructor calls, e.g., p->T::~T We now detect when the member access that we've parsed, e.g., p-> or x. may be a pseudo-destructor expression, either because the type of p or x is a scalar or because it is dependent (and, therefore, may become a scalar at template instantiation time). We then parse the pseudo-destructor grammar specifically: ::[opt] nested-name-specifier[opt] type-name :: ∼ type-name and hand those results to a new action, ActOnPseudoDestructorExpr, which will cope with both dependent member accesses of destructors and with pseudo-destructor expressions. This commit affects the parsing of pseudo-destructors, only; the semantic actions still go through the semantic actions for member access expressions. That will change soon. llvm-svn: 97045
This commit is contained in:
parent
03ac201ad9
commit
e610adae17
|
@ -1614,12 +1614,66 @@ public:
|
|||
/// with the type into which name lookup should look to find the member in
|
||||
/// the member access expression.
|
||||
///
|
||||
/// \param MayBePseudoDestructor Originally false. The action should
|
||||
/// set this true if the expression may end up being a
|
||||
/// pseudo-destructor expression, indicating to the parser that it
|
||||
/// shoudl be parsed as a pseudo-destructor rather than as a member
|
||||
/// access expression. Note that this should apply both when the
|
||||
/// object type is a scalar and when the object type is dependent.
|
||||
///
|
||||
/// \returns the (possibly modified) \p Base expression
|
||||
virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S,
|
||||
ExprArg Base,
|
||||
SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
TypeTy *&ObjectType) {
|
||||
TypeTy *&ObjectType,
|
||||
bool &MayBePseudoDestructor) {
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
/// \brief Parsed a C++ pseudo-destructor expression or a dependent
|
||||
/// member access expression that has the same syntactic form as a
|
||||
/// pseudo-destructor expression.
|
||||
///
|
||||
/// \param S The scope in which the member access expression occurs.
|
||||
///
|
||||
/// \param Base The expression in which a member is being accessed, e.g., the
|
||||
/// "x" in "x.f".
|
||||
///
|
||||
/// \param OpLoc The location of the member access operator ("." or "->")
|
||||
///
|
||||
/// \param OpKind The kind of member access operator ("." or "->")
|
||||
///
|
||||
/// \param SS The nested-name-specifier that precedes the type names
|
||||
/// in the grammar. Note that this nested-name-specifier will not
|
||||
/// cover the last "type-name ::" in the grammar, because it isn't
|
||||
/// necessarily a nested-name-specifier.
|
||||
///
|
||||
/// \param FirstTypeName The type name that follows the optional
|
||||
/// nested-name-specifier but precedes the '::', e.g., the first
|
||||
/// type-name in "type-name :: type-name". This type name may be
|
||||
/// empty. This will be either an identifier or a template-id.
|
||||
///
|
||||
/// \param CCLoc The location of the '::' in "type-name ::
|
||||
/// typename". May be invalid, if there is no \p FirstTypeName.
|
||||
///
|
||||
/// \param TildeLoc The location of the '~'.
|
||||
///
|
||||
/// \param SecondTypeName The type-name following the '~', which is
|
||||
/// the name of the type being destroyed. This will be either an
|
||||
/// identifier or a template-id.
|
||||
///
|
||||
/// \param HasTrailingLParen Whether the next token in the stream is
|
||||
/// a left parentheses.
|
||||
virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
||||
SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
const CXXScopeSpec &SS,
|
||||
UnqualifiedId &FirstTypeName,
|
||||
SourceLocation CCLoc,
|
||||
SourceLocation TildeLoc,
|
||||
UnqualifiedId &SecondTypeName,
|
||||
bool HasTrailingLParen) {
|
||||
return ExprEmpty();
|
||||
}
|
||||
|
||||
|
|
|
@ -964,7 +964,7 @@ private:
|
|||
bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
||||
TypeTy *ObjectType,
|
||||
bool EnteringContext,
|
||||
bool InMemberAccessExpr = false);
|
||||
bool *MayBePseudoDestructor = 0);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ 5.2p1: C++ Casts
|
||||
|
@ -974,6 +974,13 @@ private:
|
|||
// C++ 5.2p1: C++ Type Identification
|
||||
OwningExprResult ParseCXXTypeid();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ 5.2.4: C++ Pseudo-Destructor Expressions
|
||||
OwningExprResult ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
CXXScopeSpec &SS,
|
||||
Action::TypeTy *ObjectType);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ 9.3.2: C++ 'this' pointer
|
||||
OwningExprResult ParseCXXThis();
|
||||
|
@ -1415,7 +1422,8 @@ private:
|
|||
SourceLocation NameLoc,
|
||||
bool EnteringContext,
|
||||
TypeTy *ObjectType,
|
||||
UnqualifiedId &Id);
|
||||
UnqualifiedId &Id,
|
||||
bool AssumeTemplateId = false);
|
||||
bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
|
||||
TypeTy *ObjectType,
|
||||
UnqualifiedId &Result);
|
||||
|
|
|
@ -996,12 +996,16 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
|
|||
|
||||
CXXScopeSpec SS;
|
||||
Action::TypeTy *ObjectType = 0;
|
||||
bool MayBePseudoDestructor = false;
|
||||
if (getLang().CPlusPlus && !LHS.isInvalid()) {
|
||||
LHS = Actions.ActOnStartCXXMemberReference(CurScope, move(LHS),
|
||||
OpLoc, OpKind, ObjectType);
|
||||
OpLoc, OpKind, ObjectType,
|
||||
MayBePseudoDestructor);
|
||||
if (LHS.isInvalid())
|
||||
break;
|
||||
ParseOptionalCXXScopeSpecifier(SS, ObjectType, false, true);
|
||||
|
||||
ParseOptionalCXXScopeSpecifier(SS, ObjectType, false,
|
||||
&MayBePseudoDestructor);
|
||||
}
|
||||
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
|
@ -1012,6 +1016,17 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
|
|||
ConsumeToken();
|
||||
}
|
||||
|
||||
if (MayBePseudoDestructor) {
|
||||
LHS = ParseCXXPseudoDestructor(move(LHS), OpLoc, OpKind, SS,
|
||||
ObjectType);
|
||||
break;
|
||||
}
|
||||
|
||||
// Either the action has told is that this cannot be a
|
||||
// pseudo-destructor expression (based on the type of base
|
||||
// expression), or we didn't see a '~' in the right place. We
|
||||
// can still parse a destructor name here, but in that case it
|
||||
// names a real destructor.
|
||||
UnqualifiedId Name;
|
||||
if (ParseUnqualifiedId(SS,
|
||||
/*EnteringContext=*/false,
|
||||
|
@ -1022,10 +1037,9 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
|
|||
return ExprError();
|
||||
|
||||
if (!LHS.isInvalid())
|
||||
LHS = Actions.ActOnMemberAccessExpr(CurScope, move(LHS), OpLoc, OpKind,
|
||||
SS, Name, ObjCImpDecl,
|
||||
LHS = Actions.ActOnMemberAccessExpr(CurScope, move(LHS), OpLoc,
|
||||
OpKind, SS, Name, ObjCImpDecl,
|
||||
Tok.is(tok::l_paren));
|
||||
|
||||
break;
|
||||
}
|
||||
case tok::plusplus: // postfix-expression: postfix-expression '++'
|
||||
|
|
|
@ -45,14 +45,21 @@ using namespace clang;
|
|||
/// \param EnteringContext whether we will be entering into the context of
|
||||
/// the nested-name-specifier after parsing it.
|
||||
///
|
||||
/// \param InMemberAccessExpr Whether this scope specifier is within a
|
||||
/// \param MayBePseudoDestructor When non-NULL, points to a flag that
|
||||
/// indicates whether this nested-name-specifier may be part of a
|
||||
/// pseudo-destructor name. In this case, the flag will be set false
|
||||
/// if we don't actually end up parsing a destructor name. Moreorover,
|
||||
/// if we do end up determining that we are parsing a destructor name,
|
||||
/// the last component of the nested-name-specifier is not parsed as
|
||||
/// part of the scope specifier.
|
||||
|
||||
/// member access expression, e.g., the \p T:: in \p p->T::m.
|
||||
///
|
||||
/// \returns true if a scope specifier was parsed.
|
||||
bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
||||
Action::TypeTy *ObjectType,
|
||||
bool EnteringContext,
|
||||
bool InMemberAccessExpr) {
|
||||
bool *MayBePseudoDestructor) {
|
||||
assert(getLang().CPlusPlus &&
|
||||
"Call sites of this function should be guarded by checking for C++");
|
||||
|
||||
|
@ -79,6 +86,12 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
HasScopeSpecifier = true;
|
||||
}
|
||||
|
||||
bool CheckForDestructor = false;
|
||||
if (MayBePseudoDestructor && *MayBePseudoDestructor) {
|
||||
CheckForDestructor = true;
|
||||
*MayBePseudoDestructor = false;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (HasScopeSpecifier) {
|
||||
// C++ [basic.lookup.classref]p5:
|
||||
|
@ -173,8 +186,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
// convert it into a type within the nested-name-specifier.
|
||||
TemplateIdAnnotation *TemplateId
|
||||
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
|
||||
bool MayBePseudoDestructor
|
||||
= InMemberAccessExpr && GetLookAheadToken(2).is(tok::tilde);
|
||||
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
|
||||
*MayBePseudoDestructor = true;
|
||||
return HasScopeSpecifier;
|
||||
}
|
||||
|
||||
if (TemplateId->Kind == TNK_Type_template ||
|
||||
TemplateId->Kind == TNK_Dependent_template_name) {
|
||||
AnnotateTemplateIdTokenAsType(&SS);
|
||||
|
@ -197,7 +213,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
TypeToken.getAnnotationValue(),
|
||||
TypeToken.getAnnotationRange(),
|
||||
CCLoc,
|
||||
MayBePseudoDestructor));
|
||||
false));
|
||||
else
|
||||
SS.setScopeRep(0);
|
||||
SS.setEndLoc(CCLoc);
|
||||
|
@ -224,11 +240,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
// If we get foo:bar, this is almost certainly a typo for foo::bar. Recover
|
||||
// and emit a fixit hint for it.
|
||||
if (Next.is(tok::colon) && !ColonIsSacred) {
|
||||
bool MayBePseudoDestructor
|
||||
= InMemberAccessExpr && GetLookAheadToken(2).is(tok::tilde);
|
||||
|
||||
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
|
||||
*MayBePseudoDestructor = true;
|
||||
return HasScopeSpecifier;
|
||||
}
|
||||
|
||||
if (Actions.IsInvalidUnlessNestedName(CurScope, SS, II,
|
||||
MayBePseudoDestructor, ObjectType,
|
||||
false, ObjectType,
|
||||
EnteringContext) &&
|
||||
// If the token after the colon isn't an identifier, it's still an
|
||||
// error, but they probably meant something else strange so don't
|
||||
|
@ -243,6 +261,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
}
|
||||
|
||||
if (Next.is(tok::coloncolon)) {
|
||||
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
|
||||
*MayBePseudoDestructor = true;
|
||||
return HasScopeSpecifier;
|
||||
}
|
||||
|
||||
// We have an identifier followed by a '::'. Lookup this name
|
||||
// as the name in a nested-name-specifier.
|
||||
SourceLocation IdLoc = ConsumeToken();
|
||||
|
@ -258,11 +281,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
if (SS.isInvalid())
|
||||
continue;
|
||||
|
||||
bool MayBePseudoDestructor = InMemberAccessExpr && Tok.is(tok::tilde);
|
||||
|
||||
SS.setScopeRep(
|
||||
Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II,
|
||||
MayBePseudoDestructor, ObjectType,
|
||||
false, ObjectType,
|
||||
EnteringContext));
|
||||
SS.setEndLoc(CCLoc);
|
||||
continue;
|
||||
|
@ -298,6 +319,12 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
break;
|
||||
}
|
||||
|
||||
// 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))
|
||||
*MayBePseudoDestructor = true;
|
||||
|
||||
return HasScopeSpecifier;
|
||||
}
|
||||
|
||||
|
@ -493,6 +520,77 @@ Parser::OwningExprResult Parser::ParseCXXTypeid() {
|
|||
return move(Result);
|
||||
}
|
||||
|
||||
/// \brief Parse a C++ pseudo-destructor expression after the base,
|
||||
/// . or -> operator, and nested-name-specifier have already been
|
||||
/// parsed.
|
||||
///
|
||||
/// postfix-expression: [C++ 5.2]
|
||||
/// postfix-expression . pseudo-destructor-name
|
||||
/// postfix-expression -> pseudo-destructor-name
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
Parser::OwningExprResult
|
||||
Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
CXXScopeSpec &SS,
|
||||
Action::TypeTy *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.
|
||||
UnqualifiedId FirstTypeName;
|
||||
SourceLocation CCLoc;
|
||||
if (Tok.is(tok::identifier)) {
|
||||
FirstTypeName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
|
||||
ConsumeToken();
|
||||
assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
|
||||
CCLoc = ConsumeToken();
|
||||
} else if (Tok.is(tok::annot_template_id)) {
|
||||
FirstTypeName.setTemplateId(
|
||||
(TemplateIdAnnotation *)Tok.getAnnotationValue());
|
||||
ConsumeToken();
|
||||
assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
|
||||
CCLoc = ConsumeToken();
|
||||
} else {
|
||||
FirstTypeName.setIdentifier(0, SourceLocation());
|
||||
}
|
||||
|
||||
// Parse the tilde.
|
||||
assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail");
|
||||
SourceLocation TildeLoc = ConsumeToken();
|
||||
if (!Tok.is(tok::identifier)) {
|
||||
Diag(Tok, diag::err_destructor_tilde_identifier);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
// Parse the second type.
|
||||
UnqualifiedId SecondTypeName;
|
||||
IdentifierInfo *Name = Tok.getIdentifierInfo();
|
||||
SourceLocation NameLoc = ConsumeToken();
|
||||
SecondTypeName.setIdentifier(Name, NameLoc);
|
||||
|
||||
// If there is a '<', the second type name is a template-id. Parse
|
||||
// it as such.
|
||||
if (Tok.is(tok::less) &&
|
||||
ParseUnqualifiedIdTemplateId(SS, Name, NameLoc, false, ObjectType,
|
||||
SecondTypeName, /*AssumeTemplateName=*/true))
|
||||
return ExprError();
|
||||
|
||||
return Actions.ActOnPseudoDestructorExpr(CurScope, move(Base), OpLoc, OpKind,
|
||||
SS, FirstTypeName, CCLoc,
|
||||
TildeLoc, SecondTypeName,
|
||||
Tok.is(tok::l_paren));
|
||||
}
|
||||
|
||||
/// ParseCXXBoolLiteral - This handles the C++ Boolean literals.
|
||||
///
|
||||
/// boolean-literal: [C++ 2.13.5]
|
||||
|
@ -818,13 +916,17 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
|
|||
/// that precedes the '<'. If template arguments were parsed successfully,
|
||||
/// will be updated with the template-id.
|
||||
///
|
||||
/// \param AssumeTemplateId When true, this routine will assume that the name
|
||||
/// refers to a template without performing name lookup to verify.
|
||||
///
|
||||
/// \returns true if a parse error occurred, false otherwise.
|
||||
bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
|
||||
IdentifierInfo *Name,
|
||||
SourceLocation NameLoc,
|
||||
bool EnteringContext,
|
||||
TypeTy *ObjectType,
|
||||
UnqualifiedId &Id) {
|
||||
UnqualifiedId &Id,
|
||||
bool AssumeTemplateId) {
|
||||
assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id");
|
||||
|
||||
TemplateTy Template;
|
||||
|
@ -833,8 +935,16 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
|
|||
case UnqualifiedId::IK_Identifier:
|
||||
case UnqualifiedId::IK_OperatorFunctionId:
|
||||
case UnqualifiedId::IK_LiteralOperatorId:
|
||||
TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, EnteringContext,
|
||||
Template);
|
||||
if (AssumeTemplateId) {
|
||||
Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS,
|
||||
Id, ObjectType,
|
||||
EnteringContext);
|
||||
TNK = TNK_Dependent_template_name;
|
||||
if (!Template.get())
|
||||
return true;
|
||||
} else
|
||||
TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType,
|
||||
EnteringContext, Template);
|
||||
break;
|
||||
|
||||
case UnqualifiedId::IK_ConstructorName: {
|
||||
|
|
|
@ -2175,7 +2175,18 @@ public:
|
|||
ExprArg Base,
|
||||
SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
TypeTy *&ObjectType);
|
||||
TypeTy *&ObjectType,
|
||||
bool &MayBePseudoDestructor);
|
||||
|
||||
virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
||||
SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
const CXXScopeSpec &SS,
|
||||
UnqualifiedId &FirstTypeName,
|
||||
SourceLocation CCLoc,
|
||||
SourceLocation TildeLoc,
|
||||
UnqualifiedId &SecondTypeName,
|
||||
bool HasTrailingLParen);
|
||||
|
||||
/// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
|
||||
/// non-empty, will create a new CXXExprWithTemporaries expression.
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Parse/DeclSpec.h"
|
||||
#include "clang/Parse/Template.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
using namespace clang;
|
||||
|
||||
|
@ -2325,7 +2326,8 @@ FullExpr Sema::CreateFullExpr(Expr *SubExpr) {
|
|||
|
||||
Sema::OwningExprResult
|
||||
Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind, TypeTy *&ObjectType) {
|
||||
tok::TokenKind OpKind, TypeTy *&ObjectType,
|
||||
bool &MayBePseudoDestructor) {
|
||||
// Since this might be a postfix expression, get rid of ParenListExprs.
|
||||
Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
|
||||
|
||||
|
@ -2333,6 +2335,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
assert(BaseExpr && "no record expansion");
|
||||
|
||||
QualType BaseType = BaseExpr->getType();
|
||||
MayBePseudoDestructor = false;
|
||||
if (BaseType->isDependentType()) {
|
||||
// If we have a pointer to a dependent type and are using the -> operator,
|
||||
// the object type is the type that the pointer points to. We might still
|
||||
|
@ -2342,6 +2345,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
BaseType = Ptr->getPointeeType();
|
||||
|
||||
ObjectType = BaseType.getAsOpaquePtr();
|
||||
MayBePseudoDestructor = true;
|
||||
return move(Base);
|
||||
}
|
||||
|
||||
|
@ -2383,7 +2387,11 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
// [...] If the type of the object expression is of pointer to scalar
|
||||
// type, the unqualified-id is looked up in the context of the complete
|
||||
// postfix-expression.
|
||||
//
|
||||
// This also indicates that we should be parsing a
|
||||
// pseudo-destructor-name.
|
||||
ObjectType = 0;
|
||||
MayBePseudoDestructor = true;
|
||||
return move(Base);
|
||||
}
|
||||
|
||||
|
@ -2399,10 +2407,149 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
// type C (or of pointer to a class type C), the unqualified-id is looked
|
||||
// up in the scope of class C. [...]
|
||||
ObjectType = BaseType.getAsOpaquePtr();
|
||||
|
||||
return move(Base);
|
||||
}
|
||||
|
||||
Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
||||
SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
const CXXScopeSpec &SS,
|
||||
UnqualifiedId &FirstTypeName,
|
||||
SourceLocation CCLoc,
|
||||
SourceLocation TildeLoc,
|
||||
UnqualifiedId &SecondTypeName,
|
||||
bool HasTrailingLParen) {
|
||||
assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
|
||||
FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
|
||||
"Invalid first type name in pseudo-destructor");
|
||||
assert((SecondTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
|
||||
SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
|
||||
"Invalid second type name in pseudo-destructor");
|
||||
|
||||
Expr *BaseE = (Expr *)Base.get();
|
||||
QualType ObjectType;
|
||||
if (BaseE->isTypeDependent())
|
||||
ObjectType = Context.DependentTy;
|
||||
|
||||
// The nested-name-specifier provided by the parser, then extended
|
||||
// by the "type-name ::" in the pseudo-destructor-name, if present.
|
||||
CXXScopeSpec ExtendedSS = SS;
|
||||
|
||||
if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
|
||||
FirstTypeName.Identifier) {
|
||||
// We have a pseudo-destructor with a "type-name ::".
|
||||
// FIXME: As a temporary hack, we go ahead and resolve this to part of
|
||||
// a nested-name-specifier.
|
||||
if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
|
||||
// Resolve the identifier to a nested-name-specifier.
|
||||
CXXScopeTy *FinalScope
|
||||
= ActOnCXXNestedNameSpecifier(S, SS,
|
||||
FirstTypeName.StartLocation,
|
||||
CCLoc,
|
||||
*FirstTypeName.Identifier,
|
||||
true,
|
||||
ObjectType.getAsOpaquePtr(),
|
||||
false);
|
||||
if (SS.getBeginLoc().isInvalid())
|
||||
ExtendedSS.setBeginLoc(FirstTypeName.StartLocation);
|
||||
ExtendedSS.setEndLoc(CCLoc);
|
||||
ExtendedSS.setScopeRep(FinalScope);
|
||||
} else {
|
||||
// Resolve the template-id to a type, and that to a
|
||||
// nested-name-specifier.
|
||||
TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId;
|
||||
ASTTemplateArgsPtr TemplateArgsPtr(*this,
|
||||
TemplateId->getTemplateArgs(),
|
||||
TemplateId->NumArgs);
|
||||
TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
|
||||
TemplateId->TemplateNameLoc,
|
||||
TemplateId->LAngleLoc,
|
||||
TemplateArgsPtr,
|
||||
TemplateId->RAngleLoc);
|
||||
if (!T.isInvalid()) {
|
||||
CXXScopeTy *FinalScope
|
||||
= ActOnCXXNestedNameSpecifier(S, SS, T.get(),
|
||||
SourceRange(TemplateId->TemplateNameLoc,
|
||||
TemplateId->RAngleLoc),
|
||||
CCLoc,
|
||||
true);
|
||||
if (SS.getBeginLoc().isInvalid())
|
||||
ExtendedSS.setBeginLoc(TemplateId->TemplateNameLoc);
|
||||
ExtendedSS.setEndLoc(CCLoc);
|
||||
ExtendedSS.setScopeRep(FinalScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Produce a destructor name based on the second type-name (which
|
||||
// follows the tilde).
|
||||
TypeTy *DestructedType;
|
||||
SourceLocation EndLoc;
|
||||
if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) {
|
||||
const CXXScopeSpec *LookupSS = &SS;
|
||||
bool isDependent = isDependentScopeSpecifier(ExtendedSS);
|
||||
if (isDependent || computeDeclContext(ExtendedSS))
|
||||
LookupSS = &ExtendedSS;
|
||||
|
||||
DestructedType = getTypeName(*SecondTypeName.Identifier,
|
||||
SecondTypeName.StartLocation,
|
||||
S, LookupSS, true, ObjectType.getTypePtr());
|
||||
if (!DestructedType && isDependent) {
|
||||
// We didn't find our type, but that's okay: it's dependent
|
||||
// anyway.
|
||||
// FIXME: We should not be building a typename type here!
|
||||
NestedNameSpecifier *NNS = 0;
|
||||
SourceRange Range;
|
||||
if (SS.isSet()) {
|
||||
NNS = (NestedNameSpecifier *)ExtendedSS.getScopeRep();
|
||||
Range = SourceRange(ExtendedSS.getRange().getBegin(),
|
||||
SecondTypeName.StartLocation);
|
||||
} else {
|
||||
NNS = NestedNameSpecifier::Create(Context, SecondTypeName.Identifier);
|
||||
Range = SourceRange(SecondTypeName.StartLocation);
|
||||
}
|
||||
|
||||
DestructedType = CheckTypenameType(NNS, *SecondTypeName.Identifier,
|
||||
Range).getAsOpaquePtr();
|
||||
if (!DestructedType)
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
if (!DestructedType) {
|
||||
// FIXME: Crummy diagnostic.
|
||||
Diag(SecondTypeName.StartLocation, diag::err_destructor_class_name);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
EndLoc = SecondTypeName.EndLocation;
|
||||
} else {
|
||||
// Resolve the template-id to a type, and that to a
|
||||
// nested-name-specifier.
|
||||
TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;
|
||||
ASTTemplateArgsPtr TemplateArgsPtr(*this,
|
||||
TemplateId->getTemplateArgs(),
|
||||
TemplateId->NumArgs);
|
||||
EndLoc = TemplateId->RAngleLoc;
|
||||
TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
|
||||
TemplateId->TemplateNameLoc,
|
||||
TemplateId->LAngleLoc,
|
||||
TemplateArgsPtr,
|
||||
TemplateId->RAngleLoc);
|
||||
if (T.isInvalid() || !T.get())
|
||||
return ExprError();
|
||||
|
||||
DestructedType = T.get();
|
||||
}
|
||||
|
||||
// Form a (possibly fake) destructor name and let the member access
|
||||
// expression code deal with this.
|
||||
// FIXME: Don't do this! It's totally broken!
|
||||
UnqualifiedId Destructor;
|
||||
Destructor.setDestructorName(TildeLoc, DestructedType, EndLoc);
|
||||
return ActOnMemberAccessExpr(S, move(Base), OpLoc, OpKind, ExtendedSS,
|
||||
Destructor, DeclPtrTy(), HasTrailingLParen);
|
||||
}
|
||||
|
||||
CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
|
||||
CXXMethodDecl *Method) {
|
||||
if (PerformObjectArgumentInitialization(Exp, Method))
|
||||
|
|
|
@ -5041,10 +5041,12 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
|
|||
|
||||
// Start the member reference and compute the object's type.
|
||||
Sema::TypeTy *ObjectTy = 0;
|
||||
bool MayBePseudoDestructor = false;
|
||||
Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
|
||||
E->getOperatorLoc(),
|
||||
E->isArrow()? tok::arrow : tok::period,
|
||||
ObjectTy);
|
||||
ObjectTy,
|
||||
MayBePseudoDestructor);
|
||||
if (Base.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
|
|
Loading…
Reference in New Issue