From 2d1c21414199a7452f122598189363a3922605b1 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 3 Nov 2009 19:44:04 +0000 Subject: [PATCH] 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). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85930 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticParseKinds.td | 5 +- include/clang/Basic/DiagnosticSemaKinds.td | 2 - include/clang/Parse/Action.h | 159 +++++--------------- include/clang/Parse/Parser.h | 2 + lib/Parse/ParseDecl.cpp | 3 +- lib/Parse/ParseExpr.cpp | 16 ++ lib/Parse/ParseExprCXX.cpp | 126 ++++++---------- lib/Sema/Sema.h | 61 +------- lib/Sema/SemaExpr.cpp | 73 ++++++++- lib/Sema/SemaExprCXX.cpp | 104 ------------- lib/Sema/SemaTemplate.cpp | 35 ----- lib/Sema/TreeTransform.h | 6 +- test/SemaCXX/invalid-member-expr.cpp | 8 +- 13 files changed, 183 insertions(+), 417 deletions(-) diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 7329dde195..e27a5df143 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -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">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 3b39fa964f..a43cf5dc34 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 2ca9e8e30d..d362259995 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -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 - /// \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() - /// \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/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 3849f9d0d5..3c0bfccd0d 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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); //===--------------------------------------------------------------------===// diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 6e3a348430..be0df33067 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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()); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 12025c66eb..b2cd3a777c 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -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 '++' diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index b1250350f7..265d13a7e4 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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(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; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 18dcd851ce..bcbbeb2f80 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 63d39a05e4..f71fb643f9 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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 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(E) + << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); + + return ActOnCallExpr(0, move(Result), ExpectedLParenLoc, + MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc); } Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 10fff0e241..ed6b67787a 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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(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 = diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 7182992d42..efaab20c4e 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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(); - - // 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 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 diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 2ef405c9e3..d3f46694f3 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -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(); diff --git a/test/SemaCXX/invalid-member-expr.cpp b/test/SemaCXX/invalid-member-expr.cpp index 90932ed65e..730beb3269 100644 --- a/test/SemaCXX/invalid-member-expr.cpp +++ b/test/SemaCXX/invalid-member-expr.cpp @@ -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'}} } -- 2.40.0