diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index f3364352aa4c..0c70441083da 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -1321,6 +1321,53 @@ public: 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() + /// \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(). + /// + /// \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) { diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index d00d6d2e33d9..36b6dd4a930e 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -941,7 +941,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { ObjCImpDecl, &SS); ConsumeToken(); } else if (getLang().CPlusPlus && Tok.is(tok::tilde)) { - // We have a C++ pseudo-destructor. + // We have a C++ pseudo-destructor or a destructor call, e.g., t.~T() // Consume the tilde. ConsumeToken(); @@ -961,6 +961,8 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { &SS); ConsumeToken(); } else if (getLang().CPlusPlus && Tok.is(tok::kw_operator)) { + // We have a reference to a member operator, e.g., t.operator int or + // t.operator+. if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) { if (!LHS.isInvalid()) LHS = Actions.ActOnOverloadedOperatorReferenceExpr(CurScope, @@ -983,6 +985,27 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { // Don't emit a diagnostic; ParseConversionFunctionId does it for us return ExprError(); } + } else if (getLang().CPlusPlus && Tok.is(tok::annot_template_id)) { + // We have a reference to a member template along with explicitly- + // specified template arguments, e.g., t.f. + TemplateIdAnnotation *TemplateId + = static_cast(Tok.getAnnotationValue()); + if (!LHS.isInvalid()) { + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->getTemplateArgIsType(), + TemplateId->NumArgs); + + LHS = Actions.ActOnMemberTemplateIdReferenceExpr(CurScope, move(LHS), + OpLoc, OpKind, SS, + TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->getTemplateArgLocations(), + TemplateId->RAngleLoc); + } + ConsumeToken(); } else { if (getLang().CPlusPlus) Actions.ActOnCXXExitMemberScope(CurScope, MemberSS); diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 2a2515ff1142..ce56eb46379f 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1598,6 +1598,7 @@ public: DeclarationName MemberName, DeclPtrTy ImplDecl, const CXXScopeSpec *SS = 0); + virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, @@ -1972,6 +1973,19 @@ public: 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. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index f304ac30945c..026ff43d2d24 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2005,7 +2005,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, ImpCastExprToType(BaseExpr, BaseType); } } else if (BaseType->isObjCClassType() && - BaseType != Context.ObjCClassRedefinitionType) { + BaseType != Context.ObjCClassRedefinitionType) { BaseType = Context.ObjCClassRedefinitionType; ImpCastExprToType(BaseExpr, BaseType); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 35938260c656..dc58ecc16c7d 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1831,6 +1831,21 @@ Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base, ConvName, DeclPtrTy(), SS); } +Sema::OwningExprResult +Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc) { + // FIXME: Implement! + return ExprError(); +} + Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { Expr *FullExpr = Arg.takeAs(); if (FullExpr) diff --git a/clang/test/SemaTemplate/member-function-template.cpp b/clang/test/SemaTemplate/member-function-template.cpp index 91eb53beffc1..087f3952aba3 100644 --- a/clang/test/SemaTemplate/member-function-template.cpp +++ b/clang/test/SemaTemplate/member-function-template.cpp @@ -40,5 +40,11 @@ void test_X_f1_address() { int& (X::*pm3)(float, int) = &X::f1; } +void test_X_f0_explicit(X x, int i, long l) { + int &ir1 = x.f0(i); + int &ir2 = x.f0<>(i); + int &ir3 = x.f0(i); +} + // PR4608 class A { template x a(x z) { return z+y; } int y; };