diff options
-rw-r--r-- | include/clang/AST/ExprCXX.h | 22 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 2 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 30 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 71 | ||||
-rw-r--r-- | test/SemaCXX/qual-id-test.cpp | 23 |
6 files changed, 100 insertions, 49 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 6e9df9128f..a308889af0 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1300,23 +1300,31 @@ class CXXUnresolvedMemberExpr : public Expr { /// \brief The location of the '->' or '.' operator. SourceLocation OperatorLoc; + /// \brief The nested-name-specifier that precedes the member name, if any. + NestedNameSpecifier *Qualifier; + + /// \brief The source range covering the nested name specifier. + SourceRange QualifierRange; + /// \brief The member to which this member expression refers, which /// can be name, overloaded operator, or destructor. - /// FIXME: could also be a template-id, and we might have a - /// nested-name-specifier as well. + /// FIXME: could also be a template-id DeclarationName Member; /// \brief The location of the member name. SourceLocation MemberLoc; - + public: CXXUnresolvedMemberExpr(ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, DeclarationName Member, SourceLocation MemberLoc) : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true), Base(Base), IsArrow(IsArrow), OperatorLoc(OperatorLoc), + Qualifier(Qualifier), QualifierRange(QualifierRange), Member(Member), MemberLoc(MemberLoc) { } /// \brief Retrieve the base object of this member expressions, @@ -1333,6 +1341,14 @@ public: SourceLocation getOperatorLoc() const { return OperatorLoc; } void setOperatorLoc(SourceLocation L) { OperatorLoc = L; } + /// \brief Retrieve the nested-name-specifier that qualifies the member + /// name. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + /// \brief Retrieve the source range covering the nested-name-specifier + /// that qualifies the member name. + SourceRange getQualifierRange() const { return QualifierRange; } + /// \brief Retrieve the name of the member that this expression /// refers to. DeclarationName getMember() const { return Member; } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index f10a5e0473..cde4cdc416 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1138,6 +1138,8 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr( void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); OS << Node->getMember().getAsString(); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 2545d34818..19d313b420 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -550,6 +550,7 @@ StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) { void StmtProfiler::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *S) { VisitExpr(S); ID.AddBoolean(S->isArrow()); + VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getMember()); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index c01097e363..394bc97927 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2025,7 +2025,9 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, if (BaseType->isDependentType()) return Owned(new (Context) CXXUnresolvedMemberExpr(Context, BaseExpr, true, - OpLoc, + OpLoc, + (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), + SS? SS->getRange() : SourceRange(), MemberName, MemberLoc)); else if (const PointerType *PT = BaseType->getAs<PointerType>()) @@ -2053,6 +2055,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return Owned(new (Context) CXXUnresolvedMemberExpr(Context, BaseExpr, false, OpLoc, + (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), + SS? SS->getRange() : SourceRange(), MemberName, MemberLoc)); } @@ -2082,29 +2086,29 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, LookupResult Result = LookupQualifiedName(DC, MemberName, LookupMemberName, false); + if (!Result) + return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member_deprecated) + << MemberName << BaseExpr->getSourceRange()); + if (Result.isAmbiguous()) { + DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc, + BaseExpr->getSourceRange()); + return ExprError(); + } + if (SS && SS->isSet()) { QualType BaseTypeCanon = Context.getCanonicalType(BaseType).getUnqualifiedType(); QualType MemberTypeCanon = Context.getCanonicalType( - Context.getTypeDeclType( - dyn_cast<TypeDecl>(Result.getAsDecl()->getDeclContext()))); - + Context.getTypeDeclType( + dyn_cast<TypeDecl>(Result.getAsDecl()->getDeclContext()))); + if (BaseTypeCanon != MemberTypeCanon && !IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) return ExprError(Diag(SS->getBeginLoc(), diag::err_not_direct_base_or_virtual) << MemberTypeCanon << BaseTypeCanon); } - - if (!Result) - return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member_deprecated) - << MemberName << BaseExpr->getSourceRange()); - if (Result.isAmbiguous()) { - DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc, - BaseExpr->getSourceRange()); - return ExprError(); - } NamedDecl *MemberDecl = Result; diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 8fe28a46bf..20259a7f79 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -242,7 +242,8 @@ public: /// nested-name-specifier. Subclasses may override this function to provide /// alternate behavior. NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS, - SourceRange Range); + SourceRange Range, + QualType ObjectType = QualType()); /// \brief Transform the given template name. /// @@ -497,7 +498,8 @@ public: /// different behavior. NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, SourceRange Range, - IdentifierInfo &II); + IdentifierInfo &II, + QualType ObjectType); /// \brief Build a new nested-name-specifier given the prefix and the /// namespace named in the next step in the nested-name-specifier. @@ -1449,23 +1451,23 @@ public: OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE, bool IsArrow, SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, DeclarationName Name, SourceLocation MemberLoc) { OwningExprResult Base = move(BaseE); tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period; + CXXScopeSpec SS; - Sema::TypeTy *ObjectType = 0; - - Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), OperatorLoc, - OpKind, ObjectType); - if (Base.isInvalid()) - return SemaRef.ExprError(); - + SS.setRange(QualifierRange); + SS.setScopeRep(Qualifier); + Base = SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OperatorLoc, OpKind, MemberLoc, Name, - /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0)); + /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0), + &SS); return move(Base); } @@ -1588,27 +1590,35 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E, template<typename Derived> NestedNameSpecifier * TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, - SourceRange Range) { + SourceRange Range, + QualType ObjectType) { if (!NNS) return 0; // Transform the prefix of this nested name specifier. NestedNameSpecifier *Prefix = NNS->getPrefix(); if (Prefix) { - Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range); + Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range, + ObjectType); if (!Prefix) return 0; + + // Clear out the object type; it only applies to the first element in + // the nested-name-specifier. + ObjectType = QualType(); } switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: - assert(Prefix && - "Can't have an identifier nested-name-specifier with no prefix"); - if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix()) + assert((Prefix || !ObjectType.isNull()) && + "Identifier nested-name-specifier with no prefix or object type"); + if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix() && + ObjectType.isNull()) return NNS; return getDerived().RebuildNestedNameSpecifier(Prefix, Range, - *NNS->getAsIdentifier()); + *NNS->getAsIdentifier(), + ObjectType); case NestedNameSpecifier::Namespace: { NamespaceDecl *NS @@ -4037,18 +4047,38 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( if (Base.isInvalid()) return SemaRef.ExprError(); + Sema::TypeTy *ObjectType = 0; + Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), + E->getOperatorLoc(), + E->isArrow()? tok::arrow : tok::period, + ObjectType); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + NestedNameSpecifier *Qualifier = 0; + if (E->getQualifier()) { + Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange(), + QualType::getFromOpaquePtr(ObjectType)); + if (!Qualifier) + return SemaRef.ExprError(); + } + // FIXME: Transform the declaration name DeclarationName Name = E->getMember(); if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && + Qualifier == E->getQualifier() && Name == E->getMember()) return SemaRef.Owned(E->Retain()); - + return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base), E->isArrow(), E->getOperatorLoc(), - E->getMember(), + Qualifier, + E->getQualifierRange(), + Name, E->getMemberLoc()); } @@ -4404,7 +4434,8 @@ template<typename Derived> NestedNameSpecifier * TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, SourceRange Range, - IdentifierInfo &II) { + IdentifierInfo &II, + QualType ObjectType) { CXXScopeSpec SS; // FIXME: The source location information is all wrong. SS.setRange(Range); @@ -4412,7 +4443,7 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, return static_cast<NestedNameSpecifier *>( SemaRef.ActOnCXXNestedNameSpecifier(0, SS, Range.getEnd(), Range.getEnd(), II, - /*FIXME:ObjectType=*/0, + ObjectType.getAsOpaquePtr(), false)); } diff --git a/test/SemaCXX/qual-id-test.cpp b/test/SemaCXX/qual-id-test.cpp index 10f1a47a9d..9032d0e956 100644 --- a/test/SemaCXX/qual-id-test.cpp +++ b/test/SemaCXX/qual-id-test.cpp @@ -103,25 +103,22 @@ namespace C a.x(); a->foo(); -#if 0 - // FIXME: We need the notion of identifiers as dependent - // nested-name-specifiers without a prefix for this code to work. - - // Things that work for the wrong reason a.A::sub::x(); a.A::B::base::x(); a->A::member::foo(); - // Things that work, but shouldn't - a.bad::x(); - - // Things that fail, but shouldn't - a.sub::x(); // xpected-error{{use of undeclared identifier 'sub'}} - a.base::x(); // xpected-error{{use of undeclared identifier 'base'}} + a.bad::x(); // xpected-error{{direct or virtual}} + a.sub::x(); + a.base::x(); a.B::base::x(); // xpected-error{{use of undeclared identifier 'B'}} - a->member::foo(); // xpected-error{{use of undeclared identifier 'member'}} -#endif + a->member::foo(); } + + void test_fun5() { + // FIXME: Enable the following once we get the nested-name-specifier lookup + // right during template instantiation. + // fun5<A::sub>(); // xpected-note 2{{instantiation}} + } } // PR4703 |