aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTContext.h2
-rw-r--r--include/clang/AST/BuiltinTypes.def18
-rw-r--r--include/clang/AST/Expr.h18
-rw-r--r--include/clang/AST/ExprObjC.h18
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td14
-rw-r--r--include/clang/Sema/Sema.h13
-rw-r--r--include/clang/Serialization/ASTBitCodes.h4
-rw-r--r--lib/AST/ASTContext.cpp3
-rw-r--r--lib/AST/Type.cpp1
-rw-r--r--lib/AST/TypeLoc.cpp1
-rw-r--r--lib/CodeGen/CGExprAgg.cpp3
-rw-r--r--lib/CodeGen/CGExprComplex.cpp2
-rw-r--r--lib/CodeGen/CGExprScalar.cpp4
-rw-r--r--lib/Rewrite/RewriteObjC.cpp4
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/SemaChecking.cpp3
-rw-r--r--lib/Sema/SemaExpr.cpp410
-rw-r--r--lib/Sema/SemaExprCXX.cpp28
-rw-r--r--lib/Sema/SemaExprMember.cpp48
-rw-r--r--lib/Sema/SemaExprObjC.cpp96
-rw-r--r--lib/Sema/SemaInit.cpp18
-rw-r--r--lib/Sema/SemaObjCProperty.cpp8
-rw-r--r--lib/Sema/SemaOverload.cpp56
-rw-r--r--lib/Sema/SemaStmt.cpp4
-rw-r--r--lib/Sema/TreeTransform.h6
-rw-r--r--lib/Serialization/ASTCommon.cpp1
-rw-r--r--lib/Serialization/ASTReader.cpp1
-rw-r--r--test/SemaObjC/property-category-1.m2
-rw-r--r--test/SemaObjC/property-error-readonly-assign.m6
-rw-r--r--test/SemaObjC/property-in-class-extension.m2
-rw-r--r--test/SemaObjC/property-user-setter.m4
-rw-r--r--test/SemaObjCXX/propert-dot-error.mm2
32 files changed, 441 insertions, 360 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index a8590b2983..1a8dbe551b 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -496,7 +496,7 @@ public:
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
CanQualType VoidPtrTy, NullPtrTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
- CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
+ CanQualType ARCUnbridgedCastTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
diff --git a/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def
index bfcd55bedb..067862c1c1 100644
--- a/include/clang/AST/BuiltinTypes.def
+++ b/include/clang/AST/BuiltinTypes.def
@@ -179,24 +179,6 @@ PLACEHOLDER_TYPE(Overload, OverloadTy)
// x->foo # if only contains non-static members
PLACEHOLDER_TYPE(BoundMember, BoundMemberTy)
-// The type of an expression which refers to a pseudo-object,
-// such as those introduced by Objective C's @property or
-// VS.NET's __property declarations. A placeholder type. The
-// pseudo-object is actually accessed by emitting a call to
-// some sort of function or method; typically there is a pair
-// of a setter and a getter, with the setter used if the
-// pseudo-object reference is used syntactically as the
-// left-hand-side of an assignment operator.
-//
-// A pseudo-object reference naming an Objective-C @property is
-// always a dot access with a base of object-pointer type,
-// e.g. 'x.foo'.
-//
-// In VS.NET, a __property declaration creates an implicit
-// member with an associated name, which can then be named
-// in any of the normal ways an ordinary member could be.
-PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy)
-
// __builtin_any_type. A placeholder type. Useful for clients
// like debuggers that don't know what type to give something.
// Only a small number of operations are valid on expressions of
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index e0f5e60157..e7b1a0593f 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -1456,26 +1456,12 @@ public:
bool isPrefix() const { return isPrefix(getOpcode()); }
bool isPostfix() const { return isPostfix(getOpcode()); }
-
- static bool isIncrementOp(Opcode Op) {
- return Op == UO_PreInc || Op == UO_PostInc;
- }
bool isIncrementOp() const {
- return isIncrementOp(getOpcode());
- }
-
- static bool isDecrementOp(Opcode Op) {
- return Op == UO_PreDec || Op == UO_PostDec;
+ return Opc == UO_PreInc || Opc == UO_PostInc;
}
- bool isDecrementOp() const {
- return isDecrementOp(getOpcode());
- }
-
- static bool isIncrementDecrementOp(Opcode Op) { return Op <= UO_PreDec; }
bool isIncrementDecrementOp() const {
- return isIncrementDecrementOp(getOpcode());
+ return Opc <= UO_PreDec;
}
-
static bool isArithmeticOp(Opcode Op) {
return Op >= UO_Plus && Op <= UO_LNot;
}
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index 5e4b5b2310..55726eb4ae 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -227,6 +227,7 @@ public:
/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC
/// property.
+///
class ObjCPropertyRefExpr : public Expr {
private:
/// If the bool is true, this is an implicit property reference; the
@@ -236,11 +237,6 @@ private:
llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter;
ObjCMethodDecl *Setter;
- // FIXME: Maybe we should store the property identifier here,
- // because it's not rederivable from the other data when there's an
- // implicit property with no getter (because the 'foo' -> 'setFoo:'
- // transformation is lossy on the first character).
-
SourceLocation IdLoc;
/// \brief When the receiver in property access is 'super', this is
@@ -259,7 +255,6 @@ public:
base->containsUnexpandedParameterPack()),
PropertyOrGetter(PD, false), Setter(0),
IdLoc(l), ReceiverLoc(), Receiver(base) {
- assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
@@ -270,7 +265,6 @@ public:
st->containsUnexpandedParameterPack()),
PropertyOrGetter(PD, false), Setter(0),
IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) {
- assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -281,7 +275,6 @@ public:
Base->containsUnexpandedParameterPack()),
PropertyOrGetter(Getter, true), Setter(Setter),
IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) {
- assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -291,7 +284,6 @@ public:
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false),
PropertyOrGetter(Getter, true), Setter(Setter),
IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) {
- assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -301,7 +293,6 @@ public:
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false),
PropertyOrGetter(Getter, true), Setter(Setter),
IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) {
- assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
explicit ObjCPropertyRefExpr(EmptyShell Empty)
@@ -357,15 +348,14 @@ public:
if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl())
ResultType = Getter->getResultType();
else
- ResultType = PDecl->getType();
+ ResultType = getType();
} else {
const ObjCMethodDecl *Getter = getImplicitPropertyGetter();
- if (Getter)
- ResultType = Getter->getResultType(); // with reference!
+ ResultType = Getter->getResultType(); // with reference!
}
return ResultType;
}
-
+
QualType getSetterArgType() const {
QualType ArgType;
if (isImplicitProperty()) {
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 74272ba523..61a182e81b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3612,22 +3612,16 @@ def ext_gnu_ptr_func_arith : Extension<
"arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 function "
"type%select{|s}2 %1%select{| and %3}2 is a GNU extension">,
InGroup<PointerArith>;
+def error_readonly_property_assignment : Error<
+ "assigning to property with 'readonly' attribute not allowed">;
def error_readonly_message_assignment : Error<
"assigning to 'readonly' return result of an objective-c message not allowed">;
def ext_integer_increment_complex : Extension<
"ISO C does not support '++'/'--' on complex integer type %0">;
def ext_integer_complement_complex : Extension<
"ISO C does not support '~' for complex conjugation of %0">;
-def err_nosetter_property_assignment : Error<
- "%select{assignment to readonly property|"
- "no setter method %1 for assignment to property}0">;
-def err_nosetter_property_incdec : Error<
- "%select{%select{increment|decrement}1 of readonly property|"
- "no setter method %2 for %select{increment|decrement}1 of property}0">;
-def err_nogetter_property_compound_assignment : Error<
- "a getter method is needed to perform a compound assignment on a property">;
-def err_nogetter_property_incdec : Error<
- "no getter method %1 for %select{increment|decrement} of property">;
+def error_nosetter_property_assignment : Error<
+ "setter method is needed to assign to object using property" " assignment syntax">;
def error_no_subobject_property_setting : Error<
"expression is not assignable">;
def err_qualified_objc_access : Error<
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 2b33392e6b..b55fdea6b9 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -5319,8 +5319,6 @@ public:
ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel,
const ObjCObjectPointerType *OPT,
bool IsInstance);
- ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty,
- bool IsInstance);
bool inferObjCARCLifetime(ValueDecl *decl);
@@ -5779,13 +5777,10 @@ public:
// For compound assignment, pass both expressions and the converted type.
QualType CheckAssignmentOperands( // C99 6.5.16.[1,2]
Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType);
-
- ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc,
- UnaryOperatorKind Opcode, Expr *Op);
- ExprResult checkPseudoObjectAssignment(Scope *S, SourceLocation OpLoc,
- BinaryOperatorKind Opcode,
- Expr *LHS, Expr *RHS);
- ExprResult checkPseudoObjectRValue(Expr *E);
+
+ void ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS,
+ QualType& LHSTy);
+ ExprResult ConvertPropertyForRValue(Expr *E);
QualType CheckConditionalOperands( // C99 6.5.15
ExprResult &Cond, ExprResult &LHS, ExprResult &RHS,
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 485b8fe3bb..d237f1b634 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -556,9 +556,7 @@ namespace clang {
/// \brief The OpenCL 'half' / ARM NEON __fp16 type.
PREDEF_TYPE_HALF_ID = 33,
/// \brief ARC's unbridged-cast placeholder type.
- PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34,
- /// \brief The pseudo-object placeholder type.
- PREDEF_TYPE_PSEUDO_OBJECT = 35
+ PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34
};
/// \brief The number of predefined type IDs that are reserved for
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index ae28149407..4fbb5408dc 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -461,9 +461,6 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
// Placeholder type for bound members.
InitBuiltinType(BoundMemberTy, BuiltinType::BoundMember);
- // Placeholder type for pseudo-objects.
- InitBuiltinType(PseudoObjectTy, BuiltinType::PseudoObject);
-
// "any" type; useful for debugger-like clients.
InitBuiltinType(UnknownAnyTy, BuiltinType::UnknownAny);
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 0bac5f4f61..5b7daadd98 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1493,7 +1493,6 @@ const char *BuiltinType::getName(const PrintingPolicy &Policy) const {
case NullPtr: return "nullptr_t";
case Overload: return "<overloaded function type>";
case BoundMember: return "<bound member function type>";
- case PseudoObject: return "<pseudo-object type>";
case Dependent: return "<dependent type>";
case UnknownAny: return "<unknown type>";
case ARCUnbridgedCast: return "<ARC unbridged cast type>";
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 9bdea433a9..2724e8c46a 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -238,7 +238,6 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::BoundMember:
case BuiltinType::UnknownAny:
case BuiltinType::ARCUnbridgedCast:
- case BuiltinType::PseudoObject:
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 0fa143391d..97754d5c0b 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -326,8 +326,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
}
case CK_GetObjCProperty: {
- LValue LV =
- CGF.EmitObjCPropertyRefLValue(E->getSubExpr()->getObjCProperty());
+ LValue LV = CGF.EmitLValue(E->getSubExpr());
assert(LV.isPropertyRef());
RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV, getReturnValueSlot());
EmitMoveFromReturnSlot(E, RV);
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index b6c416bc35..4a31bcfbe9 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -363,7 +363,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
case CK_GetObjCProperty: {
- LValue LV = CGF.EmitObjCPropertyRefLValue(Op->getObjCProperty());
+ LValue LV = CGF.EmitLValue(Op);
assert(LV.isPropertyRef() && "Unknown LValue type!");
return CGF.EmitLoadOfPropertyRefLValue(LV).getComplexVal();
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 582d1c4572..b088103aa3 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -1167,10 +1167,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
break;
case CK_GetObjCProperty: {
+ assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy));
assert(E->isGLValue() && E->getObjectKind() == OK_ObjCProperty &&
"CK_GetObjCProperty for non-lvalue or non-ObjCProperty");
- LValue LV = CGF.EmitObjCPropertyRefLValue(E->getObjCProperty());
- RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV);
+ RValue RV = CGF.EmitLoadOfLValue(CGF.EmitLValue(E));
return RV.getScalarVal();
}
diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp
index 1af9a6ce04..6a392ea357 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/RewriteObjC.cpp
@@ -1304,7 +1304,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *
} else {
OMD = PropRefExpr->getImplicitPropertySetter();
Sel = OMD->getSelector();
- Ty = (*OMD->param_begin())->getType();
+ Ty = PropRefExpr->getType();
}
Super = PropRefExpr->isSuperReceiver();
if (!Super) {
@@ -1380,7 +1380,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) {
} else {
OMD = PropRefExpr->getImplicitPropertyGetter();
Sel = OMD->getSelector();
- Ty = OMD->getResultType();
+ Ty = PropRefExpr->getType();
}
Super = PropRefExpr->isSuperReceiver();
if (!Super)
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 06d02252d6..dbbb980de8 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -31,7 +31,6 @@ add_clang_library(clangSema
SemaLookup.cpp
SemaObjCProperty.cpp
SemaOverload.cpp
- SemaPseudoObject.cpp
SemaStmt.cpp
SemaTemplate.cpp
SemaTemplateDeduction.cpp
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 6e81c3c966..daab1cd487 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -4256,8 +4256,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
if (LT != Qualifiers::OCL_None)
return;
- if (ObjCPropertyRefExpr *PRE
- = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens())) {
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
if (PRE->isImplicitProperty())
return;
const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 885b9664d6..3b4a40b51a 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -363,9 +363,19 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
assert(!T.isNull() && "r-value conversion on typeless expression?");
// We can't do lvalue-to-rvalue on atomics yet.
- if (T->isAtomicType())
+ if (T->getAs<AtomicType>())
return Owned(E);
+ // Create a load out of an ObjCProperty l-value, if necessary.
+ if (E->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Res = ConvertPropertyForRValue(E);
+ if (Res.isInvalid())
+ return Owned(E);
+ E = Res.take();
+ if (!E->isGLValue())
+ return Owned(E);
+ }
+
// We don't want to throw lvalue-to-rvalue casts on top of
// expressions of certain types in C++.
if (getLangOptions().CPlusPlus &&
@@ -3959,23 +3969,6 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
unsigned NumInit = InitArgList.size();
Expr **InitList = InitArgList.release();
- // Immediately handle non-overload placeholders. Overloads can be
- // resolved contextually, but everything else here can't.
- for (unsigned I = 0; I != NumInit; ++I) {
- if (const BuiltinType *pty
- = InitList[I]->getType()->getAsPlaceholderType()) {
- if (pty->getKind() == BuiltinType::Overload) continue;
-
- ExprResult result = CheckPlaceholderExpr(InitList[I]);
-
- // Ignore failures; dropping the entire initializer list because
- // of one failure would be terrible for indexing/etc.
- if (result.isInvalid()) continue;
-
- InitList[I] = result.take();
- }
- }
-
// Semantic analysis for initializers is done by ActOnDeclarator() and
// CheckInitializer() - it requires knowledge of the object being intialized.
@@ -6960,41 +6953,51 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
/// depends on various declarations and thus must be treated specially.
///
static bool IsReadonlyProperty(Expr *E, Sema &S) {
- const ObjCPropertyRefExpr *PropExpr = dyn_cast<ObjCPropertyRefExpr>(E);
- if (!PropExpr) return false;
- if (PropExpr->isImplicitProperty()) return false;
+ if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) {
+ const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
+ if (PropExpr->isImplicitProperty()) return false;
- ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
- QualType BaseType = PropExpr->isSuperReceiver() ?
+ ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
+ QualType BaseType = PropExpr->isSuperReceiver() ?
PropExpr->getSuperReceiverType() :
PropExpr->getBase()->getType();
- if (const ObjCObjectPointerType *OPT =
- BaseType->getAsObjCInterfacePointerType())
- if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
- if (S.isPropertyReadonly(PDecl, IFace))
- return true;
+ if (const ObjCObjectPointerType *OPT =
+ BaseType->getAsObjCInterfacePointerType())
+ if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
+ if (S.isPropertyReadonly(PDecl, IFace))
+ return true;
+ }
return false;
}
static bool IsConstProperty(Expr *E, Sema &S) {
- const ObjCPropertyRefExpr *PropExpr = dyn_cast<ObjCPropertyRefExpr>(E);
- if (!PropExpr) return false;
- if (PropExpr->isImplicitProperty()) return false;
+ if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) {
+ const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
+ if (PropExpr->isImplicitProperty()) return false;
- ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
- QualType T = PDecl->getType().getNonReferenceType();
- return T.isConstQualified();
+ ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
+ QualType T = PDecl->getType();
+ if (T->isReferenceType())
+ T = T->getAs<ReferenceType>()->getPointeeType();
+ CanQualType CT = S.Context.getCanonicalType(T);
+ return CT.isConstQualified();
+ }
+ return false;
}
static bool IsReadonlyMessage(Expr *E, Sema &S) {
- const MemberExpr *ME = dyn_cast<MemberExpr>(E);
- if (!ME) return false;
- if (!isa<FieldDecl>(ME->getMemberDecl())) return false;
- ObjCMessageExpr *Base =
- dyn_cast<ObjCMessageExpr>(ME->getBase()->IgnoreParenImpCasts());
- if (!Base) return false;
- return Base->getMethodDecl() != 0;
+ if (E->getStmtClass() != Expr::MemberExprClass)
+ return false;
+ const MemberExpr *ME = cast<MemberExpr>(E);
+ NamedDecl *Member = ME->getMemberDecl();
+ if (isa<FieldDecl>(Member)) {
+ Expr *Base = ME->getBase()->IgnoreParenImpCasts();
+ if (Base->getStmtClass() != Expr::ObjCMessageExprClass)
+ return false;
+ return cast<ObjCMessageExpr>(Base)->getMethodDecl() != 0;
+ }
+ return false;
}
/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not,
@@ -7082,8 +7085,10 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
Diag = diag::err_block_decl_ref_not_modifiable_lvalue;
break;
case Expr::MLV_ReadonlyProperty:
+ Diag = diag::error_readonly_property_assignment;
+ break;
case Expr::MLV_NoSetterProperty:
- llvm_unreachable("readonly properties should be processed differently");
+ Diag = diag::error_nosetter_property_assignment;
break;
case Expr::MLV_InvalidMessageExpression:
Diag = diag::error_readonly_message_assignment;
@@ -7109,8 +7114,6 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
SourceLocation Loc,
QualType CompoundType) {
- assert(!LHSExpr->hasPlaceholderType(BuiltinType::PseudoObject));
-
// Verify that LHS is a modifiable lvalue, and emit error if not.
if (CheckForModifiableLvalue(LHSExpr, Loc, *this))
return QualType();
@@ -7121,6 +7124,14 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
AssignConvertType ConvTy;
if (CompoundType.isNull()) {
QualType LHSTy(LHSType);
+ // Simple assignment "x = y".
+ if (LHSExpr->getObjectKind() == OK_ObjCProperty) {
+ ExprResult LHSResult = Owned(LHSExpr);
+ ConvertPropertyForLValue(LHSResult, RHS, LHSTy);
+ if (LHSResult.isInvalid())
+ return QualType();
+ LHSExpr = LHSResult.take();
+ }
ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
if (RHS.isInvalid())
return QualType();
@@ -7281,6 +7292,104 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
return ResType.getUnqualifiedType();
}
}
+
+ExprResult Sema::ConvertPropertyForRValue(Expr *E) {
+ assert(E->getValueKind() == VK_LValue &&
+ E->getObjectKind() == OK_ObjCProperty);
+ const ObjCPropertyRefExpr *PRE = E->getObjCProperty();
+
+ QualType T = E->getType();
+ QualType ReceiverType;
+ if (PRE->isObjectReceiver())
+ ReceiverType = PRE->getBase()->getType();
+ else if (PRE->isSuperReceiver())
+ ReceiverType = PRE->getSuperReceiverType();
+ else
+ ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver());
+
+ ExprValueKind VK = VK_RValue;
+ if (PRE->isImplicitProperty()) {
+ if (ObjCMethodDecl *GetterMethod =
+ PRE->getImplicitPropertyGetter()) {
+ T = getMessageSendResultType(ReceiverType, GetterMethod,
+ PRE->isClassReceiver(),
+ PRE->isSuperReceiver());
+ VK = Expr::getValueKindForType(GetterMethod->getResultType());
+ }
+ else {
+ Diag(PRE->getLocation(), diag::err_getter_not_found)
+ << PRE->getBase()->getType();
+ }
+ }
+ else {
+ // lvalue-ness of an explicit property is determined by
+ // getter type.
+ QualType ResT = PRE->getGetterResultType();
+ VK = Expr::getValueKindForType(ResT);
+ }
+
+ E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty,
+ E, 0, VK);
+
+ ExprResult Result = MaybeBindToTemporary(E);
+ if (!Result.isInvalid())
+ E = Result.take();
+
+ return Owned(E);
+}
+
+void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS,
+ QualType &LHSTy) {
+ assert(LHS.get()->getValueKind() == VK_LValue &&
+ LHS.get()->getObjectKind() == OK_ObjCProperty);
+ const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty();
+
+ bool Consumed = false;
+
+ if (PropRef->isImplicitProperty()) {
+ // If using property-dot syntax notation for assignment, and there is a
+ // setter, RHS expression is being passed to the setter argument. So,
+ // type conversion (and comparison) is RHS to setter's argument type.
+ if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) {
+ ObjCMethodDecl::param_const_iterator P = SetterMD->param_begin();
+ LHSTy = (*P)->getType();
+ Consumed = (getLangOptions().ObjCAutoRefCount &&
+ (*P)->hasAttr<NSConsumedAttr>());
+
+ // Otherwise, if the getter returns an l-value, just call that.
+ } else {
+ QualType Result = PropRef->getImplicitPropertyGetter()->getResultType();
+ ExprValueKind VK = Expr::getValueKindForType(Result);
+ if (VK == VK_LValue) {
+ LHS = ImplicitCastExpr::Create(Context, LHS.get()->getType(),
+ CK_GetObjCProperty, LHS.take(), 0, VK);
+ return;
+ }
+ }
+ } else {
+ const ObjCMethodDecl *setter
+ = PropRef->getExplicitProperty()->getSetterMethodDecl();
+ if (setter) {
+ ObjCMethodDecl::param_const_iterator P = setter->param_begin();
+ LHSTy = (*P)->getType();
+ if (getLangOptions().ObjCAutoRefCount)
+ Consumed = (*P)->hasAttr<NSConsumedAttr>();
+ }
+ }
+
+ if ((getLangOptions().CPlusPlus && LHSTy->isRecordType()) ||
+ getLangOptions().ObjCAutoRefCount) {
+ InitializedEntity Entity =
+ InitializedEntity::InitializeParameter(Context, LHSTy, Consumed);
+ ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), RHS);
+ if (!ArgE.isInvalid()) {
+ RHS = ArgE;
+ if (getLangOptions().ObjCAutoRefCount && !PropRef->isSuperReceiver())
+ checkRetainCycles(const_cast<Expr*>(PropRef->getBase()), RHS.get());
+ }
+ }
+ LHSTy = LHSTy.getNonReferenceType();
+}
/// getPrimaryDecl - Helper function for CheckAddressOfOperand().
@@ -7364,39 +7473,31 @@ static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc,
/// 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.
-static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
+static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
SourceLocation OpLoc) {
- if (const BuiltinType *PTy = OrigOp.get()->getType()->getAsPlaceholderType()){
- if (PTy->getKind() == BuiltinType::Overload) {
- if (!isa<OverloadExpr>(OrigOp.get()->IgnoreParens())) {
- S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
- << OrigOp.get()->getSourceRange();
- return QualType();
- }
-
- return S.Context.OverloadTy;
- }
-
- if (PTy->getKind() == BuiltinType::UnknownAny)
- return S.Context.UnknownAnyTy;
-
- if (PTy->getKind() == BuiltinType::BoundMember) {
- S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
- << OrigOp.get()->getSourceRange();
+ if (OrigOp->isTypeDependent())
+ return S.Context.DependentTy;
+ if (OrigOp->getType() == S.Context.OverloadTy) {
+ if (!isa<OverloadExpr>(OrigOp->IgnoreParens())) {
+ S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
+ << OrigOp->getSourceRange();
return QualType();
}
-
- OrigOp = S.CheckPlaceholderExpr(OrigOp.take());
- if