From: John McCall Date: Mon, 30 Nov 2009 22:42:35 +0000 (+0000) Subject: Eliminate the use of OverloadedFunctionDecl in member expressions. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=129e2df52ed7e0434b3f1cf1867fd6a5cb083ff6;p=clang Eliminate the use of OverloadedFunctionDecl in member expressions. Create a new UnresolvedMemberExpr for these lookups. Assorted hackery around qualified member expressions; this will all go away when we implement the correct (i.e. extremely delayed) implicit-member semantics. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90161 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 6c50c7b48d..f7944771ef 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -73,6 +73,8 @@ public: return false; } + unsigned size() const { return Decls.size(); } + typedef DeclsTy::const_iterator iterator; iterator begin() const { return Decls.begin(); } iterator end() const { return Decls.end(); } diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index ce29d84c5c..23844ce5d9 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1617,6 +1617,179 @@ public: virtual child_iterator child_end(); }; +/// \brief Represents a C++ member access expression for which lookup +/// produced a set of overloaded functions. These are replaced with +/// MemberExprs in the final AST. +class UnresolvedMemberExpr : public Expr { + /// The results. These are undesugared, which is to say, they may + /// include UsingShadowDecls. + UnresolvedSet Results; + + /// \brief The expression for the base pointer or class reference, + /// e.g., the \c x in x.f. + Stmt *Base; + + /// \brief Whether this member expression used the '->' operator or + /// the '.' operator. + bool IsArrow : 1; + + /// \brief Whether the lookup results contain an unresolved using + /// declaration. + bool HasUnresolvedUsing : 1; + + /// \brief Whether this member expression has explicitly-specified template + /// arguments. + bool HasExplicitTemplateArgs : 1; + + /// \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 a name or an overloaded operator. + DeclarationName MemberName; + + /// \brief The location of the member name. + SourceLocation MemberLoc; + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name. + ExplicitTemplateArgumentList *getExplicitTemplateArgs() { + assert(HasExplicitTemplateArgs); + return reinterpret_cast(this + 1); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + const ExplicitTemplateArgumentList *getExplicitTemplateArgs() const { + return const_cast(this)->getExplicitTemplateArgs(); + } + + UnresolvedMemberExpr(QualType T, bool Dependent, + bool HasUnresolvedUsing, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Member, + SourceLocation MemberLoc, + const TemplateArgumentListInfo *TemplateArgs); + +public: + static UnresolvedMemberExpr * + Create(ASTContext &C, bool Dependent, bool HasUnresolvedUsing, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Member, + SourceLocation MemberLoc, + const TemplateArgumentListInfo *TemplateArgs); + + /// Adds a declaration to the unresolved set. By assumption, all of + /// these happen at initialization time and properties like + /// 'Dependent' and 'HasUnresolvedUsing' take them into account. + void addDecl(NamedDecl *Decl) { + Results.addDecl(Decl); + } + + typedef UnresolvedSet::iterator decls_iterator; + decls_iterator decls_begin() const { return Results.begin(); } + decls_iterator decls_end() const { return Results.end(); } + + unsigned getNumDecls() const { return Results.size(); } + + /// \brief Retrieve the base object of this member expressions, + /// e.g., the \c x in \c x.m. + Expr *getBase() { return cast(Base); } + void setBase(Expr *E) { Base = E; } + + /// \brief Determine whether this member expression used the '->' + /// operator; otherwise, it used the '.' operator. + bool isArrow() const { return IsArrow; } + void setArrow(bool A) { IsArrow = A; } + + /// \brief Retrieve the location of the '->' or '.' operator. + 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 getMemberName() const { return MemberName; } + void setMemberName(DeclarationName N) { MemberName = N; } + + // \brief Retrieve the location of the name of the member that this + // expression refers to. + SourceLocation getMemberLoc() const { return MemberLoc; } + void setMemberLoc(SourceLocation L) { MemberLoc = L; } + + /// \brief Determines whether this member expression actually had a C++ + /// template argument list explicitly specified, e.g., x.f. + bool hasExplicitTemplateArgs() const { + return HasExplicitTemplateArgs; + } + + /// \brief Copies the template arguments into the given structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + getExplicitTemplateArgs()->copyInto(List); + } + + /// \brief Retrieve the location of the left angle bracket following + /// the member name ('<'). + SourceLocation getLAngleLoc() const { + return getExplicitTemplateArgs()->LAngleLoc; + } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgumentLoc *getTemplateArgs() const { + return getExplicitTemplateArgs()->getTemplateArgs(); + } + + /// \brief Retrieve the number of template arguments provided as + /// part of this template-id. + unsigned getNumTemplateArgs() const { + return getExplicitTemplateArgs()->NumTemplateArgs; + } + + /// \brief Retrieve the location of the right angle bracket + /// following the template arguments ('>'). + SourceLocation getRAngleLoc() const { + return getExplicitTemplateArgs()->RAngleLoc; + } + + virtual SourceRange getSourceRange() const { + SourceRange Range = Base->getSourceRange(); + if (hasExplicitTemplateArgs()) + Range.setEnd(getRAngleLoc()); + else + Range.setEnd(MemberLoc); + return Range; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedMemberExprClass; + } + static bool classof(const UnresolvedMemberExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + } // end namespace clang #endif diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index cd5cfd4d37..d6f6a834d9 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -171,6 +171,14 @@ public: } virtual ~Stmt() {} +#ifndef NDEBUG + /// \brief True if this statement's refcount is in a valid state. + /// Should be used only in assertions. + bool isRetained() const { + return (RefCount >= 1); + } +#endif + /// \brief Destroy the current statement and its children. void Destroy(ASTContext &Ctx) { assert(RefCount >= 1); diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 316521b4e4..7102336180 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -133,6 +133,7 @@ EXPR(CXXExprWithTemporaries , Expr) EXPR(CXXTemporaryObjectExpr , CXXConstructExpr) EXPR(CXXUnresolvedConstructExpr, Expr) EXPR(CXXDependentScopeMemberExpr, Expr) +EXPR(UnresolvedMemberExpr , Expr) // Obj-C Expressions. EXPR(ObjCStringLiteral , Expr) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index c55d0bef3f..a0e03fed16 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2085,6 +2085,8 @@ def err_base_init_direct_and_virtual : Error< "inherited virtual base class">; def err_not_direct_base_or_virtual : Error< "type %0 is not a direct or virtual base of '%1'">; +def err_not_direct_base_or_virtual_multi : Error< + "type %0 is not a direct or virtual base of '%1'">; def err_in_class_initializer_non_integral_type : Error< "in-class initializer has non-integral, non-enumeration type %0">; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index e4de703029..624a620b9f 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1525,6 +1525,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXTemporaryObjectExprClass: case Expr::CXXUnresolvedConstructExprClass: case Expr::CXXDependentScopeMemberExprClass: + case Expr::UnresolvedMemberExprClass: case Expr::ObjCStringLiteralClass: case Expr::ObjCEncodeExprClass: case Expr::ObjCMessageExprClass: diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 0e724a8d5c..d1a0390a0a 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -573,3 +573,52 @@ Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() { Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() { return child_iterator(&Base + 1); } + +UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, + bool HasUnresolvedUsing, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName MemberName, + SourceLocation MemberLoc, + const TemplateArgumentListInfo *TemplateArgs) + : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent), + Base(Base), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), + HasExplicitTemplateArgs(TemplateArgs != 0), + OperatorLoc(OperatorLoc), + Qualifier(Qualifier), QualifierRange(QualifierRange), + MemberName(MemberName), MemberLoc(MemberLoc) { + if (TemplateArgs) + getExplicitTemplateArgs()->initializeFrom(*TemplateArgs); +} + +UnresolvedMemberExpr * +UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, + bool HasUnresolvedUsing, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + DeclarationName Member, + SourceLocation MemberLoc, + const TemplateArgumentListInfo *TemplateArgs) { + std::size_t size = sizeof(UnresolvedMemberExpr); + if (TemplateArgs) + size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); + + void *Mem = C.Allocate(size, llvm::alignof()); + return new (Mem) UnresolvedMemberExpr( + Dependent ? C.DependentTy : C.OverloadTy, + Dependent, HasUnresolvedUsing, Base, IsArrow, + OperatorLoc, Qualifier, QualifierRange, + Member, MemberLoc, TemplateArgs); +} + +Stmt::child_iterator UnresolvedMemberExpr::child_begin() { + return child_iterator(&Base); +} + +Stmt::child_iterator UnresolvedMemberExpr::child_end() { + return child_iterator(&Base + 1); +} diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 2ea9748cbb..205ea0d182 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1163,6 +1163,24 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr( } } +void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); + + // FIXME: this might originally have been written with 'template' + + OS << Node->getMemberName().getAsString(); + + if (Node->hasExplicitTemplateArgs()) { + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); + } +} + static const char *getTypeTraitName(UnaryTypeTrait UTT) { switch (UTT) { default: assert(false && "Unknown type trait"); diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 914208b71e..d832a4649e 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -558,6 +558,19 @@ StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) { ID.AddBoolean(S->isArrow()); VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getMember()); + ID.AddBoolean(S->hasExplicitTemplateArgumentList()); + if (S->hasExplicitTemplateArgumentList()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); +} + +void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + VisitNestedNameSpecifier(S->getQualifier()); + VisitName(S->getMemberName()); + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } void StmtProfiler::VisitObjCStringLiteral(ObjCStringLiteral *S) { diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index c7b574fd66..e2134a2683 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -213,6 +213,10 @@ public: return getResultKind() == FoundOverloaded; } + bool isUnresolvableResult() const { + return getResultKind() == FoundUnresolvedValue; + } + LookupResultKind getResultKind() const { sanity(); return ResultKind; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 232b502bf9..b594eceaf3 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -459,13 +459,20 @@ public: virtual void DeleteExpr(ExprTy *E); virtual void DeleteStmt(StmtTy *S); - OwningExprResult Owned(Expr* E) { return OwningExprResult(*this, E); } + OwningExprResult Owned(Expr* E) { + assert(!E || E->isRetained()); + return OwningExprResult(*this, E); + } OwningExprResult Owned(ExprResult R) { if (R.isInvalid()) return ExprError(); + assert(!R.get() || ((Expr*) R.get())->isRetained()); return OwningExprResult(*this, R.get()); } - OwningStmtResult Owned(Stmt* S) { return OwningStmtResult(*this, S); } + OwningStmtResult Owned(Stmt* S) { + assert(!S || S->isRetained()); + return OwningStmtResult(*this, S); + } virtual void ActOnEndOfTranslationUnit(); @@ -516,7 +523,7 @@ public: /// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo. QualType CreateLocInfoType(QualType T, DeclaratorInfo *DInfo); DeclarationName GetNameForDeclarator(Declarator &D); - DeclarationName GetNameFromUnqualifiedId(UnqualifiedId &Name); + DeclarationName GetNameFromUnqualifiedId(const UnqualifiedId &Name); static QualType GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo = 0); bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); bool CheckDistantExceptionSpec(QualType T); @@ -1517,31 +1524,40 @@ public: ExprArg Idx, SourceLocation RLoc); - OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base, + OwningExprResult BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation MemberLoc, - DeclarationName MemberName, - DeclPtrTy ImplDecl, - const CXXScopeSpec *SS = 0, - NamedDecl *FirstQualifierInScope = 0) { - // FIXME: Temporary helper while we migrate existing calls to - // BuildMemberReferenceExpr to support explicitly-specified template - // arguments. - return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc, - MemberName, 0, ImplDecl, SS, - FirstQualifierInScope); - } + bool IsArrow, + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + DeclarationName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo *TemplateArgs); + + OwningExprResult BuildMemberReferenceExpr(ExprArg Base, + SourceLocation OpLoc, bool IsArrow, + const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs); + + OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base, + bool IsArrow, SourceLocation OpLoc, + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + DeclPtrTy ObjCImpDecl); - OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base, + bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + const LookupResult &R); + + OwningExprResult ActOnDependentMemberExpr(ExprArg Base, + bool IsArrow, SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation MemberLoc, - DeclarationName MemberName, - const TemplateArgumentListInfo *ExplicitTemplateArgs, - DeclPtrTy ImplDecl, - const CXXScopeSpec *SS, - NamedDecl *FirstQualifierInScope = 0); + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + DeclarationName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo *TemplateArgs); virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, @@ -2140,9 +2156,7 @@ public: FunctionDecl::StorageClass& SC); DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); - bool isImplicitMemberReference(const CXXScopeSpec &SS, NamedDecl *D, - SourceLocation NameLoc, QualType &ThisType, - QualType &MemberType); + bool isImplicitMemberReference(const LookupResult &R, QualType &ThisType); //===--------------------------------------------------------------------===// // C++ Derived Classes diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 220ceddbf6..c987a7f11c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1757,7 +1757,7 @@ DeclarationName Sema::GetNameForDeclarator(Declarator &D) { } /// \brief Retrieves the canonicalized name from a parsed unqualified-id. -DeclarationName Sema::GetNameFromUnqualifiedId(UnqualifiedId &Name) { +DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { switch (Name.getKind()) { case UnqualifiedId::IK_Identifier: return DeclarationName(Name.Identifier); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 8def7d4efc..94449e2770 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -617,7 +617,54 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, return Owned(Result); } -static void DecomposeTemplateName(LookupResult &R, TemplateName TName) { +/// Decomposes the given name into a DeclarationName, its location, and +/// possibly a list of template arguments. +/// +/// If this produces template arguments, it is permitted to call +/// DecomposeTemplateName. +/// +/// This actually loses a lot of source location information for +/// non-standard name kinds; we should consider preserving that in +/// some way. +static void DecomposeUnqualifiedId(Sema &SemaRef, + const UnqualifiedId &Id, + TemplateArgumentListInfo &Buffer, + DeclarationName &Name, + SourceLocation &NameLoc, + const TemplateArgumentListInfo *&TemplateArgs) { + if (Id.getKind() == UnqualifiedId::IK_TemplateId) { + Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc); + Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc); + + ASTTemplateArgsPtr TemplateArgsPtr(SemaRef, + Id.TemplateId->getTemplateArgs(), + Id.TemplateId->NumArgs); + SemaRef.translateTemplateArguments(TemplateArgsPtr, Buffer); + TemplateArgsPtr.release(); + + TemplateName TName = + Sema::TemplateTy::make(Id.TemplateId->Template).getAsVal(); + + Name = SemaRef.Context.getNameForTemplate(TName); + NameLoc = Id.TemplateId->TemplateNameLoc; + TemplateArgs = &Buffer; + } else { + Name = SemaRef.GetNameFromUnqualifiedId(Id); + NameLoc = Id.StartLocation; + TemplateArgs = 0; + } +} + +/// Decompose the given template name into a list of lookup results. +/// +/// The unqualified ID must name a non-dependent template, which can +/// be more easily tested by checking whether DecomposeUnqualifiedId +/// found template arguments. +static void DecomposeTemplateName(LookupResult &R, const UnqualifiedId &Id) { + assert(Id.getKind() == UnqualifiedId::IK_TemplateId); + TemplateName TName = + Sema::TemplateTy::make(Id.TemplateId->Template).getAsVal(); + if (TemplateDecl *TD = TName.getAsTemplateDecl()) R.addDecl(TD); else if (OverloadedFunctionDecl *OD @@ -628,6 +675,42 @@ static void DecomposeTemplateName(LookupResult &R, TemplateName TName) { R.resolveKind(); } +static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) { + for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), + E = Record->bases_end(); I != E; ++I) { + CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType()); + CanQual BaseRT = BaseT->getAs(); + if (!BaseRT) return false; + + CXXRecordDecl *BaseRecord = cast(BaseRT->getDecl()); + if (!BaseRecord->isDefinition() || + !IsFullyFormedScope(SemaRef, BaseRecord)) + return false; + } + + return true; +} + +/// Determines whether the given scope is "fully-formed": i.e. we can +/// look into it because it's either non-dependent or is the current +/// instantiation and has no dependent base classes. +static bool IsFullyFormedScope(Sema &SemaRef, const CXXScopeSpec &SS) { + DeclContext *DC = SemaRef.computeDeclContext(SS, false); + if (!DC) return false; + if (!DC->isDependentContext()) return true; + return IsFullyFormedScope(SemaRef, cast(DC)); +} + +static bool IsFullyFormedScope(Sema &SemaRef, DeclContext *DC) { + if (isa(DC)) + return IsFullyFormedScope(SemaRef, + cast(cast(DC)->getParent())); + else if (isa(DC)) + return IsFullyFormedScope(SemaRef, cast(DC)); + else + return true; +} + Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, const CXXScopeSpec &SS, UnqualifiedId &Id, @@ -639,33 +722,14 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, if (SS.isInvalid()) return ExprError(); - TemplateArgumentListInfo ExplicitTemplateArgs; + TemplateArgumentListInfo TemplateArgsBuffer; // Decompose the UnqualifiedId into the following data. DeclarationName Name; SourceLocation NameLoc; const TemplateArgumentListInfo *TemplateArgs; - if (Id.getKind() == UnqualifiedId::IK_TemplateId) { - ExplicitTemplateArgs.setLAngleLoc(Id.TemplateId->LAngleLoc); - ExplicitTemplateArgs.setRAngleLoc(Id.TemplateId->RAngleLoc); - - ASTTemplateArgsPtr TemplateArgsPtr(*this, - Id.TemplateId->getTemplateArgs(), - Id.TemplateId->NumArgs); - translateTemplateArguments(TemplateArgsPtr, ExplicitTemplateArgs); - TemplateArgsPtr.release(); - - TemplateName TName = - TemplateTy::make(Id.TemplateId->Template).getAsVal(); - - Name = Context.getNameForTemplate(TName); - NameLoc = Id.TemplateId->TemplateNameLoc; - TemplateArgs = &ExplicitTemplateArgs; - } else { - Name = GetNameFromUnqualifiedId(Id); - NameLoc = Id.StartLocation; - TemplateArgs = 0; - } + DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, + Name, NameLoc, TemplateArgs); IdentifierInfo *II = Name.getAsIdentifierInfo(); @@ -675,7 +739,8 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // names a dependent type. // Determine whether this is a member of an unknown specialization; // we need to handle these differently. - if (SS.isSet() && !computeDeclContext(SS, false)) { + if (SS.isSet() && !(IsFullyFormedScope(*this, SS) && + IsFullyFormedScope(*this, CurContext))) { bool CheckForImplicitMember = !isAddressOfOperand; return ActOnDependentIdExpression(SS, Name, NameLoc, @@ -686,11 +751,8 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // Perform the required lookup. LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); if (TemplateArgs) { - TemplateName TName = - TemplateTy::make(Id.TemplateId->Template).getAsVal(); - // Just re-use the lookup done by isTemplateName. - DecomposeTemplateName(R, TName); + DecomposeTemplateName(R, Id); } else { LookupParsedName(R, S, &SS, true); @@ -806,9 +868,10 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, return BuildDeclarationNameExpr(SS, R, ADL); } -/// ActOnDeclarationNameExpr - Build a C++ qualified declaration name, -/// generally during template instantiation. There's a large number -/// of things which don't need to be done along this path. +/// BuildQualifiedDeclarationNameExpr - Build a C++ qualified +/// declaration name, generally during template instantiation. +/// There's a large number of things which don't need to be done along +/// this path. Sema::OwningExprResult Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS, DeclarationName Name, @@ -959,20 +1022,42 @@ Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) { /// \brief Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, - const CXXScopeSpec *SS, NamedDecl *Member, + const CXXScopeSpec &SS, NamedDecl *Member, SourceLocation Loc, QualType Ty, const TemplateArgumentListInfo *TemplateArgs = 0) { NestedNameSpecifier *Qualifier = 0; SourceRange QualifierRange; - if (SS && SS->isSet()) { - Qualifier = (NestedNameSpecifier *) SS->getScopeRep(); - QualifierRange = SS->getRange(); + if (SS.isSet()) { + Qualifier = (NestedNameSpecifier *) SS.getScopeRep(); + QualifierRange = SS.getRange(); } return MemberExpr::Create(C, Base, isArrow, Qualifier, QualifierRange, Member, Loc, TemplateArgs, Ty); } +/// Return true if all the decls in the given result are instance +/// methods. +static bool IsOnlyInstanceMethods(const LookupResult &R) { + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + NamedDecl *D = (*I)->getUnderlyingDecl(); + + CXXMethodDecl *Method; + if (isa(D)) + Method = cast(cast(D) + ->getTemplatedDecl()); + else if (isa(D)) + Method = cast(D); + else + return false; + + if (Method->isStatic()) + return false; + } + + return true; +} + /// Builds an implicit member access expression from the given /// unqualified lookup set, which is known to contain only class /// members. @@ -982,50 +1067,35 @@ Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, const TemplateArgumentListInfo *TemplateArgs) { assert(!R.empty() && !R.isAmbiguous()); - NamedDecl *D = R.getAsSingleDecl(Context); SourceLocation Loc = R.getNameLoc(); // We may have found a field within an anonymous union or struct // (C++ [class.union]). // FIXME: This needs to happen post-isImplicitMemberReference? // FIXME: template-ids inside anonymous structs? - if (FieldDecl *FD = dyn_cast(D)) + if (FieldDecl *FD = R.getAsSingle()) if (cast(FD->getDeclContext())->isAnonymousStructOrUnion()) return BuildAnonymousStructUnionMemberReference(Loc, FD); QualType ThisType; - QualType MemberType; - if (isImplicitMemberReference(SS, D, Loc, ThisType, MemberType)) { + if (isImplicitMemberReference(R, ThisType)) { Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); - MarkDeclarationReferenced(Loc, D); - if (PerformObjectMemberConversion(This, D)) - return ExprError(); - - bool ShouldCheckUse = true; - if (CXXMethodDecl *MD = dyn_cast(D)) { - // Don't diagnose the use of a virtual member function unless it's - // explicitly qualified. - if (MD->isVirtual() && !SS.isSet()) - ShouldCheckUse = false; - } - - if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc)) - return ExprError(); - return Owned(BuildMemberExpr(Context, This, true, &SS, D, Loc, MemberType, - TemplateArgs)); + return BuildMemberReferenceExpr(ExprArg(*this, This), + /*OpLoc*/ SourceLocation(), + /*IsArrow*/ true, + SS, R, TemplateArgs); } - if (CXXMethodDecl *Method = dyn_cast(D)) { - if (!Method->isStatic()) - return ExprError(Diag(Loc, diag::err_member_call_without_object)); - } + // Diagnose now if none of the available methods are static. + if (IsOnlyInstanceMethods(R)) + return ExprError(Diag(Loc, diag::err_member_call_without_object)); - if (isa(D)) { + if (R.getAsSingle()) { if (CXXMethodDecl *MD = dyn_cast(CurContext)) { if (MD->isStatic()) { // "invalid use of member 'x' in static member function" Diag(Loc, diag::err_invalid_member_use_in_static_method) - << D->getDeclName(); + << R.getLookupName(); return ExprError(); } } @@ -1034,7 +1104,7 @@ Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, // program would have been turned into implicit member expressions // above. Diag(Loc, diag::err_invalid_non_static_member_use) - << D->getDeclName(); + << R.getLookupName(); return ExprError(); } @@ -1876,29 +1946,318 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy, return GDecl; } -Action::OwningExprResult -Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, - tok::TokenKind OpKind, SourceLocation MemberLoc, - DeclarationName MemberName, - const TemplateArgumentListInfo *ExplicitTemplateArgs, - DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS, - NamedDecl *FirstQualifierInScope) { - if (SS && SS->isInvalid()) +Sema::OwningExprResult +Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc, + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + DeclarationName Name, SourceLocation NameLoc, + const TemplateArgumentListInfo *TemplateArgs) { + Expr *BaseExpr = Base.takeAs(); + + // Even in dependent contexts, try to diagnose base expressions with + // obviously wrong types, e.g.: + // + // T* t; + // t.f; + // + // In Obj-C++, however, the above expression is valid, since it could be + // accessing the 'f' property if T is an Obj-C interface. The extra check + // allows this, while still reporting an error if T is a struct pointer. + if (!IsArrow) { + const PointerType *PT = BaseExpr->getType()->getAs(); + if (PT && (!getLangOptions().ObjC1 || + PT->getPointeeType()->isRecordType())) { + Diag(NameLoc, diag::err_typecheck_member_reference_struct_union) + << BaseExpr->getType() << BaseExpr->getSourceRange(); + return ExprError(); + } + } + + assert(BaseExpr->getType()->isDependentType()); + + // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr + // must have pointer type, and the accessed type is the pointee. + return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, + IsArrow, OpLoc, + static_cast(SS.getScopeRep()), + SS.getRange(), + FirstQualifierInScope, + Name, NameLoc, + TemplateArgs)); +} + +/// We know that the given qualified member reference points only to +/// declarations which do not belong to the static type of the base +/// expression. Diagnose the problem. +static void DiagnoseQualifiedMemberReference(Sema &SemaRef, + Expr *BaseExpr, + QualType BaseType, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + const LookupResult &R) { + DeclContext *DC = R.getRepresentativeDecl()->getDeclContext(); + + // FIXME: this is an exceedingly lame diagnostic for some of the more + // complicated cases here. + SemaRef.Diag(R.getNameLoc(), diag::err_not_direct_base_or_virtual) + << QualifierRange << DC << BaseType; +} + +// Check whether the declarations we found through a nested-name +// specifier in a member expression are actually members of the base +// type. The restriction here is: +// +// C++ [expr.ref]p2: +// ... In these cases, the id-expression shall name a +// member of the class or of one of its base classes. +// +// So it's perfectly legitimate for the nested-name specifier to name +// an unrelated class, and for us to find an overload set including +// decls from classes which are not superclasses, as long as the decl +// we actually pick through overload resolution is from a superclass. +bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, + QualType BaseType, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + const LookupResult &R) { + QualType BaseTypeCanon + = Context.getCanonicalType(BaseType).getUnqualifiedType(); + + bool FoundValid = false; + + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + TypeDecl* TyD = cast((*I)->getUnderlyingDecl()->getDeclContext()); + CanQualType MemberTypeCanon + = Context.getCanonicalType(Context.getTypeDeclType(TyD)); + + if (BaseTypeCanon == MemberTypeCanon || + IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) { + FoundValid = true; + break; + } + } + + if (!FoundValid) { + DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, + Qualifier, QualifierRange, R); + return true; + } + + return false; +} + +Sema::OwningExprResult +Sema::BuildMemberReferenceExpr(ExprArg BaseArg, + SourceLocation OpLoc, bool IsArrow, + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + DeclarationName Name, SourceLocation NameLoc, + const TemplateArgumentListInfo *TemplateArgs) { + Expr *Base = BaseArg.takeAs(); + + if (Base->getType()->isDependentType()) + return ActOnDependentMemberExpr(ExprArg(*this, Base), + IsArrow, OpLoc, + SS, FirstQualifierInScope, + Name, NameLoc, + TemplateArgs); + + LookupResult R(*this, Name, NameLoc, LookupMemberName); + OwningExprResult Result = + LookupMemberExpr(R, Base, IsArrow, OpLoc, + SS, FirstQualifierInScope, + /*ObjCImpDecl*/ DeclPtrTy()); + + if (Result.isInvalid()) { + Owned(Base); return ExprError(); + } - // Since this might be a postfix expression, get rid of ParenListExprs. - Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); + if (Result.get()) + return move(Result); + return BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc, + IsArrow, SS, R, TemplateArgs); +} + +Sema::OwningExprResult +Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, + bool IsArrow, const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs) { Expr *BaseExpr = Base.takeAs(); + QualType BaseType = BaseExpr->getType(); + if (IsArrow) { + assert(BaseType->isPointerType()); + BaseType = BaseType->getAs()->getPointeeType(); + } + + NestedNameSpecifier *Qualifier = + static_cast(SS.getScopeRep()); + DeclarationName MemberName = R.getLookupName(); + SourceLocation MemberLoc = R.getNameLoc(); + + if (R.isAmbiguous()) + return ExprError(); + + if (R.empty()) { + // Rederive where we looked up. + DeclContext *DC = (SS.isSet() + ? computeDeclContext(SS, false) + : BaseType->getAs()->getDecl()); + + Diag(R.getNameLoc(), diag::err_no_member) + << MemberName << DC << BaseExpr->getSourceRange(); + return ExprError(); + } + + // We can't always diagnose the problem yet: it's permitted for + // lookup to find things from an invalid context as long as they + // don't get picked by overload resolution. + if (SS.isSet() && CheckQualifiedMemberReference(BaseExpr, BaseType, + Qualifier, SS.getRange(), R)) + return ExprError(); + + // Construct an unresolved result if we in fact got an unresolved + // result. + if (R.isOverloadedResult() || R.isUnresolvableResult()) { + bool Dependent = R.isUnresolvableResult(); + Dependent = Dependent || + UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), + TemplateArgs); + + UnresolvedMemberExpr *MemExpr + = UnresolvedMemberExpr::Create(Context, Dependent, + R.isUnresolvableResult(), + BaseExpr, IsArrow, OpLoc, + Qualifier, SS.getRange(), + MemberName, MemberLoc, + TemplateArgs); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + MemExpr->addDecl(*I); + + return Owned(MemExpr); + } + + assert(R.isSingleResult()); + NamedDecl *MemberDecl = R.getFoundDecl(); + + // FIXME: diagnose the presence of template arguments now. + + // If the decl being referenced had an error, return an error for this + // sub-expr without emitting another error, in order to avoid cascading + // error cases. + if (MemberDecl->isInvalidDecl()) + return ExprError(); + + bool ShouldCheckUse = true; + if (CXXMethodDecl *MD = dyn_cast(MemberDecl)) { + // Don't diagnose the use of a virtual member function unless it's + // explicitly qualified. + if (MD->isVirtual() && !SS.isSet()) + ShouldCheckUse = false; + } + + // Check the use of this member. + if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) { + Owned(BaseExpr); + return ExprError(); + } + + if (FieldDecl *FD = dyn_cast(MemberDecl)) { + // We may have found a field within an anonymous union or struct + // (C++ [class.union]). + if (cast(FD->getDeclContext())->isAnonymousStructOrUnion()) + return BuildAnonymousStructUnionMemberReference(MemberLoc, FD, + BaseExpr, OpLoc); + + // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] + QualType MemberType = FD->getType(); + if (const ReferenceType *Ref = MemberType->getAs()) + MemberType = Ref->getPointeeType(); + else { + Qualifiers BaseQuals = BaseType.getQualifiers(); + BaseQuals.removeObjCGCAttr(); + if (FD->isMutable()) BaseQuals.removeConst(); + + Qualifiers MemberQuals + = Context.getCanonicalType(MemberType).getQualifiers(); + + Qualifiers Combined = BaseQuals + MemberQuals; + if (Combined != MemberQuals) + MemberType = Context.getQualifiedType(MemberType, Combined); + } + + MarkDeclarationReferenced(MemberLoc, FD); + if (PerformObjectMemberConversion(BaseExpr, FD)) + return ExprError(); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + FD, MemberLoc, MemberType)); + } + + if (VarDecl *Var = dyn_cast(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, Var); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + Var, MemberLoc, + Var->getType().getNonReferenceType())); + } + + if (FunctionDecl *MemberFn = dyn_cast(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, MemberDecl); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + MemberFn, MemberLoc, + MemberFn->getType())); + } + + if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, MemberDecl); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + Enum, MemberLoc, Enum->getType())); + } + + Owned(BaseExpr); + + if (isa(MemberDecl)) + return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type) + << MemberName << int(IsArrow)); + + // We found a declaration kind that we didn't expect. This is a + // generic error message that tells the user that she can't refer + // to this member with '.' or '->'. + return ExprError(Diag(MemberLoc, + diag::err_typecheck_member_reference_unknown) + << MemberName << int(IsArrow)); +} + +/// Look up the given member of the given non-type-dependent +/// expression. This can return in one of two ways: +/// * If it returns a sentinel null-but-valid result, the caller will +/// assume that lookup was performed and the results written into +/// the provided structure. It will take over from there. +/// * Otherwise, the returned expression will be produced in place of +/// an ordinary member expression. +/// +/// The ObjCImpDecl bit is a gross hack that will need to be properly +/// fixed for ObjC++. +Sema::OwningExprResult +Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, + bool IsArrow, SourceLocation OpLoc, + const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, + DeclPtrTy ObjCImpDecl) { assert(BaseExpr && "no base expression"); // Perform default conversions. DefaultFunctionArrayConversion(BaseExpr); QualType BaseType = BaseExpr->getType(); + assert(!BaseType->isDependentType()); + + DeclarationName MemberName = R.getLookupName(); + SourceLocation MemberLoc = R.getNameLoc(); // If the user is trying to apply -> or . to a function pointer - // type, it's probably because the forgot parentheses to call that + // type, it's probably because they forgot parentheses to call that // function. Suggest the addition of those parentheses, build the // call, and continue on. if (const PointerType *Ptr = BaseType->getAs()) { @@ -1906,8 +2265,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, = Ptr->getPointeeType()->getAs()) { QualType ResultTy = Fun->getResultType(); if (Fun->getNumArgs() == 0 && - ((OpKind == tok::period && ResultTy->isRecordType()) || - (OpKind == tok::arrow && ResultTy->isPointerType() && + ((!IsArrow && ResultTy->isRecordType()) || + (IsArrow && ResultTy->isPointerType() && ResultTy->getAs()->getPointeeType() ->isRecordType()))) { SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd()); @@ -1916,10 +2275,10 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, << CodeModificationHint::CreateInsertion(Loc, "()"); OwningExprResult NewBase - = ActOnCallExpr(S, ExprArg(*this, BaseExpr), Loc, + = ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc, MultiExprArg(*this, 0, 0), 0, Loc); if (NewBase.isInvalid()) - return move(NewBase); + return ExprError(); BaseExpr = NewBase.takeAs(); DefaultFunctionArrayConversion(BaseExpr); @@ -1938,6 +2297,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); } } + // If this is an Objective-C pseudo-builtin and a definition is provided then // use that. if (Context.isObjCSelType(BaseType)) { @@ -1948,10 +2308,11 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); } } + assert(!BaseType.isNull() && "no type for member expression"); // Handle properties on ObjC 'Class' types. - if (OpKind == tok::period && BaseType->isObjCClassType()) { + if (!IsArrow && BaseType->isObjCClassType()) { // Also must look for a getter name which uses property syntax. IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); Selector Sel = PP.getSelectorTable().getNullarySelector(Member); @@ -2005,68 +2366,21 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, BaseType = Context.ObjCClassRedefinitionType; ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); } - - // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr - // must have pointer type, and the accessed type is the pointee. - if (OpKind == tok::arrow) { - if (BaseType->isDependentType()) { - NestedNameSpecifier *Qualifier = 0; - if (SS) { - Qualifier = static_cast(SS->getScopeRep()); - if (!FirstQualifierInScope) - FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier); - } - return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, true, - OpLoc, Qualifier, - SS? SS->getRange() : SourceRange(), - FirstQualifierInScope, - MemberName, - MemberLoc, - ExplicitTemplateArgs)); - } - else if (const PointerType *PT = BaseType->getAs()) + if (IsArrow) { + if (const PointerType *PT = BaseType->getAs()) BaseType = PT->getPointeeType(); else if (BaseType->isObjCObjectPointerType()) ; - else - return ExprError(Diag(MemberLoc, - diag::err_typecheck_member_reference_arrow) - << BaseType << BaseExpr->getSourceRange()); - } else if (BaseType->isDependentType()) { - // Require that the base type isn't a pointer type - // (so we'll report an error for) - // T* t; - // t.f; - // - // In Obj-C++, however, the above expression is valid, since it could be - // accessing the 'f' property if T is an Obj-C interface. The extra check - // allows this, while still reporting an error if T is a struct pointer. - const PointerType *PT = BaseType->getAs(); - - if (!PT || (getLangOptions().ObjC1 && - !PT->getPointeeType()->isRecordType())) { - NestedNameSpecifier *Qualifier = 0; - if (SS) { - Qualifier = static_cast(SS->getScopeRep()); - if (!FirstQualifierInScope) - FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier); - } - - return Owned(CXXDependentScopeMemberExpr::Create(Context, - BaseExpr, false, - OpLoc, - Qualifier, - SS? SS->getRange() : SourceRange(), - FirstQualifierInScope, - MemberName, - MemberLoc, - ExplicitTemplateArgs)); - } + else { + Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) + << BaseType << BaseExpr->getSourceRange(); + return ExprError(); } + } - // Handle field access to simple records. This also handles access to fields - // of the ObjC 'id' struct. + // Handle field access to simple records. This also handles access + // to fields of the ObjC 'id' struct. if (const RecordType *RTy = BaseType->getAs()) { RecordDecl *RDecl = RTy->getDecl(); if (RequireCompleteType(OpLoc, BaseType, @@ -2075,14 +2389,14 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return ExprError(); DeclContext *DC = RDecl; - if (SS && SS->isSet()) { + if (SS.isSet()) { // If the member name was a qualified-id, look into the // nested-name-specifier. - DC = computeDeclContext(*SS, false); + DC = computeDeclContext(SS, false); if (!isa(DC)) { Diag(MemberLoc, diag::err_qualified_member_nonclass) - << DC << SS->getRange(); + << DC << SS.getRange(); return ExprError(); } @@ -2092,135 +2406,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, } // The record definition is complete, now make sure the member is valid. - LookupResult Result(*this, MemberName, MemberLoc, LookupMemberName); - LookupQualifiedName(Result, DC); - - if (Result.empty()) - return ExprError(Diag(MemberLoc, diag::err_no_member) - << MemberName << DC << BaseExpr->getSourceRange()); - if (Result.isAmbiguous()) - return ExprError(); - - NamedDecl *MemberDecl = Result.getAsSingleDecl(Context); - - if (SS && SS->isSet()) { - TypeDecl* TyD = cast(MemberDecl->getDeclContext()); - QualType BaseTypeCanon - = Context.getCanonicalType(BaseType).getUnqualifiedType(); - QualType MemberTypeCanon - = Context.getCanonicalType(Context.getTypeDeclType(TyD)); - - if (BaseTypeCanon != MemberTypeCanon && - !IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) - return ExprError(Diag(SS->getBeginLoc(), - diag::err_not_direct_base_or_virtual) - << MemberTypeCanon << BaseTypeCanon); - } - - // If the decl being referenced had an error, return an error for this - // sub-expr without emitting another error, in order to avoid cascading - // error cases. - if (MemberDecl->isInvalidDecl()) - return ExprError(); - - bool ShouldCheckUse = true; - if (CXXMethodDecl *MD = dyn_cast(MemberDecl)) { - // Don't diagnose the use of a virtual member function unless it's - // explicitly qualified. - if (MD->isVirtual() && (!SS || !SS->isSet())) - ShouldCheckUse = false; - } - - // Check the use of this field - if (ShouldCheckUse && DiagnoseUseOfDecl(MemberDecl, MemberLoc)) - return ExprError(); - - if (FieldDecl *FD = dyn_cast(MemberDecl)) { - // We may have found a field within an anonymous union or struct - // (C++ [class.union]). - if (cast(FD->getDeclContext())->isAnonymousStructOrUnion()) - return BuildAnonymousStructUnionMemberReference(MemberLoc, FD, - BaseExpr, OpLoc); - - // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] - QualType MemberType = FD->getType(); - if (const ReferenceType *Ref = MemberType->getAs()) - MemberType = Ref->getPointeeType(); - else { - Qualifiers BaseQuals = BaseType.getQualifiers(); - BaseQuals.removeObjCGCAttr(); - if (FD->isMutable()) BaseQuals.removeConst(); - - Qualifiers MemberQuals - = Context.getCanonicalType(MemberType).getQualifiers(); - - Qualifiers Combined = BaseQuals + MemberQuals; - if (Combined != MemberQuals) - MemberType = Context.getQualifiedType(MemberType, Combined); - } - - MarkDeclarationReferenced(MemberLoc, FD); - if (PerformObjectMemberConversion(BaseExpr, FD)) - return ExprError(); - return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, - FD, MemberLoc, MemberType)); - } - - if (VarDecl *Var = dyn_cast(MemberDecl)) { - MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, - Var, MemberLoc, - Var->getType().getNonReferenceType())); - } - if (FunctionDecl *MemberFn = dyn_cast(MemberDecl)) { - MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, - MemberFn, MemberLoc, - MemberFn->getType())); - } - if (FunctionTemplateDecl *FunTmpl - = dyn_cast(MemberDecl)) { - MarkDeclarationReferenced(MemberLoc, MemberDecl); - - if (ExplicitTemplateArgs) - return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow, - (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), - SS? SS->getRange() : SourceRange(), - FunTmpl, MemberLoc, - ExplicitTemplateArgs, - Context.OverloadTy)); - - return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, - FunTmpl, MemberLoc, - Context.OverloadTy)); - } - if (OverloadedFunctionDecl *Ovl - = dyn_cast(MemberDecl)) { - if (ExplicitTemplateArgs) - return Owned(MemberExpr::Create(Context, BaseExpr, OpKind == tok::arrow, - (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), - SS? SS->getRange() : SourceRange(), - Ovl, MemberLoc, ExplicitTemplateArgs, - Context.OverloadTy)); - - return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, - Ovl, MemberLoc, Context.OverloadTy)); - } - if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { - MarkDeclarationReferenced(MemberLoc, MemberDecl); - return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, - Enum, MemberLoc, Enum->getType())); - } - if (isa(MemberDecl)) - return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type) - << MemberName << int(OpKind == tok::arrow)); - - // We found a declaration kind that we didn't expect. This is a - // generic error message that tells the user that she can't refer - // to this member with '.' or '->'. - return ExprError(Diag(MemberLoc, - diag::err_typecheck_member_reference_unknown) - << MemberName << int(OpKind == tok::arrow)); + LookupQualifiedName(R, DC); + return Owned((Expr*) 0); } // Handle pseudo-destructors (C++ [expr.pseudo]). Since anything referring @@ -2256,18 +2443,17 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, // FIXME: We've lost the precise spelling of the type by going through // DeclarationName. Can we do better? return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr, - OpKind == tok::arrow, - OpLoc, - (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0), - SS? SS->getRange() : SourceRange(), + IsArrow, OpLoc, + (NestedNameSpecifier *) SS.getScopeRep(), + SS.getRange(), MemberName.getCXXNameType(), MemberLoc)); } // Handle access to Objective-C instance variables, such as "Obj->ivar" and // (*Obj).ivar. - if ((OpKind == tok::arrow && BaseType->isObjCObjectPointerType()) || - (OpKind == tok::period && BaseType->isObjCInterfaceType())) { + if ((IsArrow && BaseType->isObjCObjectPointerType()) || + (!IsArrow && BaseType->isObjCInterfaceType())) { const ObjCObjectPointerType *OPT = BaseType->getAs(); const ObjCInterfaceType *IFaceT = OPT ? OPT->getInterfaceType() : BaseType->getAs(); @@ -2322,7 +2508,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), MemberLoc, BaseExpr, - OpKind == tok::arrow)); + IsArrow)); } return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) << IDecl->getDeclName() << MemberName @@ -2330,8 +2516,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, } } // Handle properties on 'id' and qualified "id". - if (OpKind == tok::period && (BaseType->isObjCIdType() || - BaseType->isObjCQualifiedIdType())) { + if (!IsArrow && (BaseType->isObjCIdType() || + BaseType->isObjCQualifiedIdType())) { const ObjCObjectPointerType *QIdTy = BaseType->getAs(); IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); @@ -2364,8 +2550,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, // Handle Objective-C property access, which is "Obj.property" where Obj is a // pointer to a (potentially qualified) interface type. const ObjCObjectPointerType *OPT; - if (OpKind == tok::period && - (OPT = BaseType->getAsObjCInterfacePointerType())) { + if (!IsArrow && (OPT = BaseType->getAsObjCInterfacePointerType())) { const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); ObjCInterfaceDecl *IFace = IFaceT->getDecl(); IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); @@ -2450,7 +2635,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, } // Handle the following exceptional case (*Obj).isa. - if (OpKind == tok::period && + if (!IsArrow && BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) && MemberName.getAsIdentifierInfo()->isStr("isa")) return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc, @@ -2472,74 +2657,105 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return ExprError(); } -Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg Base, +static Sema::OwningExprResult DiagnoseDtorReference(Sema &SemaRef, + SourceLocation NameLoc, + Sema::ExprArg MemExpr) { + Expr *E = (Expr *) MemExpr.get(); + SourceLocation ExpectedLParenLoc = SemaRef.PP.getLocForEndOfToken(NameLoc); + SemaRef.Diag(E->getLocStart(), diag::err_dtor_expr_without_call) + << isa(E) + << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); + + return SemaRef.ActOnCallExpr(/*Scope*/ 0, + move(MemExpr), + /*LPLoc*/ ExpectedLParenLoc, + Sema::MultiExprArg(SemaRef, 0, 0), + /*CommaLocs*/ 0, + /*RPLoc*/ ExpectedLParenLoc); +} + +/// The main callback when the parser finds something like +/// expression . [nested-name-specifier] identifier +/// expression -> [nested-name-specifier] identifier +/// where 'identifier' encompasses a fairly broad spectrum of +/// possibilities, including destructor and operator references. +/// +/// \param OpKind either tok::arrow or tok::period +/// \param HasTrailingLParen whether the next token is '(', which +/// is used to diagnose mis-uses of special members that can +/// only be called +/// \param ObjCImpDecl the current ObjC @implementation decl; +/// this is an ugly hack around the fact that ObjC @implementations +/// aren't properly put in the context chain +Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, SourceLocation OpLoc, tok::TokenKind OpKind, const CXXScopeSpec &SS, - UnqualifiedId &Member, + UnqualifiedId &Id, 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 { - DependentTemplateName *DTN = Template.getAsDependentTemplateName(); - if (DTN->isIdentifier()) - Name = DTN->getIdentifier(); - else - Name = Context.DeclarationNames.getCXXOperatorName(DTN->getOperator()); + if (SS.isSet() && SS.isInvalid()) + return ExprError(); + + TemplateArgumentListInfo TemplateArgsBuffer; + + // Decompose the name into its component parts. + DeclarationName Name; + SourceLocation NameLoc; + const TemplateArgumentListInfo *TemplateArgs; + DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, + Name, NameLoc, TemplateArgs); + + bool IsArrow = (OpKind == tok::arrow); + + NamedDecl *FirstQualifierInScope + = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S, + static_cast(SS.getScopeRep()))); + + // This is a postfix expression, so get rid of ParenListExprs. + BaseArg = MaybeConvertParenListExprToParenExpr(S, move(BaseArg)); + + Expr *Base = BaseArg.takeAs(); + OwningExprResult Result(*this); + if (Base->getType()->isDependentType()) { + Result = ActOnDependentMemberExpr(ExprArg(*this, Base), + IsArrow, OpLoc, + SS, FirstQualifierInScope, + Name, NameLoc, + TemplateArgs); + } else { + LookupResult R(*this, Name, NameLoc, LookupMemberName); + if (TemplateArgs) { + // Re-use the lookup done for the template name. + DecomposeTemplateName(R, Id); + } else { + Result = LookupMemberExpr(R, Base, IsArrow, OpLoc, + SS, FirstQualifierInScope, + ObjCImpDecl); + + if (Result.isInvalid()) { + Owned(Base); + return ExprError(); + } + + if (Result.get()) { + // The only way a reference to a destructor can be used is to + // immediately call it, which falls into this case. If the + // next token is not a '(', produce a diagnostic and build the + // call now. + if (!HasTrailingLParen && + Id.getKind() == UnqualifiedId::IK_DestructorName) + return DiagnoseDtorReference(*this, NameLoc, move(Result)); + + return move(Result); + } } - - // Translate the parser's template argument list in our AST format. - ASTTemplateArgsPtr TemplateArgsPtr(*this, - Member.TemplateId->getTemplateArgs(), - Member.TemplateId->NumArgs); - - TemplateArgumentListInfo TemplateArgs; - TemplateArgs.setLAngleLoc(Member.TemplateId->LAngleLoc); - TemplateArgs.setRAngleLoc(Member.TemplateId->RAngleLoc); - translateTemplateArguments(TemplateArgsPtr, 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, &TemplateArgs, DeclPtrTy(), - &SS); + + Result = BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc, + IsArrow, SS, R, TemplateArgs); } - - // 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); + + return move(Result); } Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, @@ -2820,20 +3036,32 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs, CommaLocs, RParenLoc)); + Expr *NakedFn = Fn->IgnoreParens(); + + // Determine whether this is a call to an unresolved member function. + if (UnresolvedMemberExpr *MemE = dyn_cast(NakedFn)) { + // If lookup was unresolved but not dependent (i.e. didn't find + // an unresolved using declaration), it has to be an overloaded + // function set, which means it must contain either multiple + // declarations (all methods or method templates) or a single + // method template. + assert((MemE->getNumDecls() > 1) || + isa(*MemE->decls_begin())); + + return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc)); + } + // Determine whether this is a call to a member function. - if (MemberExpr *MemExpr = dyn_cast(Fn->IgnoreParens())) { + if (MemberExpr *MemExpr = dyn_cast(NakedFn)) { NamedDecl *MemDecl = MemExpr->getMemberDecl(); - if (isa(MemDecl) || - isa(MemDecl) || - (isa(MemDecl) && - isa( - cast(MemDecl)->getTemplatedDecl()))) + if (isa(MemDecl)) return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, CommaLocs, RParenLoc)); } // Determine whether this is a call to a pointer-to-member function. - if (BinaryOperator *BO = dyn_cast(Fn->IgnoreParens())) { + if (BinaryOperator *BO = dyn_cast(NakedFn)) { if (BO->getOpcode() == BinaryOperator::PtrMemD || BO->getOpcode() == BinaryOperator::PtrMemI) { if (const FunctionProtoType *FPT = diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 0b3426b2f3..00fb65df92 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2236,9 +2236,6 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { /// /// FIXME: Should Objective-C also use this approach? /// -/// \param SS if non-NULL, the C++ nested-name-specifier that precedes the -/// name of the declaration referenced. -/// /// \param D the declaration being referenced from the current scope. /// /// \param NameLoc the location of the name in the source. @@ -2247,16 +2244,11 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { /// access, will be set to the type of the "this" pointer to be used when /// building that implicit member access. /// -/// \param MemberType if the reference to this declaration is an implicit -/// member access, will be set to the type of the member being referenced -/// (for use at the type of the resulting member access expression). -/// /// \returns true if this is an implicit member reference (in which case /// \p ThisType and \p MemberType will be set), or false if it is not an /// implicit member reference. -bool Sema::isImplicitMemberReference(const CXXScopeSpec &SS, NamedDecl *D, - SourceLocation NameLoc, QualType &ThisType, - QualType &MemberType) { +bool Sema::isImplicitMemberReference(const LookupResult &R, + QualType &ThisType) { // If this isn't a C++ method, then it isn't an implicit member reference. CXXMethodDecl *MD = dyn_cast(CurContext); if (!MD || MD->isStatic()) @@ -2269,33 +2261,21 @@ bool Sema::isImplicitMemberReference(const CXXScopeSpec &SS, NamedDecl *D, // class member access expression (5.2.5) using (*this) (9.3.2) // as the postfix-expression to the left of the '.' operator. DeclContext *Ctx = 0; - if (FieldDecl *FD = dyn_cast(D)) { + if (R.isUnresolvableResult()) { + // FIXME: this is just picking one at random + Ctx = R.getRepresentativeDecl()->getDeclContext(); + } else if (FieldDecl *FD = R.getAsSingle()) { Ctx = FD->getDeclContext(); - MemberType = FD->getType(); - - if (const ReferenceType *RefType = MemberType->getAs()) - MemberType = RefType->getPointeeType(); - else if (!FD->isMutable()) - MemberType - = Context.getQualifiedType(MemberType, - Qualifiers::fromCVRMask(MD->getTypeQualifiers())); - } else if (isa(D)) { - Ctx = D->getDeclContext(); - MemberType = Context.DependentTy; } else { - for (OverloadIterator Ovl(D), OvlEnd; Ovl != OvlEnd; ++Ovl) { - CXXMethodDecl *Method = dyn_cast(*Ovl); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + CXXMethodDecl *Method = dyn_cast(*I); FunctionTemplateDecl *FunTmpl = 0; - if (!Method && (FunTmpl = dyn_cast(*Ovl))) + if (!Method && (FunTmpl = dyn_cast(*I))) Method = dyn_cast(FunTmpl->getTemplatedDecl()); // FIXME: Do we have to know if there are explicit template arguments? if (Method && !Method->isStatic()) { Ctx = Method->getParent(); - if (isa(D) && !FunTmpl) - MemberType = Method->getType(); - else - MemberType = Context.OverloadTy; break; } } @@ -2307,6 +2287,8 @@ bool Sema::isImplicitMemberReference(const CXXScopeSpec &SS, NamedDecl *D, // Determine whether the declaration(s) we found are actually in a base // class. If not, this isn't an implicit member reference. ThisType = MD->getThisType(Context); + + // FIXME: this doesn't really work for overloaded lookups. QualType CtxType = Context.getTypeDeclType(cast(Ctx)); QualType ClassType diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 6b1857a0dc..6ea6a14557 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4341,9 +4341,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, llvm::SmallVector Fns; - // Try to dig out the overloaded function. - OverloadedFunctionDecl *Ovl = 0; - FunctionTemplateDecl *FunctionTemplate = 0; + // Look into the overloaded expression. if (UnresolvedLookupExpr *UL = dyn_cast(OvlExpr)) { Fns.append(UL->decls_begin(), UL->decls_end()); @@ -4351,17 +4349,15 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, HasExplicitTemplateArgs = true; UL->copyTemplateArgumentsInto(ExplicitTemplateArgs); } - } else if (MemberExpr *ME = dyn_cast(OvlExpr)) { - Ovl = dyn_cast(ME->getMemberDecl()); - FunctionTemplate = dyn_cast(ME->getMemberDecl()); - HasExplicitTemplateArgs = ME->hasExplicitTemplateArgumentList(); - if (HasExplicitTemplateArgs) + } else if (UnresolvedMemberExpr *ME + = dyn_cast(OvlExpr)) { + Fns.append(ME->decls_begin(), ME->decls_end()); + if (ME->hasExplicitTemplateArgs()) { + HasExplicitTemplateArgs = true; ME->copyTemplateArgumentsInto(ExplicitTemplateArgs); + } } - if (Ovl) Fns.append(Ovl->function_begin(), Ovl->function_end()); - if (FunctionTemplate) Fns.push_back(FunctionTemplate); - // If we didn't actually find anything, we're done. if (Fns.empty()) return 0; @@ -5133,29 +5129,34 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, SourceLocation RParenLoc) { // Dig out the member expression. This holds both the object // argument and the member function we're referring to. - MemberExpr *MemExpr = 0; - if (ParenExpr *ParenE = dyn_cast(MemExprE)) - MemExpr = dyn_cast(ParenE->getSubExpr()); - else - MemExpr = dyn_cast(MemExprE); - assert(MemExpr && "Building member call without member expression"); - + Expr *NakedMemExpr = MemExprE->IgnoreParens(); + // Extract the object argument. - Expr *ObjectArg = MemExpr->getBase(); + Expr *ObjectArg; + MemberExpr *MemExpr; CXXMethodDecl *Method = 0; - if (isa(MemExpr->getMemberDecl()) || - isa(MemExpr->getMemberDecl())) { + if (isa(NakedMemExpr)) { + MemExpr = cast(NakedMemExpr); + ObjectArg = MemExpr->getBase(); + Method = cast(MemExpr->getMemberDecl()); + } else { + UnresolvedMemberExpr *UnresExpr = cast(NakedMemExpr); + ObjectArg = UnresExpr->getBase(); + // Add overload candidates OverloadCandidateSet CandidateSet; - DeclarationName DeclName = MemExpr->getMemberDecl()->getDeclName(); - for (OverloadIterator Func(MemExpr->getMemberDecl()), FuncEnd; - Func != FuncEnd; ++Func) { - if ((Method = dyn_cast(*Func))) { + for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(), + E = UnresExpr->decls_end(); I != E; ++I) { + + // TODO: note if we found something through a using declaration + NamedDecl *Func = (*I)->getUnderlyingDecl(); + + if ((Method = dyn_cast(Func))) { // If explicit template arguments were provided, we can't call a // non-template member function. - if (MemExpr->hasExplicitTemplateArgumentList()) + if (UnresExpr->hasExplicitTemplateArgs()) continue; AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, @@ -5163,11 +5164,11 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, } else { // FIXME: avoid copy. TemplateArgumentListInfo TemplateArgs; - if (MemExpr->hasExplicitTemplateArgumentList()) - MemExpr->copyTemplateArgumentsInto(TemplateArgs); + if (UnresExpr->hasExplicitTemplateArgs()) + UnresExpr->copyTemplateArgumentsInto(TemplateArgs); - AddMethodTemplateCandidate(cast(*Func), - (MemExpr->hasExplicitTemplateArgumentList() + AddMethodTemplateCandidate(cast(Func), + (UnresExpr->hasExplicitTemplateArgs() ? &TemplateArgs : 0), ObjectArg, Args, NumArgs, CandidateSet, @@ -5175,14 +5176,16 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, } } + DeclarationName DeclName = UnresExpr->getMemberName(); + OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, MemExpr->getLocStart(), Best)) { + switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) { case OR_Success: Method = cast(Best->Function); break; case OR_No_Viable_Function: - Diag(MemExpr->getSourceRange().getBegin(), + Diag(UnresExpr->getMemberLoc(), diag::err_ovl_no_viable_member_function_in_call) << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); @@ -5190,16 +5193,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, return true; case OR_Ambiguous: - Diag(MemExpr->getSourceRange().getBegin(), - diag::err_ovl_ambiguous_member_call) + Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call) << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! return true; case OR_Deleted: - Diag(MemExpr->getSourceRange().getBegin(), - diag::err_ovl_deleted_member_call) + Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call) << Best->Function->isDeleted() << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); @@ -5208,13 +5209,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, } MemExprE = FixOverloadedFunctionReference(MemExprE, Method); - if (ParenExpr *ParenE = dyn_cast(MemExprE)) - MemExpr = dyn_cast(ParenE->getSubExpr()); - else - MemExpr = dyn_cast(MemExprE); - - } else { - Method = dyn_cast(MemExpr->getMemberDecl()); + MemExpr = cast(MemExprE->IgnoreParens()); } assert(Method && "Member call to something that isn't a method?"); @@ -5660,15 +5655,10 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { Fn->getType()); } - - if (MemberExpr *MemExpr = dyn_cast(E)) { - assert((isa(MemExpr->getMemberDecl()) || - isa(MemExpr->getMemberDecl()) || - isa(MemExpr->getMemberDecl())) && - "Expected member function or member function template"); + if (UnresolvedMemberExpr *MemExpr = dyn_cast(E)) { // FIXME: avoid copy. TemplateArgumentListInfo TemplateArgs; - if (MemExpr->hasExplicitTemplateArgumentList()) + if (MemExpr->hasExplicitTemplateArgs()) MemExpr->copyTemplateArgumentsInto(TemplateArgs); return MemberExpr::Create(Context, MemExpr->getBase()->Retain(), @@ -5677,7 +5667,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { MemExpr->getQualifierRange(), Fn, MemExpr->getMemberLoc(), - (MemExpr->hasExplicitTemplateArgumentList() + (MemExpr->hasExplicitTemplateArgs() ? &TemplateArgs : 0), Fn->getType()); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index e397c2b294..28b2174035 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -867,13 +867,10 @@ public: = SemaRef.Context.DeclarationNames.getCXXDestructorName( SemaRef.Context.getCanonicalType(DestroyedType)); - return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), - OperatorLoc, - isArrow? tok::arrow : tok::period, - DestroyedTypeLoc, - Name, - Sema::DeclPtrTy::make((Decl *)0), - &SS); + return getSema().BuildMemberReferenceExpr(move(Base), OperatorLoc, isArrow, + SS, /*FIXME: FirstQualifier*/ 0, + Name, DestroyedTypeLoc, + /*TemplateArgs*/ 0); } /// \brief Build a new unary operator expression. @@ -967,14 +964,10 @@ public: SS.setScopeRep(Qualifier); } - return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc, - isArrow? tok::arrow : tok::period, - MemberLoc, - Member->getDeclName(), - ExplicitTemplateArgs, - /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0), - &SS, - FirstQualifierInScope); + return getSema().BuildMemberReferenceExpr(move(Base), OpLoc, isArrow, + SS, FirstQualifierInScope, + Member->getDeclName(), MemberLoc, + ExplicitTemplateArgs); } /// \brief Build a new binary operator expression. @@ -1049,10 +1042,13 @@ public: SourceLocation OpLoc, SourceLocation AccessorLoc, IdentifierInfo &Accessor) { - return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc, - tok::period, AccessorLoc, + CXXScopeSpec SS; + return getSema().BuildMemberReferenceExpr(move(Base), + OpLoc, /*IsArrow*/ false, + SS, /*FirstQualifierInScope*/ 0, DeclarationName(&Accessor), - /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0)); + AccessorLoc, + /* TemplateArgs */ 0); } /// \brief Build a new initializer list expression. @@ -1530,67 +1526,38 @@ public: SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, + NamedDecl *FirstQualifierInScope, DeclarationName Name, SourceLocation MemberLoc, - NamedDecl *FirstQualifierInScope) { - OwningExprResult Base = move(BaseE); - tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period; - + const TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; SS.setRange(QualifierRange); SS.setScopeRep(Qualifier); - return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, - move(Base), OperatorLoc, OpKind, - MemberLoc, - Name, - /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0), - &SS, - FirstQualifierInScope); + return SemaRef.BuildMemberReferenceExpr(move(BaseE), OperatorLoc, IsArrow, + SS, FirstQualifierInScope, + Name, MemberLoc, TemplateArgs); } - /// \brief Build a new member reference expression with explicit template - /// arguments. + /// \brief Build a new member reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildCXXDependentScopeMemberExpr(ExprArg BaseE, - bool IsArrow, - SourceLocation OperatorLoc, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - TemplateName Template, - SourceLocation TemplateNameLoc, - NamedDecl *FirstQualifierInScope, - const TemplateArgumentListInfo &TemplateArgs) { + OwningExprResult RebuildUnresolvedMemberExpr(ExprArg BaseE, + SourceLocation OperatorLoc, + bool IsArrow, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs) { OwningExprResult Base = move(BaseE); - tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period; CXXScopeSpec SS; SS.setRange(QualifierRange); SS.setScopeRep(Qualifier); - // FIXME: We're going to end up looking up the template based on its name, - // twice! Also, duplicates part of Sema::BuildMemberAccessExpr. - DeclarationName Name; - if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl()) - Name = ActualTemplate->getDeclName(); - else if (OverloadedFunctionDecl *Ovl - = Template.getAsOverloadedFunctionDecl()) - Name = Ovl->getDeclName(); - else { - DependentTemplateName *DTN = Template.getAsDependentTemplateName(); - if (DTN->isIdentifier()) - Name = DTN->getIdentifier(); - else - Name = SemaRef.Context.DeclarationNames.getCXXOperatorName( - DTN->getOperator()); - } - return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, move(Base), - OperatorLoc, OpKind, - TemplateNameLoc, Name, - &TemplateArgs, - Sema::DeclPtrTy(), &SS); + return SemaRef.BuildMemberReferenceExpr(move(Base), OperatorLoc, IsArrow, + SS, R, TemplateArgs); } /// \brief Build a new Objective-C @encode expression. @@ -4903,28 +4870,12 @@ TreeTransform::TransformCXXDependentScopeMemberExpr( E->getOperatorLoc(), Qualifier, E->getQualifierRange(), + FirstQualifierInScope, Name, E->getMemberLoc(), - FirstQualifierInScope); + /*TemplateArgs*/ 0); } - // FIXME: This is an ugly hack, which forces the same template name to - // be looked up multiple times. Yuck! - TemporaryBase Rebase(*this, E->getMemberLoc(), DeclarationName()); - TemplateName OrigTemplateName; - if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) - OrigTemplateName = SemaRef.Context.getDependentTemplateName(0, II); - else - OrigTemplateName - = SemaRef.Context.getDependentTemplateName(0, - Name.getCXXOverloadedOperator()); - - TemplateName Template - = getDerived().TransformTemplateName(OrigTemplateName, - QualType::getFromOpaquePtr(ObjectType)); - if (Template.isNull()) - return SemaRef.ExprError(); - TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { TemplateArgumentLoc Loc; @@ -4938,10 +4889,75 @@ TreeTransform::TransformCXXDependentScopeMemberExpr( E->getOperatorLoc(), Qualifier, E->getQualifierRange(), - Template, - E->getMemberLoc(), FirstQualifierInScope, - TransArgs); + Name, + E->getMemberLoc(), + &TransArgs); +} + +template +Sema::OwningExprResult +TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old, + bool isAddressOfOperand) { + // Transform the base of the expression. + OwningExprResult Base = getDerived().TransformExpr(Old->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + NestedNameSpecifier *Qualifier = 0; + if (Old->getQualifier()) { + Qualifier + = getDerived().TransformNestedNameSpecifier(Old->getQualifier(), + Old->getQualifierRange()); + if (Qualifier == 0) + return SemaRef.ExprError(); + } + + LookupResult R(SemaRef, Old->getMemberName(), Old->getMemberLoc(), + Sema::LookupOrdinaryName); + + // Transform all the decls. + for (UnresolvedMemberExpr::decls_iterator I = Old->decls_begin(), + E = Old->decls_end(); I != E; ++I) { + NamedDecl *InstD = static_cast(getDerived().TransformDecl(*I)); + if (!InstD) + return SemaRef.ExprError(); + + // Expand using declarations. + if (isa(InstD)) { + UsingDecl *UD = cast(InstD); + for (UsingDecl::shadow_iterator I = UD->shadow_begin(), + E = UD->shadow_end(); I != E; ++I) + R.addDecl(*I); + continue; + } + + R.addDecl(InstD); + } + + R.resolveKind(); + + TemplateArgumentListInfo TransArgs; + if (Old->hasExplicitTemplateArgs()) { + TransArgs.setLAngleLoc(Old->getLAngleLoc()); + TransArgs.setRAngleLoc(Old->getRAngleLoc()); + for (unsigned I = 0, N = Old->getNumTemplateArgs(); I != N; ++I) { + TemplateArgumentLoc Loc; + if (getDerived().TransformTemplateArgument(Old->getTemplateArgs()[I], + Loc)) + return SemaRef.ExprError(); + TransArgs.addArgument(Loc); + } + } + + return getDerived().RebuildUnresolvedMemberExpr(move(Base), + Old->getOperatorLoc(), + Old->isArrow(), + Qualifier, + Old->getQualifierRange(), + R, + (Old->hasExplicitTemplateArgs() + ? &TransArgs : 0)); } template diff --git a/test/SemaCXX/qual-id-test.cpp b/test/SemaCXX/qual-id-test.cpp index ecb6aa9b35..02e69996c7 100644 --- a/test/SemaCXX/qual-id-test.cpp +++ b/test/SemaCXX/qual-id-test.cpp @@ -48,7 +48,7 @@ namespace C a.A::sub::x(); a.A::B::base::x(); - a.bad::x(); // expected-error{{type 'struct bad' is not a direct or virtual base of ''struct A::sub''}} + a.bad::x(); // expected-error{{type 'struct bad' is not a direct or virtual base of ''A::sub''}} a->foo(); a->member::foo(); @@ -69,7 +69,7 @@ namespace C a->A::sub::x(); a->A::B::base::x(); - a->bad::x(); // expected-error{{type 'struct bad' is not a direct or virtual base of ''struct A::sub''}} + a->bad::x(); // expected-error{{type 'struct bad' is not a direct or virtual base of ''A::sub''}} (*a)->foo(); (*a)->member::foo(); diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp index a82e84d36c..2351d882f9 100644 --- a/test/SemaTemplate/instantiate-method.cpp +++ b/test/SemaTemplate/instantiate-method.cpp @@ -95,7 +95,9 @@ struct X0 : X0Base { template struct X1 : X0 { int &f2() { - return X0Base::f(); // expected-error{{call to non-static member function without an object argument}} + // FIXME: We should be able to do this lookup and diagnose the error + // *despite* the fact that we can't decide the relationship yet. + return X0Base::f(); // expected-FIXME-error{{call to non-static member function without an object argument}} } };