diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/Sema.h | 25 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 50 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 39 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 32 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateExpr.cpp | 12 |
5 files changed, 126 insertions, 32 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 63ecdcb108..5093d71ac0 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -833,9 +833,8 @@ public: SourceLocation *CommaLocs, SourceLocation RParenLoc); - ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, - SourceLocation MemberLoc, - IdentifierInfo &Member); + OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc); /// Helpers for dealing with blocks and functions. void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body); @@ -1519,7 +1518,8 @@ public: tok::TokenKind OpKind, SourceLocation MemberLoc, IdentifierInfo &Member, - DeclPtrTy ImplDecl); + DeclPtrTy ImplDecl, + const CXXScopeSpec *SS = 0); virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, @@ -1882,6 +1882,23 @@ 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 diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 27e0ccf7d5..e1cba36c82 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -14,6 +14,7 @@ #include "Sema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/Parse/DeclSpec.h" #include "llvm/ADT/STLExtras.h" @@ -337,6 +338,55 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, T.getTypePtr()); } +Action::OwningExprResult +Sema::ActOnCXXEnterMemberScope(Scope *S, CXXScopeSpec &SS, ExprArg Base, + tok::TokenKind OpKind) { + 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/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ffc6d13bb4..76296c690c 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2103,7 +2103,11 @@ Action::OwningExprResult Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation MemberLoc, IdentifierInfo &Member, - DeclPtrTy ObjCImpDecl) { + DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) { + // FIXME: handle the CXXScopeSpec for proper lookup of qualified-ids + if (SS && SS->isInvalid()) + return ExprError(); + Expr *BaseExpr = Base.takeAs<Expr>(); assert(BaseExpr && "no record expression"); @@ -2126,9 +2130,6 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, BaseType = PT->getPointeeType(); else if (BaseType->isObjCObjectPointerType()) ; - else if (getLangOptions().CPlusPlus && BaseType->isRecordType()) - return Owned(BuildOverloadedArrowExpr(S, BaseExpr, OpLoc, - MemberLoc, Member)); else return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) @@ -2164,12 +2165,38 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, BaseExpr->getSourceRange())) return ExprError(); + DeclContext *DC = RDecl; + if (SS && SS->isSet()) { + // If the member name was a qualified-id, look into the + // nested-name-specifier. + DC = computeDeclContext(*SS, false); + + // FIXME: If DC is not computable, we should build a + // CXXUnresolvedMemberExpr. + assert(DC && "Cannot handle non-computable dependent contexts in lookup"); + } + // The record definition is complete, now make sure the member is valid. - // FIXME: Qualified name lookup for C++ is a bit more complicated than this. LookupResult Result - = LookupQualifiedName(RDecl, DeclarationName(&Member), + = LookupQualifiedName(DC, DeclarationName(&Member), LookupMemberName, false); + if (SS && SS->isSet()) + { + QualType BaseTypeCanon + = Context.getCanonicalType(BaseType).getUnqualifiedType(); + QualType MemberTypeCanon + = Context.getCanonicalType( + 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) << &Member << BaseExpr->getSourceRange()); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 8dd84c0b5d..c28e052ae6 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4553,10 +4553,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, /// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator-> /// (if one exists), where @c Base is an expression of class type and /// @c Member is the name of the member we're trying to find. -Action::ExprResult -Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, - SourceLocation MemberLoc, - IdentifierInfo &Member) { +Sema::OwningExprResult +Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { + Expr *Base = static_cast<Expr *>(BaseIn.get()); assert(Base->getType()->isRecordType() && "left-hand side must have class type"); // C++ [over.ref]p1: @@ -4569,15 +4568,13 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow); OverloadCandidateSet CandidateSet; const RecordType *BaseRecord = Base->getType()->getAs<RecordType>(); - + DeclContext::lookup_const_iterator Oper, OperEnd; for (llvm::tie(Oper, OperEnd) = BaseRecord->getDecl()->lookup(OpName); Oper != OperEnd; ++Oper) AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Base, 0, 0, CandidateSet, /*SuppressUserConversions=*/false); - ExprOwningPtr<Expr> BasePtr(this, Base); - // Perform overload resolution. OverloadCandidateSet::iterator Best; switch (BestViableFunction(CandidateSet, OpLoc, Best)) { @@ -4588,34 +4585,34 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, case OR_No_Viable_Function: if (CandidateSet.empty()) Diag(OpLoc, diag::err_typecheck_member_reference_arrow) - << BasePtr->getType() << BasePtr->getSourceRange(); + << Base->getType() << Base->getSourceRange(); else Diag(OpLoc, diag::err_ovl_no_viable_oper) - << "operator->" << BasePtr->getSourceRange(); + << "operator->" << Base->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); - return true; + return ExprError(); case OR_Ambiguous: Diag(OpLoc, diag::err_ovl_ambiguous_oper) - << "operator->" << BasePtr->getSourceRange(); + << "operator->" << Base->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); - return true; + return ExprError(); case OR_Deleted: Diag(OpLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() - << "operator->" << BasePtr->getSourceRange(); + << "operator->" << Base->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); - return true; + return ExprError(); } // Convert the object parameter. CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); if (PerformObjectArgumentInitialization(Base, Method)) - return true; + return ExprError(); // No concerns about early exits now. - BasePtr.take(); + BaseIn.release(); // Build the operator call. Expr *FnExpr = new (Context) DeclRefExpr(Method, Method->getType(), @@ -4624,8 +4621,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, Base = new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, &Base, 1, Method->getResultType().getNonReferenceType(), OpLoc); - return ActOnMemberReferenceExpr(S, ExprArg(*this, Base), OpLoc, tok::arrow, - MemberLoc, Member, DeclPtrTy()).release(); + return Owned(Base); } /// FixOverloadedFunctionReference - E is an expression that refers to diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp index 3169998fb3..2e7ed1a632 100644 --- a/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -1270,14 +1270,18 @@ TemplateExprInstantiator::VisitCXXUnresolvedMemberExpr( if (Base.isInvalid()) return SemaRef.ExprError(); + tok::TokenKind OpKind = E->isArrow() ? tok::arrow : tok::period; + CXXScopeSpec SS; + Base = SemaRef.ActOnCXXEnterMemberScope(0, SS, move(Base), OpKind); // FIXME: Instantiate the declaration name. - return SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0, + Base = SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0, move(Base), E->getOperatorLoc(), - E->isArrow()? tok::arrow - : tok::period, + OpKind, E->getMemberLoc(), /*FIXME:*/*E->getMember().getAsIdentifierInfo(), - /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0)); + /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0)); + SemaRef.ActOnCXXExitMemberScope(0, SS); + return move(Base); } //---------------------------------------------------------------------------- |