diff options
Diffstat (limited to 'lib')
-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 |
12 files changed, 518 insertions, 284 deletions
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; +} + /// 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 @@ -255,58 +299,134 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, + TypeTy *ObjectTypePtr, bool EnteringContext) { NestedNameSpecifier *Prefix = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + + // Determine where to perform name lookup + DeclContext *LookupCtx = 0; + bool isDependent = false; + if (ObjectTypePtr) { + // This nested-name-specifier occurs in a member access expression, e.g., + // x->B::f, and we are looking into the type of the object. + assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); + QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); + LookupCtx = computeDeclContext(ObjectType); + isDependent = ObjectType->isDependentType(); + } else if (SS.isSet()) { + // This nested-name-specifier occurs after another nested-name-specifier, + // so long into the context associated with the prior nested-name-specifier. + LookupCtx = computeDeclContext(SS, EnteringContext); + isDependent = isDependentScopeSpecifier(SS); + } - NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName, - false, false, SourceLocation(), - EnteringContext); + LookupResult Found; + bool ObjectTypeSearchedInScope = false; + if (LookupCtx) { + // Perform "qualified" name lookup into the declaration context we + // computed, which is either the type of the base of a member access + // expression or the declaration context associated with a prior + // nested-name-specifier. + + // The declaration context must be complete. + if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) + return 0; - if (SD) { + Found = LookupQualifiedName(LookupCtx, &II, LookupNestedNameSpecifierName, + false); + + if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound && S) { + // C++ [basic.lookup.classref]p4: + // If the id-expression in a class member access is a qualified-id of + // the form + // + // class-name-or-namespace-name::... + // + // the class-name-or-namespace-name following the . or -> operator is + // looked up both in the context of the entire postfix-expression and in + // the scope of the class of the object expression. If the name is found + // only in the scope of the class of the object expression, the name + // shall refer to a class-name. If the name is found only in the + // context of the entire postfix-expression, the name shall refer to a + // class-name or namespace-name. [...] + // + // Qualified name lookup into a class will not find a namespace-name, + // so we do not need to diagnoste that case specifically. However, + // this qualified name lookup may find nothing. In that case, perform + // unqualified name lookup in the given scope. + + // FIXME: When we're instantiating a template, do we actually have to + // look in the scope of the template? Seems fishy... + Found = LookupName(S, &II, LookupNestedNameSpecifierName); + ObjectTypeSearchedInScope = true; + } + } else if (isDependent) { + // We were not able to compute the declaration context for a dependent + // base object type or prior nested-name-specifier, so this + // nested-name-specifier refers to an unknown specialization. Just build + // a dependent nested-name-specifier. + return NestedNameSpecifier::Create(Context, Prefix, &II); + } else { + // Perform unqualified name lookup in the current scope. + Found = LookupName(S, &II, LookupNestedNameSpecifierName); + } + + // FIXME: Deal with ambiguities cleanly. + NamedDecl *SD = Found; + if (isAcceptableNestedNameSpecifier(Context, SD)) { + if (ObjectTypePtr && !ObjectTypeSearchedInScope && S) { + // C++ [basic.lookup.classref]p4: + // [...] If the name is found in both contexts, the + // class-name-or-namespace-name shall refer to the same entity. + // + // We already found the name in the scope of the object. Now, look + // into the current scope (the scope of the postfix-expression) to + // see if we can find the same name there. + LookupResult FoundOuter + = LookupName(S, &II, LookupNestedNameSpecifierName); + + // FIXME: Handle ambiguities in FoundOuter! + NamedDecl *OuterDecl = FoundOuter; + if (isAcceptableNestedNameSpecifier(Context, OuterDecl) && + OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() && + (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) || + !Context.hasSameType( + Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)), + Context.getTypeDeclType(cast<TypeDecl>(SD))))) { + Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous) + << &II; + Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type) + << QualType::getFromOpaquePtr(ObjectTypePtr); + Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope); + + // Fall through so that we'll pick the name we found in the object type, + // since that's probably what the user wanted anyway. + } + } + if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) return NestedNameSpecifier::Create(Context, Prefix, Namespace); - if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) { - // 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(Type); - bool AcceptableType = false; - if (T->isDependentType()) - AcceptableType = true; - else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { - if (TD->getUnderlyingType()->isRecordType() || - (getLangOptions().CPlusPlus0x && - TD->getUnderlyingType()->isEnumeralType())) - AcceptableType = true; - } else if (isa<RecordDecl>(Type) || - (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type))) - AcceptableType = true; - - if (AcceptableType) - return NestedNameSpecifier::Create(Context, Prefix, false, - T.getTypePtr()); - } - // FIXME: It would be nice to maintain the namespace alias name, then // see through that alias when resolving the nested-name-specifier down to // a declaration context. if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) return NestedNameSpecifier::Create(Context, Prefix, - Alias->getNamespace()); - // Fall through to produce an error: we found something that isn't - // a class or a namespace. - } else if (SS.isSet() && isDependentScopeSpecifier(SS)) - return NestedNameSpecifier::Create(Context, Prefix, &II); + Alias->getNamespace()); + + QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); + return NestedNameSpecifier::Create(Context, Prefix, false, + T.getTypePtr()); + } // If we didn't find anything during our lookup, try again with // ordinary name lookup, which can help us produce better error // messages. if (!SD) - SD = LookupParsedName(S, &SS, &II, LookupOrdinaryName, - false, false, SourceLocation(), - EnteringContext); + SD = LookupName(S, &II, LookupOrdinaryName); + unsigned DiagID; if (SD) DiagID = diag::err_expected_class_or_namespace; @@ -338,58 +458,6 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, T.getTypePtr()); } -Action::OwningExprResult -Sema::ActOnCXXEnterMemberScope(Scope *S, CXXScopeSpec &SS, ExprArg Base, - tok::TokenKind OpKind) { - // Since this might be a postfix expression, get rid of ParenListExprs. - Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); - - Expr *BaseExpr = (Expr*)Base.get(); - assert(BaseExpr && "no record expansion"); - - QualType BaseType = BaseExpr->getType(); - // FIXME: handle dependent types - if (BaseType->isDependentType()) - return move(Base); - - // C++ [over.match.oper]p8: - // [...] When operator->returns, the operator-> is applied to the value - // returned, with the original second operand. - if (OpKind == tok::arrow) { - while (BaseType->isRecordType()) { - Base = BuildOverloadedArrowExpr(S, move(Base), BaseExpr->getExprLoc()); - BaseExpr = (Expr*)Base.get(); - if (BaseExpr == NULL) - return ExprError(); - BaseType = BaseExpr->getType(); - } - } - - if (BaseType->isPointerType()) - BaseType = BaseType->getPointeeType(); - - // We could end up with various non-record types here, such as extended - // vector types or Objective-C interfaces. Just return early and let - // ActOnMemberReferenceExpr do the work. - if (!BaseType->isRecordType()) - return move(Base); - - SS.setRange(BaseExpr->getSourceRange()); - SS.setScopeRep( - NestedNameSpecifier::Create(Context, 0, false, BaseType.getTypePtr()) - ); - - if (S) - ActOnCXXEnterDeclaratorScope(S,SS); - return move(Base); -} - -void Sema::ActOnCXXExitMemberScope(Scope *S, const CXXScopeSpec &SS) { - if (S && SS.isSet()) - ActOnCXXExitDeclaratorScope(S,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 diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 0dc4b8d180..87330ab0b6 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1754,6 +1754,48 @@ Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, return E; } +Sema::OwningExprResult +Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, + tok::TokenKind OpKind, TypeTy *&ObjectType) { + // Since this might be a postfix expression, get rid of ParenListExprs. + Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); + + Expr *BaseExpr = (Expr*)Base.get(); + assert(BaseExpr && "no record expansion"); + + QualType BaseType = BaseExpr->getType(); + if (BaseType->isDependentType()) { + // FIXME: member of the current instantiation + ObjectType = BaseType.getAsOpaquePtr(); + return move(Base); + } + + // C++ [over.match.oper]p8: + // [...] When operator->returns, the operator-> is applied to the value + // returned, with the original second operand. + if (OpKind == tok::arrow) { + while (BaseType->isRecordType()) { + Base = BuildOverloadedArrowExpr(S, move(Base), BaseExpr->getExprLoc()); + BaseExpr = (Expr*)Base.get(); + if (BaseExpr == NULL) + return ExprError(); + BaseType = BaseExpr->getType(); + } + } + + if (BaseType->isPointerType()) + BaseType = BaseType->getPointeeType(); + + // We could end up with various non-record types here, such as extended + // vector types or Objective-C interfaces. Just return early and let + // ActOnMemberReferenceExpr do the work. + if (!BaseType->isRecordType()) + return move(Base); + + ObjectType = BaseType.getAsOpaquePtr(); + return move(Base); +} + Sema::OwningExprResult Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 4a699de6c8..38abd1641d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1004,8 +1004,9 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name, LookupNameKind NameKind, bool RedeclarationOnly) { assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context"); - if (!Name) return LookupResult::CreateLookupResult(Context, 0); - + if (!Name) + return LookupResult::CreateLookupResult(Context, 0); + // If we're performing qualified name lookup (e.g., lookup into a // struct), find fields as part of ordinary name lookup. unsigned IDNS @@ -1013,16 +1014,25 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name, getLangOptions().CPlusPlus); if (NameKind == LookupOrdinaryName) IDNS |= Decl::IDNS_Member; - + + // Make sure that the declaration context is complete. + assert((!isa<TagDecl>(LookupCtx) || + LookupCtx->isDependentContext() || + cast<TagDecl>(LookupCtx)->isDefinition() || + Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>() + ->isBeingDefined()) && + "Declaration context must already be complete!"); + // Perform qualified name lookup into the LookupCtx. DeclContext::lookup_iterator I, E; for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I) if (isAcceptableLookupResult(*I, NameKind, IDNS)) retu |