diff options
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 17 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCXXABI.cpp | 7 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGCXXABI.h | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 22 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprConstant.cpp | 51 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprScalar.cpp | 6 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGValue.h | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.h | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 41 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 238 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 34 |
11 files changed, 222 insertions, 201 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index bb22113ed64..71a2fa08d49 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1784,11 +1784,11 @@ public: const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS = 0); ExprResult - BuildAnonymousStructUnionMemberReference(SourceLocation Loc, - const CXXScopeSpec &SS, - IndirectFieldDecl *IndirectField, - Expr *BaseObjectExpr = 0, - SourceLocation OpLoc = SourceLocation()); + BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, + SourceLocation nameLoc, + IndirectFieldDecl *indirectField, + Expr *baseObjectExpr = 0, + SourceLocation opLoc = SourceLocation()); ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs); @@ -2271,7 +2271,12 @@ public: //// ActOnCXXThis - Parse 'this' pointer. - ExprResult ActOnCXXThis(SourceLocation ThisLoc); + ExprResult ActOnCXXThis(SourceLocation loc); + + /// tryCaptureCXXThis - Try to capture a 'this' pointer. Returns a + /// pointer to an instance method whose 'this' pointer is + /// capturable, or null if this is not possible. + CXXMethodDecl *tryCaptureCXXThis(); /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp index 7fb1ffde2d0..8373b660b2f 100644 --- a/clang/lib/CodeGen/CGCXXABI.cpp +++ b/clang/lib/CodeGen/CGCXXABI.cpp @@ -105,10 +105,9 @@ llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { MD->getParent()->getTypeForDecl())); } -llvm::Constant *CGCXXABI::EmitMemberPointer(const FieldDecl *FD) { - return GetBogusMemberPointer(CGM, - CGM.getContext().getMemberPointerType(FD->getType(), - FD->getParent()->getTypeForDecl())); +llvm::Constant *CGCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, + CharUnits offset) { + return GetBogusMemberPointer(CGM, QualType(MPT, 0)); } bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) { diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 547f98ac214..de4df3dcbe8 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -122,7 +122,8 @@ public: virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); /// Create a member pointer for the given field. - virtual llvm::Constant *EmitMemberPointer(const FieldDecl *FD); + virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT, + CharUnits offset); /// Emit a comparison between two member pointers. Returns an i1. virtual llvm::Value * diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 8bac4c0b02b..2108e21ed35 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1178,24 +1178,10 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { setObjCGCLValueClass(getContext(), E, LV); return LV; } - - // If we're emitting an instance method as an independent lvalue, - // we're actually emitting a member pointer. - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND)) - if (MD->isInstance()) { - llvm::Value *V = CGM.getCXXABI().EmitMemberPointer(MD); - return MakeAddrLValue(V, MD->getType(), Alignment); - } - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) - return EmitFunctionDeclLValue(*this, E, FD); - - // If we're emitting a field as an independent lvalue, we're - // actually emitting a member pointer. - if (const FieldDecl *FD = dyn_cast<FieldDecl>(ND)) { - llvm::Value *V = CGM.getCXXABI().EmitMemberPointer(FD); - return MakeAddrLValue(V, FD->getType(), Alignment); - } - + + if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(ND)) + return EmitFunctionDeclLValue(*this, E, fn); + assert(false && "Unhandled DeclRefExpr"); // an invalid LValue, but the assert will diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 51b1de37a95..4d8a60e1e8f 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -450,17 +450,10 @@ public: llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return Visit(E->getInitializer()); } - + llvm::Constant *VisitUnaryAddrOf(UnaryOperator *E) { - if (const MemberPointerType *MPT = - E->getType()->getAs<MemberPointerType>()) { - DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr()); - NamedDecl *ND = DRE->getDecl(); - if (MPT->isMemberFunctionPointer()) - return CGM.getCXXABI().EmitMemberPointer(cast<CXXMethodDecl>(ND)); - else - return CGM.getCXXABI().EmitMemberPointer(cast<FieldDecl>(ND)); - } + if (E->getType()->isMemberPointerType()) + return CGM.getMemberPointerConstant(E); return 0; } @@ -934,6 +927,38 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, return C; } +static uint64_t getFieldOffset(ASTContext &C, const FieldDecl *field) { + const ASTRecordLayout &layout = C.getASTRecordLayout(field->getParent()); + return layout.getFieldOffset(field->getFieldIndex()); +} + +llvm::Constant * +CodeGenModule::getMemberPointerConstant(const UnaryOperator *uo) { + // Member pointer constants always have a very particular form. + const MemberPointerType *type = cast<MemberPointerType>(uo->getType()); + const ValueDecl *decl = cast<DeclRefExpr>(uo->getSubExpr())->getDecl(); + + // A member function pointer. + if (const CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(decl)) + return getCXXABI().EmitMemberPointer(method); + + // Otherwise, a member data pointer. + uint64_t fieldOffset; + if (const FieldDecl *field = dyn_cast<FieldDecl>(decl)) + fieldOffset = getFieldOffset(getContext(), field); + else { + const IndirectFieldDecl *ifield = cast<IndirectFieldDecl>(decl); + + fieldOffset = 0; + for (IndirectFieldDecl::chain_iterator ci = ifield->chain_begin(), + ce = ifield->chain_end(); ci != ce; ++ci) + fieldOffset += getFieldOffset(getContext(), cast<FieldDecl>(*ci)); + } + + CharUnits chars = getContext().toCharUnitsFromBits((int64_t) fieldOffset); + return getCXXABI().EmitMemberDataPointer(type, chars); +} + static void FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T, std::vector<llvm::Constant *> &Elements, @@ -1000,9 +1025,10 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T, uint64_t StartIndex = StartOffset / 8; uint64_t EndIndex = StartIndex + CGM.getContext().getTypeSize(T) / 8; + // FIXME: hardcodes Itanium member pointer representation! llvm::Constant *NegativeOne = llvm::ConstantInt::get(llvm::Type::getInt8Ty(CGM.getLLVMContext()), - -1ULL, /*isSigned=*/true); + -1ULL, /*isSigned*/true); // Fill in the null data member pointer. for (uint64_t I = StartIndex; I != EndIndex; ++I) @@ -1123,6 +1149,5 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { // Itanium C++ ABI 2.3: // A NULL pointer is represented as -1. - return llvm::ConstantInt::get(getTypes().ConvertTypeForMem(T), -1ULL, - /*isSigned=*/true); + return getCXXABI().EmitNullMemberPointer(T->castAs<MemberPointerType>()); } diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 096430e5ce9..57627be9e39 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -307,9 +307,9 @@ public: Value *VisitUnaryAddrOf(const UnaryOperator *E) { - // If the sub-expression is an instance member reference, - // EmitDeclRefLValue will magically emit it with the appropriate - // value as the "address". + if (isa<MemberPointerType>(E->getType())) // never sugared + return CGF.CGM.getMemberPointerConstant(E); + return EmitLValue(E->getSubExpr()).getAddress(); } Value *VisitUnaryDeref(const UnaryOperator *E) { diff --git a/clang/lib/CodeGen/CGValue.h b/clang/lib/CodeGen/CGValue.h index 30c872a8d52..7f77d552032 100644 --- a/clang/lib/CodeGen/CGValue.h +++ b/clang/lib/CodeGen/CGValue.h @@ -254,7 +254,7 @@ public: static LValue MakeAddr(llvm::Value *V, QualType T, unsigned Alignment, ASTContext &Context, llvm::MDNode *TBAAInfo = 0) { - Qualifiers Quals = Context.getCanonicalType(T).getQualifiers(); + Qualifiers Quals = T.getQualifiers(); Quals.setObjCGCAttr(Context.getObjCGCAttrKind(T)); LValue R; diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 7652b88fdc2..39117c2da7f 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -438,6 +438,8 @@ public: Types.UpdateCompletedType(TD); } + llvm::Constant *getMemberPointerConstant(const UnaryOperator *e); + /// EmitConstantExpr - Try to emit the given expression as a /// constant; returns 0 if the expression cannot be emitted as a /// constant. diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 8a7ac0a83a4..2068c2925cf 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -79,7 +79,8 @@ public: llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); - llvm::Constant *EmitMemberPointer(const FieldDecl *FD); + llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT, + CharUnits offset); llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF, llvm::Value *L, @@ -493,43 +494,13 @@ ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { /*Packed=*/false); } -static uint64_t getFieldOffset(const FieldDecl *FD, CodeGenModule &CGM) { - const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(FD->getParent()); - const llvm::StructType *ClassLTy = RL.getLLVMType(); - - unsigned FieldNo = RL.getLLVMFieldNo(FD); - return - CGM.getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo); -} - -llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const FieldDecl *FD) { +llvm::Constant * +ItaniumCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, + CharUnits offset) { // Itanium C++ ABI 2.3: // A pointer to data member is an offset from the base address of // the class object containing it, represented as a ptrdiff_t - - const RecordDecl *parent = FD->getParent(); - if (!parent->isAnonymousStructOrUnion()) - return llvm::ConstantInt::get(getPtrDiffTy(), getFieldOffset(FD, CGM)); - - // Handle a field injected from an anonymous struct or union. - - assert(FD->getDeclName() && "Requested pointer to member with no name!"); - - // Find the record which the field was injected into. - while (parent->isAnonymousStructOrUnion()) - parent = cast<RecordDecl>(parent->getParent()); - - RecordDecl::lookup_const_result lookup = parent->lookup(FD->getDeclName()); - assert(lookup.first != lookup.second && "Didn't find the field!"); - const IndirectFieldDecl *indirectFD = cast<IndirectFieldDecl>(*lookup.first); - - uint64_t Offset = 0; - for (IndirectFieldDecl::chain_iterator - I= indirectFD->chain_begin(), E= indirectFD->chain_end(); I!=E; ++I) { - Offset += getFieldOffset(cast<FieldDecl>(*I), CGM); - } - - return llvm::ConstantInt::get(getPtrDiffTy(), Offset); + return llvm::ConstantInt::get(getPtrDiffTy(), offset.getQuantity()); } llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 49637f23059..01fc1c4e6f5 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -889,109 +889,116 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, const DeclarationNameInfo &MemberNameInfo); ExprResult -Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, - const CXXScopeSpec &SS, - IndirectFieldDecl *IndirectField, - Expr *BaseObjectExpr, - SourceLocation OpLoc) { - // Build the expression that refers to the base object, from - // which we will build a sequence of member references to each - // of the anonymous union objects and, eventually, the field we - // found via name lookup. - bool BaseObjectIsPointer = false; - Qualifiers BaseQuals; - VarDecl *BaseObject = IndirectField->getVarDecl(); - if (BaseObject) { - // BaseObject is an anonymous struct/union variable (and is, - // therefore, not part of another non-anonymous record). - MarkDeclarationReferenced(Loc, BaseObject); - BaseObjectExpr = - new (Context) DeclRefExpr(BaseObject, BaseObject->getType(), - VK_LValue, Loc); - BaseQuals - = Context.getCanonicalType(BaseObject->getType()).getQualifiers(); - } else if (BaseObjectExpr) { +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(); + 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(SS, 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 *ObjectPtr = ObjectType->getAs<PointerType>()) { - BaseObjectIsPointer = true; - ObjectType = ObjectPtr->getPointeeType(); + QualType objectType = baseObjectExpr->getType(); + + if (const PointerType *ptr = objectType->getAs<PointerType>()) { + baseObjectIsPointer = true; + objectType = ptr->getPointeeType(); + } else { + baseObjectIsPointer = false; } - BaseQuals - = Context.getCanonicalType(ObjectType).getQualifiers(); + 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". - DeclContext *DC = getFunctionLevelDeclContext(); - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) { - if (!MD->isStatic()) { - QualType AnonFieldType - = Context.getTagDeclType( - cast<RecordDecl>( - (*IndirectField->chain_begin())->getDeclContext())); - QualType ThisType = Context.getTagDeclType(MD->getParent()); - if ((Context.getCanonicalType(AnonFieldType) - == Context.getCanonicalType(ThisType)) || - IsDerivedFrom(ThisType, AnonFieldType)) { - // Our base object expression is "this". - BaseObjectExpr = new (Context) CXXThisExpr(Loc, - MD->getThisType(Context), - /*isImplicit=*/true); - BaseObjectIsPointer = true; - } - } else { - return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method) - << IndirectField->getDeclName()); - } - BaseQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers()); + CXXMethodDecl *method = tryCaptureCXXThis(); + if (!method) { + Diag(loc, diag::err_invalid_member_use_in_static_method) + << indirectField->getDeclName(); + return ExprError(); } - if (!BaseObjectExpr) { - // The field is referenced for a pointer-to-member expression, e.g: - // - // struct S { - // union { - // char c; - // }; - // }; - // char S::*foo = &S::c; - // - FieldDecl *field = IndirectField->getAnonField(); - DeclarationNameInfo NameInfo(field->getDeclName(), Loc); - return BuildDeclRefExpr(field, field->getType().getNonReferenceType(), - VK_LValue, NameInfo, &SS); - } + // Our base object expression is "this". + baseObjectExpr = + new (Context) CXXThisExpr(loc, method->getThisType(Context), + /*isImplicit=*/ true); + baseObjectIsPointer = true; + baseQuals = Qualifiers::fromCVRMask(method->getTypeQualifiers()); } // Build the implicit member references to the field of the // anonymous struct/union. - Expr *Result = BaseObjectExpr; + Expr *result = baseObjectExpr; + IndirectFieldDecl::chain_iterator + FI = indirectField->chain_begin(), FEnd = indirectField->chain_end(); - 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, + SS, 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; - // Skip the first VarDecl if present. - if (BaseObject) - FI++; for (; FI != FEnd; FI++) { - FieldDecl *Field = cast<FieldDecl>(*FI); + FieldDecl *field = cast<FieldDecl>(*FI); // FIXME: these are somewhat meaningless - DeclarationNameInfo MemberNameInfo(Field->getDeclName(), Loc); - DeclAccessPair FoundDecl = DeclAccessPair::make(Field, Field->getAccess()); + DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); + DeclAccessPair foundDecl = DeclAccessPair::make(field, field->getAccess()); + CXXScopeSpec memberSS; - Result = BuildFieldReferenceExpr(*this, Result, BaseObjectIsPointer, - SS, Field, FoundDecl, MemberNameInfo) + result = BuildFieldReferenceExpr(*this, result, /*isarrow*/ false, + memberSS, field, foundDecl, memberNameInfo) .take(); - - // All the implicit accesses are dot-accesses. - BaseObjectIsPointer = false; } - return Owned(Result); + return Owned(result); } /// Decomposes the given name into a DeclarationNameInfo, its location, and @@ -1186,23 +1193,24 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, /// Diagnose a reference to a field with no object available. static void DiagnoseInstanceReference(Sema &SemaRef, const CXXScopeSpec &SS, - const LookupResult &R) { - SourceLocation Loc = R.getNameLoc(); + NamedDecl *rep, + const DeclarationNameInfo &nameInfo) { + SourceLocation Loc = nameInfo.getLoc(); SourceRange Range(Loc); if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); - if (R.getAsSingle<FieldDecl>() || R.getAsSingle<IndirectFieldDecl>()) { + 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 << R.getLookupName(); + << Range << nameInfo.getName(); return; } } SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use) - << R.getLookupName() << Range; + << nameInfo.getName() << Range; return; } @@ -1678,7 +1686,8 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, case IMA_Error_StaticContext: case IMA_Error_Unrelated: - DiagnoseInstanceReference(*this, SS, R); + DiagnoseInstanceReference(*this, SS, R.getRepresentativeDecl(), + R.getLookupNameInfo()); return ExprError(); } @@ -2075,29 +2084,30 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, bool IsKnownInstance) { assert(!R.empty() && !R.isAmbiguous()); - SourceLocation Loc = R.getNameLoc(); + 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 (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>()) - return BuildAnonymousStructUnionMemberReference(Loc, SS, FD); + return BuildAnonymousStructUnionMemberReference(SS, R.getNameLoc(), FD); - - // If this is known to be an instance access, go ahead and build a + // If this is known to be an instance access, go ahead and build an + // implicit 'this' expression now. // 'this' expression now. - DeclContext *DC = getFunctionLevelDeclContext(); - QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context); - Expr *This = 0; // null signifies implicit access + CXXMethodDecl *method = tryCaptureCXXThis(); + assert(method && "didn't correctly pre-flight capture of 'this'"); + + QualType thisType = method->getThisType(Context); + Expr *baseExpr = 0; // null signifies implicit access if (IsKnownInstance) { SourceLocation Loc = R.getNameLoc(); if (SS.getRange().isValid()) Loc = SS.getRange().getBegin(); - This = new (Context) CXXThisExpr(Loc, ThisType, /*isImplicit=*/true); + baseExpr = new (Context) CXXThisExpr(loc, thisType, /*isImplicit=*/true); } - return BuildMemberReferenceExpr(This, ThisType, + return BuildMemberReferenceExpr(baseExpr, thisType, /*OpLoc*/ SourceLocation(), /*IsArrow*/ true, SS, @@ -2221,6 +2231,7 @@ static ExprValueKind getValueKindForDecl(ASTContext &Context, // FIXME: It's not clear to me why NonTypeTemplateParmDecl is a VarDecl. if (isa<VarDecl>(D) && !isa<NonTypeTemplateParmDecl>(D)) return VK_LValue; if (isa<FieldDecl>(D)) return VK_LValue; + if (isa<IndirectFieldDecl>(D)) return VK_LValue; if (!Context.getLangOptions().CPlusPlus) return VK_RValue; if (isa<FunctionDecl>(D)) { if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance()) @@ -2273,9 +2284,13 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, if (VD->isInvalidDecl()) return ExprError(); - // Handle anonymous. - if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(VD)) - return BuildAnonymousStructUnionMemberReference(Loc, SS, FD); + // Handle members of anonymous structs and unions. If we got here, + // and the reference is to a class member indirect field, then this + // must be the subject of a pointer-to-member expression. + if (IndirectFieldDecl *indirectField = dyn_cast<IndirectFieldDecl>(VD)) + if (!indirectField->isCXXClassMember()) + return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(), + indirectField); ExprValueKind VK = getValueKindForDecl(Context, VD); @@ -3161,14 +3176,15 @@ static void DiagnoseQualifiedMemberReference(Sema &SemaRef, Expr *BaseExpr, QualType BaseType, const CXXScopeSpec &SS, - const LookupResult &R) { + NamedDecl *rep, + const DeclarationNameInfo &nameInfo) { // If this is an implicit member access, use a different set of // diagnostics. if (!BaseExpr) - return DiagnoseInstanceReference(SemaRef, SS, R); + return DiagnoseInstanceReference(SemaRef, SS, rep, nameInfo); - SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_of_unrelated) - << SS.getRange() << R.getRepresentativeDecl() << BaseType; + SemaRef.Diag(nameInfo.getLoc(), diag::err_qualified_member_of_unrelated) + << SS.getRange() << rep << BaseType; } // Check whether the declarations we found through a nested-name @@ -3217,7 +3233,9 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, return false; } - DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS, R); + DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS, + R.getRepresentativeDecl(), + R.getLookupNameInfo()); return true; } @@ -3455,7 +3473,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl)) // We may have found a field within an anonymous union or struct // (C++ [class.union]). - return BuildAnonymousStructUnionMemberReference(MemberLoc, SS, FD, + return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD, BaseExpr, OpLoc); if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) { @@ -7255,7 +7273,7 @@ void Sema::ConvertPropertyForLValue(Expr *&LHS, Expr *&RHS, QualType &LHSTy) { /// - *(x + 1) -> x, if x is an array /// - &"123"[2] -> 0 /// - & __real__ x -> x -static NamedDecl *getPrimaryDecl(Expr *E) { +static ValueDecl *getPrimaryDecl(Expr *E) { switch (E->getStmtClass()) { case Stmt::DeclRefExprClass: return cast<DeclRefExpr>(E)->getDecl(); @@ -7332,7 +7350,7 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, // Technically, there should be a check for array subscript // expressions here, but the result of one is always an lvalue anyway. } - NamedDecl *dcl = getPrimaryDecl(op); + ValueDecl *dcl = getPrimaryDecl(op); Expr::LValueClassification lval = op->ClassifyLValue(S.Context); if (lval == Expr::LV_ClassTemporary) { @@ -7408,17 +7426,17 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, } } else if (isa<FunctionTemplateDecl>(dcl)) { return S.Context.OverloadTy; - } else if (FieldDecl *FD = dyn_cast<FieldDecl>(dcl)) { + } else if (isa<FieldDecl>(dcl) || isa<IndirectFieldDecl>(dcl)) { // Okay: we can take the address of a field. // Could be a pointer to member, though, if there is an explicit // scope qualifier for the class. if (isa<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier()) { DeclContext *Ctx = dcl->getDeclContext(); if (Ctx && Ctx->isRecord()) { - if (FD->getType()->isReferenceType()) { + if (dcl->getType()->isReferenceType()) { S.Diag(OpLoc, diag::err_cannot_form_pointer_to_member_of_reference_type) - << FD->getDeclName() << FD->getType(); + << dcl->getDeclName() << dcl->getType(); return QualType(); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 73e9778a742..81031a54eed 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -559,19 +559,22 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { return false; } -ExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { - /// C++ 9.3.2: In the body of a non-static member function, the keyword this - /// is a non-lvalue expression whose value is the address of the object for - /// which the function is called. - - // Ignore block scopes (but nothing else). +CXXMethodDecl *Sema::tryCaptureCXXThis() { + // Ignore block scopes: we can capture through them. + // Ignore nested enum scopes: we'll diagnose non-constant expressions + // where they're invalid, and other uses are legitimate. + // Don't ignore nested class scopes: you can't use 'this' in a local class. DeclContext *DC = CurContext; - while (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext(); + while (true) { + if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext(); + else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext(); + else break; + } - // If we're not an instance method, error out. + // If we're not in an instance method, error out. CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC); if (!method || !method->isInstance()) - return ExprError(Diag(ThisLoc, diag::err_invalid_this_use)); + return 0; // Mark that we're closing on 'this' in all the block scopes, if applicable. for (unsigned idx = FunctionScopes.size() - 1; @@ -579,7 +582,18 @@ ExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { --idx) cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true; - return Owned(new (Context) CXXThisExpr(ThisLoc, method->getThisType(Context), + return method; +} + +ExprResult Sema::ActOnCXXThis(SourceLocation loc) { + /// C++ 9.3.2: In the body of a non-static member function, the keyword this + /// is a non-lvalue expression whose value is the address of the object for + /// which the function is called. + + CXXMethodDecl *method = tryCaptureCXXThis(); + if (!method) return Diag(loc, diag::err_invalid_this_use); + + return Owned(new (Context) CXXThisExpr(loc, method->getThisType(Context), /*isImplicit=*/false)); } |