diff options
Diffstat (limited to 'lib/Sema')
-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 |
7 files changed, 772 insertions, 538 deletions
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, - TemplateArgs)); + return BuildMemberReferenceExpr(ExprArg(*this, This), + /*OpLoc*/ SourceLocation(), + /*IsArrow*/ true, + SS, R, TemplateArgs); } - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(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<FieldDecl>(D)) { + 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) - << 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<Expr>(); + + // 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<PointerType>(); + 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<NestedNameSpecifier*>(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<TypeDecl>((*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<Expr>(); + + 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<Expr>(); + QualType BaseType = BaseExpr->getType(); + if (IsArrow) { + assert(BaseType->isPointerType()); + BaseType = BaseType->getAs<PointerType>()->getPointeeType(); + } + + NestedNameSpecifier *Qualifier = + static_cast<NestedNameSpecifier*>(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<RecordType>()->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<CXXMethodDecl>(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<FieldDecl>(MemberDecl)) { + // We may have found a field within an anonymous union or struct + // (C++ [class.union]). + if (cast<RecordDecl>(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<ReferenceType>()) + 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<VarDecl>(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, Var); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + Var, MemberLoc, + Var->getType().getNonReferenceType())); + } + + if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, MemberDecl); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + MemberFn, MemberLoc, + MemberFn->getType())); + } + + if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, MemberDecl); + return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, + Enum, MemberLoc, Enum->getType())); + } + + Owned(BaseExpr); + + if (isa<TypeDecl>(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<PointerType>()) { @@ -1906,8 +2265,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, = Ptr->getPointeeType()->getAs<FunctionProtoType>()) { 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<PointerType>()->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<Expr>(); 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<NestedNameSpecifier *>(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<PointerType>()) + if (IsArrow) { + if (const PointerType *PT = BaseType->getAs<PointerType>()) BaseType = PT->getPointeeType(); else if (BaseType->isObjCObjectPointerType()) ; - else - return ExprError(Diag(MemberLoc, - diag::err_typecheck_member_reference_arro |