Replace the code that parses member access expressions after "." or

"->" with a use of ParseUnqualifiedId. Collapse
ActOnMemberReferenceExpr, ActOnDestructorReferenceExpr (both of them),
ActOnOverloadedOperatorReferenceExpr,
ActOnConversionOperatorReferenceExpr, and
ActOnMemberTemplateIdReferenceExpr into a single, new action
ActOnMemberAccessExpr that does the same thing more cleanly (and can
keep more source-location information).

llvm-svn: 85930
This commit is contained in:
Douglas Gregor 2009-11-03 19:44:04 +00:00
parent d697debebf
commit 30d60cb36e
13 changed files with 183 additions and 417 deletions

View File

@ -216,7 +216,8 @@ def err_declaration_does_not_declare_param : Error<
def err_no_matching_param : Error<"parameter named %0 is missing">;
/// C++ parser diagnostics
def err_expected_unqualified_id : Error<"expected unqualified-id">;
def err_expected_unqualified_id : Error<
"expected %select{identifier|unqualified-id}0">;
def err_func_def_no_params : Error<
"function definition does not declare parameters">;
def err_expected_lparen_after_type : Error<
@ -233,6 +234,8 @@ def err_expected_catch : Error<"expected catch">;
def err_expected_lbrace_or_comma : Error<"expected '{' or ','">;
def err_using_namespace_in_class : Error<
"'using namespace' in class not allowed">;
def err_ident_in_pseudo_dtor_not_a_type : Error<
"identifier %0 in pseudo-destructor expression does not name a type">;
// C++ derived classes
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;

View File

@ -1725,8 +1725,6 @@ def err_throw_incomplete_ptr : Error<
def err_return_in_constructor_handler : Error<
"return in the catch of a function try block of a constructor is illegal">;
def err_ident_in_pseudo_dtor_not_a_type : Error<
"identifier %0 in pseudo-destructor expression does not name a type">;
def err_operator_arrow_circular : Error<
"circular pointer delegation detected">;
def err_pseudo_dtor_base_not_scalar : Error<

View File

@ -922,16 +922,42 @@ public:
SourceLocation RLoc) {
return ExprEmpty();
}
virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation MemberLoc,
IdentifierInfo &Member,
DeclPtrTy ObjCImpDecl,
const CXXScopeSpec *SS = 0) {
/// \brief Parsed a member access expresion (C99 6.5.2.3, C++ [expr.ref])
/// of the form \c x.m or \c p->m.
///
/// \param S the scope in which the member access expression occurs.
///
/// \param Base the class or pointer to class into which this member
/// access expression refers, e.g., \c x in \c x.m.
///
/// \param OpLoc the location of the "." or "->" operator.
///
/// \param OpKind the kind of member access operator, which will be either
/// tok::arrow ("->") or tok::period (".").
///
/// \param SS in C++, the nested-name-specifier that precedes the member
/// name, if any.
///
/// \param Member the name of the member that we are referring to. In C,
/// this will always store an identifier; in C++, we may also have operator
/// names, conversion function names, destructors, and template names.
///
/// \param ObjCImpDecl the Objective-C implementation declaration.
/// FIXME: Do we really need this?
///
/// \param HasTrailingLParen whether this member name is immediately followed
/// by a left parentheses ('(').
virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
const CXXScopeSpec &SS,
UnqualifiedId &Member,
DeclPtrTy ObjCImpDecl,
bool HasTrailingLParen) {
return ExprEmpty();
}
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations. There are guaranteed to be one fewer commas than arguments,
@ -1361,123 +1387,6 @@ public:
return ExprEmpty();
}
/// ActOnDestructorReferenceExpr - Parsed a destructor reference, for example:
///
/// t->~T();
virtual OwningExprResult
ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation ClassNameLoc,
IdentifierInfo *ClassName,
const CXXScopeSpec &SS,
bool HasTrailingLParen) {
return ExprEmpty();
}
/// \brief Parsed a C++ destructor reference that refers to a type.
///
/// This action is used when parsing a destructor reference that uses a
/// template-id, e.g.,
///
/// \code
/// t->~Tmpl<T1, T2>
/// \endcode
///
/// \param S the scope in which the destructor reference occurs.
/// \param Base the base object of the destructor reference expression.
/// \param OpLoc the location of the operator ('.' or '->').
/// \param OpKind the kind of the destructor reference operator ('.' or '->').
/// \param TypeRange the source range that covers the destructor type.
/// \param Type the type that is being destroyed.
/// \param SS the scope specifier that precedes the destructor name.
/// \param HasTrailingLParen whether the destructor name is followed by a '('.
virtual OwningExprResult
ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceRange TypeRange,
TypeTy *Type,
const CXXScopeSpec &SS,
bool HasTrailingLParen) {
return ExprEmpty();
}
/// ActOnOverloadedOperatorReferenceExpr - Parsed an overloaded operator
/// reference, for example:
///
/// t.operator++();
virtual OwningExprResult
ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation ClassNameLoc,
OverloadedOperatorKind OverOpKind,
const CXXScopeSpec *SS = 0) {
return ExprEmpty();
}
/// ActOnConversionOperatorReferenceExpr - Parsed an overloaded conversion
/// function reference, for example:
///
/// t.operator int();
virtual OwningExprResult
ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation ClassNameLoc,
TypeTy *Ty,
const CXXScopeSpec *SS = 0) {
return ExprEmpty();
}
/// \brief Parsed a reference to a member template-id.
///
/// This callback will occur instead of ActOnMemberReferenceExpr() when the
/// member in question is a template for which the code provides an
/// explicitly-specified template argument list, e.g.,
///
/// \code
/// x.f<int>()
/// \endcode
///
/// \param S the scope in which the member reference expression occurs
///
/// \param Base the expression to the left of the "." or "->".
///
/// \param OpLoc the location of the "." or "->".
///
/// \param OpKind the kind of operator, which will be "." or "->".
///
/// \param SS the scope specifier that precedes the template-id in, e.g.,
/// \c x.Base::f<int>().
///
/// \param Template the declaration of the template that is being referenced.
///
/// \param TemplateNameLoc the location of the template name referred to by
/// \p Template.
///
/// \param LAngleLoc the location of the left angle bracket ('<')
///
/// \param TemplateArgs the (possibly-empty) template argument list provided
/// as part of the member reference.
///
/// \param RAngleLoc the location of the right angle bracket ('>')
virtual OwningExprResult
ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
const CXXScopeSpec &SS,
// FIXME: "template" keyword?
TemplateTy Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc) {
return ExprEmpty();
}
/// ActOnFinishFullExpr - Called whenever a full expression has been parsed.
/// (C++ [intro.execution]p12).
virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr) {

View File

@ -1216,10 +1216,12 @@ private:
IdentifierInfo *Name,
SourceLocation NameLoc,
bool EnteringContext,
TypeTy *ObjectType,
UnqualifiedId &Id);
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
bool AllowConstructorName,
TypeTy *ObjectType,
UnqualifiedId &Result);
//===--------------------------------------------------------------------===//

View File

@ -2314,6 +2314,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
/*EnteringContext=*/true,
/*AllowDestructorName=*/true,
/*AllowConstructorName=*/!D.getDeclSpec().hasTypeSpecifier(),
/*ObjectType=*/0,
D.getName())) {
D.SetIdentifier(0, Tok.getLocation());
D.setInvalidType(true);
@ -2348,7 +2349,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
Diag(Tok, diag::err_expected_member_name_or_semi)
<< D.getDeclSpec().getSourceRange();
else if (getLang().CPlusPlus)
Diag(Tok, diag::err_expected_unqualified_id);
Diag(Tok, diag::err_expected_unqualified_id) << getLang().CPlusPlus;
else
Diag(Tok, diag::err_expected_ident_lparen);
D.SetIdentifier(0, Tok.getLocation());

View File

@ -968,6 +968,21 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
ConsumeToken();
}
UnqualifiedId Name;
if (ParseUnqualifiedId(SS,
/*EnteringContext=*/false,
/*AllowDestructorName=*/true,
/*AllowConstructorName=*/false,
ObjectType,
Name))
return ExprError();
if (!LHS.isInvalid())
LHS = Actions.ActOnMemberAccessExpr(CurScope, move(LHS), OpLoc, OpKind,
SS, Name, ObjCImpDecl,
Tok.is(tok::l_paren));
#if 0
if (Tok.is(tok::identifier)) {
if (!LHS.isInvalid())
LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc,
@ -1072,6 +1087,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) {
Diag(Tok, diag::err_expected_ident);
return ExprError();
}
#endif
break;
}
case tok::plusplus: // postfix-expression: postfix-expression '++'

View File

@ -315,76 +315,13 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
/*EnteringContext=*/false,
/*AllowDestructorName=*/false,
/*AllowConstructorName=*/false,
/*ObjectType=*/0,
Name))
return ExprError();
return Actions.ActOnIdExpression(CurScope, SS, Name, Tok.is(tok::l_paren),
isAddressOfOperand);
#if 0
// unqualified-id:
// identifier
// operator-function-id
// conversion-function-id
// '~' class-name [TODO]
// template-id
//
switch (Tok.getKind()) {
default:
return ExprError(Diag(Tok, diag::err_expected_unqualified_id));
case tok::identifier: {
// Consume the identifier so that we can see if it is followed by a '('.
IdentifierInfo &II = *Tok.getIdentifierInfo();
SourceLocation L = ConsumeToken();
return Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren),
&SS, isAddressOfOperand);
}
case tok::kw_operator: {
SourceLocation OperatorLoc = Tok.getLocation();
if (OverloadedOperatorKind Op = TryParseOperatorFunctionId())
return Actions.ActOnCXXOperatorFunctionIdExpr(
CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS,
isAddressOfOperand);
if (TypeTy *Type = ParseConversionFunctionId())
return Actions.ActOnCXXConversionFunctionExpr(CurScope, OperatorLoc, Type,
Tok.is(tok::l_paren), SS,
isAddressOfOperand);
// We already complained about a bad conversion-function-id,
// above.
return ExprError();
}
case tok::annot_template_id: {
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
assert((TemplateId->Kind == TNK_Function_template ||
TemplateId->Kind == TNK_Dependent_template_name) &&
"A template type name is not an ID expression");
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
TemplateId->getTemplateArgs(),
TemplateId->getTemplateArgIsType(),
TemplateId->NumArgs);
OwningExprResult Result
= Actions.ActOnTemplateIdExpr(SS,
TemplateTy::make(TemplateId->Template),
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->getTemplateArgLocations(),
TemplateId->RAngleLoc);
ConsumeToken(); // Consume the template-id token
return move(Result);
}
} // switch.
assert(0 && "The switch was supposed to take care everything.");
#endif
}
/// ParseCXXCasts - This handles the various ways to cast expressions to another
@ -806,6 +743,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
IdentifierInfo *Name,
SourceLocation NameLoc,
bool EnteringContext,
TypeTy *ObjectType,
UnqualifiedId &Id) {
assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id");
@ -814,14 +752,13 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
switch (Id.getKind()) {
case UnqualifiedId::IK_Identifier:
TNK = Actions.isTemplateName(CurScope, *Id.Identifier, Id.StartLocation,
&SS, /*ObjectType=*/0, EnteringContext,
Template);
&SS, ObjectType, EnteringContext, Template);
break;
case UnqualifiedId::IK_OperatorFunctionId: {
// FIXME: Temporary hack: warn that we are completely ignoring the
// template arguments for now.
// Parse the enclosed template argument list.
// Parse the enclosed template argument list and throw it away.
SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
TemplateArgIsTypeList TemplateArgIsType;
@ -840,15 +777,32 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
}
case UnqualifiedId::IK_ConstructorName:
TNK = Actions.isTemplateName(CurScope, *Name, NameLoc,
&SS, /*ObjectType=*/0, EnteringContext,
Template);
TNK = Actions.isTemplateName(CurScope, *Name, NameLoc, &SS, ObjectType,
EnteringContext, Template);
break;
case UnqualifiedId::IK_DestructorName:
TNK = Actions.isTemplateName(CurScope, *Name, NameLoc,
&SS, /*ObjectType=*/0, EnteringContext,
Template);
if (ObjectType) {
Template = Actions.ActOnDependentTemplateName(SourceLocation(), *Name,
NameLoc, SS, ObjectType);
TNK = TNK_Dependent_template_name;
if (!Template.get())
return true;
} else {
TNK = Actions.isTemplateName(CurScope, *Name, NameLoc, &SS, ObjectType,
EnteringContext, Template);
if (TNK == TNK_Non_template && Id.DestructorName == 0) {
// The identifier following the destructor did not refer to a template
// or to a type. Complain.
if (ObjectType)
Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
<< Name;
else
Diag(NameLoc, diag::err_destructor_class_name);
return true;
}
}
break;
default:
@ -974,6 +928,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
bool AllowConstructorName,
TypeTy *ObjectType,
UnqualifiedId &Result) {
// unqualified-id:
// identifier
@ -997,7 +952,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// If the next token is a '<', we may have a template.
if (Tok.is(tok::less))
return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext,
Result);
ObjectType, Result);
return false;
}
@ -1110,7 +1065,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
// If the next token is a '<', we may have a template.
if (Tok.is(tok::less))
return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(),
EnteringContext, Result);
EnteringContext, ObjectType,
Result);
return false;
}
@ -1166,24 +1122,30 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
IdentifierInfo *ClassName = Tok.getIdentifierInfo();
SourceLocation ClassNameLoc = ConsumeToken();
if (Tok.is(tok::less)) {
Result.setDestructorName(TildeLoc, 0, ClassNameLoc);
return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc,
EnteringContext, ObjectType, Result);
}
// Note that this is a destructor name.
Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc,
CurScope, &SS);
if (!Ty) {
Diag(ClassNameLoc, diag::err_destructor_class_name);
if (ObjectType)
Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
<< ClassName;
else
Diag(ClassNameLoc, diag::err_destructor_class_name);
return true;
}
Result.setDestructorName(TildeLoc, Ty, ClassNameLoc);
if (Tok.is(tok::less))
return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc,
EnteringContext, Result);
return false;
}
Diag(Tok, diag::err_expected_unqualified_id);
Diag(Tok, diag::err_expected_unqualified_id)
<< getLang().CPlusPlus;
return true;
}

View File

@ -1714,13 +1714,14 @@ public:
const CXXScopeSpec *SS,
NamedDecl *FirstQualifierInScope = 0);
virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation MemberLoc,
IdentifierInfo &Member,
DeclPtrTy ImplDecl,
const CXXScopeSpec *SS = 0);
virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
const CXXScopeSpec &SS,
UnqualifiedId &Member,
DeclPtrTy ObjCImpDecl,
bool HasTrailingLParen);
virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl);
bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
FunctionDecl *FDecl,
@ -2096,52 +2097,6 @@ public:
tok::TokenKind OpKind,
TypeTy *&ObjectType);
virtual OwningExprResult
ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation ClassNameLoc,
IdentifierInfo *ClassName,
const CXXScopeSpec &SS,
bool HasTrailingLParen);
virtual OwningExprResult
ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceRange TypeRange,
TypeTy *Type,
const CXXScopeSpec &SS,
bool HasTrailingLParen);
virtual OwningExprResult
ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation ClassNameLoc,
OverloadedOperatorKind OverOpKind,
const CXXScopeSpec *SS = 0);
virtual OwningExprResult
ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation ClassNameLoc,
TypeTy *Ty,
const CXXScopeSpec *SS = 0);
virtual OwningExprResult
ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
const CXXScopeSpec &SS,
// FIXME: "template" keyword?
TemplateTy Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc);
/// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
/// non-empty, will create a new CXXExprWithTemporaries expression.
/// Otherwise, just returs the passed in expression.

View File

@ -2479,13 +2479,72 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
return ExprError();
}
Action::OwningExprResult
Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
tok::TokenKind OpKind, SourceLocation MemberLoc,
IdentifierInfo &Member,
DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) {
return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc,
DeclarationName(&Member), ObjCImpDecl, SS);
Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
const CXXScopeSpec &SS,
UnqualifiedId &Member,
DeclPtrTy ObjCImpDecl,
bool HasTrailingLParen) {
if (Member.getKind() == UnqualifiedId::IK_TemplateId) {
TemplateName Template
= TemplateName::getFromVoidPointer(Member.TemplateId->Template);
// FIXME: We're going to end up looking up the template based on its name,
// twice!
DeclarationName Name;
if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl())
Name = ActualTemplate->getDeclName();
else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl())
Name = Ovl->getDeclName();
else
Name = Template.getAsDependentTemplateName()->getName();
// Translate the parser's template argument list in our AST format.
ASTTemplateArgsPtr TemplateArgsPtr(*this,
Member.TemplateId->getTemplateArgs(),
Member.TemplateId->getTemplateArgIsType(),
Member.TemplateId->NumArgs);
llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
translateTemplateArguments(TemplateArgsPtr,
Member.TemplateId->getTemplateArgLocations(),
TemplateArgs);
TemplateArgsPtr.release();
// Do we have the save the actual template name? We might need it...
return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind,
Member.TemplateId->TemplateNameLoc,
Name, true, Member.TemplateId->LAngleLoc,
TemplateArgs.data(), TemplateArgs.size(),
Member.TemplateId->RAngleLoc, DeclPtrTy(),
&SS);
}
// FIXME: We lose a lot of source information by mapping directly to the
// DeclarationName.
OwningExprResult Result
= BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind,
Member.getSourceRange().getBegin(),
GetNameFromUnqualifiedId(Member),
ObjCImpDecl, &SS);
if (Result.isInvalid() || HasTrailingLParen ||
Member.getKind() != UnqualifiedId::IK_DestructorName)
return move(Result);
// The only way a reference to a destructor can be used is to
// immediately call them. Since the next token is not a '(', produce a
// diagnostic and build the call now.
Expr *E = (Expr *)Result.get();
SourceLocation ExpectedLParenLoc
= PP.getLocForEndOfToken(Member.getSourceRange().getEnd());
Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
<< isa<CXXPseudoDestructorExpr>(E)
<< CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
return ActOnCallExpr(0, move(Result), ExpectedLParenLoc,
MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc);
}
Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,

View File

@ -2114,110 +2114,6 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
return move(Base);
}
Sema::OwningExprResult
Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation ClassNameLoc,
IdentifierInfo *ClassName,
const CXXScopeSpec &SS,
bool HasTrailingLParen) {
if (SS.isInvalid())
return ExprError();
QualType BaseType;
if (isUnknownSpecialization(SS))
BaseType = Context.getTypenameType((NestedNameSpecifier *)SS.getScopeRep(),
ClassName);
else {
TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, &SS);
// FIXME: If Base is dependent, we might not be able to resolve it here.
if (!BaseTy) {
Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
<< ClassName;
return ExprError();
}
BaseType = GetTypeFromParser(BaseTy);
}
return ActOnDestructorReferenceExpr(S, move(Base), OpLoc, OpKind,
SourceRange(ClassNameLoc),
BaseType.getAsOpaquePtr(),
SS, HasTrailingLParen);
}
Sema::OwningExprResult
Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceRange TypeRange,
TypeTy *T,
const CXXScopeSpec &SS,
bool HasTrailingLParen) {
QualType Type = GetTypeFromParser(T);
CanQualType CanType = Context.getCanonicalType(Type);
DeclarationName DtorName =
Context.DeclarationNames.getCXXDestructorName(CanType);
OwningExprResult Result
= BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind,
TypeRange.getBegin(), DtorName, DeclPtrTy(),
&SS);
if (Result.isInvalid() || HasTrailingLParen)
return move(Result);
// The only way a reference to a destructor can be used is to
// immediately call them. Since the next token is not a '(', produce a
// diagnostic and build the call now.
Expr *E = (Expr *)Result.get();
SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(TypeRange.getEnd());
Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
<< isa<CXXPseudoDestructorExpr>(E)
<< CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
return ActOnCallExpr(0, move(Result), ExpectedLParenLoc,
MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc);
}
Sema::OwningExprResult
Sema::ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation ClassNameLoc,
OverloadedOperatorKind OverOpKind,
const CXXScopeSpec *SS) {
if (SS && SS->isInvalid())
return ExprError();
DeclarationName Name =
Context.DeclarationNames.getCXXOperatorName(OverOpKind);
return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
Name, DeclPtrTy(), SS);
}
Sema::OwningExprResult
Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
SourceLocation ClassNameLoc,
TypeTy *Ty,
const CXXScopeSpec *SS) {
if (SS && SS->isInvalid())
return ExprError();
//FIXME: Preserve type source info.
QualType ConvType = GetTypeFromParser(Ty);
CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType);
DeclarationName ConvName =
Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc,
ConvName, DeclPtrTy(), SS);
}
CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
CXXMethodDecl *Method) {
MemberExpr *ME =

View File

@ -1336,41 +1336,6 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(const CXXScopeSpec &SS,
RAngleLoc);
}
Sema::OwningExprResult
Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
const CXXScopeSpec &SS,
TemplateTy TemplateD,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc) {
TemplateName Template = TemplateD.getAsVal<TemplateName>();
// FIXME: We're going to end up looking up the template based on its name,
// twice!
DeclarationName Name;
if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl())
Name = ActualTemplate->getDeclName();
else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl())
Name = Ovl->getDeclName();
else
Name = Template.getAsDependentTemplateName()->getName();
// Translate the parser's template argument list in our AST format.
llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs;
translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
TemplateArgsIn.release();
// Do we have the save the actual template name? We might need it...
return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, TemplateNameLoc,
Name, true, LAngleLoc,
TemplateArgs.data(), TemplateArgs.size(),
RAngleLoc, DeclPtrTy(), &SS);
}
/// \brief Form a dependent template name.
///
/// This action forms a dependent template name given the template

View File

@ -1034,9 +1034,9 @@ public:
SourceLocation OpLoc,
SourceLocation AccessorLoc,
IdentifierInfo &Accessor) {
return getSema().ActOnMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc,
return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc,
tok::period, AccessorLoc,
Accessor,
DeclarationName(&Accessor),
/*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
}
@ -1568,7 +1568,7 @@ public:
SS.setScopeRep(Qualifier);
// FIXME: We're going to end up looking up the template based on its name,
// twice! Also, duplicates part of Sema::ActOnMemberTemplateIdReferenceExpr.
// twice! Also, duplicates part of Sema::BuildMemberAccessExpr.
DeclarationName Name;
if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl())
Name = ActualTemplate->getDeclName();

View File

@ -5,8 +5,8 @@ class X {};
void test() {
X x;
x.int; // expected-error{{expected identifier}}
x.~int(); // expected-error{{expected identifier}}
x.int; // expected-error{{expected unqualified-id}}
x.~int(); // expected-error{{expected the class name}}
x.operator; // expected-error{{missing type specifier after 'operator'}}
x.operator typedef; // expected-error{{missing type specifier after 'operator'}}
}
@ -14,8 +14,8 @@ void test() {
void test2() {
X *x;
x->int; // expected-error{{expected identifier}}
x->~int(); // expected-error{{expected identifier}}
x->int; // expected-error{{expected unqualified-id}}
x->~int(); // expected-error{{expected the class name}}
x->operator; // expected-error{{missing type specifier after 'operator'}}
x->operator typedef; // expected-error{{missing type specifier after 'operator'}}
}