diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-09-02 22:59:36 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-09-02 22:59:36 +0000 |
commit | 2dd078ae50ff7be1fb25ebeedde45e9ab691a4f0 (patch) | |
tree | 0e30fbe6d5c2cbab6ad0dc64accd298ad7822f9f | |
parent | 6c35415912d1e43c21fcaa2823934ae993f2718b (diff) |
Rewrite of our handling of name lookup in C++ member access expressions, e.g.,
x->Base::f
We no longer try to "enter" the context of the type that "x" points
to. Instead, we drag that object type through the parser and pass it
into the Sema routines that need to know how to perform lookup within
member access expressions.
We now implement most of the crazy name lookup rules in C++
[basic.lookup.classref] for non-templated code, including performing
lookup both in the context of the type referred to by the member
access and in the scope of the member access itself and then detecting
ambiguities when the two lookups collide (p1 and p4; p3 and p7 are
still TODO). This change also corrects our handling of name lookup
within template arguments of template-ids inside the
nested-name-specifier (p6; we used to look into the scope of the
object expression for them) and fixes PR4703.
I have disabled some tests that involve member access expressions
where the object expression has dependent type, because we don't yet
have the ability to describe dependent nested-name-specifiers starting
with an identifier.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80843 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 130 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 8 | ||||
-rw-r--r-- | lib/Parse/MinimalAction.cpp | 5 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 9 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 13 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 17 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 52 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 33 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 238 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 42 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 41 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 326 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 13 | ||||
-rw-r--r-- | test/SemaCXX/nested-name-spec.cpp | 2 | ||||
-rw-r--r-- | test/SemaCXX/qual-id-test.cpp | 41 | ||||
-rw-r--r-- | test/SemaTemplate/member-function-template.cpp | 1 |
18 files changed, 644 insertions, 346 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e29e6ab4c7..a5d318eb25 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -366,6 +366,12 @@ def note_previous_access_declaration : Note< // C++ name lookup def err_incomplete_nested_name_spec : Error< "incomplete type %0 named in nested name specifier">; +def err_nested_name_member_ref_lookup_ambiguous : Error< + "lookup of %0 in member access expression is ambiguous">; +def note_ambig_member_ref_object_type : Note< + "lookup in the object type %0 refers here">; +def note_ambig_member_ref_scope : Note< + "lookup from the current scope refers here">; // C++ class members def err_storageclass_invalid_for_member : Error< diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 0c70441083..31acc87cb4 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -209,10 +209,12 @@ public: /// \brief Determine whether the given identifier refers to the name of a /// template. /// + /// \param S the scope in which name lookup occurs + /// /// \param II the identifier that we are querying to determine whether it /// is a template. /// - /// \param S the scope in which name lookup occurs + /// \param IdLoc the source location of the identifier /// /// \param SS the C++ scope specifier that precedes the template name, if /// any. @@ -224,8 +226,11 @@ public: /// of the template that the name refers to. /// /// \returns the kind of template that this name refers to. - virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S, + virtual TemplateNameKind isTemplateName(Scope *S, + const IdentifierInfo &II, + SourceLocation IdLoc, const CXXScopeSpec *SS, + TypeTy *ObjectType, bool EnteringContext, TemplateTy &Template) = 0; @@ -236,17 +241,39 @@ public: return 0; } - /// ActOnCXXNestedNameSpecifier - Called during parsing of a - /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now - /// we want to resolve "bar::". 'SS' is empty or the previously parsed - /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar', - /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'. - /// Returns a CXXScopeTy* object representing the C++ scope. + /// \brief Parsed an identifier followed by '::' in a C++ + /// nested-name-specifier. + /// + /// \param S the scope in which the nested-name-specifier was parsed. + /// + /// \param SS the nested-name-specifier that precedes the identifier. For + /// example, if we are parsing "foo::bar::", \p SS will describe the "foo::" + /// that has already been parsed. + /// + /// \param IdLoc the location of the identifier we have just parsed (e.g., + /// the "bar" in "foo::bar::". + /// + /// \param CCLoc the location of the '::' at the end of the + /// nested-name-specifier. + /// + /// \param II the identifier that represents the scope that this + /// nested-name-specifier refers to, e.g., the "bar" in "foo::bar::". + /// + /// \param ObjectType if this nested-name-specifier occurs as part of a + /// C++ member access expression such as "x->Base::f", the type of the base + /// object (e.g., *x in the example, if "x" were a pointer). + /// + /// \param EnteringContext if true, then we intend to immediately enter the + /// context of this nested-name-specifier, e.g., for an out-of-line + /// definition of a class member. + /// + /// \returns a CXXScopeTy* object representing the C++ scope. virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, + TypeTy *ObjectType, bool EnteringContext) { return 0; } @@ -267,27 +294,6 @@ public: return 0; } - /// ActOnCXXEnterMemberScope - Called when a C++ class member accessor ('.' - /// or '->') is parsed. After this method is called, according to - /// [C++ 3.4.5p4], qualified-ids should be looked up in the contexts of both - /// the entire postfix-expression and the scope of the class of the object - /// expression. - /// 'SS' should be an empty CXXScopeSpec to be filled with the class's scope. - virtual OwningExprResult ActOnCXXEnterMemberScope(Scope *S, - CXXScopeSpec &SS, - ExprArg Base, - tok::TokenKind OpKind) { - return ExprEmpty(); - } - - /// ActOnCXXExitMemberScope - Called when a postfix-expression that previously - /// invoked ActOnCXXEnterMemberScope() is finished. 'SS' is the same - /// CXXScopeSpec that was passed to ActOnCXXEnterMemberScope. Used to - /// indicate that names should revert to being looked up in the defining - /// scope. - virtual void ActOnCXXExitMemberScope(Scope *S, const CXXScopeSpec &SS) { - } - /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be @@ -1280,6 +1286,31 @@ public: return ExprEmpty(); } + /// \brief Invoked when the parser is starting to parse a C++ member access + /// expression such as x.f or x->f. + /// + /// \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 ObjectType originally NULL. The action should fill in this type + /// with the type into which name lookup should look to find the member in + /// the member access expression. + /// + /// \returns the (possibly modified) \p Base expression + virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S, + ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + TypeTy *&ObjectType) { + return ExprEmpty(); + } + /// ActOnDestructorReferenceExpr - Parsed a destructor reference, for example: /// /// t->~T(); @@ -1597,10 +1628,26 @@ public: /// example, given "MetaFun::template apply", the scope specifier \p /// SS will be "MetaFun::", \p TemplateKWLoc contains the location /// of the "template" keyword, and "apply" is the \p Name. + /// + /// \param TemplateKWLoc the location of the "template" keyword (if any). + /// + /// \param Name the name of the template (an identifier) + /// + /// \param NameLoc the location of the identifier + /// + /// \param SS the nested-name-specifier that precedes the "template" keyword + /// or the template name. FIXME: If the dependent template name occurs in + /// a member access expression, e.g., "x.template f<T>", this + /// nested-name-specifier will be empty. + /// + /// \param ObjectType if this dependent template name occurs in the + /// context of a member access expression, the type of the object being + /// accessed. virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, - const CXXScopeSpec &SS) { + const CXXScopeSpec &SS, + TypeTy *ObjectType) { return TemplateTy(); } @@ -2128,26 +2175,11 @@ public: virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S, const CXXScopeSpec *SS); - /// \brief Determine whether the given identifier refers to the name of a - /// template. - /// - /// \param II the identifier that we are querying to determine whether it - /// is a template. - /// - /// \param S the scope in which name lookup occurs - /// - /// \param SS the C++ scope specifier that precedes the template name, if - /// any. - /// - /// \param EnteringContext whether we are potentially entering the context - /// referred to by the scope specifier \p SS - /// - /// \param Template if the name does refer to a template, the declaration - /// of the template that the name refers to. - /// - /// \returns the kind of template that this name refers to. - virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S, + virtual TemplateNameKind isTemplateName(Scope *S, + const IdentifierInfo &II, + SourceLocation IdLoc, const CXXScopeSpec *SS, + TypeTy *ObjectType, bool EnteringContext, TemplateTy &Template); diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index e366c2f256..641b09947b 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -770,13 +770,9 @@ private: // C++ Expressions OwningExprResult ParseCXXIdExpression(bool isAddressOfOperand = false); - /// ParseOptionalCXXScopeSpecifier - Parse global scope or - /// nested-name-specifier if present. Returns true if a nested-name-specifier - /// was parsed from the token stream. Note that this routine will not parse - /// ::new or ::delete, it will just leave them in the token stream. - /// bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, - bool EnteringContext = false); + TypeTy *ObjectType, + bool EnteringContext); //===--------------------------------------------------------------------===// // C++ 5.2p1: C++ Casts diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index ee23c0038a..d89cc8c3ea 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -160,8 +160,11 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *, } TemplateNameKind -MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S, +MinimalAction::isTemplateName(Scope *S, + const IdentifierInfo &II, + SourceLocation IdLoc, const CXXScopeSpec *SS, + TypeTy *ObjectType, bool EnteringScope, TemplateTy &TemplateDecl) { return TNK_Non_template; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 25bed0937b..25ff53ca9f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -743,7 +743,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ->Kind == TNK_Type_template) { // We have a qualified template-id, e.g., N::A<int> CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, true); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); assert(Tok.is(tok::annot_template_id) && "ParseOptionalCXXScopeSpecifier not working"); AnnotateTemplateIdTokenAsType(&SS); @@ -1596,7 +1596,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, Attr = ParseAttributes(); CXXScopeSpec SS; - if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) { + if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); if (Tok.isNot(tok::l_brace)) { @@ -2034,7 +2034,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope))) { CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, true)) { + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) { if(Tok.isNot(tok::star)) { // The scope spec really belongs to the direct-declarator. D.getCXXScopeSpec() = SS; @@ -2191,7 +2191,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (D.mayHaveIdentifier()) { // ParseDeclaratorInternal might already have parsed the scope. bool afterCXXScope = D.getCXXScopeSpec().isSet() || - ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), true); + ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, + true); if (afterCXXScope) { // Change the declaration context for name lookup, until this function // is exited (and the declarator has been parsed). diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 31926ce0f5..f50147c599 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -117,7 +117,7 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, CXXScopeSpec SS; // Parse (optional) nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); if (SS.isInvalid() || Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_namespace_name); @@ -216,7 +216,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, CXXScopeSpec SS; // Parse (optional) nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); AttributeList *AttrList = 0; IdentifierInfo *NamespcName = 0; @@ -273,7 +273,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, IsTypeName = false; // Parse nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); AttributeList *AttrList = 0; @@ -538,7 +538,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Parse the (optional) nested-name-specifier. CXXScopeSpec SS; - if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, true)) + if (getLang().CPlusPlus && + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) Diag(Tok, diag::err_expected_ident); @@ -813,7 +814,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { // Parse optional '::' and optional nested-name-specifier. CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, true); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); // The location of the base class itself. SourceLocation BaseLoc = Tok.getLocation(); @@ -1299,7 +1300,7 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) { Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) { // parse '::'[opt] nested-name-specifier[opt] CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); TypeTy *TemplateTypeTy = 0; if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 36b6dd4a93..8fca14ff98 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -923,14 +923,14 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { tok::TokenKind OpKind = Tok.getKind(); SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token. - CXXScopeSpec MemberSS; CXXScopeSpec SS; + Action::TypeTy *ObjectType = 0; if (getLang().CPlusPlus && !LHS.isInvalid()) { - LHS = Actions.ActOnCXXEnterMemberScope(CurScope, MemberSS, move(LHS), - OpKind); + LHS = Actions.ActOnStartCXXMemberReference(CurScope, move(LHS), + OpLoc, OpKind, ObjectType); if (LHS.isInvalid()) break; - ParseOptionalCXXScopeSpecifier(SS); + ParseOptionalCXXScopeSpecifier(SS, ObjectType, false); } if (Tok.is(tok::identifier)) { @@ -947,8 +947,6 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { ConsumeToken(); if (!Tok.is(tok::identifier)) { - if (getLang().CPlusPlus) - Actions.ActOnCXXExitMemberScope(CurScope, MemberSS); Diag(Tok, diag::err_expected_ident); return ExprError(); } @@ -980,8 +978,6 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { Tok.getLocation(), ConvType, &SS); } else { - if (getLang().CPlusPlus) - Actions.ActOnCXXExitMemberScope(CurScope, MemberSS); // Don't emit a diagnostic; ParseConversionFunctionId does it for us return ExprError(); } @@ -1007,14 +1003,9 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { } ConsumeToken(); } else { - if (getLang().CPlusPlus) - Actions.ActOnCXXExitMemberScope(CurScope, MemberSS); Diag(Tok, diag::err_expected_ident); return ExprError(); } - - if (getLang().CPlusPlus) - Actions.ActOnCXXExitMemberScope(CurScope, MemberSS); break; } case tok::plusplus: // postfix-expression: postfix-expression '++' diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index e9cca9fe1d..4cd952e393 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -16,10 +16,11 @@ #include "clang/Parse/DeclSpec.h" using namespace clang; -/// ParseOptionalCXXScopeSpecifier - Parse global scope or -/// nested-name-specifier if present. Returns true if a nested-name-specifier -/// was parsed from the token stream. Note that this routine will not parse -/// ::new or ::delete, it will just leave them in the token stream. +/// \brief Parse global scope or nested-name-specifier if present. +/// +/// Parses a C++ global scope specifier ('::') or nested-name-specifier (which +/// may be preceded by '::'). Note that this routine will not parse ::new or +/// ::delete; it will just leave them in the token stream. /// /// '::'[opt] nested-name-specifier /// '::' @@ -28,9 +29,22 @@ using namespace clang; /// type-name '::' /// namespace-name '::' /// nested-name-specifier identifier '::' -/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO] +/// nested-name-specifier 'template'[opt] simple-template-id '::' +/// +/// +/// \param SS the scope specifier that will be set to the parsed +/// nested-name-specifier (or empty) +/// +/// \param ObjectType if this nested-name-specifier is being parsed following +/// the "." or "->" of a member access expression, this parameter provides the +/// type of the object whose members are being accessed. /// +/// \param EnteringContext whether we will be entering into the context of +/// the nested-name-specifier after parsing it. +/// +/// \returns true if a scope specifier was parsed. bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, + Action::TypeTy *ObjectType, bool EnteringContext) { assert(getLang().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -59,16 +73,28 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, } while (true) { + if (HasScopeSpecifier) { + // C++ [basic.lookup.classref]p5: + // If the qualified-id has the form + // ::class-name-or-namespace-name::... + // the class-name-or-namespace-name is looked up in global scope as a + // class-name or namespace-name. + // + // To implement this, we clear out the object type as soon as we've + // seen a leading '::' or part of a nested-name-specifier. + ObjectType = 0; + } + // nested-name-specifier: // nested-name-specifier 'template'[opt] simple-template-id '::' // Parse the optional 'template' keyword, then make sure we have // 'identifier <' after it. if (Tok.is(tok::kw_template)) { - // If we don't have a scope specifier, this isn't a + // If we don't have a scope specifier or an object type, this isn't a // nested-name-specifier, since they aren't allowed to start with // 'template'. - if (!HasScopeSpecifier) + if (!HasScopeSpecifier && !ObjectType) break; SourceLocation TemplateKWLoc = ConsumeToken(); @@ -91,7 +117,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, TemplateTy Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, *Tok.getIdentifierInfo(), - Tok.getLocation(), SS); + Tok.getLocation(), SS, + ObjectType); if (!Template) break; if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, @@ -173,7 +200,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, SS.setScopeRep( Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II, - EnteringContext)); + ObjectType, EnteringContext)); SS.setEndLoc(CCLoc); continue; } @@ -182,7 +209,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // type-name '<' if (Next.is(tok::less)) { TemplateTy Template; - if (TemplateNameKind TNK = Actions.isTemplateName(II, CurScope, &SS, + if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, II, + Tok.getLocation(), + &SS, + ObjectType, EnteringContext, Template)) { // We have found a template name, so annotate this this token @@ -267,7 +297,7 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // '::' unqualified-id // CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); // unqualified-id: // identifier diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 4d37ac7202..36d5db599d 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -884,7 +884,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { // simple-template-id SourceLocation TypenameLoc = ConsumeToken(); CXXScopeSpec SS; - bool HadNestedNameSpecifier = ParseOptionalCXXScopeSpecifier(SS, false); + bool HadNestedNameSpecifier + = ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); if (!HadNestedNameSpecifier) { Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); return false; @@ -928,7 +929,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { CXXScopeSpec SS; if (getLang().CPlusPlus) - ParseOptionalCXXScopeSpecifier(SS, EnteringContext); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext); if (Tok.is(tok::identifier)) { // Determine whether the identifier is a type name. @@ -959,8 +960,10 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { if (NextToken().is(tok::less)) { TemplateTy Template; if (TemplateNameKind TNK - = Actions.isTemplateName(*Tok.getIdentifierInfo(), - CurScope, &SS, EnteringContext, Template)) + = Actions.isTemplateName(CurScope, *Tok.getIdentifierInfo(), + Tok.getLocation(), &SS, + /*ObjectType=*/0, EnteringContext, + Template)) if (AnnotateTemplateIdToken(Template, TNK, &SS)) { // If an unrecoverable error occurred, we need to return true here, // because the token stream is in a damaged state. We may not return @@ -1022,7 +1025,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { "Cannot be a type or scope token!"); CXXScopeSpec SS; - if (!ParseOptionalCXXScopeSpecifier(SS, EnteringContext)) + if (!ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext)) return Tok.is(tok::annot_template_id); // Push the current token back into the token stream (or revert it if it is diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index e2205d6df5..6f462e593b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1983,6 +1983,12 @@ public: TypeTy *Ty, SourceLocation RParen); + virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S, + ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + TypeTy *&ObjectType); + virtual OwningExprResult ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, @@ -2029,6 +2035,7 @@ public: bool RequireCompleteDeclContext(const CXXScopeSpec &SS); + DeclContext *computeDeclContext(QualType T); DeclContext *computeDeclContext(const CXXScopeSpec &SS, bool EnteringContext = false); bool isDependentScopeSpecifier(const CXXScopeSpec &SS); @@ -2051,6 +2058,7 @@ public: SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, + TypeTy *ObjectType, bool EnteringContext); /// ActOnCXXNestedNameSpecifier - Called during parsing of a @@ -2067,23 +2075,6 @@ public: SourceRange TypeRange, SourceLocation CCLoc); - /// ActOnCXXEnterMemberScope - Called when a C++ class member accessor ('.' - /// or '->') is parsed. After this method is called, according to - /// [C++ 3.4.5p4], qualified-ids should be looked up in the contexts of both - /// the entire postfix-expression and the scope of the class of the object - /// expression. - /// 'SS' should be an empty CXXScopeSpec to be filled with the class's scope. - virtual OwningExprResult ActOnCXXEnterMemberScope(Scope *S, CXXScopeSpec &SS, - ExprArg Base, - tok::TokenKind OpKind); - - /// ActOnCXXExitMemberScope - Called when a postfix-expression that previously - /// invoked ActOnCXXEnterMemberScope() is finished. 'SS' is the same - /// CXXScopeSpec that was passed to ActOnCXXEnterMemberScope. Used to - /// indicate that names should revert to being looked up in the defining - /// scope. - virtual void ActOnCXXExitMemberScope(Scope *S, const CXXScopeSpec &SS); - /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be @@ -2311,8 +2302,11 @@ public: //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // - virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S, + virtual TemplateNameKind isTemplateName(Scope *S, + const IdentifierInfo &II, + SourceLocation IdLoc, const CXXScopeSpec *SS, + TypeTy *ObjectType, bool EnteringContext, TemplateTy &Template); bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); @@ -2400,7 +2394,8 @@ public: virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, - const CXXScopeSpec &SS); + const CXXScopeSpec &SS, + TypeTy *ObjectType); bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, ClassTemplateSpecializationDecl *PrevDecl, diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index d89a610cae..251ffea925 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -22,6 +22,20 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; +/// \brief Compute the DeclContext that is associated with the given type. +/// +/// \param T the type for which we are attempting to find a DeclContext. +/// +/// \returns the declaration context represented by the type T, +/// or NULL if the declaration context cannot be computed (e.g., because it is +/// dependent and not the current instantiation). +DeclContext *Sema::computeDeclContext(QualType T) { + if (const TagType *Tag = T->getAs<TagType>()) + return Tag->getDecl(); + + return 0; +} + /// \brief Compute the DeclContext that is associated with the given /// scope specifier. /// @@ -244,6 +258,36 @@ Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, return NestedNameSpecifier::GlobalSpecifier(Context); } +/// \brief Determines whether the given declaration is an valid acceptable +/// result for name lookup of a nested-name-specifier. +bool isAcceptableNestedNameSpecifier(ASTContext &Context, NamedDecl *SD) { + if (!SD) + return false; + + // Namespace and namespace aliases are fine. + if (isa<NamespaceDecl>(SD) || isa<NamespaceAliasDecl>(SD)) + return true; + + if (!isa<TypeDecl>(SD)) + return false; + + // Determine whether we have a class (or, in C++0x, an enum) or + // a typedef thereof. If so, build the nested-name-specifier. + QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); + if (T->isDependentType()) + return true; + else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { + if (TD->getUnderlyingType()->isRecordType() || + (Context.getLangOptions().CPlusPlus0x && + TD->getUnderlyingType()->isEnumeralType())) + return true; + } else if (isa<RecordDecl>(SD) || + (Context.getLangOptions().CPlusPlus0x && isa<EnumDecl>(SD))) + return true; + + return false |