diff options
author | John McCall <rjmccall@apple.com> | 2009-11-30 22:42:35 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-11-30 22:42:35 +0000 |
commit | 129e2df52ed7e0434b3f1cf1867fd6a5cb083ff6 (patch) | |
tree | 06f74638a1c208fe9589dccbb0c0c59e48f3d0fb | |
parent | abce6999b271f4928aa98b11d42ffebedcde1e13 (diff) |
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
-rw-r--r-- | include/clang/AST/Decl.h | 2 | ||||
-rw-r--r-- | include/clang/AST/ExprCXX.h | 173 | ||||
-rw-r--r-- | include/clang/AST/Stmt.h | 8 | ||||
-rw-r--r-- | include/clang/AST/StmtNodes.def | 1 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 1 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 49 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 18 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/Lookup.h | 4 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 70 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 920 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 40 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 92 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 182 | ||||
-rw-r--r-- | test/SemaCXX/qual-id-test.cpp | 4 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-method.cpp | 4 |
18 files changed, 1044 insertions, 541 deletions
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<ExplicitTemplateArgumentList *>(this + 1); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + const ExplicitTemplateArgumentList *getExplicitTemplateArgs() const { + return const_cast<UnresolvedMemberExpr*>(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<Expr>(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<int>. + 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<UnresolvedMemberExpr>()); + 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<TemplateName>(); + + 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<TemplateName>(); + 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<RecordType> BaseRT = BaseT->getAs<RecordType>(); + if (!BaseRT) return false; + + CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(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<CXXRecordDecl>(DC)); +} + +static bool IsFullyFormedScope(Sema &SemaRef, DeclContext *DC) { + if (isa<CXXMethodDecl>(DC)) + return IsFullyFormedScope(SemaRef, + cast<CXXRecordDecl>(cast<CXXMethodDecl>(DC)->getParent())); + else if (isa<CXXRecordDecl>(DC)) + return IsFullyFormedScope(SemaRef, cast<CXXRecordDecl>(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<TemplateName>(); - - 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<TemplateName>(); - // 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<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. @@ -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<FieldDecl>(D)) + if (FieldDecl *FD = R.getAsSingle<FieldDecl>()) if (cast<RecordDecl>(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<CXXMethodDecl>(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, - |