From: John McCall Date: Thu, 18 Nov 2010 19:01:18 +0000 (+0000) Subject: Add an assertion, fix a whole bunch of bugs, comment the assertion X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0943168ac126b8047f30f6bd215fbe7db14d61ba;p=clang Add an assertion, fix a whole bunch of bugs, comment the assertion out because there are still bugs left. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@119722 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 20fd7905eb..2ffaeb55cb 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -267,7 +267,10 @@ public: /// give its value kind. static ExprValueKind getValueKindForType(QualType T) { if (const ReferenceType *RT = T->getAs()) - return isa(RT) ? VK_LValue : VK_XValue; + return (isa(RT) + ? VK_LValue + : (RT->getPointeeType()->isFunctionType() + ? VK_LValue : VK_XValue)); return VK_RValue; } @@ -2455,8 +2458,8 @@ class ConditionalOperator : public Expr { public: ConditionalOperator(Expr *cond, SourceLocation QLoc, Expr *lhs, SourceLocation CLoc, Expr *rhs, Expr *save, - QualType t, ExprValueKind VK) - : Expr(ConditionalOperatorClass, t, VK, OK_Ordinary, + QualType t, ExprValueKind VK, ExprObjectKind OK) + : Expr(ConditionalOperatorClass, t, VK, OK, // FIXME: the type of the conditional operator doesn't // depend on the type of the conditional, but the standard // seems to imply that it could. File a bug! @@ -3422,7 +3425,8 @@ class ExtVectorElementExpr : public Expr { public: ExtVectorElementExpr(QualType ty, ExprValueKind VK, Expr *base, IdentifierInfo &accessor, SourceLocation loc) - : Expr(ExtVectorElementExprClass, ty, VK, OK_VectorComponent, + : Expr(ExtVectorElementExprClass, ty, VK, + (VK == VK_RValue ? OK_Ordinary : OK_VectorComponent), base->isTypeDependent(), base->isValueDependent()), Base(base), Accessor(&accessor), AccessorLoc(loc) {} diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index a1d464e6fd..5c333f818b 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -423,7 +423,7 @@ public: Operand(Operand), Range(R) { } CXXUuidofExpr(QualType Ty, Expr *Operand, SourceRange R) - : Expr(CXXUuidofExprClass, Ty, /*FIXME*/ VK_LValue, OK_Ordinary, + : Expr(CXXUuidofExprClass, Ty, VK_RValue, OK_Ordinary, false, Operand->isTypeDependent()), Operand(Operand), Range(R) { } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index aa3d790b8e..1790351f63 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4204,14 +4204,12 @@ public: void ConvertPropertyAssignment(Expr *LHS, Expr *&RHS, QualType& LHSTy); - QualType CheckCommaOperands( // C99 6.5.17 - Expr *lex, Expr *&rex, SourceLocation OpLoc); QualType CheckConditionalOperands( // C99 6.5.15 Expr *&cond, Expr *&lhs, Expr *&rhs, Expr *&save, - ExprValueKind &VK, SourceLocation questionLoc); + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc); QualType CXXCheckConditionalOperands( // C++ 5.16 - Expr *&cond, Expr *&lhs, Expr *&rhs, Expr *&save, ExprValueKind &VK, - SourceLocation questionLoc); + Expr *&cond, Expr *&lhs, Expr *&rhs, Expr *&save, + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc); QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool *NonStandardCompositeType = 0); @@ -4223,19 +4221,6 @@ public: QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx, SourceLocation l, bool isRel); - /// type checking unary operators (subroutines of ActOnUnaryOp). - /// C99 6.5.3.1, 6.5.3.2, 6.5.3.4 - QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc, - bool isInc, bool isPrefix); - QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc); - QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc); - QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc, bool isReal); - - /// type checking primary expressions. - QualType CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, - const IdentifierInfo *Comp, - SourceLocation CmpLoc); - /// type checking declaration initializers (C99 6.7.8) bool CheckInitList(const InitializedEntity &Entity, InitListExpr *&InitList, QualType &DeclType); diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 63bf2dd091..6260330f9f 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -677,7 +677,7 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type, SourceLocation RParenLoc) : Expr(CXXUnresolvedConstructExprClass, Type->getType().getNonReferenceType(), - VK_RValue, OK_Ordinary, + VK_LValue, OK_Ordinary, Type->getType()->isDependentType(), true), Type(Type), LParenLoc(LParenLoc), diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 4677910798..ba5970038d 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -64,6 +64,21 @@ Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const { kind = Cl::CL_Void; } +#if 0 + // Enable this assertion for testing. + switch (kind) { + case Cl::CL_LValue: assert(getValueKind() == VK_LValue); break; + case Cl::CL_XValue: assert(getValueKind() == VK_XValue); break; + case Cl::CL_Function: + case Cl::CL_Void: + case Cl::CL_DuplicateVectorComponents: + case Cl::CL_MemberFunction: + case Cl::CL_SubObjCPropertySetting: + case Cl::CL_ClassTemporary: + case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break; + } +#endif + Cl::ModifiableType modifiable = Cl::CM_Untested; if (Loc) modifiable = IsModifiable(Ctx, this, kind, *Loc); @@ -380,6 +395,10 @@ static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) { // *E1 is an lvalue if (E->isArrow()) return Cl::CL_LValue; + Expr *Base = E->getBase()->IgnoreParenImpCasts(); + if (isa(Base) || + isa(Base)) + return Cl::CL_SubObjCPropertySetting; return ClassifyInternal(Ctx, E->getBase()); } diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp index 7987c65ad2..0f58a9ee0c 100644 --- a/lib/Rewrite/RewriteObjC.cpp +++ b/lib/Rewrite/RewriteObjC.cpp @@ -3151,7 +3151,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, new (Context) ConditionalOperator(lessThanExpr, SourceLocation(), CE, SourceLocation(), STCE, (Expr*)0, - returnType, VK_RValue); + returnType, VK_RValue, OK_Ordinary); ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), CondExpr); } @@ -4687,7 +4687,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { SourceLocation(), cast(LHSStmt), SourceLocation(), cast(RHSStmt), (Expr*)0, - Exp->getType(), VK_RValue); + Exp->getType(), VK_RValue, OK_Ordinary); return CondExpr; } else if (const ObjCIvarRefExpr *IRE = dyn_cast(BlockExp)) { CPT = IRE->getType()->getAs(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 77f604a653..7217b25652 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4906,7 +4906,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Construct a reference to the "other" object. We'll be using this // throughout the generated ASTs. - Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, VK_RValue, Loc).take(); + Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, VK_LValue, Loc).take(); assert(OtherRef && "Reference to parameter cannot fail!"); // Construct the "this" pointer. We'll be using this throughout the generated @@ -5012,11 +5012,11 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, MemberLookup.addDecl(*Field); MemberLookup.resolveKind(); ExprResult From = BuildMemberReferenceExpr(OtherRef, OtherRefType, - Loc, /*IsArrow=*/false, - SS, 0, MemberLookup, 0); + Loc, /*IsArrow=*/false, + SS, 0, MemberLookup, 0); ExprResult To = BuildMemberReferenceExpr(This, This->getType(), - Loc, /*IsArrow=*/true, - SS, 0, MemberLookup, 0); + Loc, /*IsArrow=*/true, + SS, 0, MemberLookup, 0); assert(!From.isInvalid() && "Implicit field reference cannot fail"); assert(!To.isInvalid() && "Implicit field reference cannot fail"); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 25c27fe628..b70486a1b8 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -778,6 +778,12 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, return ExprError(); } } + + // This ridiculousness brought to you by 'extern void x;' and the + // GNU compiler collection. + } else if (!getLangOptions().CPlusPlus && !Ty.hasQualifiers() && + Ty->isVoidType()) { + VK = VK_RValue; } } @@ -2092,7 +2098,9 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, static ExprValueKind getValueKindForDecl(ASTContext &Context, const ValueDecl *D) { - if (isa(D) || isa(D)) return VK_LValue; + // FIXME: It's not clear to me why NonTypeTemplateParmDecl is a VarDecl. + if (isa(D) && !isa(D)) return VK_LValue; + if (isa(D)) return VK_LValue; if (!Context.getLangOptions().CPlusPlus) return VK_RValue; if (isa(D)) { if (isa(D) && cast(D)->isInstance()) @@ -2592,9 +2600,10 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, return move(Result); } -QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) { +static QualType CheckRealImagOperand(Sema &S, Expr *&V, SourceLocation Loc, + bool isReal) { if (V->isTypeDependent()) - return Context.DependentTy; + return S.Context.DependentTy; // These operators return the element type of a complex type. if (const ComplexType *CT = V->getType()->getAs()) @@ -2605,15 +2614,15 @@ QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) { return V->getType(); // Test for placeholders. - ExprResult PR = CheckPlaceholderExpr(V, Loc); + ExprResult PR = S.CheckPlaceholderExpr(V, Loc); if (PR.isInvalid()) return QualType(); if (PR.take() != V) { V = PR.take(); - return CheckRealImagOperand(V, Loc, isReal); + return CheckRealImagOperand(S, V, Loc, isReal); } // Reject anything else. - Diag(Loc, diag::err_realimag_invalid_type) << V->getType() + S.Diag(Loc, diag::err_realimag_invalid_type) << V->getType() << (isReal ? "__real" : "__imag"); return QualType(); } @@ -2633,6 +2642,19 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, return BuildUnaryOp(S, OpLoc, Opc, Input); } +/// Expressions of certain arbitrary types are forbidden by C from +/// having l-value type. These are: +/// - 'void', but not qualified void +/// - function types +/// +/// The exact rule here is C99 6.3.2.1: +/// An lvalue is an expression with an object type or an incomplete +/// type other than void. +static bool IsCForbiddenLValueType(ASTContext &C, QualType T) { + return ((T->isVoidType() && !T.hasQualifiers()) || + T->isFunctionType()); +} + ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc) { @@ -2771,6 +2793,10 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, // GNU extension: subscripting on pointer to void Diag(LLoc, diag::ext_gnu_void_ptr) << BaseExpr->getSourceRange(); + + // C forbids expressions of unqualified void type from being l-values. + // See IsCForbiddenLValueType. + if (!ResultType.hasQualifiers()) VK = VK_RValue; } else if (!ResultType->isDependentType() && RequireCompleteType(LLoc, ResultType, PDiag(diag::err_subscript_incomplete_type) @@ -2784,13 +2810,20 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, return ExprError(); } + assert(VK == VK_RValue || LangOpts.CPlusPlus || + !IsCForbiddenLValueType(Context, ResultType)); + return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp, ResultType, VK, OK, RLoc)); } -QualType Sema:: -CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, - const IdentifierInfo *CompName, +/// 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. @@ -2811,25 +2844,36 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, // 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 (vecType->getPointAccessorIdx(*compStr) != -1) { - do + } else if (!HexSwizzle && + (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) { + do { + if (HasIndex[Idx]) HasRepeated = true; + HasIndex[Idx] = true; compStr++; - while (*compStr && vecType->getPointAccessorIdx(*compStr) != -1); - } else if (HexSwizzle || vecType->getNumericAccessorIdx(*compStr) != -1) { - do + } 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++; - while (*compStr && vecType->getNumericAccessorIdx(*compStr) != -1); + } } 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. - Diag(OpLoc, diag::err_ext_vector_component_name_illegal) + S.Diag(OpLoc, diag::err_ext_vector_component_name_illegal) << llvm::StringRef(compStr, 1) << SourceRange(CompLoc); return QualType(); } @@ -2844,7 +2888,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, while (*compStr) { if (!vecType->isAccessorWithinNumElements(*compStr++)) { - Diag(OpLoc, diag::err_ext_vector_component_exceeds_length) + S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length) << baseType << SourceRange(CompLoc); return QualType(); } @@ -2864,12 +2908,14 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, if (CompSize == 1) return vecType->getElementType(); - QualType VT = Context.getExtVectorType(vecType->getElementType(), CompSize); + 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 (unsigned i = 0, E = ExtVectorDecls.size(); i != E; ++i) { - if (ExtVectorDecls[i]->getUnderlyingType() == VT) - return Context.getTypedefType(ExtVectorDecls[i]); + for (unsigned i = 0, E = S.ExtVectorDecls.size(); i != E; ++i) { + if (S.ExtVectorDecls[i]->getUnderlyingType() == VT) + return S.Context.getTypedefType(S.ExtVectorDecls[i]); } return VT; // should never get here (a typedef type should always be found). } @@ -3271,8 +3317,18 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, // 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). - ExprValueKind VK = IsArrow ? VK_LValue : BaseExpr->getValueKind(); + // 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 && FD->isBitField()) + OK = OK_BitField; // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] QualType MemberType = FD->getType(); @@ -3297,8 +3353,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, return ExprError(); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, FD, FoundDecl, MemberNameInfo, - MemberType, VK, - FD->isBitField() ? OK_BitField : OK_Ordinary)); + MemberType, VK, OK)); } if (VarDecl *Var = dyn_cast(MemberDecl)) { @@ -3306,8 +3361,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, Var, FoundDecl, MemberNameInfo, Var->getType().getNonReferenceType(), - Expr::getValueKindForType(Var->getType()), - OK_Ordinary)); + VK_LValue, OK_Ordinary)); } if (CXXMethodDecl *MemberFn = dyn_cast(MemberDecl)) { @@ -3469,15 +3523,21 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (Getter || Setter) { QualType PType; - if (Getter) + ExprValueKind VK = VK_LValue; + if (Getter) { PType = Getter->getSendResultType(); - else + if (!getLangOptions().CPlusPlus && + IsCForbiddenLValueType(Context, PType)) + 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) ObjCImplicitSetterGetterRefExpr(Getter, - PType, VK_LValue, - OK_ObjCProperty, + PType, VK, OK, Setter, MemberLoc, BaseExpr)); } return ExprError(Diag(MemberLoc, diag::err_property_not_found) @@ -3657,10 +3717,15 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, SetterSel, Context)) SMD = dyn_cast(SDecl); QualType PType = OMD->getSendResultType(); + + ExprValueKind VK = VK_LValue; + if (!getLangOptions().CPlusPlus && + IsCForbiddenLValueType(Context, PType)) + VK = VK_RValue; + ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); + return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(OMD, PType, - VK_LValue, - OK_ObjCProperty, - SMD, + VK, OK, SMD, MemberLoc, BaseExpr)); } @@ -3689,13 +3754,14 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Handle 'field access' to vectors, such as 'V.xx'. if (BaseType->isExtVectorType()) { IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - QualType ret = CheckExtVectorComponent(BaseType, OpLoc, Member, MemberLoc); + ExprValueKind VK = BaseExpr->getValueKind(); + QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc, + Member, MemberLoc); if (ret.isNull()) return ExprError(); - return Owned(new (Context) ExtVectorElementExpr(ret, - BaseExpr->getValueKind(), - BaseExpr, *Member, - MemberLoc)); + + return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr, + *Member, MemberLoc)); } Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) @@ -4727,6 +4793,7 @@ ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L, /// C99 6.5.15 QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, Expr *&SAVE, ExprValueKind &VK, + ExprObjectKind &OK, SourceLocation QuestionLoc) { // If both LHS and RHS are overloaded functions, try to resolve them. if (Context.hasSameType(LHS->getType(), RHS->getType()) && @@ -4745,9 +4812,11 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // C++ is sufficiently different to merit its own checker. if (getLangOptions().CPlusPlus) - return CXXCheckConditionalOperands(Cond, LHS, RHS, SAVE, VK, QuestionLoc); + return CXXCheckConditionalOperands(Cond, LHS, RHS, SAVE, + VK, OK, QuestionLoc); VK = VK_RValue; + OK = OK_Ordinary; UsualUnaryConversions(Cond); if (SAVE) { @@ -5113,15 +5182,16 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, } ExprValueKind VK = VK_RValue; + ExprObjectKind OK = OK_Ordinary; QualType result = CheckConditionalOperands(CondExpr, LHSExpr, RHSExpr, - SAVEExpr, VK, QuestionLoc); + SAVEExpr, VK, OK, QuestionLoc); if (result.isNull()) return ExprError(); return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc, LHSExpr, ColonLoc, RHSExpr, SAVEExpr, - result, VK)); + result, VK, OK)); } // CheckPointerTypesForAssignment - This is a very tricky routine (despite @@ -6774,14 +6844,15 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, } // C99 6.5.17 -QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) { - DiagnoseUnusedExprResult(LHS); +static QualType CheckCommaOperands(Sema &S, Expr *LHS, Expr *&RHS, + SourceLocation Loc) { + S.DiagnoseUnusedExprResult(LHS); - ExprResult LHSResult = CheckPlaceholderExpr(LHS, Loc); + ExprResult LHSResult = S.CheckPlaceholderExpr(LHS, Loc); if (LHSResult.isInvalid()) return QualType(); - ExprResult RHSResult = CheckPlaceholderExpr(RHS, Loc); + ExprResult RHSResult = S.CheckPlaceholderExpr(RHS, Loc); if (RHSResult.isInvalid()) return QualType(); RHS = RHSResult.take(); @@ -6789,14 +6860,14 @@ QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) { // C's comma performs lvalue conversion (C99 6.3.2.1) on both its // operands, but not unary promotions. // C++'s comma does not do any conversions at all (C++ [expr.comma]p1). - if (!getLangOptions().CPlusPlus) { - DefaultFunctionArrayLvalueConversion(LHS); + if (!S.getLangOptions().CPlusPlus) { + S.DefaultFunctionArrayLvalueConversion(LHS); if (!LHS->getType()->isVoidType()) - RequireCompleteType(Loc, LHS->getType(), diag::err_incomplete_type); + S.RequireCompleteType(Loc, LHS->getType(), diag::err_incomplete_type); - DefaultFunctionArrayLvalueConversion(RHS); + S.DefaultFunctionArrayLvalueConversion(RHS); if (!RHS->getType()->isVoidType()) - RequireCompleteType(Loc, RHS->getType(), diag::err_incomplete_type); + S.RequireCompleteType(Loc, RHS->getType(), diag::err_incomplete_type); } return RHS->getType(); @@ -6804,22 +6875,24 @@ QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) { /// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine /// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions. -QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, - bool isInc, bool isPrefix) { +static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, + ExprValueKind &VK, + SourceLocation OpLoc, + bool isInc, bool isPrefix) { if (Op->isTypeDependent()) - return Context.DependentTy; + return S.Context.DependentTy; QualType ResType = Op->getType(); assert(!ResType.isNull() && "no type for increment/decrement expression"); - if (getLangOptions().CPlusPlus && ResType->isBooleanType()) { + if (S.getLangOptions().CPlusPlus && ResType->isBooleanType()) { // Decrement of bool is not allowed. if (!isInc) { - Diag(OpLoc, diag::err_decrement_bool) << Op->getSourceRange(); + S.Diag(OpLoc, diag::err_decrement_bool) << Op->getSourceRange(); return QualType(); } // Increment of bool sets it to true, but is deprecated. - Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange(); + S.Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange(); } else if (ResType->isRealType()) { // OK! } else if (ResType->isAnyPointerType()) { @@ -6827,56 +6900,62 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, // C99 6.5.2.4p2, 6.5.6p2 if (PointeeTy->isVoidType()) { - if (getLangOptions().CPlusPlus) { - Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type) + if (S.getLangOptions().CPlusPlus) { + S.Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type) << Op->getSourceRange(); return QualType(); } // Pointer to void is a GNU extension in C. - Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange(); + S.Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange(); } else if (PointeeTy->isFunctionType()) { - if (getLangOptions().CPlusPlus) { - Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type) + if (S.getLangOptions().CPlusPlus) { + S.Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type) << Op->getType() << Op->getSourceRange(); return QualType(); } - Diag(OpLoc, diag::ext_gnu_ptr_func_arith) + S.Diag(OpLoc, diag::ext_gnu_ptr_func_arith) << ResType << Op->getSourceRange(); - } else if (RequireCompleteType(OpLoc, PointeeTy, - PDiag(diag::err_typecheck_arithmetic_incomplete_type) + } else if (S.RequireCompleteType(OpLoc, PointeeTy, + S.PDiag(diag::err_typecheck_arithmetic_incomplete_type) << Op->getSourceRange() << ResType)) return QualType(); // Diagnose bad cases where we step over interface counts. - else if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { - Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) + else if (PointeeTy->isObjCObjectType() && S.LangOpts.ObjCNonFragileABI) { + S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) << PointeeTy << Op->getSourceRange(); return QualType(); } } else if (ResType->isAnyComplexType()) { // C99 does not support ++/-- on complex types, we allow as an extension. - Diag(OpLoc, diag::ext_integer_increment_complex) + S.Diag(OpLoc, diag::ext_integer_increment_complex) << ResType << Op->getSourceRange(); } else if (ResType->isPlaceholderType()) { - ExprResult PR = CheckPlaceholderExpr(Op, OpLoc); + ExprResult PR = S.CheckPlaceholderExpr(Op, OpLoc); if (PR.isInvalid()) return QualType(); - return CheckIncrementDecrementOperand(PR.take(), OpLoc, isInc, isPrefix); + return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc, + isInc, isPrefix); } else { - Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) + S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) << ResType << int(isInc) << Op->getSourceRange(); return QualType(); } // At this point, we know we have a real, complex or pointer type. // Now make sure the operand is a modifiable lvalue. - if (CheckForModifiableLvalue(Op, OpLoc, *this)) + if (CheckForModifiableLvalue(Op, OpLoc, S)) return QualType(); // In C++, a prefix increment is the same type as the operand. Otherwise // (in C or with postfix), the increment is the unqualified type of the // operand. - return isPrefix && getLangOptions().CPlusPlus - ? ResType : ResType.getUnqualifiedType(); + if (isPrefix && S.getLangOptions().CPlusPlus) { + VK = VK_LValue; + return ResType; + } else { + VK = VK_RValue; + return ResType.getUnqualifiedType(); + } } void Sema::ConvertPropertyAssignment(Expr *LHS, Expr *&RHS, QualType& LHSTy) { @@ -6971,20 +7050,21 @@ static NamedDecl *getPrimaryDecl(Expr *E) { /// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue. /// In C++, the operand might be an overloaded function name, in which case /// we allow the '&' but retain the overloaded-function type. -QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) { +static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, + SourceLocation OpLoc) { if (OrigOp->isTypeDependent()) - return Context.DependentTy; - if (OrigOp->getType() == Context.OverloadTy) - return Context.OverloadTy; + return S.Context.DependentTy; + if (OrigOp->getType() == S.Context.OverloadTy) + return S.Context.OverloadTy; - ExprResult PR = CheckPlaceholderExpr(OrigOp, OpLoc); + ExprResult PR = S.CheckPlaceholderExpr(OrigOp, OpLoc); if (PR.isInvalid()) return QualType(); OrigOp = PR.take(); // Make sure to ignore parentheses in subsequent checks Expr *op = OrigOp->IgnoreParens(); - if (getLangOptions().C99) { + if (S.getLangOptions().C99) { // Implement C99-only parts of addressof rules. if (UnaryOperator* uOp = dyn_cast(op)) { if (uOp->getOpcode() == UO_Deref) @@ -6996,23 +7076,24 @@ QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) { // expressions here, but the result of one is always an lvalue anyway. } NamedDecl *dcl = getPrimaryDecl(op); - Expr::isLvalueResult lval = op->isLvalue(Context); + Expr::isLvalueResult lval = op->isLvalue(S.Context); if (lval == Expr::LV_ClassTemporary) { - Diag(OpLoc, isSFINAEContext()? diag::err_typecheck_addrof_class_temporary - : diag::ext_typecheck_addrof_class_temporary) + bool sfinae = S.isSFINAEContext(); + S.Diag(OpLoc, sfinae ? diag::err_typecheck_addrof_class_temporary + : diag::ext_typecheck_addrof_class_temporary) << op->getType() << op->getSourceRange(); - if (isSFINAEContext()) + if (sfinae) return QualType(); } else if (isa(op)) { - return Context.getPointerType(op->getType()); + return S.Context.getPointerType(op->getType()); } else if (lval == Expr::LV_MemberFunction) { // If it's an instance method, make a member pointer. // The expression must have exactly the form &A::foo. // If the underlying expression isn't a decl ref, give up. if (!isa(op)) { - Diag(OpLoc, diag::err_invalid_form_pointer_member_function) + S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function) << OrigOp->getSourceRange(); return QualType(); } @@ -7021,45 +7102,45 @@ QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) { // The id-expression was parenthesized. if (OrigOp != DRE) { - Diag(OpLoc, diag::err_parens_pointer_member_function) + S.Diag(OpLoc, diag::err_parens_pointer_member_function) << OrigOp->getSourceRange(); // The method was named without a qualifier. } else if (!DRE->getQualifier()) { - Diag(OpLoc, diag::err_unqualified_pointer_member_function) + S.Diag(OpLoc, diag::err_unqualified_pointer_member_function) << op->getSourceRange(); } - return Context.getMemberPointerType(op->getType(), - Context.getTypeDeclType(MD->getParent()).getTypePtr()); + return S.Context.getMemberPointerType(op->getType(), + S.Context.getTypeDeclType(MD->getParent()).getTypePtr()); } else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) { // C99 6.5.3.2p1 // The operand must be either an l-value or a function designator if (!op->getType()->isFunctionType()) { // FIXME: emit more specific diag... - Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) + S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) << op->getSourceRange(); return QualType(); } } else if (op->getBitField()) { // C99 6.5.3.2p1 // The operand cannot be a bit-field - Diag(OpLoc, diag::err_typecheck_address_of) + S.Diag(OpLoc, diag::err_typecheck_address_of) << "bit-field" << op->getSourceRange(); return QualType(); } else if (op->refersToVectorElement()) { // The operand cannot be an element of a vector - Diag(OpLoc, diag::err_typecheck_address_of) + S.Diag(OpLoc, diag::err_typecheck_address_of) << "vector element" << op->getSourceRange(); return QualType(); } else if (isa(op)) { // cannot take address of a property expression. - Diag(OpLoc, diag::err_typecheck_address_of) + S.Diag(OpLoc, diag::err_typecheck_address_of) << "property expression" << op->getSourceRange(); return QualType(); } else if (ConditionalOperator *CO = dyn_cast(op)) { // FIXME: Can LHS ever be null here? - if (!CheckAddressOfOperand(CO->getTrueExpr(), OpLoc).isNull()) - return CheckAddressOfOperand(CO->getFalseExpr(), OpLoc); + if (!CheckAddressOfOperand(S, CO->getTrueExpr(), OpLoc).isNull()) + return CheckAddressOfOperand(S, CO->getFalseExpr(), OpLoc); } else if (dcl) { // C99 6.5.3.2p1 // We have an lvalue with a decl. Make sure the decl is not declared // with the register storage-class specifier. @@ -7067,13 +7148,13 @@ QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) { // in C++ it is not error to take address of a register // variable (c++03 7.1.1P3) if (vd->getStorageClass() == SC_Register && - !getLangOptions().CPlusPlus) { - Diag(OpLoc, diag::err_typecheck_address_of) + !S.getLangOptions().CPlusPlus) { + S.Diag(OpLoc, diag::err_typecheck_address_of) << "register variable" << op->getSourceRange(); return QualType(); } } else if (isa(dcl)) { - return Context.OverloadTy; + return S.Context.OverloadTy; } else if (FieldDecl *FD = dyn_cast(dcl)) { // Okay: we can take the address of a field. // Could be a pointer to member, though, if there is an explicit @@ -7082,14 +7163,14 @@ QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) { DeclContext *Ctx = dcl->getDeclContext(); if (Ctx && Ctx->isRecord()) { if (FD->getType()->isReferenceType()) { - Diag(OpLoc, - diag::err_cannot_form_pointer_to_member_of_reference_type) + S.Diag(OpLoc, + diag::err_cannot_form_pointer_to_member_of_reference_type) << FD->getDeclName() << FD->getType(); return QualType(); } - return Context.getMemberPointerType(op->getType(), - Context.getTypeDeclType(cast(Ctx)).getTypePtr()); + return S.Context.getMemberPointerType(op->getType(), + S.Context.getTypeDeclType(cast(Ctx)).getTypePtr()); } } } else if (!isa(dcl)) @@ -7100,21 +7181,22 @@ QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) { // Taking the address of a void variable is technically illegal, but we // allow it in cases which are otherwise valid. // Example: "extern void x; void* y = &x;". - Diag(OpLoc, diag::ext_typecheck_addrof_void) << op->getSourceRange(); + S.Diag(OpLoc, diag::ext_typecheck_addrof_void) << op->getSourceRange(); } // If the operand has type "type", the result has type "pointer to type". if (op->getType()->isObjCObjectType()) - return Context.getObjCObjectPointerType(op->getType()); - return Context.getPointerType(op->getType()); + return S.Context.getObjCObjectPointerType(op->getType()); + return S.Context.getPointerType(op->getType()); } /// CheckIndirectionOperand - Type check unary indirection (prefix '*'). -QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) { +static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, + SourceLocation OpLoc) { if (Op->isTypeDependent()) - return Context.DependentTy; + return S.Context.DependentTy; - UsualUnaryConversions(Op); + S.UsualUnaryConversions(Op); QualType OpTy = Op->getType(); QualType Result; @@ -7128,16 +7210,25 @@ QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) { OpTy->getAs()) Result = OPT->getPointeeType(); else { - ExprResult PR = CheckPlaceholderExpr(Op, OpLoc); + ExprResult PR = S.CheckPlaceholderExpr(Op, OpLoc); if (PR.isInvalid()) return QualType(); - if (PR.take() != Op) return CheckIndirectionOperand(PR.take(), OpLoc); + if (PR.take() != Op) + return CheckIndirectionOperand(S, PR.take(), VK, OpLoc); } if (Result.isNull()) { - Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer) + S.Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer) << OpTy << Op->getSourceRange(); return QualType(); } + + // Dereferences are usually l-values... + VK = VK_LValue; + + // ...except that certain expressions are never l-values in C. + if (!S.getLangOptions().CPlusPlus && + IsCForbiddenLValueType(S.Context, Result)) + VK = VK_RValue; return Result; } @@ -7221,8 +7312,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, case BO_Assign: ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, QualType()); if (getLangOptions().CPlusPlus) { - VK = rhs->getValueKind(); - OK = rhs->getObjectKind(); + VK = lhs->getValueKind(); + OK = lhs->getObjectKind(); } break; case BO_PtrMemD: @@ -7307,7 +7398,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); break; case BO_Comma: - ResultTy = CheckCommaOperands(lhs, rhs, OpLoc); + ResultTy = CheckCommaOperands(*this, lhs, rhs, OpLoc); if (getLangOptions().CPlusPlus) { VK = rhs->getValueKind(); OK = rhs->getObjectKind(); @@ -7552,24 +7643,20 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, switch (Opc) { case UO_PreInc: case UO_PreDec: - VK = VK_LValue; - OK = Input->getObjectKind(); - // fallthrough case UO_PostInc: case UO_PostDec: - resultType = CheckIncrementDecrementOperand(Input, OpLoc, + resultType = CheckIncrementDecrementOperand(*this, Input, VK, OpLoc, Opc == UO_PreInc || Opc == UO_PostInc, Opc == UO_PreInc || Opc == UO_PreDec); break; case UO_AddrOf: - resultType = CheckAddressOfOperand(Input, OpLoc); + resultType = CheckAddressOfOperand(*this, Input, OpLoc); break; case UO_Deref: DefaultFunctionArrayLvalueConversion(Input); - resultType = CheckIndirectionOperand(Input, OpLoc); - VK = VK_LValue; + resultType = CheckIndirectionOperand(*this, Input, VK, OpLoc); break; case UO_Plus: case UO_Minus: @@ -7639,7 +7726,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, break; case UO_Real: case UO_Imag: - resultType = CheckRealImagOperand(Input, OpLoc, Opc == UO_Real); + resultType = CheckRealImagOperand(*this, Input, OpLoc, Opc == UO_Real); // _Real and _Imag map ordinary l-values into ordinary l-values. if (Input->getValueKind() != VK_RValue && Input->getObjectKind() == OK_Ordinary) diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index fbd36fd61d..fde207ed38 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1601,7 +1601,7 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, Expr *Condition = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar, ConditionVar->getLocation(), ConditionVar->getType().getNonReferenceType(), - Expr::getValueKindForType(ConditionVar->getType())); + VK_LValue); if (ConvertToBoolean && CheckBooleanCondition(Condition, StmtLoc)) return ExprError(); @@ -2594,6 +2594,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) { /// extension. In this case, LHS == Cond. (But they're not aliases.) QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, Expr *&SAVE, ExprValueKind &VK, + ExprObjectKind &OK, SourceLocation QuestionLoc) { // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++ // interface pointers. @@ -2613,6 +2614,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // Assume r-value. VK = VK_RValue; + OK = OK_Ordinary; // Either of the arguments dependent? if (LHS->isTypeDependent() || RHS->isTypeDependent()) @@ -2697,15 +2699,20 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // category and have the same type, the result is of that type and // value category and it is a bit-field if the second or the third // operand is a bit-field, or if both are bit-fields. - // We can't support the bitfield parts of that correctly right now, - // though, so we just require both sides to be ordinary values. + // We only extend this to bitfields, not to the crazy other kinds of + // l-values. bool Same = Context.hasSameType(LTy, RTy); if (Same && LHS->getValueKind() != VK_RValue && LHS->getValueKind() == RHS->getValueKind() && - LHS->getObjectKind() == OK_Ordinary && - RHS->getObjectKind() == OK_Ordinary) { + (LHS->getObjectKind() == OK_Ordinary || + LHS->getObjectKind() == OK_BitField) && + (RHS->getObjectKind() == OK_Ordinary || + RHS->getObjectKind() == OK_BitField)) { VK = LHS->getValueKind(); + if (LHS->getObjectKind() == OK_BitField || + RHS->getObjectKind() == OK_BitField) + OK = OK_BitField; return LTy; } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index a99a72f3c8..04b88e2bde 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -431,16 +431,20 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, return ExprError(); if (Getter) { - QualType PType; - PType = Getter->getSendResultType(); + QualType PType = Getter->getSendResultType(); + ExprValueKind VK = VK_LValue; + ExprObjectKind OK = OK_ObjCProperty; + if (!getLangOptions().CPlusPlus && !PType.hasQualifiers() && + PType->isVoidType()) + VK = VK_RValue, OK = OK_Ordinary; + if (Super) return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, - VK_LValue, OK_ObjCProperty, - Setter, MemberLoc, SuperLoc, SuperType)); + VK, OK, Setter, MemberLoc, + SuperLoc, SuperType)); else return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, - VK_LValue, OK_ObjCProperty, - Setter, MemberLoc, BaseExpr)); + VK, OK, Setter, MemberLoc, BaseExpr)); } @@ -547,16 +551,23 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, if (Getter || Setter) { QualType PType; - if (Getter) + ExprValueKind VK = VK_LValue; + if (Getter) { PType = Getter->getSendResultType(); - else { + if (!getLangOptions().CPlusPlus && + !PType.hasQualifiers() && PType->isVoidType()) + VK = VK_RValue; + } else { for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(), E = Setter->param_end(); PI != E; ++PI) PType = (*PI)->getType(); + VK = VK_LValue; } + + ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty); + return Owned(new (Context) ObjCImplicitSetterGetterRefExpr( - Getter, PType, VK_LValue, OK_ObjCProperty, - Setter, + Getter, PType, VK, OK, Setter, propertyNameLoc, IFace, receiverNameLoc)); } return ExprError(Diag(propertyNameLoc, diag::err_property_not_found) diff --git a/test/CodeGenObjCXX/property-derived-to-base-conv.mm b/test/CodeGenObjCXX/property-derived-to-base-conv.mm index ada1202848..d7c743c690 100644 --- a/test/CodeGenObjCXX/property-derived-to-base-conv.mm +++ b/test/CodeGenObjCXX/property-derived-to-base-conv.mm @@ -1,7 +1,11 @@ // RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -emit-llvm -o - %s // rdar: // 7501812 -struct A { int member; }; +struct A { + int member; + void foo(); + A *operator->(); +}; struct B : A { }; @interface BInt { @@ -14,6 +18,8 @@ struct B : A { }; @end void g(BInt *bint) { - bint.value.member = 17; + bint.value.foo(); + bint.value->member = 17; + int x = bint.value.member; } diff --git a/test/SemaObjCXX/propert-dot-error.mm b/test/SemaObjCXX/propert-dot-error.mm index 3113e17283..47b7dc64d5 100644 --- a/test/SemaObjCXX/propert-dot-error.mm +++ b/test/SemaObjCXX/propert-dot-error.mm @@ -5,6 +5,10 @@ struct X { X(); X(const X&); ~X(); + + static int staticData; + int data; + void method(); }; @interface A { @@ -19,3 +23,19 @@ void f(A* a) { a.x = X(); // expected-error {{setter method is needed to assign to object using property assignment syntax}} } +struct Y : X { }; + +@interface B { +@private + Y *y; +} +- (Y)value; +- (void)setValue : (Y) arg; +@property Y value; +@end + +void g(B *b) { + b.value.data = 17; // expected-error {{not assignable}} + b.value.staticData = 17; + b.value.method(); +}