diff options
-rw-r--r-- | clang/include/clang/AST/ExprCXX.h | 125 | ||||
-rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 45 | ||||
-rw-r--r-- | clang/lib/AST/StmtPrinter.cpp | 16 | ||||
-rw-r--r-- | clang/lib/AST/StmtProfile.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 17 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 517 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 117 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 86 | ||||
-rw-r--r-- | clang/test/SemaTemplate/instantiate-method.cpp | 4 | ||||
-rw-r--r-- | clang/test/SemaTemplate/qualified-id.cpp | 11 |
11 files changed, 647 insertions, 315 deletions
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 23844ce5d96..66f4b5d2b5c 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -1410,18 +1410,26 @@ public: /// \brief Represents a C++ member access expression where the actual /// member referenced could not be resolved because the base /// expression or the member name was dependent. +/// +/// Like UnresolvedMemberExprs, these can be either implicit or +/// explicit accesses. It is only possible to get one of these with +/// an implicit access if a qualifier is provided. class CXXDependentScopeMemberExpr : public Expr { /// \brief The expression for the base pointer or class reference, - /// e.g., the \c x in x.f. + /// e.g., the \c x in x.f. Can be null in implicit accesses. Stmt *Base; + /// \brief The type of the base expression. Never null, even for + /// implicit accesses. + QualType BaseType; + /// \brief Whether this member expression used the '->' operator or /// the '.' operator. bool IsArrow : 1; /// \brief Whether this member expression has explicitly-specified template /// arguments. - bool HasExplicitTemplateArgumentList : 1; + bool HasExplicitTemplateArgs : 1; /// \brief The location of the '->' or '.' operator. SourceLocation OperatorLoc; @@ -1452,9 +1460,7 @@ class CXXDependentScopeMemberExpr : public Expr { /// \brief Retrieve the explicit template argument list that followed the /// member template name, if any. ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() { - if (!HasExplicitTemplateArgumentList) - return 0; - + assert(HasExplicitTemplateArgs); return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1); } @@ -1466,7 +1472,7 @@ class CXXDependentScopeMemberExpr : public Expr { } CXXDependentScopeMemberExpr(ASTContext &C, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -1477,7 +1483,8 @@ class CXXDependentScopeMemberExpr : public Expr { public: CXXDependentScopeMemberExpr(ASTContext &C, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, + bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -1485,15 +1492,15 @@ public: DeclarationName Member, SourceLocation MemberLoc) : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true), - Base(Base), IsArrow(IsArrow), HasExplicitTemplateArgumentList(false), - OperatorLoc(OperatorLoc), + Base(Base), BaseType(BaseType), IsArrow(IsArrow), + HasExplicitTemplateArgs(false), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), FirstQualifierFoundInScope(FirstQualifierFoundInScope), Member(Member), MemberLoc(MemberLoc) { } static CXXDependentScopeMemberExpr * Create(ASTContext &C, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -1502,11 +1509,21 @@ public: SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs); + /// \brief True if this is an implicit access, i.e. one in which the + /// member being accessed was not written in the source. The source + /// location of the operator is invalid in this case. + bool isImplicitAccess() const { return Base == 0; } + /// \brief Retrieve the base object of this member expressions, /// e.g., the \c x in \c x.m. - Expr *getBase() { return cast<Expr>(Base); } + Expr *getBase() const { + assert(!isImplicitAccess()); + return cast<Expr>(Base); + } void setBase(Expr *E) { Base = E; } + QualType getBaseType() const { return BaseType; } + /// \brief Determine whether this member expression used the '->' /// operator; otherwise, it used the '.' operator. bool isArrow() const { return IsArrow; } @@ -1551,60 +1568,59 @@ public: /// \brief Determines whether this member expression actually had a C++ /// template argument list explicitly specified, e.g., x.f<int>. - bool hasExplicitTemplateArgumentList() const { - return HasExplicitTemplateArgumentList; + bool hasExplicitTemplateArgs() const { + return HasExplicitTemplateArgs; } /// \brief Copies the template arguments (if present) into the given /// structure. void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { - if (hasExplicitTemplateArgumentList()) - getExplicitTemplateArgumentList()->copyInto(List); + assert(HasExplicitTemplateArgs); + getExplicitTemplateArgumentList()->copyInto(List); } /// \brief Retrieve the location of the left angle bracket following the /// member name ('<'), if any. SourceLocation getLAngleLoc() const { - if (!HasExplicitTemplateArgumentList) - return SourceLocation(); - + assert(HasExplicitTemplateArgs); return getExplicitTemplateArgumentList()->LAngleLoc; } /// \brief Retrieve the template arguments provided as part of this /// template-id. const TemplateArgumentLoc *getTemplateArgs() const { - if (!HasExplicitTemplateArgumentList) - return 0; - + assert(HasExplicitTemplateArgs); return getExplicitTemplateArgumentList()->getTemplateArgs(); } /// \brief Retrieve the number of template arguments provided as part of this /// template-id. unsigned getNumTemplateArgs() const { - if (!HasExplicitTemplateArgumentList) - return 0; - + assert(HasExplicitTemplateArgs); return getExplicitTemplateArgumentList()->NumTemplateArgs; } /// \brief Retrieve the location of the right angle bracket following the /// template arguments ('>'). SourceLocation getRAngleLoc() const { - if (!HasExplicitTemplateArgumentList) - return SourceLocation(); - + assert(HasExplicitTemplateArgs); return getExplicitTemplateArgumentList()->RAngleLoc; } virtual SourceRange getSourceRange() const { - if (HasExplicitTemplateArgumentList) - return SourceRange(Base->getSourceRange().getBegin(), - getRAngleLoc()); + SourceRange Range; + if (!isImplicitAccess()) + Range.setBegin(Base->getSourceRange().getBegin()); + else if (getQualifier()) + Range.setBegin(getQualifierRange().getBegin()); + else + Range.setBegin(MemberLoc); - return SourceRange(Base->getSourceRange().getBegin(), - MemberLoc); + if (hasExplicitTemplateArgs()) + Range.setEnd(getRAngleLoc()); + else + Range.setEnd(MemberLoc); + return Range; } static bool classof(const Stmt *T) { @@ -1618,17 +1634,31 @@ public: }; /// \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. +/// produced a set of overloaded functions. +/// +/// The member access may be explicit or implicit: +/// struct A { +/// int a, b; +/// int explicitAccess() { return this->a + this->A::b; } +/// int implicitAccess() { return a + A::b; } +/// }; +/// +/// In the final AST, an explicit access always becomes a MemberExpr. +/// An implicit access may become either a MemberExpr or a +/// DeclRefExpr, depending on whether the member is static. 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. + /// e.g., the \c x in x.f. This can be null if this is an 'unbased' + /// member expression Stmt *Base; + /// \brief The type of the base expression; never null. + QualType BaseType; + /// \brief Whether this member expression used the '->' operator or /// the '.' operator. bool IsArrow : 1; @@ -1672,7 +1702,7 @@ class UnresolvedMemberExpr : public Expr { UnresolvedMemberExpr(QualType T, bool Dependent, bool HasUnresolvedUsing, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -1683,7 +1713,7 @@ class UnresolvedMemberExpr : public Expr { public: static UnresolvedMemberExpr * Create(ASTContext &C, bool Dependent, bool HasUnresolvedUsing, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -1704,11 +1734,21 @@ public: unsigned getNumDecls() const { return Results.size(); } + /// \brief True if this is an implicit access, i.e. one in which the + /// member being accessed was not written in the source. The source + /// location of the operator is invalid in this case. + bool isImplicitAccess() const { return Base == 0; } + /// \brief Retrieve the base object of this member expressions, /// e.g., the \c x in \c x.m. - Expr *getBase() { return cast<Expr>(Base); } + Expr *getBase() { + assert(!isImplicitAccess()); + return cast<Expr>(Base); + } void setBase(Expr *E) { Base = E; } + QualType getBaseType() const { return BaseType; } + /// \brief Determine whether this member expression used the '->' /// operator; otherwise, it used the '.' operator. bool isArrow() const { return IsArrow; } @@ -1772,7 +1812,14 @@ public: } virtual SourceRange getSourceRange() const { - SourceRange Range = Base->getSourceRange(); + SourceRange Range; + if (!isImplicitAccess()) + Range.setBegin(Base->getSourceRange().getBegin()); + else if (getQualifier()) + Range.setBegin(getQualifierRange().getBegin()); + else + Range.setBegin(MemberLoc); + if (hasExplicitTemplateArgs()) Range.setEnd(getRAngleLoc()); else diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index d1a0390a0a6..7a6fbdca8bc 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -518,7 +518,8 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() { } CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, + bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -527,8 +528,8 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs) : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true), - Base(Base), IsArrow(IsArrow), - HasExplicitTemplateArgumentList(TemplateArgs), + Base(Base), BaseType(BaseType), IsArrow(IsArrow), + HasExplicitTemplateArgs(TemplateArgs != 0), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), FirstQualifierFoundInScope(FirstQualifierFoundInScope), @@ -539,7 +540,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, CXXDependentScopeMemberExpr * CXXDependentScopeMemberExpr::Create(ASTContext &C, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -548,22 +549,22 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C, SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs) { if (!TemplateArgs) - return new (C) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc, - Qualifier, QualifierRange, - FirstQualifierFoundInScope, - Member, MemberLoc); + return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType, + IsArrow, OperatorLoc, + Qualifier, QualifierRange, + FirstQualifierFoundInScope, + Member, MemberLoc); std::size_t size = sizeof(CXXDependentScopeMemberExpr); if (TemplateArgs) size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); void *Mem = C.Allocate(size, llvm::alignof<CXXDependentScopeMemberExpr>()); - return new (Mem) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc, - Qualifier, QualifierRange, - FirstQualifierFoundInScope, - Member, - MemberLoc, - TemplateArgs); + return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType, + IsArrow, OperatorLoc, + Qualifier, QualifierRange, + FirstQualifierFoundInScope, + Member, MemberLoc, TemplateArgs); } Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() { @@ -571,12 +572,15 @@ Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() { } Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() { + if (isImplicitAccess()) + return child_iterator(&Base); return child_iterator(&Base + 1); } UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, bool HasUnresolvedUsing, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, + bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -584,7 +588,8 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs) : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent), - Base(Base), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), + Base(Base), BaseType(BaseType), IsArrow(IsArrow), + HasUnresolvedUsing(HasUnresolvedUsing), HasExplicitTemplateArgs(TemplateArgs != 0), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), @@ -596,7 +601,7 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, UnresolvedMemberExpr * UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, bool HasUnresolvedUsing, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -610,8 +615,8 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>()); return new (Mem) UnresolvedMemberExpr( Dependent ? C.DependentTy : C.OverloadTy, - Dependent, HasUnresolvedUsing, Base, IsArrow, - OperatorLoc, Qualifier, QualifierRange, + Dependent, HasUnresolvedUsing, Base, BaseType, + IsArrow, OperatorLoc, Qualifier, QualifierRange, Member, MemberLoc, TemplateArgs); } @@ -620,5 +625,7 @@ Stmt::child_iterator UnresolvedMemberExpr::child_begin() { } Stmt::child_iterator UnresolvedMemberExpr::child_end() { + if (isImplicitAccess()) + return child_iterator(&Base); return child_iterator(&Base + 1); } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 205ea0d182d..a7e42af04d8 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1145,17 +1145,19 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr( void StmtPrinter::VisitCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *Node) { - PrintExpr(Node->getBase()); - OS << (Node->isArrow() ? "->" : "."); + if (!Node->isImplicitAccess()) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); - else if (Node->hasExplicitTemplateArgumentList()) + else if (Node->hasExplicitTemplateArgs()) // FIXME: Track use of "template" keyword explicitly? OS << "template "; OS << Node->getMember().getAsString(); - if (Node->hasExplicitTemplateArgumentList()) { + if (Node->hasExplicitTemplateArgs()) { OS << TemplateSpecializationType::PrintTemplateArgumentList( Node->getTemplateArgs(), Node->getNumTemplateArgs(), @@ -1164,8 +1166,10 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr( } void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { - PrintExpr(Node->getBase()); - OS << (Node->isArrow() ? "->" : "."); + if (!Node->isImplicitAccess()) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index d832a4649e7..1b6b022901e 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -554,18 +554,24 @@ StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) { void StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) { - VisitExpr(S); - ID.AddBoolean(S->isArrow()); + ID.AddBoolean(S->isImplicitAccess()); + if (!S->isImplicitAccess()) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + } VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getMember()); - ID.AddBoolean(S->hasExplicitTemplateArgumentList()); - if (S->hasExplicitTemplateArgumentList()) + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) { - VisitExpr(S); - ID.AddBoolean(S->isArrow()); + ID.AddBoolean(S->isImplicitAccess()); + if (!S->isImplicitAccess()) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + } VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getMemberName()); ID.AddBoolean(S->hasExplicitTemplateArgs()); diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index f961406e3e5..4b437995f15 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1023,7 +1023,7 @@ public: SourceLocation RLoc, ExprArg Base,ExprArg Idx); - ExprResult + OwningExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, @@ -1451,9 +1451,10 @@ public: FieldDecl *Field, Expr *BaseObjectExpr = 0, SourceLocation OpLoc = SourceLocation()); - OwningExprResult BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs); + OwningExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + bool IsDefiniteInstance); bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R, bool HasTrailingLParen); @@ -1525,6 +1526,7 @@ public: SourceLocation RLoc); OwningExprResult BuildMemberReferenceExpr(ExprArg Base, + QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, @@ -1534,6 +1536,7 @@ public: const TemplateArgumentListInfo *TemplateArgs); OwningExprResult BuildMemberReferenceExpr(ExprArg Base, + QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, LookupResult &R, @@ -1551,6 +1554,7 @@ public: const LookupResult &R); OwningExprResult ActOnDependentMemberExpr(ExprArg Base, + QualType BaseType, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, @@ -1592,6 +1596,11 @@ public: MultiExprArg Args, SourceLocation *CommaLocs, SourceLocation RParenLoc); + OwningExprResult BuildResolvedCallExpr(Expr *Fn, + NamedDecl *NDecl, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc); virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index bf14d0d3032..8e14fcdd6b2 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -703,18 +703,173 @@ static bool IsDependentIdExpression(Sema &SemaRef, const CXXScopeSpec &SS) { // We can't look into record types unless they're fully-formed. if (!IsFullyFormedScope(SemaRef, cast<CXXRecordDecl>(DC))) return true; - // We can always look into fully-formed record types, but if we're - // in a dependent but not fully-formed context, we can't decide - // whether the qualifier names a base class. We shouldn't be trying - // to decide that yet anyway, but we are, so we need to delay that - // decision. - CXXRecordDecl *CurRecord; - if (CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) - CurRecord = cast<CXXRecordDecl>(CurMethod->getParent()); - else - CurRecord = dyn_cast<CXXRecordDecl>(SemaRef.CurContext); + return false; +} + +/// Determines if the given class is provably not derived from all of +/// the prospective base classes. +static bool IsProvablyNotDerivedFrom(Sema &SemaRef, + CXXRecordDecl *Record, + const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) { + Record = Record->getCanonicalDecl(); + if (Bases.count(Record)) + return false; + + for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), + E = Record->bases_end(); I != E; ++I) { + CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType()); + CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>(); + if (!BaseRT) return false; + + CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl()); + if (!BaseRecord->isDefinition()) + return false; + + if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases)) + return false; + } + + return true; +} + +static bool IsInstanceMember(NamedDecl *D) { + assert(isa<CXXRecordDecl>(D->getDeclContext()) && + "checking whether non-member is instance member"); + + if (isa<FieldDecl>(D)) return true; + + if (isa<CXXMethodDecl>(D)) + return !cast<CXXMethodDecl>(D)->isStatic(); + + if (isa<FunctionTemplateDecl>(D)) { + D = cast<FunctionTemplateDecl>(D)->getTemplatedDecl(); + return !cast<CXXMethodDecl>(D)->isStatic(); + } + + return false; +} + +enum IMAKind { + /// The reference is definitely not an instance member access. + IMA_Static, + + /// The reference may be an implicit instance member access. + IMA_Mixed, + + /// The reference may be to an instance member, but it is invalid if + /// so, because the context is not an instance method. + IMA_Mixed_StaticContext, + + /// The reference may be to an instance member, but it is invalid if + /// so, because the context is from an unrelated class. + IMA_Mixed_Unrelated, + + /// The reference is definitely an implicit instance member access. + IMA_Instance, + + /// The reference may be to an unresolved using declaration. + IMA_Unresolved, + + /// The reference may be to an unresolved using declaration and the + /// context is not an instance method. + IMA_Unresolved_StaticContext, + + /// The reference is to a member of an anonymous structure in a + /// non-class context. + IMA_AnonymousMember, + + /// All possible referrents are instance members and the current + /// context is not an instance method. + IMA_Error_StaticContext, + + /// All possible referrents are instance members of an unrelated + /// class. + IMA_Error_Unrelated +}; - return CurRecord && !IsFullyFormedScope(SemaRef, CurRecord); +/// The given lookup names class member(s) and is not being used for +/// an address-of-member expression. Classify the type of access +/// according to whether it's possible that this reference names an +/// instance member. This is best-effort; it is okay to +/// conservatively answer "yes", in which case some errors will simply +/// not be caught until template-instantiation. +static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, + const LookupResult &R) { + assert(!R.empty() && isa<CXXRecordDecl>((*R.begin())->getDeclContext())); + + bool isStaticContext = + (!isa<CXXMethodDecl>(SemaRef.CurContext) || + cast<CXXMethodDecl>(SemaRef.CurContext)->isStatic()); + + if (R.isUnresolvableResult()) + return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; + + // Collect all the declaring classes of instance members we find. + bool hasNonInstance = false; + llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes; + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + NamedDecl *D = (*I)->getUnderlyingDecl(); + if (IsInstanceMember(D)) { + CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext()); + + // If this is a member of an anonymous record, move out to the + // innermost non-anonymous struct or union. If there isn't one, + // that's a special case. + while (R->isAnonymousStructOrUnion()) { + R = dyn_cast<CXXRecordDecl>(R->getParent()); + if (!R) return IMA_AnonymousMember; + } + Classes.insert(R->getCanonicalDecl()); + } + else + hasNonInstance = true; + } + + // If we didn't find any instance members, it can't be an implicit + // member reference. + if (Classes.empty()) + return IMA_Static; + + // If the current context is not an instance method, it can't be + // an implicit member reference. + if (isStaticContext) + return (hasNonInstance ? IMA_Mixed_StaticContext : IMA_Error_StaticContext); + + // If we can prove that the current context is unrelated to all the + // declaring classes, it can't be an implicit member reference (in + // which case it's an error if any of those members are selected). + if (IsProvablyNotDerivedFrom(SemaRef, + cast<CXXMethodDecl>(SemaRef.CurContext)->getParent(), + Classes)) + return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); + + return (hasNonInstance ? IMA_Mixed : IMA_Instance); +} + +/// Diagnose a reference to a field with no object available. +static void DiagnoseInstanceReference(Sema &SemaRef, + const CXXScopeSpec &SS, + const LookupResult &R) { + SourceLocation Loc = R.getNameLoc(); + SourceRange Range(Loc); + if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); + + if (R.getAsSingle<FieldDecl>()) { + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) { + if (MD->isStatic()) { + // "invalid use of member 'x' in static member function" + SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method) + << Range << R.getLookupName(); + return; + } + } + + SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use) + << R.getLookupName() << Range; + return; + } + + SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range; } Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, @@ -847,23 +1002,41 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, } } - // &SomeClass::foo is an abstract member reference, regardless of - // the nature of foo, but &SomeClass::foo(...) is not. If this is - // *not* an abstract member reference, and any of the results is a - // class member (which necessarily means they're all class members), - // then we make an implicit member reference instead. - // - // This check considers all the same information as the "needs ADL" - // check, but there's no simple logical relationship other than the - // fact that they can never be simultaneously true. We could - // calculate them both in one pass if that proves important for - // performance. - if (!ADL) { + // Check whether this might be a C++ implicit instance member access. + // C++ [expr.prim.general]p6: + // Within the definition of a non-static member function, an + // identifier that names a non-static member is transformed to a + // class member access expression. + // But note that &SomeClass::foo is grammatically distinct, even + // though we don't parse it that way. + if (!R.empty() && (*R.begin())->getDeclContext()->isRecord()) { bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty()); - if (!isAbstractMemberPointer && !R.empty() && - isa<CXXRecordDecl>((*R.begin())->getDeclContext())) { - return BuildImplicitMemberReferenceExpr(SS, R, TemplateArgs); + if (!isAbstractMemberPointer) { + switch (ClassifyImplicitMemberAccess(*this, R)) { + case IMA_Instance: + return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); + + case IMA_AnonymousMember: + assert(R.isSingleResult()); + return BuildAnonymousStructUnionMemberReference(R.getNameLoc(), + R.getAsSingle<FieldDecl>()); + + case IMA_Mixed: + case IMA_Mixed_Unrelated: + case IMA_Unresolved: + return BuildImplicitMemberExpr(SS, R, TemplateArgs, false); + + case IMA_Static: + case IMA_Mixed_StaticContext: + case IMA_Unresolved_StaticContext: + break; + + case IMA_Error_StaticContext: + case IMA_Error_Unrelated: + DiagnoseInstanceReference(*this, SS, R); + return ExprError(); + } } } @@ -1041,35 +1214,15 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, 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<FunctionTemplateDecl>(D)) - Method = cast<CXXMethodDecl>(cast<FunctionTemplateDecl>(D) - ->getTemplatedDecl()); - else if (isa<CXXMethodDecl>(D)) - Method = cast<CXXMethodDecl>(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. +/// Builds an implicit member access expression. The current context +/// is known to be an instance method, and the given unqualified lookup +/// set is known to contain only instance members, at least one of which +/// is from an appropriate type. Sema::OwningExprResult -Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs) { +Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + bool IsKnownInstance) { assert(!R.empty() && !R.isAmbiguous()); SourceLocation Loc = R.getNameLoc(); @@ -1082,44 +1235,18 @@ Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion()) return BuildAnonymousStructUnionMemberReference(Loc, FD); - QualType ThisType; - if (isImplicitMemberReference(R, ThisType)) { - Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); - return BuildMemberReferenceExpr(ExprArg(*this, This), - /*OpLoc*/ SourceLocation(), - /*IsArrow*/ true, - SS, R, TemplateArgs); + // If this is known to be an instance access, go ahead and build a + // 'this' expression now. + QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context); + Expr *This = 0; // null signifies implicit access + if (IsKnownInstance) { + This = new (Context) CXXThisExpr(SourceLocation(), ThisType); } - // Diagnose now if none of the available methods are static. - if (IsOnlyInstanceMethods(R)) - return ExprError(Diag(Loc, diag::err_member_call_without_object)); - - if (R.getAsSingle<FieldDecl>()) { - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { - if (MD->isStatic()) { - // "invalid use of member 'x' in static member function" - Diag(Loc, diag::err_invalid_member_use_in_static_method) - << R.getLookupName(); - return ExprError(); - } - } - - // Any other ways we could have found the field in a well-formed - // program would have been turned into implicit member expressions - // above. - Diag(Loc, diag::err_invalid_non_static_member_use) - << R.getLookupName(); - return ExprError(); - } - - // We're not in an implicit member-reference context, but the lookup - // results might not require an instance. Try to build a non-member - // decl reference. - if (TemplateArgs) - return BuildTemplateIdExpr(SS, R, /* ADL */ false, *TemplateArgs); - - return BuildDeclarationNameExpr(SS, R, /*ADL*/ false); + return BuildMemberReferenceExpr(ExprArg(*this, This), ThisType, + /*OpLoc*/ SourceLocation(), + /*IsArrow*/ true, + SS, R, TemplateArgs); } bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, @@ -1205,8 +1332,6 @@ Sema::OwningExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL) { - assert(R.getResultKind() != LookupResult::FoundUnresolvedValue); - // If this isn't an overloaded result and we don't need ADL, just // build an ordinary singleton decl ref. if (!NeedsADL && !R.isOverloadedResult()) @@ -1968,7 +2093,8 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy, } Sema::OwningExprResult -Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc, +Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType, + bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, DeclarationName Name, SourceLocation NameLoc, @@ -1985,20 +2111,21 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc, // 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<PointerType>(); + const PointerType *PT = BaseType->getAs<PointerType>(); if (PT && (!getLangOptions().ObjC1 || PT->getPointeeType()->isRecordType())) { + assert(BaseExpr && "cannot happen with implicit member accesses"); Diag(NameLoc, diag::err_typecheck_member_reference_struct_union) - << BaseExpr->getType() << BaseExpr->getSourceRange(); + << BaseType << BaseExpr->getSourceRange(); return ExprError(); } } - assert(BaseExpr->getType()->isDependentType()); + assert(BaseType->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, + return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType, IsArrow, OpLoc, static_cast<NestedNameSpecifier*>(SS.getScopeRep()), SS.getRange(), @@ -2041,34 +2168,71 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, const LookupResult &R) { - QualType BaseTypeCanon - = Context.getCanonicalType(BaseType).getUnqualifiedType(); - - bool FoundValid = false; + const RecordType *BaseRT = BaseType->getAs<RecordType>(); + if (!BaseRT) { + // We can't check this yet because the base type is still + // dependent. + assert(BaseType->isDependentType()); + return false; + } + CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl()); for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - TypeDecl* TyD = cast<TypeDecl>((*I)->getUnderlyingDecl()->getDeclContext()); - CanQualType MemberTypeCanon - = Context.getCanonicalType(Context.getTypeDeclType(TyD)); + // If this is an implicit member reference and we find a + // non-instance member, it's not an error. + if (!BaseExpr && !IsInstanceMember((*I)->getUnderlyingDecl())) + return false; - if (BaseTypeCanon == MemberTypeCanon || - IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) { - FoundValid = true; - break; - } + // Note that we use the DC of the decl, not the underlying decl. + CXXRecordDecl *RecordD = cast<CXXRecordDecl>((*I)->getDeclContext()); + while (RecordD->isAnonymousStructOrUnion()) + RecordD = cast<CXXRecordDecl>(RecordD->getParent()); + + llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord; + MemberRecord.insert(RecordD->getCanonicalDecl()); + + if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord)) + return false; } - if (!FoundValid) { - DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, + DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, Qualifier, QualifierRange, R); + return true; +} + +static bool +LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, + SourceRange BaseRange, const RecordType *RTy, + SourceLocation OpLoc, const CXXScopeSpec &SS) { + RecordDecl *RDecl = RTy->getDecl(); + if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), + PDiag(diag::err_typecheck_incomplete_tag) + << BaseRange)) return true; + + DeclContext *DC = RDecl; + if (SS.isSet()) { + // If the member name was a qualified-id, look into the + // nested-name-specifier. + DC = SemaRef.computeDeclContext(SS, false); + + assert(DC && "Cannot handle non-computable dependent contexts in lookup"); + + if (!isa<TypeDecl>(DC)) { + SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass) + << DC << SS.getRange(); + return true; + } } + // The record definition is complete, now look up the member. + SemaRef.LookupQualifiedName(R, DC); + return false; } Sema::OwningExprResult -Sema::BuildMemberReferenceExpr(ExprArg BaseArg, +Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, @@ -2076,38 +2240,52 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, const TemplateArgumentListInfo *TemplateArgs) { Expr *Base = BaseArg.takeAs<Expr>(); - if (Base->getType()->isDependentType()) - return ActOnDependentMemberExpr(ExprArg(*this, Base), + if (BaseType->isDependentType()) + return ActOnDependentMemberExpr(ExprArg(*this, Base), BaseType, 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(); - } + // Implicit member accesses. + if (!Base) { + QualType RecordTy = BaseType; + if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType(); + if (LookupMemberExprInRecord(*this, R, SourceRange(), + RecordTy->getAs<RecordType>(), + OpLoc, SS)) + return ExprError(); + + // Explicit member accesses. + } else { + OwningExprResult Result = + LookupMemberExpr(R, Base, IsArrow, OpLoc, + SS, FirstQualifierInScope, + /*ObjCImpDecl*/ DeclPtrTy()); - if (Result.get()) - return move(Result); + if (Result.isInvalid()) { + Owned(Base); + return ExprError(); + } + + if (Result.get()) + return move(Result); + } - return BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc, - IsArrow, SS, R, TemplateArgs); + return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType, + OpLoc, IsArrow, SS, R, TemplateArgs); } Sema::OwningExprResult -Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, - bool IsArrow, const CXXScopeSpec &SS, +Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, + SourceLocation OpLoc, bool IsArrow, + const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { Expr *BaseExpr = Base.takeAs<Expr>(); - QualType BaseType = BaseExpr->getType(); + QualType BaseType = BaseExprType; if (IsArrow) { assert(BaseType->isPointerType()); BaseType = BaseType->getAs<PointerType>()->getPointeeType(); @@ -2128,7 +2306,8 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, : BaseType->getAs<RecordType>()->getDecl()); Diag(R.getNameLoc(), diag::err_no_member) - << MemberName << DC << BaseExpr->getSourceRange(); + << MemberName << DC + << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); return ExprError(); } @@ -2142,15 +2321,15 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, // 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); + bool Dependent = + R.isUnresolvableResult() || + UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs); UnresolvedMemberExpr *MemExpr = UnresolvedMemberExpr::Create(Context, Dependent, R.isUnresolvableResult(), - BaseExpr, IsArrow, OpLoc, + BaseExpr, BaseExprType, + IsArrow, OpLoc, Qualifier, SS.getRange(), MemberName, MemberLoc, TemplateArgs); @@ -2171,6 +2350,15 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, if (MemberDecl->isInvalidDecl()) return ExprError(); + // Handle the implicit-member-access case. + if (!BaseExpr) { + // If this is not an instance member, convert to a non-member access. + if (!IsInstanceMember(MemberDecl)) + return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl); + + BaseExpr = new (Context) CXXThisExpr(SourceLocation(), BaseExprType); + } + bool ShouldCheckUse = true; if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) { // Don't diagnose the use of a virtual member function unless it's @@ -2403,31 +2591,9 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Handle field access to simple records. This also handles access // to fields of the ObjC 'id' struct. if (const RecordType *RTy = BaseType->getAs<RecordType>()) { - RecordDecl *RDecl = RTy->getDecl(); - if (RequireCompleteType(OpLoc, BaseType, - PDiag(diag::err_typecheck_incomplete_tag) - << BaseExpr->getSourceRange())) + if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(), + RTy, OpLoc, SS)) return ExprError(); - - DeclContext *DC = RDecl; - if (SS.isSet()) { - // If the member name was a qualified-id, look into the - // nested-name-specifier. - DC = computeDeclContext(SS, false); - - if (!isa<TypeDecl>(DC)) { - Diag(MemberLoc, diag::err_qualified_member_nonclass) - << DC << SS.getRange(); - return ExprError(); - } - - // FIXME: If DC is not computable, we should build a - // CXXDependentScopeMemberExpr. - assert(DC && "Cannot handle non-computable dependent contexts in lookup"); - } - - // The record definition is complete, now make sure the member is valid. - LookupQualifiedName(R, DC); return Owned((Expr*) 0); } @@ -2739,7 +2905,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, Expr *Base = BaseArg.takeAs<Expr>(); OwningExprResult Result(*this); if (Base->getType()->isDependentType()) { - Result = ActOnDependentMemberExpr(ExprArg(*this, Base), + Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(), IsArrow, OpLoc, SS, FirstQualifierInScope, Name, NameLoc, @@ -2772,8 +2938,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, } } - Result = BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc, - IsArrow, SS, R, TemplateArgs); + Result = BuildMemberReferenceExpr(ExprArg(*this, Base), Base->getType(), + OpLoc, IsArrow, SS, R, TemplateArgs); } return move(Result); @@ -3070,16 +3236,16 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, isa<FunctionTemplateDecl>(*MemE->decls_begin())); (void)MemE; - return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc)); + return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc); } // Determine whether this is a call to a member function. if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(NakedFn)) { NamedDecl *MemDecl = MemExpr->getMemberDecl(); if (isa<CXXMethodDecl>(MemDecl)) - return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc)); + return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc); } // Determine whether this is a call to a pointer-to-member function. @@ -3171,13 +3337,28 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, } else { assert(Fns.size() <= 1 && "overloaded without Overloaded flag"); if (Fns.empty()) - NDecl = FDecl = 0; + NDecl = 0; else { NDecl = Fns[0]; - FDecl = dyn_cast<FunctionDecl>(NDecl); } } + return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc); +} + +/// BuildCallExpr - Build a call to a resolved expression, i.e. an +/// expression not of \p OverloadTy. The expression should +/// unary-convert to an expression of function-pointer or +/// block-pointer type. +/// +/// \param NDecl the declaration being called, if available +Sema::OwningExprResult +Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc) { + FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl); + // Promote the function operand. UsualUnaryConversions(Fn); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 6ea6a145576..726e4a01a4d 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5122,7 +5122,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, /// parameter). The caller needs to validate that the member /// expression refers to a member function or an overloaded member /// function. -Sema::ExprResult +Sema::OwningExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, @@ -5131,22 +5131,35 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // argument and the member function we're referring to. Expr *NakedMemExpr = MemExprE->IgnoreParens(); - // Extract the object argument. - Expr *ObjectArg; - MemberExpr *MemExpr; CXXMethodDecl *Method = 0; if (isa<MemberExpr>(NakedMemExpr)) { MemExpr = cast<MemberExpr>(NakedMemExpr); - ObjectArg = MemExpr->getBase(); Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl()); } else { UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr); - ObjectArg = UnresExpr->getBase(); + + // Mock up an object argument. + Expr *ObjectArg; + if (UnresExpr->isImplicitAccess()) { + // It would be nice to avoid creating this, but the overload APIs are written + // to work on expressions. + ObjectArg = new(Context) CXXThisExpr(SourceLocation(), + UnresExpr->getBaseType()); + } else { + ObjectArg = UnresExpr->getBase(); + } // Add overload candidates OverloadCandidateSet CandidateSet; + // FIXME: avoid copy. + TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0; + if (UnresExpr->hasExplicitTemplateArgs()) { + UnresExpr->copyTemplateArgumentsInto(TemplateArgsBuffer); + TemplateArgs = &TemplateArgsBuffer; + } + for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(), E = UnresExpr->decls_end(); I != E; ++I) { @@ -5156,20 +5169,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, if ((Method = dyn_cast<CXXMethodDecl>(Func))) { // If explicit template arguments were provided, we can't call a // non-template member function. - if (UnresExpr->hasExplicitTemplateArgs()) + if (TemplateArgs) continue; AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); } else { - // FIXME: avoid copy. - TemplateArgumentListInfo TemplateArgs; - if (UnresExpr->hasExplicitTemplateArgs()) - UnresExpr->copyTemplateArgumentsInto(TemplateArgs); - AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func), - (UnresExpr->hasExplicitTemplateArgs() - ? &TemplateArgs : 0), + TemplateArgs, ObjectArg, Args, NumArgs, CandidateSet, /*SuppressUsedConversions=*/false); @@ -5190,14 +5197,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! - return true; + return ExprError(); case OR_Ambiguous: Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call) << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! - return true; + return ExprError(); case OR_Deleted: Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call) @@ -5205,16 +5212,29 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! - return true; + return ExprError(); } MemExprE = FixOverloadedFunctionReference(MemExprE, Method); + + // Clean up the 'this' expression we created above; FixOFR doesn't + // actually use it. + if (UnresExpr->isImplicitAccess()) + Owned(ObjectArg); + + // If overload resolution picked a static member, build a + // non-member call based on that function. + if (Method->isStatic()) { + return BuildResolvedCallExpr(MemExprE, Method, LParenLoc, + Args, NumArgs, RParenLoc); + } + MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens()); } assert(Method && "Member call to something that isn't a method?"); ExprOwningPtr<CXXMemberCallExpr> - TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExpr, Args, + TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs, Method->getResultType().getNonReferenceType(), RParenLoc)); @@ -5222,24 +5242,25 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // Check for a valid return type. if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(), TheCall.get(), Method)) - return true; + return ExprError(); // Convert the object argument (for a non-static member function call). + Expr *ObjectArg = MemExpr->getBase(); if (!Method->isStatic() && PerformObjectArgumentInitialization(ObjectArg, Method)) - return true; + return ExprError(); MemExpr->setBase(ObjectArg); // Convert the rest of the arguments const FunctionProtoType *Proto = cast<FunctionProtoType>(Method->getType()); if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs, RParenLoc)) - return true; + return ExprError(); if (CheckFunctionCall(Method, TheCall.get())) - return true; + return ExprError(); - return MaybeBindToTemporary(TheCall.release()).release(); + return MaybeBindToTemporary(TheCall.release()); } /// BuildCallToObjectOfClassType - Build a call to an object of class @@ -5632,19 +5653,11 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { } if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { + // FIXME: avoid copy. + TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0; if (ULE->hasExplicitTemplateArgs()) { - // FIXME: avoid copy. - TemplateArgumentListInfo TemplateArgs; - if (ULE->hasExplicitTemplateArgs()) - ULE->copyTemplateArgumentsInto(TemplateArgs); - - return DeclRefExpr::Create(Context, - ULE->getQualifier(), - ULE->getQualifierRange(), - Fn, - ULE->getNameLoc(), - Fn->getType(), - &TemplateArgs); + ULE->copyTemplateArgumentsInto(TemplateArgsBuffer); + TemplateArgs = &TemplateArgsBuffer; } return DeclRefExpr::Create(Context, @@ -5652,23 +5665,43 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { ULE->getQualifierRange(), Fn, ULE->getNameLoc(), - Fn->getType()); + Fn->getType(), + TemplateArgs); } if (UnresolvedMemberExpr *MemExpr = dyn_cast<UnresolvedMemberExpr>(E)) { // FIXME: avoid copy. - TemplateArgumentListInfo TemplateArgs; - if (MemExpr->hasExplicitTemplateArgs()) - MemExpr->copyTemplateArgumentsInto(TemplateArgs); + TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0; + if (MemExpr->hasExplicitTemplateArgs()) { + MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer); + TemplateArgs = &TemplateArgsBuffer; + } + + Expr *Base; + + // If we're filling in + if (MemExpr->isImplicitAccess()) { + if (cast<CXXMethodDecl>(Fn)->isStatic()) { + return DeclRefExpr::Create(Context, + MemExpr->getQualifier(), + MemExpr->getQualifierRange(), + Fn, + MemExpr->getMemberLoc(), + Fn->getType(), + TemplateArgs); + } else + Base = new (Context) CXXThisExpr(SourceLocation(), + MemExpr->getBaseType()); + } else + Base = MemExpr->getBase()->Retain(); - return MemberExpr::Create(Context, MemExpr->getBase()->Retain(), + return MemberExpr::Create(Context, Base, MemExpr->isArrow(), MemExpr->getQualifier(), MemExpr->getQualifierRange(), Fn, MemExpr->getMemberLoc(), - (MemExpr->hasExplicitTemplateArgs() - ? &TemplateArgs : 0), + TemplateArgs, Fn->getType()); } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f47577e9097..5f5d891a226 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -361,13 +361,13 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, QualType ThisType; if (CheckForImplicitMember && IsImplicitDependentMemberReference(*this, Qualifier, ThisType)) { - Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); - // Since the 'this' expression is synthesized, we don't need to // perform the double-lookup check. NamedDecl *FirstQualifierInScope = 0; - return Owned(CXXDependentScopeMemberExpr::Create(Context, This, true, + return Owned(CXXDependentScopeMemberExpr::Create(Context, + /*This*/ 0, ThisType, + /*IsArrow*/ true, /*Op*/ SourceLocation(), Qualifier, SS.getRange(), FirstQualifierInScope, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 28b21740356..145e3c70a64 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -863,11 +863,14 @@ public: SS.setScopeRep(Qualifier); } + QualType BaseType = ((Expr*) Base.get())->getType(); + DeclarationName Name = SemaRef.Context.DeclarationNames.getCXXDestructorName( SemaRef.Context.getCanonicalType(DestroyedType)); - return getSema().BuildMemberReferenceExpr(move(Base), OperatorLoc, isArrow, + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, + OperatorLoc, isArrow, SS, /*FIXME: FirstQualifier*/ 0, Name, DestroyedTypeLoc, /*TemplateArgs*/ 0); @@ -964,7 +967,11 @@ public: SS.setScopeRep(Qualifier); } - return getSema().BuildMemberReferenceExpr(move(Base), OpLoc, isArrow, + QualType BaseType = ((Expr*) Base.get())->getType(); + + // FIXME: wait, this is re-performing lookup? + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, + OpLoc, isArrow, SS, FirstQualifierInScope, Member->getDeclName(), MemberLoc, ExplicitTemplateArgs); @@ -1042,8 +1049,10 @@ public: SourceLocation OpLoc, SourceLocation AccessorLoc, IdentifierInfo &Accessor) { + CXXScopeSpec SS; - return getSema().BuildMemberReferenceExpr(move(Base), + QualType BaseType = ((Expr*) Base.get())->getType(); + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, OpLoc, /*IsArrow*/ false, SS, /*FirstQualifierInScope*/ 0, DeclarationName(&Accessor), @@ -1522,6 +1531,7 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXDependentScopeMemberExpr(ExprArg BaseE, + QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -1534,7 +1544,8 @@ public: SS.setRange(QualifierRange); SS.setScopeRep(Qualifier); - return SemaRef.BuildMemberReferenceExpr(move(BaseE), OperatorLoc, IsArrow, + return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType, + OperatorLoc, IsArrow, SS, FirstQualifierInScope, Name, MemberLoc, TemplateArgs); } @@ -1544,19 +1555,19 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildUnresolvedMemberExpr(ExprArg BaseE, + QualType BaseType, SourceLocation OperatorLoc, bool IsArrow, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { - OwningExprResult Base = move(BaseE); - CXXScopeSpec SS; SS.setRange(QualifierRange); SS.setScopeRep(Qualifier); - return SemaRef.BuildMemberReferenceExpr(move(Base), OperatorLoc, IsArrow, + return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType, + OperatorLoc, IsArrow, SS, R, TemplateArgs); } @@ -4819,18 +4830,32 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *E, bool isAddressOfOperand) { // Transform the base of the expression. - OwningExprResult Base = getDerived().TransformExpr(E->getBase()); - if (Base.isInvalid()) - return SemaRef.ExprError(); + OwningExprResult Base(SemaRef, (Expr*) 0); + Expr *OldBase; + QualType BaseType; + QualType ObjectType; + if (!E->isImplicitAccess()) { + OldBase = E->getBase(); + Base = getDerived().TransformExpr(OldBase); + if (Base.isInvalid()) + return SemaRef.ExprError(); - // Start the member reference and compute the object's type. - Sema::TypeTy *ObjectType = 0; - Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), - E->getOperatorLoc(), + // Start the member reference and compute the object's type. + Sema::TypeTy *ObjectTy = 0; + Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), + E->getOperatorLoc(), E->isArrow()? tok::arrow : tok::period, - ObjectType); - if (Base.isInvalid()) - return SemaRef.ExprError(); + ObjectTy); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + ObjectType = QualType::getFromOpaquePtr(ObjectTy); + BaseType = ((Expr*) Base.get())->getType(); + } else { + OldBase = 0; + BaseType = getDerived().TransformType(E->getBaseType()); + ObjectType = BaseType->getAs<PointerType>()->getPointeeType(); + } // Transform the first part of the nested-name-specifier that qualifies // the member name. @@ -4843,29 +4868,31 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( if (E->getQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), E->getQualifierRange(), - QualType::getFromOpaquePtr(ObjectType), - FirstQualifierInScope); + ObjectType, + FirstQualifierInScope); if (!Qualifier) return SemaRef.ExprError(); } DeclarationName Name = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc(), - QualType::getFromOpaquePtr(ObjectType)); + ObjectType); if (!Name) return SemaRef.ExprError(); - if (!E->hasExplicitTemplateArgumentList()) { + if (!E->hasExplicitTemplateArgs()) { // This is a reference to a member without an explicitly-specified // template argument list. Optimize for this common case. if (!getDerived().AlwaysRebuild() && - Base.get() == E->getBase() && + Base.get() == OldBase && + BaseType == E->getBaseType() && Qualifier == E->getQualifier() && Name == E->getMember() && FirstQualifierInScope == E->getFirstQualifierFoundInScope()) return SemaRef.Owned(E->Retain()); return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base), + BaseType, E->isArrow(), E->getOperatorLoc(), Qualifier, @@ -4885,6 +4912,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( } return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base), + BaseType, E->isArrow(), E->getOperatorLoc(), Qualifier, @@ -4900,9 +4928,16 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old, bool isAddressOfOperand) { // Transform the base of the expression. - OwningExprResult Base = getDerived().TransformExpr(Old->getBase()); - if (Base.isInvalid()) - return SemaRef.ExprError(); + OwningExprResult Base(SemaRef, (Expr*) 0); + QualType BaseType; + if (!Old->isImplicitAccess()) { + Base = getDerived().TransformExpr(Old->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + BaseType = ((Expr*) Base.get())->getType(); + } else { + BaseType = getDerived().TransformType(Old->getBaseType()); + } NestedNameSpecifier *Qualifier = 0; if (Old->getQualifier()) { @@ -4951,6 +4986,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old, } return getDerived().RebuildUnresolvedMemberExpr(move(Base), + BaseType, Old->getOperatorLoc(), Old->isArrow(), Qualifier, diff --git a/clang/test/SemaTemplate/instantiate-method.cpp b/clang/test/SemaTemplate/instantiate-method.cpp index 2351d882f9c..231e2812f66 100644 --- a/clang/test/SemaTemplate/instantiate-method.cpp +++ b/clang/test/SemaTemplate/instantiate-method.cpp @@ -95,9 +95,7 @@ struct X0 : X0Base { template<typename U> struct X1 : X0<U> { int &f2() { - // 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}} + return X0Base::f(); } }; diff --git a/clang/test/SemaTemplate/qualified-id.cpp b/clang/test/SemaTemplate/qualified-id.cpp index a07f05ca78e..ab57950acff 100644 --- a/clang/test/SemaTemplate/qualified-id.cpp +++ b/clang/test/SemaTemplate/qualified-id.cpp @@ -18,3 +18,14 @@ namespace test1 { } }; } + +namespace test2 { + class Impl { + int foo(); + }; + template <class T> class Magic : public Impl { + int foo() { + return Impl::foo(); + } + }; +} |