diff options
author | John McCall <rjmccall@apple.com> | 2011-02-03 08:15:49 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-02-03 08:15:49 +0000 |
commit | 5808ce43f8d7e71f5acacc9ca320268c4f37565a (patch) | |
tree | 50a9b47a2ac607cfe51b3498125d8d4b07667e17 /lib/Sema/SemaExpr.cpp | |
parent | 553304523bcce281aa3b1afe0f84ae34a90a3c86 (diff) |
More capturing of 'this': implicit member expressions. Getting that
right for anonymous struct/union members led to me discovering some
seemingly broken code in that area of Sema, which I fixed, partly by
changing the representation of member pointer constants so that
IndirectFieldDecls aren't expanded. This led to assorted cleanups with
member pointers in CodeGen, and while I was doing that I saw some random
other things to clean up.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124785 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 238 |
1 files changed, 128 insertions, 110 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 49637f2305..01fc1c4e6f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/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(); } |