|  | //===--- SemaExprMember.cpp - Semantic Analysis for Expressions -----------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | //  This file implements semantic analysis member access expressions. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | #include "clang/Sema/SemaInternal.h" | 
|  | #include "clang/Sema/Lookup.h" | 
|  | #include "clang/Sema/Scope.h" | 
|  | #include "clang/AST/DeclCXX.h" | 
|  | #include "clang/AST/DeclObjC.h" | 
|  | #include "clang/AST/DeclTemplate.h" | 
|  | #include "clang/AST/ExprCXX.h" | 
|  | #include "clang/AST/ExprObjC.h" | 
|  | #include "clang/Lex/Preprocessor.h" | 
|  |  | 
|  | using namespace clang; | 
|  | using namespace sema; | 
|  |  | 
|  | /// 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) { | 
|  | if (Bases.count(Record->getCanonicalDecl())) | 
|  | return false; | 
|  |  | 
|  | RecordDecl *RD = Record->getDefinition(); | 
|  | if (!RD) return false; | 
|  | Record = cast<CXXRecordDecl>(RD); | 
|  |  | 
|  | 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 (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | 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, | 
|  |  | 
|  | /// 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 | 
|  | }; | 
|  |  | 
|  | /// 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, | 
|  | Scope *CurScope, | 
|  | const LookupResult &R) { | 
|  | assert(!R.empty() && (*R.begin())->isCXXClassMember()); | 
|  |  | 
|  | DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); | 
|  |  | 
|  | bool isStaticContext = | 
|  | (!isa<CXXMethodDecl>(DC) || | 
|  | cast<CXXMethodDecl>(DC)->isStatic()); | 
|  |  | 
|  | // C++0x [expr.prim]p4: | 
|  | //   Otherwise, if a member-declarator declares a non-static data member | 
|  | // of a class X, the expression this is a prvalue of type "pointer to X" | 
|  | // within the optional brace-or-equal-initializer. | 
|  | if (CurScope->getFlags() & Scope::ThisScope) | 
|  | isStaticContext = false; | 
|  |  | 
|  | if (R.isUnresolvableResult()) | 
|  | return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; | 
|  |  | 
|  | // Collect all the declaring classes of instance members we find. | 
|  | bool hasNonInstance = false; | 
|  | bool hasField = false; | 
|  | llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes; | 
|  | for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { | 
|  | NamedDecl *D = *I; | 
|  |  | 
|  | if (D->isCXXInstanceMember()) { | 
|  | if (dyn_cast<FieldDecl>(D)) | 
|  | hasField = true; | 
|  |  | 
|  | CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext()); | 
|  | 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) { | 
|  | if (hasNonInstance) | 
|  | return IMA_Mixed_StaticContext; | 
|  |  | 
|  | if (SemaRef.getLangOptions().CPlusPlus0x && hasField) { | 
|  | // C++0x [expr.prim.general]p10: | 
|  | //   An id-expression that denotes a non-static data member or non-static | 
|  | //   member function of a class can only be used: | 
|  | //   (...) | 
|  | //   - if that id-expression denotes a non-static data member and it | 
|  | //     appears in an unevaluated operand. | 
|  | const Sema::ExpressionEvaluationContextRecord& record | 
|  | = SemaRef.ExprEvalContexts.back(); | 
|  | bool isUnevaluatedExpression = (record.Context == Sema::Unevaluated); | 
|  | if (isUnevaluatedExpression) | 
|  | return IMA_Mixed_StaticContext; | 
|  | } | 
|  |  | 
|  | return IMA_Error_StaticContext; | 
|  | } | 
|  |  | 
|  | CXXRecordDecl *contextClass; | 
|  | if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) | 
|  | contextClass = MD->getParent()->getCanonicalDecl(); | 
|  | else | 
|  | contextClass = cast<CXXRecordDecl>(DC); | 
|  |  | 
|  | // [class.mfct.non-static]p3: | 
|  | // ...is used in the body of a non-static member function of class X, | 
|  | // if name lookup (3.4.1) resolves the name in the id-expression to a | 
|  | // non-static non-type member of some class C [...] | 
|  | // ...if C is not X or a base class of X, the class member access expression | 
|  | // is ill-formed. | 
|  | if (R.getNamingClass() && | 
|  | contextClass != R.getNamingClass()->getCanonicalDecl() && | 
|  | contextClass->isProvablyNotDerivedFrom(R.getNamingClass())) | 
|  | return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); | 
|  |  | 
|  | // 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, contextClass, 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, | 
|  | NamedDecl *rep, | 
|  | const DeclarationNameInfo &nameInfo) { | 
|  | SourceLocation Loc = nameInfo.getLoc(); | 
|  | SourceRange Range(Loc); | 
|  | if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); | 
|  |  | 
|  | if (isa<FieldDecl>(rep) || isa<IndirectFieldDecl>(rep)) { | 
|  | 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 << nameInfo.getName(); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use) | 
|  | << nameInfo.getName() << Range; | 
|  | return; | 
|  | } | 
|  |  | 
|  | SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range; | 
|  | } | 
|  |  | 
|  | /// Builds an expression which might be an implicit member expression. | 
|  | ExprResult | 
|  | Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, | 
|  | LookupResult &R, | 
|  | const TemplateArgumentListInfo *TemplateArgs) { | 
|  | switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) { | 
|  | case IMA_Instance: | 
|  | return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); | 
|  |  | 
|  | 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: | 
|  | if (TemplateArgs) | 
|  | return BuildTemplateIdExpr(SS, R, false, *TemplateArgs); | 
|  | return BuildDeclarationNameExpr(SS, R, false); | 
|  |  | 
|  | case IMA_Error_StaticContext: | 
|  | case IMA_Error_Unrelated: | 
|  | DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(), | 
|  | R.getLookupNameInfo()); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | llvm_unreachable("unexpected instance member access kind"); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | /// Check an ext-vector component access expression. | 
|  | /// | 
|  | /// VK should be set in advance to the value kind of the base | 
|  | /// expression. | 
|  | static QualType | 
|  | CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, | 
|  | SourceLocation OpLoc, const IdentifierInfo *CompName, | 
|  | SourceLocation CompLoc) { | 
|  | // FIXME: Share logic with ExtVectorElementExpr::containsDuplicateElements, | 
|  | // see FIXME there. | 
|  | // | 
|  | // FIXME: This logic can be greatly simplified by splitting it along | 
|  | // halving/not halving and reworking the component checking. | 
|  | const ExtVectorType *vecType = baseType->getAs<ExtVectorType>(); | 
|  |  | 
|  | // The vector accessor can't exceed the number of elements. | 
|  | const char *compStr = CompName->getNameStart(); | 
|  |  | 
|  | // This flag determines whether or not the component is one of the four | 
|  | // special names that indicate a subset of exactly half the elements are | 
|  | // to be selected. | 
|  | bool HalvingSwizzle = false; | 
|  |  | 
|  | // This flag determines whether or not CompName has an 's' char prefix, | 
|  | // indicating that it is a string of hex values to be used as vector indices. | 
|  | bool HexSwizzle = *compStr == 's' || *compStr == 'S'; | 
|  |  | 
|  | bool HasRepeated = false; | 
|  | bool HasIndex[16] = {}; | 
|  |  | 
|  | int Idx; | 
|  |  | 
|  | // Check that we've found one of the special components, or that the component | 
|  | // names must come from the same set. | 
|  | if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || | 
|  | !strcmp(compStr, "even") || !strcmp(compStr, "odd")) { | 
|  | HalvingSwizzle = true; | 
|  | } else if (!HexSwizzle && | 
|  | (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) { | 
|  | do { | 
|  | if (HasIndex[Idx]) HasRepeated = true; | 
|  | HasIndex[Idx] = true; | 
|  | compStr++; | 
|  | } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1); | 
|  | } else { | 
|  | if (HexSwizzle) compStr++; | 
|  | while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) { | 
|  | if (HasIndex[Idx]) HasRepeated = true; | 
|  | HasIndex[Idx] = true; | 
|  | compStr++; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!HalvingSwizzle && *compStr) { | 
|  | // We didn't get to the end of the string. This means the component names | 
|  | // didn't come from the same set *or* we encountered an illegal name. | 
|  | S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal) | 
|  | << StringRef(compStr, 1) << SourceRange(CompLoc); | 
|  | return QualType(); | 
|  | } | 
|  |  | 
|  | // Ensure no component accessor exceeds the width of the vector type it | 
|  | // operates on. | 
|  | if (!HalvingSwizzle) { | 
|  | compStr = CompName->getNameStart(); | 
|  |  | 
|  | if (HexSwizzle) | 
|  | compStr++; | 
|  |  | 
|  | while (*compStr) { | 
|  | if (!vecType->isAccessorWithinNumElements(*compStr++)) { | 
|  | S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length) | 
|  | << baseType << SourceRange(CompLoc); | 
|  | return QualType(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // The component accessor looks fine - now we need to compute the actual type. | 
|  | // The vector type is implied by the component accessor. For example, | 
|  | // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc. | 
|  | // vec4.s0 is a float, vec4.s23 is a vec3, etc. | 
|  | // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2. | 
|  | unsigned CompSize = HalvingSwizzle ? (vecType->getNumElements() + 1) / 2 | 
|  | : CompName->getLength(); | 
|  | if (HexSwizzle) | 
|  | CompSize--; | 
|  |  | 
|  | if (CompSize == 1) | 
|  | return vecType->getElementType(); | 
|  |  | 
|  | if (HasRepeated) VK = VK_RValue; | 
|  |  | 
|  | QualType VT = S.Context.getExtVectorType(vecType->getElementType(), CompSize); | 
|  | // Now look up the TypeDefDecl from the vector type. Without this, | 
|  | // diagostics look bad. We want extended vector types to appear built-in. | 
|  | for (Sema::ExtVectorDeclsType::iterator | 
|  | I = S.ExtVectorDecls.begin(S.ExternalSource), | 
|  | E = S.ExtVectorDecls.end(); | 
|  | I != E; ++I) { | 
|  | if ((*I)->getUnderlyingType() == VT) | 
|  | return S.Context.getTypedefType(*I); | 
|  | } | 
|  |  | 
|  | return VT; // should never get here (a typedef type should always be found). | 
|  | } | 
|  |  | 
|  | static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl, | 
|  | IdentifierInfo *Member, | 
|  | const Selector &Sel, | 
|  | ASTContext &Context) { | 
|  | if (Member) | 
|  | if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member)) | 
|  | return PD; | 
|  | if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel)) | 
|  | return OMD; | 
|  |  | 
|  | for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), | 
|  | E = PDecl->protocol_end(); I != E; ++I) { | 
|  | if (Decl *D = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel, | 
|  | Context)) | 
|  | return D; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy, | 
|  | IdentifierInfo *Member, | 
|  | const Selector &Sel, | 
|  | ASTContext &Context) { | 
|  | // Check protocols on qualified interfaces. | 
|  | Decl *GDecl = 0; | 
|  | for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), | 
|  | E = QIdTy->qual_end(); I != E; ++I) { | 
|  | if (Member) | 
|  | if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { | 
|  | GDecl = PD; | 
|  | break; | 
|  | } | 
|  | // Also must look for a getter or setter name which uses property syntax. | 
|  | if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) { | 
|  | GDecl = OMD; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (!GDecl) { | 
|  | for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), | 
|  | E = QIdTy->qual_end(); I != E; ++I) { | 
|  | // Search in the protocol-qualifier list of current protocol. | 
|  | GDecl = FindGetterSetterNameDeclFromProtocolList(*I, Member, Sel, | 
|  | Context); | 
|  | if (GDecl) | 
|  | return GDecl; | 
|  | } | 
|  | } | 
|  | return GDecl; | 
|  | } | 
|  |  | 
|  | ExprResult | 
|  | Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType, | 
|  | bool IsArrow, SourceLocation OpLoc, | 
|  | const CXXScopeSpec &SS, | 
|  | NamedDecl *FirstQualifierInScope, | 
|  | const DeclarationNameInfo &NameInfo, | 
|  | const TemplateArgumentListInfo *TemplateArgs) { | 
|  | // 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 = BaseType->getAs<PointerType>(); | 
|  | if (PT && (!getLangOptions().ObjC1 || | 
|  | PT->getPointeeType()->isRecordType())) { | 
|  | assert(BaseExpr && "cannot happen with implicit member accesses"); | 
|  | Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union) | 
|  | << BaseType << BaseExpr->getSourceRange(); | 
|  | return ExprError(); | 
|  | } | 
|  | } | 
|  |  | 
|  | assert(BaseType->isDependentType() || | 
|  | NameInfo.getName().isDependentName() || | 
|  | isDependentScopeSpecifier(SS)); | 
|  |  | 
|  | // 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, BaseType, | 
|  | IsArrow, OpLoc, | 
|  | SS.getWithLocInContext(Context), | 
|  | FirstQualifierInScope, | 
|  | NameInfo, 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, | 
|  | const CXXScopeSpec &SS, | 
|  | NamedDecl *rep, | 
|  | const DeclarationNameInfo &nameInfo) { | 
|  | // If this is an implicit member access, use a different set of | 
|  | // diagnostics. | 
|  | if (!BaseExpr) | 
|  | return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo); | 
|  |  | 
|  | SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated) | 
|  | << SS.getRange() << rep << 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, | 
|  | const CXXScopeSpec &SS, | 
|  | const LookupResult &R) { | 
|  | 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) { | 
|  | // If this is an implicit member reference and we find a | 
|  | // non-instance member, it's not an error. | 
|  | if (!BaseExpr && !(*I)->isCXXInstanceMember()) | 
|  | return false; | 
|  |  | 
|  | // Note that we use the DC of the decl, not the underlying decl. | 
|  | DeclContext *DC = (*I)->getDeclContext(); | 
|  | while (DC->isTransparentContext()) | 
|  | DC = DC->getParent(); | 
|  |  | 
|  | if (!DC->isRecord()) | 
|  | continue; | 
|  |  | 
|  | llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord; | 
|  | MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl()); | 
|  |  | 
|  | if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS, | 
|  | R.getRepresentativeDecl(), | 
|  | R.getLookupNameInfo()); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool | 
|  | LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, | 
|  | SourceRange BaseRange, const RecordType *RTy, | 
|  | SourceLocation OpLoc, CXXScopeSpec &SS, | 
|  | bool HasTemplateArgs) { | 
|  | RecordDecl *RDecl = RTy->getDecl(); | 
|  | if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), | 
|  | SemaRef.PDiag(diag::err_typecheck_incomplete_tag) | 
|  | << BaseRange)) | 
|  | return true; | 
|  |  | 
|  | if (HasTemplateArgs) { | 
|  | // LookupTemplateName doesn't expect these both to exist simultaneously. | 
|  | QualType ObjectType = SS.isSet() ? QualType() : QualType(RTy, 0); | 
|  |  | 
|  | bool MOUS; | 
|  | SemaRef.LookupTemplateName(R, 0, SS, ObjectType, false, MOUS); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | 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); | 
|  |  | 
|  | if (SemaRef.RequireCompleteDeclContext(SS, DC)) { | 
|  | SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) | 
|  | << SS.getRange() << DC; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | 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); | 
|  |  | 
|  | if (!R.empty()) | 
|  | return false; | 
|  |  | 
|  | // We didn't find anything with the given name, so try to correct | 
|  | // for typos. | 
|  | DeclarationName Name = R.getLookupName(); | 
|  | TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(), | 
|  | R.getLookupKind(), NULL, | 
|  | &SS, DC, false, | 
|  | Sema::CTC_MemberLookup); | 
|  | NamedDecl *ND = Corrected.getCorrectionDecl(); | 
|  | R.clear(); | 
|  | if (ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND))) { | 
|  | std::string CorrectedStr( | 
|  | Corrected.getAsString(SemaRef.getLangOptions())); | 
|  | std::string CorrectedQuotedStr( | 
|  | Corrected.getQuoted(SemaRef.getLangOptions())); | 
|  | R.setLookupName(Corrected.getCorrection()); | 
|  | R.addDecl(ND); | 
|  | SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) | 
|  | << Name << DC << CorrectedQuotedStr << SS.getRange() | 
|  | << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr); | 
|  | SemaRef.Diag(ND->getLocation(), diag::note_previous_decl) | 
|  | << ND->getDeclName(); | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | ExprResult | 
|  | Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, | 
|  | SourceLocation OpLoc, bool IsArrow, | 
|  | CXXScopeSpec &SS, | 
|  | NamedDecl *FirstQualifierInScope, | 
|  | const DeclarationNameInfo &NameInfo, | 
|  | const TemplateArgumentListInfo *TemplateArgs) { | 
|  | if (BaseType->isDependentType() || | 
|  | (SS.isSet() && isDependentScopeSpecifier(SS))) | 
|  | return ActOnDependentMemberExpr(Base, BaseType, | 
|  | IsArrow, OpLoc, | 
|  | SS, FirstQualifierInScope, | 
|  | NameInfo, TemplateArgs); | 
|  |  | 
|  | LookupResult R(*this, NameInfo, LookupMemberName); | 
|  |  | 
|  | // 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, TemplateArgs != 0)) | 
|  | return ExprError(); | 
|  |  | 
|  | // Explicit member accesses. | 
|  | } else { | 
|  | ExprResult BaseResult = Owned(Base); | 
|  | ExprResult Result = | 
|  | LookupMemberExpr(R, BaseResult, IsArrow, OpLoc, | 
|  | SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0); | 
|  |  | 
|  | if (BaseResult.isInvalid()) | 
|  | return ExprError(); | 
|  | Base = BaseResult.take(); | 
|  |  | 
|  | if (Result.isInvalid()) { | 
|  | Owned(Base); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | if (Result.get()) | 
|  | return move(Result); | 
|  |  | 
|  | // LookupMemberExpr can modify Base, and thus change BaseType | 
|  | BaseType = Base->getType(); | 
|  | } | 
|  |  | 
|  | return BuildMemberReferenceExpr(Base, BaseType, | 
|  | OpLoc, IsArrow, SS, FirstQualifierInScope, | 
|  | R, TemplateArgs); | 
|  | } | 
|  |  | 
|  | static ExprResult | 
|  | BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, | 
|  | const CXXScopeSpec &SS, FieldDecl *Field, | 
|  | DeclAccessPair FoundDecl, | 
|  | const DeclarationNameInfo &MemberNameInfo); | 
|  |  | 
|  | ExprResult | 
|  | Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, | 
|  | SourceLocation loc, | 
|  | IndirectFieldDecl *indirectField, | 
|  | Expr *baseObjectExpr, | 
|  | SourceLocation opLoc) { | 
|  | // First, build the expression that refers to the base object. | 
|  |  | 
|  | bool baseObjectIsPointer = false; | 
|  | Qualifiers baseQuals; | 
|  |  | 
|  | // Case 1:  the base of the indirect field is not a field. | 
|  | VarDecl *baseVariable = indirectField->getVarDecl(); | 
|  | CXXScopeSpec EmptySS; | 
|  | if (baseVariable) { | 
|  | assert(baseVariable->getType()->isRecordType()); | 
|  |  | 
|  | // In principle we could have a member access expression that | 
|  | // accesses an anonymous struct/union that's a static member of | 
|  | // the base object's class.  However, under the current standard, | 
|  | // static data members cannot be anonymous structs or unions. | 
|  | // Supporting this is as easy as building a MemberExpr here. | 
|  | assert(!baseObjectExpr && "anonymous struct/union is static data member?"); | 
|  |  | 
|  | DeclarationNameInfo baseNameInfo(DeclarationName(), loc); | 
|  |  | 
|  | ExprResult result | 
|  | = BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable); | 
|  | if (result.isInvalid()) return ExprError(); | 
|  |  | 
|  | baseObjectExpr = result.take(); | 
|  | baseObjectIsPointer = false; | 
|  | baseQuals = baseObjectExpr->getType().getQualifiers(); | 
|  |  | 
|  | // Case 2: the base of the indirect field is a field and the user | 
|  | // wrote a member expression. | 
|  | } else if (baseObjectExpr) { | 
|  | // The caller provided the base object expression. Determine | 
|  | // whether its a pointer and whether it adds any qualifiers to the | 
|  | // anonymous struct/union fields we're looking into. | 
|  | QualType objectType = baseObjectExpr->getType(); | 
|  |  | 
|  | if (const PointerType *ptr = objectType->getAs<PointerType>()) { | 
|  | baseObjectIsPointer = true; | 
|  | objectType = ptr->getPointeeType(); | 
|  | } else { | 
|  | baseObjectIsPointer = false; | 
|  | } | 
|  | baseQuals = objectType.getQualifiers(); | 
|  |  | 
|  | // Case 3: the base of the indirect field is a field and we should | 
|  | // build an implicit member access. | 
|  | } else { | 
|  | // We've found a member of an anonymous struct/union that is | 
|  | // inside a non-anonymous struct/union, so in a well-formed | 
|  | // program our base object expression is "this". | 
|  | QualType ThisTy = getAndCaptureCurrentThisType(); | 
|  | if (ThisTy.isNull()) { | 
|  | Diag(loc, diag::err_invalid_member_use_in_static_method) | 
|  | << indirectField->getDeclName(); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | // Our base object expression is "this". | 
|  | baseObjectExpr | 
|  | = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true); | 
|  | baseObjectIsPointer = true; | 
|  | baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers(); | 
|  | } | 
|  |  | 
|  | // Build the implicit member references to the field of the | 
|  | // anonymous struct/union. | 
|  | Expr *result = baseObjectExpr; | 
|  | IndirectFieldDecl::chain_iterator | 
|  | FI = indirectField->chain_begin(), FEnd = indirectField->chain_end(); | 
|  |  | 
|  | // Build the first member access in the chain with full information. | 
|  | if (!baseVariable) { | 
|  | FieldDecl *field = cast<FieldDecl>(*FI); | 
|  |  | 
|  | // FIXME: use the real found-decl info! | 
|  | DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess()); | 
|  |  | 
|  | // Make a nameInfo that properly uses the anonymous name. | 
|  | DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); | 
|  |  | 
|  | result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer, | 
|  | EmptySS, field, foundDecl, | 
|  | memberNameInfo).take(); | 
|  | baseObjectIsPointer = false; | 
|  |  | 
|  | // FIXME: check qualified member access | 
|  | } | 
|  |  | 
|  | // In all cases, we should now skip the first declaration in the chain. | 
|  | ++FI; | 
|  |  | 
|  | while (FI != FEnd) { | 
|  | FieldDecl *field = cast<FieldDecl>(*FI++); | 
|  |  | 
|  | // FIXME: these are somewhat meaningless | 
|  | DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); | 
|  | DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess()); | 
|  |  | 
|  | result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false, | 
|  | (FI == FEnd? SS : EmptySS), field, | 
|  | foundDecl, memberNameInfo).take(); | 
|  | } | 
|  |  | 
|  | return Owned(result); | 
|  | } | 
|  |  | 
|  | /// \brief Build a MemberExpr AST node. | 
|  | static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, | 
|  | const CXXScopeSpec &SS, ValueDecl *Member, | 
|  | DeclAccessPair FoundDecl, | 
|  | const DeclarationNameInfo &MemberNameInfo, | 
|  | QualType Ty, | 
|  | ExprValueKind VK, ExprObjectKind OK, | 
|  | const TemplateArgumentListInfo *TemplateArgs = 0) { | 
|  | return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C), | 
|  | Member, FoundDecl, MemberNameInfo, | 
|  | TemplateArgs, Ty, VK, OK); | 
|  | } | 
|  |  | 
|  | ExprResult | 
|  | Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, | 
|  | SourceLocation OpLoc, bool IsArrow, | 
|  | const CXXScopeSpec &SS, | 
|  | NamedDecl *FirstQualifierInScope, | 
|  | LookupResult &R, | 
|  | const TemplateArgumentListInfo *TemplateArgs, | 
|  | bool SuppressQualifierCheck) { | 
|  | QualType BaseType = BaseExprType; | 
|  | if (IsArrow) { | 
|  | assert(BaseType->isPointerType()); | 
|  | BaseType = BaseType->getAs<PointerType>()->getPointeeType(); | 
|  | } | 
|  | R.setBaseObjectType(BaseType); | 
|  |  | 
|  | const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo(); | 
|  | DeclarationName MemberName = MemberNameInfo.getName(); | 
|  | SourceLocation MemberLoc = MemberNameInfo.getLoc(); | 
|  |  | 
|  | 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 ? BaseExpr->getSourceRange() : SourceRange()); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | // Diagnose lookups that find only declarations from a non-base | 
|  | // type.  This is possible for either qualified lookups (which may | 
|  | // have been qualified with an unrelated type) or implicit member | 
|  | // expressions (which were found with unqualified lookup and thus | 
|  | // may have come from an enclosing scope).  Note that it's okay for | 
|  | // lookup to find declarations from a non-base type as long as those | 
|  | // aren't the ones picked by overload resolution. | 
|  | if ((SS.isSet() || !BaseExpr || | 
|  | (isa<CXXThisExpr>(BaseExpr) && | 
|  | cast<CXXThisExpr>(BaseExpr)->isImplicit())) && | 
|  | !SuppressQualifierCheck && | 
|  | CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R)) | 
|  | return ExprError(); | 
|  |  | 
|  | // Construct an unresolved result if we in fact got an unresolved | 
|  | // result. | 
|  | if (R.isOverloadedResult() || R.isUnresolvableResult()) { | 
|  | // Suppress any lookup-related diagnostics; we'll do these when we | 
|  | // pick a member. | 
|  | R.suppressDiagnostics(); | 
|  |  | 
|  | UnresolvedMemberExpr *MemExpr | 
|  | = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(), | 
|  | BaseExpr, BaseExprType, | 
|  | IsArrow, OpLoc, | 
|  | SS.getWithLocInContext(Context), | 
|  | MemberNameInfo, | 
|  | TemplateArgs, R.begin(), R.end()); | 
|  |  | 
|  | return Owned(MemExpr); | 
|  | } | 
|  |  | 
|  | assert(R.isSingleResult()); | 
|  | DeclAccessPair FoundDecl = R.begin().getPair(); | 
|  | 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(); | 
|  |  | 
|  | // Handle the implicit-member-access case. | 
|  | if (!BaseExpr) { | 
|  | // If this is not an instance member, convert to a non-member access. | 
|  | if (!MemberDecl->isCXXInstanceMember()) | 
|  | return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl); | 
|  |  | 
|  | SourceLocation Loc = R.getNameLoc(); | 
|  | if (SS.getRange().isValid()) | 
|  | Loc = SS.getRange().getBegin(); | 
|  | BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true); | 
|  | } | 
|  |  | 
|  | 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(); | 
|  | } | 
|  |  | 
|  | // Perform a property load on the base regardless of whether we | 
|  | // actually need it for the declaration. | 
|  | if (BaseExpr->getObjectKind() == OK_ObjCProperty) { | 
|  | ExprResult Result = ConvertPropertyForRValue(BaseExpr); | 
|  | if (Result.isInvalid()) | 
|  | return ExprError(); | 
|  | BaseExpr = Result.take(); | 
|  | } | 
|  |  | 
|  | if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) | 
|  | return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, | 
|  | SS, FD, FoundDecl, MemberNameInfo); | 
|  |  | 
|  | if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl)) | 
|  | // We may have found a field within an anonymous union or struct | 
|  | // (C++ [class.union]). | 
|  | return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD, | 
|  | BaseExpr, OpLoc); | 
|  |  | 
|  | if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) { | 
|  | MarkDeclarationReferenced(MemberLoc, Var); | 
|  | return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, | 
|  | Var, FoundDecl, MemberNameInfo, | 
|  | Var->getType().getNonReferenceType(), | 
|  | VK_LValue, OK_Ordinary)); | 
|  | } | 
|  |  | 
|  | if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) { | 
|  | ExprValueKind valueKind; | 
|  | QualType type; | 
|  | if (MemberFn->isInstance()) { | 
|  | valueKind = VK_RValue; | 
|  | type = Context.BoundMemberTy; | 
|  | } else { | 
|  | valueKind = VK_LValue; | 
|  | type = MemberFn->getType(); | 
|  | } | 
|  |  | 
|  | MarkDeclarationReferenced(MemberLoc, MemberDecl); | 
|  | return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, | 
|  | MemberFn, FoundDecl, MemberNameInfo, | 
|  | type, valueKind, OK_Ordinary)); | 
|  | } | 
|  | assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?"); | 
|  |  | 
|  | if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) { | 
|  | MarkDeclarationReferenced(MemberLoc, MemberDecl); | 
|  | return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, | 
|  | Enum, FoundDecl, MemberNameInfo, | 
|  | Enum->getType(), VK_RValue, OK_Ordinary)); | 
|  | } | 
|  |  | 
|  | Owned(BaseExpr); | 
|  |  | 
|  | // We found something that we didn't expect. Complain. | 
|  | if (isa<TypeDecl>(MemberDecl)) | 
|  | Diag(MemberLoc, diag::err_typecheck_member_reference_type) | 
|  | << MemberName << BaseType << int(IsArrow); | 
|  | else | 
|  | Diag(MemberLoc, diag::err_typecheck_member_reference_unknown) | 
|  | << MemberName << BaseType << int(IsArrow); | 
|  |  | 
|  | Diag(MemberDecl->getLocation(), diag::note_member_declared_here) | 
|  | << MemberName; | 
|  | R.suppressDiagnostics(); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | /// Given that normal member access failed on the given expression, | 
|  | /// and given that the expression's type involves builtin-id or | 
|  | /// builtin-Class, decide whether substituting in the redefinition | 
|  | /// types would be profitable.  The redefinition type is whatever | 
|  | /// this translation unit tried to typedef to id/Class;  we store | 
|  | /// it to the side and then re-use it in places like this. | 
|  | static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) { | 
|  | const ObjCObjectPointerType *opty | 
|  | = base.get()->getType()->getAs<ObjCObjectPointerType>(); | 
|  | if (!opty) return false; | 
|  |  | 
|  | const ObjCObjectType *ty = opty->getObjectType(); | 
|  |  | 
|  | QualType redef; | 
|  | if (ty->isObjCId()) { | 
|  | redef = S.Context.getObjCIdRedefinitionType(); | 
|  | } else if (ty->isObjCClass()) { | 
|  | redef = S.Context.getObjCClassRedefinitionType(); | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Do the substitution as long as the redefinition type isn't just a | 
|  | // possibly-qualified pointer to builtin-id or builtin-Class again. | 
|  | opty = redef->getAs<ObjCObjectPointerType>(); | 
|  | if (opty && !opty->getObjectType()->getInterface() != 0) | 
|  | return false; | 
|  |  | 
|  | base = S.ImpCastExprToType(base.take(), redef, CK_BitCast); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// 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++. | 
|  | ExprResult | 
|  | Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, | 
|  | bool &IsArrow, SourceLocation OpLoc, | 
|  | CXXScopeSpec &SS, | 
|  | Decl *ObjCImpDecl, bool HasTemplateArgs) { | 
|  | assert(BaseExpr.get() && "no base expression"); | 
|  |  | 
|  | // Perform default conversions. | 
|  | BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); | 
|  |  | 
|  | if (IsArrow) { | 
|  | BaseExpr = DefaultLvalueConversion(BaseExpr.take()); | 
|  | if (BaseExpr.isInvalid()) | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | QualType BaseType = BaseExpr.get()->getType(); | 
|  | assert(!BaseType->isDependentType()); | 
|  |  | 
|  | DeclarationName MemberName = R.getLookupName(); | 
|  | SourceLocation MemberLoc = R.getNameLoc(); | 
|  |  | 
|  | // For later type-checking purposes, turn arrow accesses into dot | 
|  | // accesses.  The only access type we support that doesn't follow | 
|  | // the C equivalence "a->b === (*a).b" is ObjC property accesses, | 
|  | // and those never use arrows, so this is unaffected. | 
|  | if (IsArrow) { | 
|  | if (const PointerType *Ptr = BaseType->getAs<PointerType>()) | 
|  | BaseType = Ptr->getPointeeType(); | 
|  | else if (const ObjCObjectPointerType *Ptr | 
|  | = BaseType->getAs<ObjCObjectPointerType>()) | 
|  | BaseType = Ptr->getPointeeType(); | 
|  | else if (BaseType->isRecordType()) { | 
|  | // Recover from arrow accesses to records, e.g.: | 
|  | //   struct MyRecord foo; | 
|  | //   foo->bar | 
|  | // This is actually well-formed in C++ if MyRecord has an | 
|  | // overloaded operator->, but that should have been dealt with | 
|  | // by now. | 
|  | Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) | 
|  | << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() | 
|  | << FixItHint::CreateReplacement(OpLoc, "."); | 
|  | IsArrow = false; | 
|  | } else if (BaseType == Context.BoundMemberTy) { | 
|  | goto fail; | 
|  | } else { | 
|  | Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) | 
|  | << BaseType << BaseExpr.get()->getSourceRange(); | 
|  | return ExprError(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Handle field access to simple records. | 
|  | if (const RecordType *RTy = BaseType->getAs<RecordType>()) { | 
|  | if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(), | 
|  | RTy, OpLoc, SS, HasTemplateArgs)) | 
|  | return ExprError(); | 
|  |  | 
|  | // Returning valid-but-null is how we indicate to the caller that | 
|  | // the lookup result was filled in. | 
|  | return Owned((Expr*) 0); | 
|  | } | 
|  |  | 
|  | // Handle ivar access to Objective-C objects. | 
|  | if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>()) { | 
|  | IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); | 
|  |  | 
|  | // There are three cases for the base type: | 
|  | //   - builtin id (qualified or unqualified) | 
|  | //   - builtin Class (qualified or unqualified) | 
|  | //   - an interface | 
|  | ObjCInterfaceDecl *IDecl = OTy->getInterface(); | 
|  | if (!IDecl) { | 
|  | if (getLangOptions().ObjCAutoRefCount && | 
|  | (OTy->isObjCId() || OTy->isObjCClass())) | 
|  | goto fail; | 
|  | // There's an implicit 'isa' ivar on all objects. | 
|  | // But we only actually find it this way on objects of type 'id', | 
|  | // apparently. | 
|  | if (OTy->isObjCId() && Member->isStr("isa")) | 
|  | return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc, | 
|  | Context.getObjCClassType())); | 
|  |  | 
|  | if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) | 
|  | return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, | 
|  | ObjCImpDecl, HasTemplateArgs); | 
|  | goto fail; | 
|  | } | 
|  |  | 
|  | ObjCInterfaceDecl *ClassDeclared; | 
|  | ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); | 
|  |  | 
|  | if (!IV) { | 
|  | // Attempt to correct for typos in ivar names. | 
|  | LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), | 
|  | LookupMemberName); | 
|  | TypoCorrection Corrected = CorrectTypo( | 
|  | R.getLookupNameInfo(), LookupMemberName, NULL, NULL, IDecl, false, | 
|  | IsArrow ? CTC_ObjCIvarLookup : CTC_ObjCPropertyLookup); | 
|  | if ((IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>())) { | 
|  | Diag(R.getNameLoc(), | 
|  | diag::err_typecheck_member_reference_ivar_suggest) | 
|  | << IDecl->getDeclName() << MemberName << IV->getDeclName() | 
|  | << FixItHint::CreateReplacement(R.getNameLoc(), | 
|  | IV->getNameAsString()); | 
|  | Diag(IV->getLocation(), diag::note_previous_decl) | 
|  | << IV->getDeclName(); | 
|  | } else { | 
|  | if (IsArrow && IDecl->FindPropertyDeclaration(Member)) { | 
|  | Diag(MemberLoc, | 
|  | diag::err_property_found_suggest) | 
|  | << Member << BaseExpr.get()->getType() | 
|  | << FixItHint::CreateReplacement(OpLoc, "."); | 
|  | return ExprError(); | 
|  | } | 
|  | Res.clear(); | 
|  | Res.setLookupName(Member); | 
|  |  | 
|  | Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) | 
|  | << IDecl->getDeclName() << MemberName | 
|  | << BaseExpr.get()->getSourceRange(); | 
|  | return ExprError(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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 (IV->isInvalidDecl()) | 
|  | return ExprError(); | 
|  |  | 
|  | // Check whether we can reference this field. | 
|  | if (DiagnoseUseOfDecl(IV, MemberLoc)) | 
|  | return ExprError(); | 
|  | if (IV->getAccessControl() != ObjCIvarDecl::Public && | 
|  | IV->getAccessControl() != ObjCIvarDecl::Package) { | 
|  | ObjCInterfaceDecl *ClassOfMethodDecl = 0; | 
|  | if (ObjCMethodDecl *MD = getCurMethodDecl()) | 
|  | ClassOfMethodDecl =  MD->getClassInterface(); | 
|  | else if (ObjCImpDecl && getCurFunctionDecl()) { | 
|  | // Case of a c-function declared inside an objc implementation. | 
|  | // FIXME: For a c-style function nested inside an objc implementation | 
|  | // class, there is no implementation context available, so we pass | 
|  | // down the context as argument to this routine. Ideally, this context | 
|  | // need be passed down in the AST node and somehow calculated from the | 
|  | // AST for a function decl. | 
|  | if (ObjCImplementationDecl *IMPD = | 
|  | dyn_cast<ObjCImplementationDecl>(ObjCImpDecl)) | 
|  | ClassOfMethodDecl = IMPD->getClassInterface(); | 
|  | else if (ObjCCategoryImplDecl* CatImplClass = | 
|  | dyn_cast<ObjCCategoryImplDecl>(ObjCImpDecl)) | 
|  | ClassOfMethodDecl = CatImplClass->getClassInterface(); | 
|  | } | 
|  |  | 
|  | if (IV->getAccessControl() == ObjCIvarDecl::Private) { | 
|  | if (ClassDeclared != IDecl || | 
|  | ClassOfMethodDecl != ClassDeclared) | 
|  | Diag(MemberLoc, diag::error_private_ivar_access) | 
|  | << IV->getDeclName(); | 
|  | } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl)) | 
|  | // @protected | 
|  | Diag(MemberLoc, diag::error_protected_ivar_access) | 
|  | << IV->getDeclName(); | 
|  | } | 
|  | if (getLangOptions().ObjCAutoRefCount) { | 
|  | Expr *BaseExp = BaseExpr.get()->IgnoreParenImpCasts(); | 
|  | if (UnaryOperator *UO = dyn_cast<UnaryOperator>(BaseExp)) | 
|  | if (UO->getOpcode() == UO_Deref) | 
|  | BaseExp = UO->getSubExpr()->IgnoreParenCasts(); | 
|  |  | 
|  | if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(BaseExp)) | 
|  | if (DE->getType().getObjCLifetime() == Qualifiers::OCL_Weak) | 
|  | Diag(DE->getLocation(), diag::error_arc_weak_ivar_access); | 
|  | } | 
|  |  | 
|  | return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), | 
|  | MemberLoc, BaseExpr.take(), | 
|  | IsArrow)); | 
|  | } | 
|  |  | 
|  | // Objective-C property access. | 
|  | const ObjCObjectPointerType *OPT; | 
|  | if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) { | 
|  | // This actually uses the base as an r-value. | 
|  | BaseExpr = DefaultLvalueConversion(BaseExpr.take()); | 
|  | if (BaseExpr.isInvalid()) | 
|  | return ExprError(); | 
|  |  | 
|  | assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType())); | 
|  |  | 
|  | IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); | 
|  |  | 
|  | const ObjCObjectType *OT = OPT->getObjectType(); | 
|  |  | 
|  | // id, with and without qualifiers. | 
|  | if (OT->isObjCId()) { | 
|  | // Check protocols on qualified interfaces. | 
|  | Selector Sel = PP.getSelectorTable().getNullarySelector(Member); | 
|  | if (Decl *PMDecl = FindGetterSetterNameDecl(OPT, Member, Sel, Context)) { | 
|  | if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) { | 
|  | // Check the use of this declaration | 
|  | if (DiagnoseUseOfDecl(PD, MemberLoc)) | 
|  | return ExprError(); | 
|  |  | 
|  | QualType T = PD->getType(); | 
|  | if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) | 
|  | T = getMessageSendResultType(BaseType, Getter, false, false); | 
|  |  | 
|  | return Owned(new (Context) ObjCPropertyRefExpr(PD, T, | 
|  | VK_LValue, | 
|  | OK_ObjCProperty, | 
|  | MemberLoc, | 
|  | BaseExpr.take())); | 
|  | } | 
|  |  | 
|  | if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) { | 
|  | // Check the use of this method. | 
|  | if (DiagnoseUseOfDecl(OMD, MemberLoc)) | 
|  | return ExprError(); | 
|  | Selector SetterSel = | 
|  | SelectorTable::constructSetterName(PP.getIdentifierTable(), | 
|  | PP.getSelectorTable(), Member); | 
|  | ObjCMethodDecl *SMD = 0; | 
|  | if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0, | 
|  | SetterSel, Context)) | 
|  | SMD = dyn_cast<ObjCMethodDecl>(SDecl); | 
|  | QualType PType = getMessageSendResultType(BaseType, OMD, false, | 
|  | false); | 
|  |  | 
|  | ExprValueKind VK = VK_LValue; | 
|  | if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType()) | 
|  | VK = VK_RValue; | 
|  | ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); | 
|  |  | 
|  | return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType, | 
|  | VK, OK, | 
|  | MemberLoc, BaseExpr.take())); | 
|  | } | 
|  | } | 
|  | // Use of id.member can only be for a property reference. Do not | 
|  | // use the 'id' redefinition in this case. | 
|  | if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) | 
|  | return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, | 
|  | ObjCImpDecl, HasTemplateArgs); | 
|  |  | 
|  | return ExprError(Diag(MemberLoc, diag::err_property_not_found) | 
|  | << MemberName << BaseType); | 
|  | } | 
|  |  | 
|  | // 'Class', unqualified only. | 
|  | if (OT->isObjCClass()) { | 
|  | // Only works in a method declaration (??!). | 
|  | ObjCMethodDecl *MD = getCurMethodDecl(); | 
|  | if (!MD) { | 
|  | if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) | 
|  | return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, | 
|  | ObjCImpDecl, HasTemplateArgs); | 
|  |  | 
|  | goto fail; | 
|  | } | 
|  |  | 
|  | // Also must look for a getter name which uses property syntax. | 
|  | Selector Sel = PP.getSelectorTable().getNullarySelector(Member); | 
|  | ObjCInterfaceDecl *IFace = MD->getClassInterface(); | 
|  | ObjCMethodDecl *Getter; | 
|  | if ((Getter = IFace->lookupClassMethod(Sel))) { | 
|  | // Check the use of this method. | 
|  | if (DiagnoseUseOfDecl(Getter, MemberLoc)) | 
|  | return ExprError(); | 
|  | } else | 
|  | Getter = IFace->lookupPrivateMethod(Sel, false); | 
|  | // If we found a getter then this may be a valid dot-reference, we | 
|  | // will look for the matching setter, in case it is needed. | 
|  | Selector SetterSel = | 
|  | SelectorTable::constructSetterName(PP.getIdentifierTable(), | 
|  | PP.getSelectorTable(), Member); | 
|  | ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel); | 
|  | if (!Setter) { | 
|  | // If this reference is in an @implementation, also check for 'private' | 
|  | // methods. | 
|  | Setter = IFace->lookupPrivateMethod(SetterSel, false); | 
|  | } | 
|  | // Look through local category implementations associated with the class. | 
|  | if (!Setter) | 
|  | Setter = IFace->getCategoryClassMethod(SetterSel); | 
|  |  | 
|  | if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) | 
|  | return ExprError(); | 
|  |  | 
|  | if (Getter || Setter) { | 
|  | QualType PType; | 
|  |  | 
|  | ExprValueKind VK = VK_LValue; | 
|  | if (Getter) { | 
|  | PType = getMessageSendResultType(QualType(OT, 0), Getter, true, | 
|  | false); | 
|  | if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType()) | 
|  | VK = VK_RValue; | 
|  | } else { | 
|  | // Get the expression type from Setter's incoming parameter. | 
|  | PType = (*(Setter->param_end() -1))->getType(); | 
|  | } | 
|  | ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); | 
|  |  | 
|  | // FIXME: we must check that the setter has property type. | 
|  | return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, | 
|  | PType, VK, OK, | 
|  | MemberLoc, BaseExpr.take())); | 
|  | } | 
|  |  | 
|  | if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) | 
|  | return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, | 
|  | ObjCImpDecl, HasTemplateArgs); | 
|  |  | 
|  | return ExprError(Diag(MemberLoc, diag::err_property_not_found) | 
|  | << MemberName << BaseType); | 
|  | } | 
|  |  | 
|  | // Normal property access. | 
|  | return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), OpLoc, | 
|  | MemberName, MemberLoc, | 
|  | SourceLocation(), QualType(), false); | 
|  | } | 
|  |  | 
|  | // Handle 'field access' to vectors, such as 'V.xx'. | 
|  | if (BaseType->isExtVectorType()) { | 
|  | // FIXME: this expr should store IsArrow. | 
|  | IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); | 
|  | ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind()); | 
|  | QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc, | 
|  | Member, MemberLoc); | 
|  | if (ret.isNull()) | 
|  | return ExprError(); | 
|  |  | 
|  | return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(), | 
|  | *Member, MemberLoc)); | 
|  | } | 
|  |  | 
|  | // Adjust builtin-sel to the appropriate redefinition type if that's | 
|  | // not just a pointer to builtin-sel again. | 
|  | if (IsArrow && | 
|  | BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) && | 
|  | !Context.getObjCSelRedefinitionType()->isObjCSelType()) { | 
|  | BaseExpr = ImpCastExprToType(BaseExpr.take(), | 
|  | Context.getObjCSelRedefinitionType(), | 
|  | CK_BitCast); | 
|  | return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, | 
|  | ObjCImpDecl, HasTemplateArgs); | 
|  | } | 
|  |  | 
|  | // Failure cases. | 
|  | fail: | 
|  |  | 
|  | // Recover from dot accesses to pointers, e.g.: | 
|  | //   type *foo; | 
|  | //   foo.bar | 
|  | // This is actually well-formed in two cases: | 
|  | //   - 'type' is an Objective C type | 
|  | //   - 'bar' is a pseudo-destructor name which happens to refer to | 
|  | //     the appropriate pointer type | 
|  | if (const PointerType *Ptr = BaseType->getAs<PointerType>()) { | 
|  | if (!IsArrow && Ptr->getPointeeType()->isRecordType() && | 
|  | MemberName.getNameKind() != DeclarationName::CXXDestructorName) { | 
|  | Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) | 
|  | << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() | 
|  | << FixItHint::CreateReplacement(OpLoc, "->"); | 
|  |  | 
|  | // Recurse as an -> access. | 
|  | IsArrow = true; | 
|  | return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, | 
|  | ObjCImpDecl, HasTemplateArgs); | 
|  | } | 
|  | } | 
|  |  | 
|  | // If the user is trying to apply -> or . to a function name, it's probably | 
|  | // because they forgot parentheses to call that function. | 
|  | QualType ZeroArgCallTy; | 
|  | UnresolvedSet<4> Overloads; | 
|  | if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) { | 
|  | if (ZeroArgCallTy.isNull()) { | 
|  | Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) | 
|  | << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange(); | 
|  | UnresolvedSet<2> PlausibleOverloads; | 
|  | for (OverloadExpr::decls_iterator It = Overloads.begin(), | 
|  | DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { | 
|  | const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It); | 
|  | QualType OverloadResultTy = OverloadDecl->getResultType(); | 
|  | if ((!IsArrow && OverloadResultTy->isRecordType()) || | 
|  | (IsArrow && OverloadResultTy->isPointerType() && | 
|  | OverloadResultTy->getPointeeType()->isRecordType())) | 
|  | PlausibleOverloads.addDecl(It.getDecl()); | 
|  | } | 
|  | NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc()); | 
|  | return ExprError(); | 
|  | } | 
|  | if ((!IsArrow && ZeroArgCallTy->isRecordType()) || | 
|  | (IsArrow && ZeroArgCallTy->isPointerType() && | 
|  | ZeroArgCallTy->getPointeeType()->isRecordType())) { | 
|  | // At this point, we know BaseExpr looks like it's potentially callable | 
|  | // with 0 arguments, and that it returns something of a reasonable type, | 
|  | // so we can emit a fixit and carry on pretending that BaseExpr was | 
|  | // actually a CallExpr. | 
|  | SourceLocation ParenInsertionLoc = | 
|  | PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd()); | 
|  | Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) | 
|  | << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange() | 
|  | << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); | 
|  | // FIXME: Try this before emitting the fixit, and suppress diagnostics | 
|  | // while doing so. | 
|  | ExprResult NewBase = | 
|  | ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc, | 
|  | MultiExprArg(*this, 0, 0), | 
|  | ParenInsertionLoc.getLocWithOffset(1)); | 
|  | if (NewBase.isInvalid()) | 
|  | return ExprError(); | 
|  | BaseExpr = NewBase; | 
|  | BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); | 
|  | return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, | 
|  | ObjCImpDecl, HasTemplateArgs); | 
|  | } | 
|  | } | 
|  |  | 
|  | Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) | 
|  | << BaseType << BaseExpr.get()->getSourceRange(); | 
|  |  | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | /// The main callback when the parser finds something like | 
|  | ///   expression . [nested-name-specifier] identifier | 
|  | ///   expression -> [nested-name-specifier] identifier | 
|  | /// where 'identifier' encompasses a fairly broad spectrum of | 
|  | /// possibilities, including destructor and operator references. | 
|  | /// | 
|  | /// \param OpKind either tok::arrow or tok::period | 
|  | /// \param HasTrailingLParen whether the next token is '(', which | 
|  | ///   is used to diagnose mis-uses of special members that can | 
|  | ///   only be called | 
|  | /// \param ObjCImpDecl the current ObjC @implementation decl; | 
|  | ///   this is an ugly hack around the fact that ObjC @implementations | 
|  | ///   aren't properly put in the context chain | 
|  | ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, | 
|  | SourceLocation OpLoc, | 
|  | tok::TokenKind OpKind, | 
|  | CXXScopeSpec &SS, | 
|  | UnqualifiedId &Id, | 
|  | Decl *ObjCImpDecl, | 
|  | bool HasTrailingLParen) { | 
|  | if (SS.isSet() && SS.isInvalid()) | 
|  | return ExprError(); | 
|  |  | 
|  | // Warn about the explicit constructor calls Microsoft extension. | 
|  | if (getLangOptions().MicrosoftExt && | 
|  | Id.getKind() == UnqualifiedId::IK_ConstructorName) | 
|  | Diag(Id.getSourceRange().getBegin(), | 
|  | diag::ext_ms_explicit_constructor_call); | 
|  |  | 
|  | TemplateArgumentListInfo TemplateArgsBuffer; | 
|  |  | 
|  | // Decompose the name into its component parts. | 
|  | DeclarationNameInfo NameInfo; | 
|  | const TemplateArgumentListInfo *TemplateArgs; | 
|  | DecomposeUnqualifiedId(Id, TemplateArgsBuffer, | 
|  | NameInfo, TemplateArgs); | 
|  |  | 
|  | DeclarationName Name = NameInfo.getName(); | 
|  | bool IsArrow = (OpKind == tok::arrow); | 
|  |  | 
|  | NamedDecl *FirstQualifierInScope | 
|  | = (!SS.isSet() ? 0 : FindFirstQualifierInScope(S, | 
|  | static_cast<NestedNameSpecifier*>(SS.getScopeRep()))); | 
|  |  | 
|  | // This is a postfix expression, so get rid of ParenListExprs. | 
|  | ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base); | 
|  | if (Result.isInvalid()) return ExprError(); | 
|  | Base = Result.take(); | 
|  |  | 
|  | if (Base->getType()->isDependentType() || Name.isDependentName() || | 
|  | isDependentScopeSpecifier(SS)) { | 
|  | Result = ActOnDependentMemberExpr(Base, Base->getType(), | 
|  | IsArrow, OpLoc, | 
|  | SS, FirstQualifierInScope, | 
|  | NameInfo, TemplateArgs); | 
|  | } else { | 
|  | LookupResult R(*this, NameInfo, LookupMemberName); | 
|  | ExprResult BaseResult = Owned(Base); | 
|  | Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc, | 
|  | SS, ObjCImpDecl, TemplateArgs != 0); | 
|  | if (BaseResult.isInvalid()) | 
|  | return ExprError(); | 
|  | Base = BaseResult.take(); | 
|  |  | 
|  | if (Result.isInvalid()) { | 
|  | Owned(Base); | 
|  | return ExprError(); | 
|  | } | 
|  |  | 
|  | if (Result.get()) { | 
|  | // The only way a reference to a destructor can be used is to | 
|  | // immediately call it, which falls into this case.  If the | 
|  | // next token is not a '(', produce a diagnostic and build the | 
|  | // call now. | 
|  | if (!HasTrailingLParen && | 
|  | Id.getKind() == UnqualifiedId::IK_DestructorName) | 
|  | return DiagnoseDtorReference(NameInfo.getLoc(), Result.get()); | 
|  |  | 
|  | return move(Result); | 
|  | } | 
|  |  | 
|  | Result = BuildMemberReferenceExpr(Base, Base->getType(), | 
|  | OpLoc, IsArrow, SS, FirstQualifierInScope, | 
|  | R, TemplateArgs); | 
|  | } | 
|  |  | 
|  | return move(Result); | 
|  | } | 
|  |  | 
|  | static ExprResult | 
|  | BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, | 
|  | const CXXScopeSpec &SS, FieldDecl *Field, | 
|  | DeclAccessPair FoundDecl, | 
|  | const DeclarationNameInfo &MemberNameInfo) { | 
|  | // x.a is an l-value if 'a' has a reference type. Otherwise: | 
|  | // x.a is an l-value/x-value/pr-value if the base is (and note | 
|  | //   that *x is always an l-value), except that if the base isn't | 
|  | //   an ordinary object then we must have an rvalue. | 
|  | ExprValueKind VK = VK_LValue; | 
|  | ExprObjectKind OK = OK_Ordinary; | 
|  | if (!IsArrow) { | 
|  | if (BaseExpr->getObjectKind() == OK_Ordinary) | 
|  | VK = BaseExpr->getValueKind(); | 
|  | else | 
|  | VK = VK_RValue; | 
|  | } | 
|  | if (VK != VK_RValue && Field->isBitField()) | 
|  | OK = OK_BitField; | 
|  |  | 
|  | // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] | 
|  | QualType MemberType = Field->getType(); | 
|  | if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) { | 
|  | MemberType = Ref->getPointeeType(); | 
|  | VK = VK_LValue; | 
|  | } else { | 
|  | QualType BaseType = BaseExpr->getType(); | 
|  | if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType(); | 
|  |  | 
|  | Qualifiers BaseQuals = BaseType.getQualifiers(); | 
|  |  | 
|  | // GC attributes are never picked up by members. | 
|  | BaseQuals.removeObjCGCAttr(); | 
|  |  | 
|  | // CVR attributes from the base are picked up by members, | 
|  | // except that 'mutable' members don't pick up 'const'. | 
|  | if (Field->isMutable()) BaseQuals.removeConst(); | 
|  |  | 
|  | Qualifiers MemberQuals | 
|  | = S.Context.getCanonicalType(MemberType).getQualifiers(); | 
|  |  | 
|  | // TR 18037 does not allow fields to be declared with address spaces. | 
|  | assert(!MemberQuals.hasAddressSpace()); | 
|  |  | 
|  | Qualifiers Combined = BaseQuals + MemberQuals; | 
|  | if (Combined != MemberQuals) | 
|  | MemberType = S.Context.getQualifiedType(MemberType, Combined); | 
|  | } | 
|  |  | 
|  | S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field); | 
|  | ExprResult Base = | 
|  | S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), | 
|  | FoundDecl, Field); | 
|  | if (Base.isInvalid()) | 
|  | return ExprError(); | 
|  | return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS, | 
|  | Field, FoundDecl, MemberNameInfo, | 
|  | MemberType, VK, OK)); | 
|  | } | 
|  |  | 
|  | /// 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. | 
|  | ExprResult | 
|  | Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, | 
|  | LookupResult &R, | 
|  | const TemplateArgumentListInfo *TemplateArgs, | 
|  | bool IsKnownInstance) { | 
|  | assert(!R.empty() && !R.isAmbiguous()); | 
|  |  | 
|  | SourceLocation loc = R.getNameLoc(); | 
|  |  | 
|  | // We may have found a field within an anonymous union or struct | 
|  | // (C++ [class.union]). | 
|  | // FIXME: template-ids inside anonymous structs? | 
|  | if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>()) | 
|  | return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD); | 
|  |  | 
|  | // If this is known to be an instance access, go ahead and build an | 
|  | // implicit 'this' expression now. | 
|  | // 'this' expression now. | 
|  | QualType ThisTy = getAndCaptureCurrentThisType(); | 
|  | assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'"); | 
|  |  | 
|  | Expr *baseExpr = 0; // null signifies implicit access | 
|  | if (IsKnownInstance) { | 
|  | SourceLocation Loc = R.getNameLoc(); | 
|  | if (SS.getRange().isValid()) | 
|  | Loc = SS.getRange().getBegin(); | 
|  | baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true); | 
|  | } | 
|  |  | 
|  | return BuildMemberReferenceExpr(baseExpr, ThisTy, | 
|  | /*OpLoc*/ SourceLocation(), | 
|  | /*IsArrow*/ true, | 
|  | SS, | 
|  | /*FirstQualifierInScope*/ 0, | 
|  | R, TemplateArgs); | 
|  | } |