[cfe-commits] r142914 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ include/clang/Serialization/ lib/AST/ lib/CodeGen/ lib/Rewrite/ lib/Sema/ lib/Serialization/ test/SemaObjC/ test/SemaObjCXX/
John McCall
rjmccall at apple.com
Tue Oct 25 00:27:56 PDT 2011
Author: rjmccall
Date: Tue Oct 25 02:27:56 2011
New Revision: 142914
URL: http://llvm.org/viewvc/llvm-project?rev=142914&view=rev
Log:
Introduce a placeholder type for "pseudo object"
expressions: expressions which refer to a logical rather
than a physical l-value, where the logical object is
actually accessed via custom getter/setter code.
A subsequent patch will generalize the AST for these
so that arbitrary "implementing" sub-expressions can
be provided.
Right now the only client is ObjC properties, but
this should be generalizable to similar language
features, e.g. Managed C++'s __property methods.
Modified:
cfe/trunk/include/clang/AST/ASTContext.h
cfe/trunk/include/clang/AST/BuiltinTypes.def
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/AST/ExprObjC.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/include/clang/Serialization/ASTBitCodes.h
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/AST/Type.cpp
cfe/trunk/lib/AST/TypeLoc.cpp
cfe/trunk/lib/CodeGen/CGExprAgg.cpp
cfe/trunk/lib/CodeGen/CGExprComplex.cpp
cfe/trunk/lib/CodeGen/CGExprScalar.cpp
cfe/trunk/lib/Rewrite/RewriteObjC.cpp
cfe/trunk/lib/Sema/SemaChecking.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaExprMember.cpp
cfe/trunk/lib/Sema/SemaExprObjC.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaObjCProperty.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/lib/Sema/TreeTransform.h
cfe/trunk/lib/Serialization/ASTCommon.cpp
cfe/trunk/lib/Serialization/ASTReader.cpp
cfe/trunk/test/SemaObjC/property-category-1.m
cfe/trunk/test/SemaObjC/property-error-readonly-assign.m
cfe/trunk/test/SemaObjC/property-in-class-extension.m
cfe/trunk/test/SemaObjC/property-user-setter.m
cfe/trunk/test/SemaObjCXX/propert-dot-error.mm
Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Tue Oct 25 02:27:56 2011
@@ -496,7 +496,7 @@
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
CanQualType VoidPtrTy, NullPtrTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
- CanQualType ARCUnbridgedCastTy;
+ CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
Modified: cfe/trunk/include/clang/AST/BuiltinTypes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/BuiltinTypes.def?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/BuiltinTypes.def (original)
+++ cfe/trunk/include/clang/AST/BuiltinTypes.def Tue Oct 25 02:27:56 2011
@@ -179,6 +179,24 @@
// 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
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Tue Oct 25 02:27:56 2011
@@ -1456,12 +1456,26 @@
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 Opc == UO_PreInc || Opc == UO_PostInc;
+ return isIncrementOp(getOpcode());
+ }
+
+ static bool isDecrementOp(Opcode Op) {
+ return Op == UO_PreDec || Op == UO_PostDec;
}
+ bool isDecrementOp() const {
+ return isDecrementOp(getOpcode());
+ }
+
+ static bool isIncrementDecrementOp(Opcode Op) { return Op <= UO_PreDec; }
bool isIncrementDecrementOp() const {
- return Opc <= UO_PreDec;
+ return isIncrementDecrementOp(getOpcode());
}
+
static bool isArithmeticOp(Opcode Op) {
return Op >= UO_Plus && Op <= UO_LNot;
}
Modified: cfe/trunk/include/clang/AST/ExprObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprObjC.h?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprObjC.h (original)
+++ cfe/trunk/include/clang/AST/ExprObjC.h Tue Oct 25 02:27:56 2011
@@ -227,7 +227,6 @@
/// 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
@@ -237,6 +236,11 @@
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
@@ -255,6 +259,7 @@
base->containsUnexpandedParameterPack()),
PropertyOrGetter(PD, false), Setter(0),
IdLoc(l), ReceiverLoc(), Receiver(base) {
+ assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
@@ -265,6 +270,7 @@
st->containsUnexpandedParameterPack()),
PropertyOrGetter(PD, false), Setter(0),
IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) {
+ assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -275,6 +281,7 @@
Base->containsUnexpandedParameterPack()),
PropertyOrGetter(Getter, true), Setter(Setter),
IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) {
+ assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
}
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@@ -284,6 +291,7 @@
: 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,
@@ -293,6 +301,7 @@
: 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)
@@ -348,14 +357,15 @@
if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl())
ResultType = Getter->getResultType();
else
- ResultType = getType();
+ ResultType = PDecl->getType();
} else {
const ObjCMethodDecl *Getter = getImplicitPropertyGetter();
- ResultType = Getter->getResultType(); // with reference!
+ if (Getter)
+ ResultType = Getter->getResultType(); // with reference!
}
return ResultType;
}
-
+
QualType getSetterArgType() const {
QualType ArgType;
if (isImplicitProperty()) {
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Oct 25 02:27:56 2011
@@ -3612,16 +3612,22 @@
"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 error_nosetter_property_assignment : Error<
- "setter method is needed to assign to object using property" " assignment syntax">;
+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_no_subobject_property_setting : Error<
"expression is not assignable">;
def err_qualified_objc_access : Error<
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Oct 25 02:27:56 2011
@@ -5319,6 +5319,8 @@
ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel,
const ObjCObjectPointerType *OPT,
bool IsInstance);
+ ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty,
+ bool IsInstance);
bool inferObjCARCLifetime(ValueDecl *decl);
@@ -5777,10 +5779,13 @@
// 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);
-
- void ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS,
- QualType& LHSTy);
- ExprResult ConvertPropertyForRValue(Expr *E);
+
+ 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);
QualType CheckConditionalOperands( // C99 6.5.15
ExprResult &Cond, ExprResult &LHS, ExprResult &RHS,
Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Tue Oct 25 02:27:56 2011
@@ -556,7 +556,9 @@
/// \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
+ PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34,
+ /// \brief The pseudo-object placeholder type.
+ PREDEF_TYPE_PSEUDO_OBJECT = 35
};
/// \brief The number of predefined type IDs that are reserved for
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Tue Oct 25 02:27:56 2011
@@ -461,6 +461,9 @@
// 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);
Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Tue Oct 25 02:27:56 2011
@@ -1493,6 +1493,7 @@
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>";
Modified: cfe/trunk/lib/AST/TypeLoc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypeLoc.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypeLoc.cpp (original)
+++ cfe/trunk/lib/AST/TypeLoc.cpp Tue Oct 25 02:27:56 2011
@@ -238,6 +238,7 @@
case BuiltinType::BoundMember:
case BuiltinType::UnknownAny:
case BuiltinType::ARCUnbridgedCast:
+ case BuiltinType::PseudoObject:
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Tue Oct 25 02:27:56 2011
@@ -326,7 +326,8 @@
}
case CK_GetObjCProperty: {
- LValue LV = CGF.EmitLValue(E->getSubExpr());
+ LValue LV =
+ CGF.EmitObjCPropertyRefLValue(E->getSubExpr()->getObjCProperty());
assert(LV.isPropertyRef());
RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV, getReturnValueSlot());
EmitMoveFromReturnSlot(E, RV);
Modified: cfe/trunk/lib/CodeGen/CGExprComplex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprComplex.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprComplex.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprComplex.cpp Tue Oct 25 02:27:56 2011
@@ -363,7 +363,7 @@
case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
case CK_GetObjCProperty: {
- LValue LV = CGF.EmitLValue(Op);
+ LValue LV = CGF.EmitObjCPropertyRefLValue(Op->getObjCProperty());
assert(LV.isPropertyRef() && "Unknown LValue type!");
return CGF.EmitLoadOfPropertyRefLValue(LV).getComplexVal();
}
Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Tue Oct 25 02:27:56 2011
@@ -1167,10 +1167,10 @@
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");
- RValue RV = CGF.EmitLoadOfLValue(CGF.EmitLValue(E));
+ LValue LV = CGF.EmitObjCPropertyRefLValue(E->getObjCProperty());
+ RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV);
return RV.getScalarVal();
}
Modified: cfe/trunk/lib/Rewrite/RewriteObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Rewrite/RewriteObjC.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Rewrite/RewriteObjC.cpp (original)
+++ cfe/trunk/lib/Rewrite/RewriteObjC.cpp Tue Oct 25 02:27:56 2011
@@ -1304,7 +1304,7 @@
} else {
OMD = PropRefExpr->getImplicitPropertySetter();
Sel = OMD->getSelector();
- Ty = PropRefExpr->getType();
+ Ty = (*OMD->param_begin())->getType();
}
Super = PropRefExpr->isSuperReceiver();
if (!Super) {
@@ -1380,7 +1380,7 @@
} else {
OMD = PropRefExpr->getImplicitPropertyGetter();
Sel = OMD->getSelector();
- Ty = PropRefExpr->getType();
+ Ty = OMD->getResultType();
}
Super = PropRefExpr->isSuperReceiver();
if (!Super)
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Oct 25 02:27:56 2011
@@ -4256,7 +4256,8 @@
if (LT != Qualifiers::OCL_None)
return;
- if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
+ if (ObjCPropertyRefExpr *PRE
+ = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens())) {
if (PRE->isImplicitProperty())
return;
const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Oct 25 02:27:56 2011
@@ -363,19 +363,9 @@
assert(!T.isNull() && "r-value conversion on typeless expression?");
// We can't do lvalue-to-rvalue on atomics yet.
- if (T->getAs<AtomicType>())
+ if (T->isAtomicType())
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 &&
@@ -3969,6 +3959,23 @@
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.
@@ -7085,10 +7092,8 @@
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:
- Diag = diag::error_nosetter_property_assignment;
+ llvm_unreachable("readonly properties should be processed differently");
break;
case Expr::MLV_InvalidMessageExpression:
Diag = diag::error_readonly_message_assignment;
@@ -7114,6 +7119,8 @@
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();
@@ -7124,14 +7131,6 @@
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();
@@ -7293,12 +7292,35 @@
}
}
-ExprResult Sema::ConvertPropertyForRValue(Expr *E) {
+static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel,
+ const ObjCPropertyRefExpr *PRE) {
+ bool instanceProperty;
+ QualType searchType;
+ if (PRE->isObjectReceiver()) {
+ searchType = PRE->getBase()->getType()
+ ->castAs<ObjCObjectPointerType>()->getPointeeType();
+ instanceProperty = true;
+ } else if (PRE->isSuperReceiver()) {
+ searchType = PRE->getSuperReceiverType();
+ instanceProperty = false;
+ if (const ObjCObjectPointerType *PT
+ = searchType->getAs<ObjCObjectPointerType>()) {
+ searchType = PT->getPointeeType();
+ instanceProperty = true;
+ }
+ } else if (PRE->isClassReceiver()) {
+ searchType = S.Context.getObjCInterfaceType(PRE->getClassReceiver());
+ instanceProperty = false;
+ }
+
+ return S.LookupMethodInObjectType(sel, searchType, instanceProperty);
+}
+
+ExprResult Sema::checkPseudoObjectRValue(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();
@@ -7308,28 +7330,50 @@
ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver());
ExprValueKind VK = VK_RValue;
+ QualType T;
if (PRE->isImplicitProperty()) {
if (ObjCMethodDecl *GetterMethod =
PRE->getImplicitPropertyGetter()) {
- T = getMessageSendResultType(ReceiverType, GetterMethod,
+ T = getMessageSendResultType(ReceiverType, GetterMethod,
PRE->isClassReceiver(),
PRE->isSuperReceiver());
VK = Expr::getValueKindForType(GetterMethod->getResultType());
- }
- else {
+ } else {
Diag(PRE->getLocation(), diag::err_getter_not_found)
<< PRE->getBase()->getType();
+ return ExprError();
+ }
+ } else {
+ ObjCPropertyDecl *prop = PRE->getExplicitProperty();
+
+ ObjCMethodDecl *getter =
+ LookupMethodInReceiverType(*this, prop->getGetterName(), PRE);
+ if (getter && !getter->hasRelatedResultType())
+ DiagnosePropertyAccessorMismatch(prop, getter, PRE->getLocation());
+ if (!getter) getter = prop->getGetterMethodDecl();
+
+ // Figure out the type of the expression. Mostly this is the
+ // result type of the getter, if possible.
+ if (getter) {
+ T = getMessageSendResultType(ReceiverType, getter,
+ PRE->isClassReceiver(),
+ PRE->isSuperReceiver());
+ VK = Expr::getValueKindForType(getter->getResultType());
+
+ // As a special case, if the method returns 'id', try to get a
+ // better type from the property.
+ if (VK == VK_RValue && T->isObjCIdType() &&
+ prop->getType()->isObjCRetainableType())
+ T = prop->getType();
+ } else {
+ T = prop->getType();
+ VK = Expr::getValueKindForType(T);
+ T = T.getNonLValueExprType(Context);
}
}
- 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);
+
+ E->setType(T);
+ E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty, E, 0, VK);
ExprResult Result = MaybeBindToTemporary(E);
if (!Result.isInvalid())
@@ -7338,57 +7382,215 @@
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);
+namespace {
+ struct PseudoObjectInfo {
+ const ObjCPropertyRefExpr *RefExpr;
+ bool HasSetter;
+ Selector SetterSelector;
+ ParmVarDecl *SetterParam;
+ QualType SetterParamType;
+
+ void setSetter(ObjCMethodDecl *setter) {
+ HasSetter = true;
+ SetterParam = *setter->param_begin();
+ SetterParamType = SetterParam->getType().getUnqualifiedType();
+ }
+
+ PseudoObjectInfo(Sema &S, Expr *E)
+ : RefExpr(E->getObjCProperty()), HasSetter(false), SetterParam(0) {
+
+ assert(E->getValueKind() == VK_LValue &&
+ E->getObjectKind() == OK_ObjCProperty);
+
+ // Try to find a setter.
+
+ // For implicit properties, just trust the lookup we already did.
+ if (RefExpr->isImplicitProperty()) {
+ if (ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter()) {
+ setSetter(setter);
+ SetterSelector = setter->getSelector();
+ } else {
+ IdentifierInfo *getterName =
+ RefExpr->getImplicitPropertyGetter()->getSelector()
+ .getIdentifierInfoForSlot(0);
+ SetterSelector =
+ SelectorTable::constructSetterName(S.PP.getIdentifierTable(),
+ S.PP.getSelectorTable(),
+ getterName);
+ }
return;
}
+
+ // For explicit properties, this is more involved.
+ ObjCPropertyDecl *prop = RefExpr->getExplicitProperty();
+ SetterSelector = prop->getSetterName();
+
+ // Do a normal method lookup first.
+ if (ObjCMethodDecl *setter =
+ LookupMethodInReceiverType(S, SetterSelector, RefExpr))
+ return setSetter(setter);
+
+ // If that failed, trust the type on the @property declaration.
+ if (!prop->isReadOnly()) {
+ HasSetter = true;
+ SetterParamType = prop->getType().getUnqualifiedType();
+ }
}
- } else {
- const ObjCMethodDecl *setter
- = PropRef->getExplicitProperty()->getSetterMethodDecl();
- if (setter) {
- ObjCMethodDecl::param_const_iterator P = setter->param_begin();
- LHSTy = (*P)->getType();
+ };
+}
+
+/// Check an increment or decrement of a pseudo-object expression.
+ExprResult Sema::checkPseudoObjectIncDec(Scope *S, SourceLocation opcLoc,
+ UnaryOperatorKind opcode, Expr *op) {
+ assert(UnaryOperator::isIncrementDecrementOp(opcode));
+ PseudoObjectInfo info(*this, op);
+
+ // If there's no setter, we have no choice but to try to assign to
+ // the result of the getter.
+ if (!info.HasSetter) {
+ QualType resultType = info.RefExpr->getGetterResultType();
+ assert(!resultType.isNull() && "property has no setter and no getter!");
+
+ // Only do this if the getter returns an l-value reference type.
+ if (const LValueReferenceType *refType
+ = resultType->getAs<LValueReferenceType>()) {
+ op = ImplicitCastExpr::Create(Context, refType->getPointeeType(),
+ CK_GetObjCProperty, op, 0, VK_LValue);
+ return BuildUnaryOp(S, opcLoc, opcode, op);
+ }
+
+ // Otherwise, it's an error.
+ Diag(opcLoc, diag::err_nosetter_property_incdec)
+ << unsigned(info.RefExpr->isImplicitProperty())
+ << unsigned(UnaryOperator::isDecrementOp(opcode))
+ << info.SetterSelector
+ << op->getSourceRange();
+ return ExprError();
+ }
+
+ // ++/-- behave like compound assignments, i.e. they need a getter.
+ QualType getterResultType = info.RefExpr->getGetterResultType();
+ if (getterResultType.isNull()) {
+ assert(info.RefExpr->isImplicitProperty());
+ Diag(opcLoc, diag::err_nogetter_property_incdec)
+ << unsigned(UnaryOperator::isDecrementOp(opcode))
+ << info.RefExpr->getImplicitPropertyGetter()->getSelector()
+ << op->getSourceRange();
+ return ExprError();
+ }
+
+ // HACK: change the type of the operand to prevent further placeholder
+ // transformation.
+ op->setType(getterResultType.getNonLValueExprType(Context));
+ op->setObjectKind(OK_Ordinary);
+
+ ExprResult result = CreateBuiltinUnaryOp(opcLoc, opcode, op);
+ if (result.isInvalid()) return ExprError();
+
+ // Change the object kind back.
+ op->setObjectKind(OK_ObjCProperty);
+ return result;
+}
+
+ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc,
+ BinaryOperatorKind opcode,
+ Expr *LHS, Expr *RHS) {
+ assert(BinaryOperator::isAssignmentOp(opcode));
+ PseudoObjectInfo info(*this, LHS);
+
+ // If there's no setter, we have no choice but to try to assign to
+ // the result of the getter.
+ if (!info.HasSetter) {
+ QualType resultType = info.RefExpr->getGetterResultType();
+ assert(!resultType.isNull() && "property has no setter and no getter!");
+
+ // Only do this if the getter returns an l-value reference type.
+ if (const LValueReferenceType *refType
+ = resultType->getAs<LValueReferenceType>()) {
+ LHS = ImplicitCastExpr::Create(Context, refType->getPointeeType(),
+ CK_GetObjCProperty, LHS, 0, VK_LValue);
+ return BuildBinOp(S, opcLoc, opcode, LHS, RHS);
+ }
+
+ // Otherwise, it's an error.
+ Diag(opcLoc, diag::err_nosetter_property_assignment)
+ << unsigned(info.RefExpr->isImplicitProperty())
+ << info.SetterSelector
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ return ExprError();
+ }
+
+ // If there is a setter, we definitely want to use it.
+
+ // If this is a simple assignment, just initialize the parameter
+ // with the RHS.
+ if (opcode == BO_Assign) {
+ LHS->setType(info.SetterParamType.getNonLValueExprType(Context));
+
+ // Under certain circumstances, we need to type-check the RHS as a
+ // straight-up parameter initialization. This gives somewhat
+ // inferior diagnostics, so we try to avoid it.
+
+ if (RHS->isTypeDependent()) {
+ // Just build the expression.
+
+ } else if ((getLangOptions().CPlusPlus && LHS->getType()->isRecordType()) ||
+ (getLangOptions().ObjCAutoRefCount &&
+ info.SetterParam &&
+ info.SetterParam->hasAttr<NSConsumedAttr>())) {
+ InitializedEntity param = (info.SetterParam
+ ? InitializedEntity::InitializeParameter(Context, info.SetterParam)
+ : InitializedEntity::InitializeParameter(Context, info.SetterParamType,
+ /*consumed*/ false));
+ ExprResult arg = PerformCopyInitialization(param, opcLoc, RHS);
+ if (arg.isInvalid()) return ExprError();
+ RHS = arg.take();
+
+ // Warn about assignments of +1 objects to unsafe pointers in ARC.
+ // CheckAssignmentOperands does this on the other path.
if (getLangOptions().ObjCAutoRefCount)
- Consumed = (*P)->hasAttr<NSConsumedAttr>();
+ checkUnsafeExprAssigns(opcLoc, LHS, RHS);
+ } else {
+ ExprResult RHSResult = Owned(RHS);
+
+ LHS->setObjectKind(OK_Ordinary);
+ QualType resultType = CheckAssignmentOperands(LHS, RHSResult, opcLoc,
+ /*compound*/ QualType());
+ LHS->setObjectKind(OK_ObjCProperty);
+
+ if (!RHSResult.isInvalid()) RHS = RHSResult.take();
+ if (resultType.isNull()) return ExprError();
}
+
+ // Warn about property sets in ARC that might cause retain cycles.
+ if (getLangOptions().ObjCAutoRefCount && !info.RefExpr->isSuperReceiver())
+ checkRetainCycles(const_cast<Expr*>(info.RefExpr->getBase()), RHS);
+
+ return new (Context) BinaryOperator(LHS, RHS, opcode, RHS->getType(),
+ RHS->getValueKind(),
+ RHS->getObjectKind(),
+ opcLoc);
}
- 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());
- }
+ // If this is a compound assignment, we need to use the getter, too.
+ QualType getterResultType = info.RefExpr->getGetterResultType();
+ if (getterResultType.isNull()) {
+ Diag(opcLoc, diag::err_nogetter_property_compound_assignment)
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ return ExprError();
}
- LHSTy = LHSTy.getNonReferenceType();
+
+ // HACK: change the type of the LHS to prevent further placeholder
+ // transformation.
+ LHS->setType(getterResultType.getNonLValueExprType(Context));
+ LHS->setObjectKind(OK_Ordinary);
+
+ ExprResult result = CreateBuiltinBinOp(opcLoc, opcode, LHS, RHS);
+ if (result.isInvalid()) return ExprError();
+
+ // Change the object kind back.
+ LHS->setObjectKind(OK_ObjCProperty);
+ return result;
}
@@ -7473,31 +7675,39 @@
/// 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, Expr *OrigOp,
+static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
SourceLocation OpLoc) {
- 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();
+ 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();
return QualType();
}
-
- return S.Context.OverloadTy;
- }
- if (OrigOp->getType() == S.Context.UnknownAnyTy)
- return S.Context.UnknownAnyTy;
- if (OrigOp->getType() == S.Context.BoundMemberTy) {
- S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
- << OrigOp->getSourceRange();
- return QualType();
+
+ OrigOp = S.CheckPlaceholderExpr(OrigOp.take());
+ if (OrigOp.isInvalid()) return QualType();
}
- assert(!OrigOp->getType()->isPlaceholderType());
+ if (OrigOp.get()->isTypeDependent())
+ return S.Context.DependentTy;
+
+ assert(!OrigOp.get()->getType()->isPlaceholderType());
// Make sure to ignore parentheses in subsequent checks
- Expr *op = OrigOp->IgnoreParens();
+ Expr *op = OrigOp.get()->IgnoreParens();
if (S.getLangOptions().C99) {
// Implement C99-only parts of addressof rules.
@@ -7530,16 +7740,16 @@
// If the underlying expression isn't a decl ref, give up.
if (!isa<DeclRefExpr>(op)) {
S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
- << OrigOp->getSourceRange();
+ << OrigOp.get()->getSourceRange();
return QualType();
}
DeclRefExpr *DRE = cast<DeclRefExpr>(op);
CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());
// The id-expression was parenthesized.
- if (OrigOp != DRE) {
+ if (OrigOp.get() != DRE) {
S.Diag(OpLoc, diag::err_parens_pointer_member_function)
- << OrigOp->getSourceRange();
+ << OrigOp.get()->getSourceRange();
// The method was named without a qualifier.
} else if (!DRE->getQualifier()) {
@@ -7553,10 +7763,15 @@
// 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...
- S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
- << op->getSourceRange();
- return QualType();
+ // Use a special diagnostic for loads from property references.
+ if (isa<ObjCPropertyRefExpr>(op->IgnoreImplicit()->IgnoreParens())) {
+ AddressOfError = AO_Property_Expansion;
+ } else {
+ // FIXME: emit more specific diag...
+ S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
+ << op->getSourceRange();
+ return QualType();
+ }
}
} else if (op->getObjectKind() == OK_BitField) { // C99 6.5.3.2p1
// The operand cannot be a bit-field
@@ -7781,23 +7996,6 @@
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
- // Check if a 'foo<int>' involved in a binary op, identifies a single
- // function unambiguously (i.e. an lvalue ala 13.4)
- // But since an assignment can trigger target based overload, exclude it in
- // our blind search. i.e:
- // template<class T> void f(); template<class T, class U> void f(U);
- // f<int> == 0; // resolve f<int> blindly
- // void (*p)(int); p = f<int>; // resolve f<int> using target
- if (Opc != BO_Assign) {
- ExprResult resolvedLHS = CheckPlaceholderExpr(LHS.get());
- if (!resolvedLHS.isUsable()) return ExprError();
- LHS = move(resolvedLHS);
-
- ExprResult resolvedRHS = CheckPlaceholderExpr(RHS.get());
- if (!resolvedRHS.isUsable()) return ExprError();
- RHS = move(resolvedRHS);
- }
-
switch (Opc) {
case BO_Assign:
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
@@ -8093,38 +8291,83 @@
return BuildBinOp(S, TokLoc, Opc, LHSExpr, RHSExpr);
}
+/// Build an overloaded binary operator expression in the given scope.
+static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
+ BinaryOperatorKind Opc,
+ Expr *LHS, Expr *RHS) {
+ // Find all of the overloaded operators visible from this
+ // point. We perform both an operator-name lookup from the local
+ // scope and an argument-dependent lookup based on the types of
+ // the arguments.
+ UnresolvedSet<16> Functions;
+ OverloadedOperatorKind OverOp
+ = BinaryOperator::getOverloadedOperator(Opc);
+ if (Sc && OverOp != OO_None)
+ S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(),
+ RHS->getType(), Functions);
+
+ // Build the (potentially-overloaded, potentially-dependent)
+ // binary operation.
+ return S.CreateOverloadedBinOp(OpLoc, Opc, Functions, LHS, RHS);
+}
+
ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
BinaryOperatorKind Opc,
Expr *LHSExpr, Expr *RHSExpr) {
+ // Handle pseudo-objects in the LHS.
+ if (const BuiltinType *pty = LHSExpr->getType()->getAsPlaceholderType()) {
+ // Assignments with a pseudo-object l-value need special analysis.
+ if (pty->getKind() == BuiltinType::PseudoObject &&
+ BinaryOperator::isAssignmentOp(Opc))
+ return checkPseudoObjectAssignment(S, OpLoc, Opc, LHSExpr, RHSExpr);
+
+ // Don't resolve overloads if the other type is overloadable.
+ if (pty->getKind() == BuiltinType::Overload) {
+ // We can't actually test that if we still have a placeholder,
+ // though. Fortunately, none of the exceptions we see in that
+ // code below are valid when the LHS is an overload set.
+ ExprResult resolvedRHS = CheckPlaceholderExpr(RHSExpr);
+ if (resolvedRHS.isInvalid()) return ExprError();
+ RHSExpr = resolvedRHS.take();
+
+ if (RHSExpr->getType()->isOverloadableType())
+ return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
+ }
+
+ ExprResult LHS = CheckPlaceholderExpr(LHSExpr);
+ if (LHS.isInvalid()) return ExprError();
+ LHSExpr = LHS.take();
+ }
+
+ // Handle pseudo-objects in the RHS.
+ if (const BuiltinType *pty = RHSExpr->getType()->getAsPlaceholderType()) {
+ // An overload in the RHS can potentially be resolved by the type
+ // being assigned to.
+ if (Opc == BO_Assign && pty->getKind() == BuiltinType::Overload)
+ return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr);
+
+ // Don't resolve overloads if the other type is overloadable.
+ if (pty->getKind() == BuiltinType::Overload &&
+ LHSExpr->getType()->isOverloadableType())
+ return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
+
+ ExprResult resolvedRHS = CheckPlaceholderExpr(RHSExpr);
+ if (!resolvedRHS.isUsable()) return ExprError();
+ RHSExpr = resolvedRHS.take();
+ }
+
if (getLangOptions().CPlusPlus) {
bool UseBuiltinOperator;
if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) {
UseBuiltinOperator = false;
- } else if (Opc == BO_Assign &&
- LHSExpr->getObjectKind() == OK_ObjCProperty) {
- UseBuiltinOperator = true;
} else {
UseBuiltinOperator = !LHSExpr->getType()->isOverloadableType() &&
!RHSExpr->getType()->isOverloadableType();
}
- if (!UseBuiltinOperator) {
- // Find all of the overloaded operators visible from this
- // point. We perform both an operator-name lookup from the local
- // scope and an argument-dependent lookup based on the types of
- // the arguments.
- UnresolvedSet<16> Functions;
- OverloadedOperatorKind OverOp
- = BinaryOperator::getOverloadedOperator(Opc);
- if (S && OverOp != OO_None)
- LookupOverloadedOperatorName(OverOp, S, LHSExpr->getType(),
- RHSExpr->getType(), Functions);
-
- // Build the (potentially-overloaded, potentially-dependent)
- // binary operation.
- return CreateOverloadedBinOp(OpLoc, Opc, Functions, LHSExpr, RHSExpr);
- }
+ if (!UseBuiltinOperator)
+ return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
}
// Build a built-in binary operation.
@@ -8150,12 +8393,9 @@
Opc == UO_PreDec);
break;
case UO_AddrOf:
- resultType = CheckAddressOfOperand(*this, Input.get(), OpLoc);
+ resultType = CheckAddressOfOperand(*this, Input, OpLoc);
break;
case UO_Deref: {
- ExprResult resolved = CheckPlaceholderExpr(Input.get());
- if (!resolved.isUsable()) return ExprError();
- Input = move(resolved);
Input = DefaultFunctionArrayLvalueConversion(Input.take());
resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
break;
@@ -8177,11 +8417,6 @@
Opc == UO_Plus &&
resultType->isPointerType())
break;
- else if (resultType->isPlaceholderType()) {
- Input = CheckPlaceholderExpr(Input.take());
- if (Input.isInvalid()) return ExprError();
- return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take());
- }
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -8199,11 +8434,7 @@
<< resultType << Input.get()->getSourceRange();
else if (resultType->hasIntegerRepresentation())
break;
- else if (resultType->isPlaceholderType()) {
- Input = CheckPlaceholderExpr(Input.take());
- if (Input.isInvalid()) return ExprError();
- return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take());
- } else {
+ else {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
}
@@ -8231,10 +8462,6 @@
Input = ImpCastExprToType(Input.take(), Context.BoolTy,
ScalarTypeToBooleanCastKind(resultType));
}
- } else if (resultType->isPlaceholderType()) {
- Input = CheckPlaceholderExpr(Input.take());
- if (Input.isInvalid()) return ExprError();
- return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take());
} else {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -8275,6 +8502,32 @@
ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
UnaryOperatorKind Opc, Expr *Input) {
+ // First things first: handle placeholders so that the
+ // overloaded-operator check considers the right type.
+ if (const BuiltinType *pty = Input->getType()->getAsPlaceholderType()) {
+ // Increment and decrement of pseudo-object references.
+ if (pty->getKind() == BuiltinType::PseudoObject &&
+ UnaryOperator::isIncrementDecrementOp(Opc))
+ return checkPseudoObjectIncDec(S, OpLoc, Opc, Input);
+
+ // extension is always a builtin operator.
+ if (Opc == UO_Extension)
+ return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
+
+ // & gets special logic for several kinds of placeholder.
+ // The builtin code knows what to do.
+ if (Opc == UO_AddrOf &&
+ (pty->getKind() == BuiltinType::Overload ||
+ pty->getKind() == BuiltinType::UnknownAny ||
+ pty->getKind() == BuiltinType::BoundMember))
+ return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
+
+ // Anything else needs to be handled now.
+ ExprResult Result = CheckPlaceholderExpr(Input);
+ if (Result.isInvalid()) return ExprError();
+ Input = Result.take();
+ }
+
if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType() &&
UnaryOperator::getOverloadedOperator(Opc) != OO_None) {
// Find all of the overloaded operators visible from this
@@ -10151,6 +10404,10 @@
case BuiltinType::UnknownAny:
return diagnoseUnknownAnyExpr(*this, E);
+ // Pseudo-objects.
+ case BuiltinType::PseudoObject:
+ return checkPseudoObjectRValue(E);
+
// Everything else should be impossible.
#define BUILTIN_TYPE(Id, SingletonId) \
case BuiltinType::Id:
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Oct 25 02:27:56 2011
@@ -2260,15 +2260,7 @@
break;
case ICK_Lvalue_To_Rvalue:
- // Should this get its own ICK?
- if (From->getObjectKind() == OK_ObjCProperty) {
- ExprResult FromRes = ConvertPropertyForRValue(From);
- if (FromRes.isInvalid())
- return ExprError();
- From = FromRes.take();
- if (!From->isGLValue()) break;
- }
-
+ assert(From->getObjectKind() != OK_ObjCProperty);
FromType = FromType.getUnqualifiedType();
From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue,
From, 0, VK_RValue);
@@ -4194,6 +4186,10 @@
if (Result.isInvalid()) return ExprError();
Base = Result.get();
+ Result = CheckPlaceholderExpr(Base);
+ if (Result.isInvalid()) return ExprError();
+ Base = Result.take();
+
QualType BaseType = Base->getType();
MayBePseudoDestructor = false;
if (BaseType->isDependentType()) {
@@ -4592,6 +4588,12 @@
/// Perform the conversions required for an expression used in a
/// context that ignores the result.
ExprResult Sema::IgnoredValueConversions(Expr *E) {
+ if (E->hasPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(E);
+ if (result.isInvalid()) return Owned(E);
+ E = result.take();
+ }
+
// C99 6.3.2.1:
// [Except in specific positions,] an lvalue that does not have
// array type is converted to the value stored in the
@@ -4607,14 +4609,6 @@
return Owned(E);
}
- // We always want to do this on ObjC property references.
- if (E->getObjectKind() == OK_ObjCProperty) {
- ExprResult Res = ConvertPropertyForRValue(E);
- if (Res.isInvalid()) return Owned(E);
- E = Res.take();
- if (E->isRValue()) return Owned(E);
- }
-
// Otherwise, this rule does not apply in C++, at least not for the moment.
if (getLangOptions().CPlusPlus) return Owned(E);
Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprMember.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprMember.cpp Tue Oct 25 02:27:56 2011
@@ -777,7 +777,7 @@
QualType BaseType = BaseExprType;
if (IsArrow) {
assert(BaseType->isPointerType());
- BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+ BaseType = BaseType->castAs<PointerType>()->getPointeeType();
}
R.setBaseObjectType(BaseType);
@@ -814,15 +814,6 @@
CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
return ExprError();
- // Perform a property load on the base regardless of whether we
- // actually need it for the declaration.
- if (BaseExpr && BaseExpr->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = ConvertPropertyForRValue(BaseExpr);
- if (Result.isInvalid())
- return ExprError();
- BaseExpr = Result.take();
- }
-
// Construct an unresolved result if we in fact got an unresolved
// result.
if (R.isOverloadedResult() || R.isUnresolvableResult()) {
@@ -1209,11 +1200,8 @@
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
- QualType T = PD->getType();
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
- T = getMessageSendResultType(BaseType, Getter, false, false);
-
- return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD,
+ Context.PseudoObjectTy,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
@@ -1231,16 +1219,10 @@
if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
SetterSel, Context))
SMD = dyn_cast<ObjCMethodDecl>(SDecl);
- QualType PType = getMessageSendResultType(BaseType, OMD, false,
- false);
- ExprValueKind VK = VK_LValue;
- if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType())
- VK = VK_RValue;
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
- return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType,
- VK, OK,
+ return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD,
+ Context.PseudoObjectTy,
+ VK_LValue, OK_ObjCProperty,
MemberLoc, BaseExpr.take()));
}
}
@@ -1295,23 +1277,9 @@
return ExprError();
if (Getter || Setter) {
- QualType PType;
-
- ExprValueKind VK = VK_LValue;
- if (Getter) {
- PType = getMessageSendResultType(QualType(OT, 0), Getter, true,
- false);
- if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType())
- VK = VK_RValue;
- } else {
- // Get the expression type from Setter's incoming parameter.
- PType = (*(Setter->param_end() -1))->getType();
- }
- ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
-
- // FIXME: we must check that the setter has property type.
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
+ Context.PseudoObjectTy,
+ VK_LValue, OK_ObjCProperty,
MemberLoc, BaseExpr.take()));
}
Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Tue Oct 25 02:27:56 2011
@@ -527,6 +527,35 @@
return Method;
}
+/// LookupMethodInType - Look up a method in an ObjCObjectType.
+ObjCMethodDecl *Sema::LookupMethodInObjectType(Selector sel, QualType type,
+ bool isInstance) {
+ const ObjCObjectType *objType = type->castAs<ObjCObjectType>();
+ if (ObjCInterfaceDecl *iface = objType->getInterface()) {
+ // Look it up in the main interface (and categories, etc.)
+ if (ObjCMethodDecl *method = iface->lookupMethod(sel, isInstance))
+ return method;
+
+ // Okay, look for "private" methods declared in any
+ // @implementations we've seen.
+ if (isInstance) {
+ if (ObjCMethodDecl *method = LookupPrivateInstanceMethod(sel, iface))
+ return method;
+ } else {
+ if (ObjCMethodDecl *method = LookupPrivateClassMethod(sel, iface))
+ return method;
+ }
+ }
+
+ // Check qualifiers.
+ for (ObjCObjectType::qual_iterator
+ i = objType->qual_begin(), e = objType->qual_end(); i != e; ++i)
+ if (ObjCMethodDecl *method = (*i)->lookupMethod(sel, isInstance))
+ return method;
+
+ return 0;
+}
+
/// LookupMethodInQualifiedType - Lookups up a method in protocol qualifier
/// list of a qualified objective pointer type.
ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel,
@@ -575,23 +604,14 @@
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
- QualType ResTy = PD->getType();
- ResTy = ResTy.getNonLValueExprType(Context);
- Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
- ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
- if (Getter &&
- (Getter->hasRelatedResultType()
- || DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)))
- ResTy = getMessageSendResultType(QualType(OPT, 0), Getter, false,
- Super);
if (Super)
- return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy,
VK_LValue, OK_ObjCProperty,
MemberLoc,
SuperLoc, SuperType));
else
- return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy,
VK_LValue, OK_ObjCProperty,
MemberLoc, BaseExpr));
}
@@ -603,17 +623,16 @@
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
- QualType T = PD->getType();
- if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
- T = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
if (Super)
- return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD,
+ Context.PseudoObjectTy,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
SuperLoc, SuperType));
else
- return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD,
+ Context.PseudoObjectTy,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
@@ -668,28 +687,16 @@
return ExprError();
if (Getter || Setter) {
- QualType PType;
- if (Getter)
- PType = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
- else {
- ParmVarDecl *ArgDecl = *Setter->param_begin();
- PType = ArgDecl->getType().getUnqualifiedType(); // can't be an array
- }
-
- 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) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
+ Context.PseudoObjectTy,
+ VK_LValue, OK_ObjCProperty,
MemberLoc,
SuperLoc, SuperType));
else
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
+ Context.PseudoObjectTy,
+ VK_LValue, OK_ObjCProperty,
MemberLoc, BaseExpr));
}
@@ -825,34 +832,17 @@
return ExprError();
if (Getter || Setter) {
- QualType PType;
-
- ExprValueKind VK = VK_LValue;
- if (Getter) {
- PType = getMessageSendResultType(Context.getObjCInterfaceType(IFace),
- Getter, true,
- receiverNamePtr->isStr("super"));
- 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);
-
if (IsSuper)
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
+ Context.PseudoObjectTy,
+ VK_LValue, OK_ObjCProperty,
propertyNameLoc,
receiverNameLoc,
Context.getObjCInterfaceType(IFace)));
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- PType, VK, OK,
+ Context.PseudoObjectTy,
+ VK_LValue, OK_ObjCProperty,
propertyNameLoc,
receiverNameLoc, IFace));
}
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Oct 25 02:27:56 2011
@@ -3795,15 +3795,8 @@
setSequenceKind(NormalSequence);
for (unsigned I = 0; I != NumArgs; ++I)
- if (Args[I]->getObjectKind() == OK_ObjCProperty) {
- ExprResult Result = S.ConvertPropertyForRValue(Args[I]);
- if (Result.isInvalid()) {
- SetFailed(FK_ConversionFromPropertyFailed);
- return;
- }
- Args[I] = Result.take();
- } else if (const BuiltinType *PlaceholderTy
- = Args[I]->getType()->getAsPlaceholderType()) {
+ if (const BuiltinType *PlaceholderTy
+ = Args[I]->getType()->getAsPlaceholderType()) {
// FIXME: should we be doing this here?
if (PlaceholderTy->getKind() != BuiltinType::Overload) {
ExprResult result = S.CheckPlaceholderExpr(Args[I]);
@@ -4493,13 +4486,6 @@
assert(Args.size() == 1);
CurInit = Args.get()[0];
if (!CurInit.get()) return ExprError();
-
- // Read from a property when initializing something with it.
- if (CurInit.get()->getObjectKind() == OK_ObjCProperty) {
- CurInit = S.ConvertPropertyForRValue(CurInit.take());
- if (CurInit.isInvalid())
- return ExprError();
- }
break;
}
Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Tue Oct 25 02:27:56 2011
@@ -800,9 +800,7 @@
SelfExpr, true, true);
ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
ParmVarDecl *Param = (*P);
- QualType T = Param->getType();
- if (T->isReferenceType())
- T = T->getAs<ReferenceType>()->getPointeeType();
+ QualType T = Param->getType().getNonReferenceType();
Expr *rhs = new (Context) DeclRefExpr(Param, T,
VK_LValue, SourceLocation());
ExprResult Res = BuildBinOp(S, lhs->getLocEnd(),
@@ -954,8 +952,8 @@
ObjCMethodDecl *GetterMethod,
SourceLocation Loc) {
if (GetterMethod &&
- GetterMethod->getResultType().getNonReferenceType()
- != property->getType().getNonReferenceType()) {
+ !Context.hasSameType(GetterMethod->getResultType().getNonReferenceType(),
+ property->getType().getNonReferenceType())) {
AssignConvertType result = Incompatible;
if (property->getType()->isObjCObjectPointerType())
result = CheckAssignmentConstraints(Loc, GetterMethod->getResultType(),
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Oct 25 02:27:56 2011
@@ -575,17 +575,6 @@
/// Return true on unrecoverable error.
static bool checkPlaceholderForOverload(Sema &S, Expr *&E,
UnbridgedCastsSet *unbridgedCasts = 0) {
- // ObjCProperty l-values are placeholder-like.
- if (E->getObjectKind() == OK_ObjCProperty) {
- ExprResult result = S.ConvertPropertyForRValue(E);
- if (result.isInvalid())
- return true;
-
- E = result.take();
- return false;
- }
-
- // Handle true placeholders.
if (const BuiltinType *placeholder = E->getType()->getAsPlaceholderType()) {
// We can't handle overloaded expressions here because overload
// resolution might reasonably tweak them.
@@ -1003,6 +992,9 @@
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action, bool AllowExplicit,
ImplicitConversionSequence& ICS) {
+ if (checkPlaceholderForOverload(*this, From))
+ return ExprError();
+
// Objective-C ARC: Determine whether we will allow the writeback conversion.
bool AllowObjCWritebackConversion
= getLangOptions().ObjCAutoRefCount &&
@@ -4086,6 +4078,9 @@
/// PerformContextuallyConvertToBool - Perform a contextual conversion
/// of the expression From to bool (C++0x [conv]p3).
ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) {
+ if (checkPlaceholderForOverload(*this, From))
+ return ExprError();
+
ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From);
if (!ICS.isBad())
return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting);
@@ -4145,6 +4140,9 @@
/// PerformContextuallyConvertToObjCPointer - Perform a contextual
/// conversion of the expression From to an Objective-C pointer type.
ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) {
+ if (checkPlaceholderForOverload(*this, From))
+ return ExprError();
+
QualType Ty = Context.getObjCIdType();
ImplicitConversionSequence ICS =
TryContextuallyConvertToObjCPointer(*this, From);
@@ -9009,39 +9007,9 @@
if (checkPlaceholderForOverload(*this, Args[1]))
return ExprError();
- // The LHS is more complicated.
- if (Args[0]->getObjectKind() == OK_ObjCProperty) {
-
- // There's a tension for assignment operators between primitive
- // property assignment and the overloaded operators.
- if (BinaryOperator::isAssignmentOp(Opc)) {
- const ObjCPropertyRefExpr *PRE = LHS->getObjCProperty();
-
- // Is the property "logically" settable?
- bool Settable = (PRE->isExplicitProperty() ||
- PRE->getImplicitPropertySetter());
-
- // To avoid gratuitously inventing semantics, use the primitive
- // unless it isn't. Thoughts in case we ever really care:
- // - If the property isn't logically settable, we have to
- // load and hope.
- // - If the property is settable and this is simple assignment,
- // we really should use the primitive.
- // - If the property is settable, then we could try overloading
- // on a generic lvalue of the appropriate type; if it works
- // out to a builtin candidate, we would do that same operation
- // on the property, and otherwise just error.
- if (Settable)
- return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
- }
-
- ExprResult Result = ConvertPropertyForRValue(Args[0]);
- if (Result.isInvalid())
- return ExprError();
- Args[0] = Result.take();
- }
-
- // Handle all the other placeholders.
+ // Do placeholder-like conversion on the LHS; note that we should
+ // not get here with a PseudoObject LHS.
+ assert(Args[0]->getObjectKind() != OK_ObjCProperty);
if (checkPlaceholderForOverload(*this, Args[0]))
return ExprError();
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Oct 25 02:27:56 2011
@@ -492,6 +492,10 @@
if (!Cond)
return StmtError();
+ CondResult = CheckPlaceholderExpr(Cond);
+ if (CondResult.isInvalid())
+ return StmtError();
+
CondResult
= ConvertToIntegralOrEnumerationType(SwitchLoc, Cond,
PDiag(diag::err_typecheck_statement_requires_integer),
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Oct 25 02:27:56 2011
@@ -2249,8 +2249,8 @@
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildObjCPropertyRefExpr(Expr *BaseArg,
- ObjCPropertyDecl *Property,
- SourceLocation PropertyLoc) {
+ ObjCPropertyDecl *Property,
+ SourceLocation PropertyLoc) {
CXXScopeSpec SS;
ExprResult Base = getSema().Owned(BaseArg);
LookupResult R(getSema(), Property->getDeclName(), PropertyLoc,
@@ -8049,7 +8049,7 @@
E->getLocation());
return getDerived().RebuildObjCPropertyRefExpr(Base.get(),
- E->getType(),
+ SemaRef.Context.PseudoObjectTy,
E->getImplicitPropertyGetter(),
E->getImplicitPropertySetter(),
E->getLocation());
Modified: cfe/trunk/lib/Serialization/ASTCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTCommon.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTCommon.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTCommon.cpp Tue Oct 25 02:27:56 2011
@@ -52,6 +52,7 @@
case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break;
case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break;
case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER; break;
+ case BuiltinType::PseudoObject:ID = PREDEF_TYPE_PSEUDO_OBJECT;break;
case BuiltinType::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break;
case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break;
case BuiltinType::ARCUnbridgedCast:
Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Tue Oct 25 02:27:56 2011
@@ -3857,6 +3857,7 @@
case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break;
case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break;
case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; break;
+ case PREDEF_TYPE_PSEUDO_OBJECT: T = Context.PseudoObjectTy; break;
case PREDEF_TYPE_DEPENDENT_ID: T = Context.DependentTy; break;
case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break;
case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break;
Modified: cfe/trunk/test/SemaObjC/property-category-1.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-category-1.m?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/property-category-1.m (original)
+++ cfe/trunk/test/SemaObjC/property-category-1.m Tue Oct 25 02:27:56 2011
@@ -48,6 +48,6 @@
@implementation I0 // expected-warning {{property 'p0' requires method 'p0' to be define}}
- (void) foo {
- self.p0 = 0; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+ self.p0 = 0; // expected-error {{assignment to readonly property}}
}
@end
Modified: cfe/trunk/test/SemaObjC/property-error-readonly-assign.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-error-readonly-assign.m?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/property-error-readonly-assign.m (original)
+++ cfe/trunk/test/SemaObjC/property-error-readonly-assign.m Tue Oct 25 02:27:56 2011
@@ -13,9 +13,9 @@
@end
void f0(A *a, B* b) {
- a.x = 10; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+ a.x = 10; // expected-error {{assignment to readonly property}}
a.ok = 20;
- b.x = 10; // expected-error {{setter method is needed to assign to object using property assignment syntax}}
+ b.x = 10; // expected-error {{no setter method 'setX:' for assignment to property}}
b.ok = 20;
}
@@ -39,6 +39,6 @@
@implementation NSWindow (Category)
-(void)methodToMakeClangCrash
{
- self.frame = NSMakeRect(); // expected-error {{setter method is needed to assign to object using property assignment syntax}}
+ self.frame = NSMakeRect(); // expected-error {{no setter method 'setFrame:' for assignment to property}}
}
@end
Modified: cfe/trunk/test/SemaObjC/property-in-class-extension.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-in-class-extension.m?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/property-in-class-extension.m (original)
+++ cfe/trunk/test/SemaObjC/property-in-class-extension.m Tue Oct 25 02:27:56 2011
@@ -9,7 +9,7 @@
void FUNC () {
Foo *foo;
- foo.bar = 0; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+ foo.bar = 0; // expected-error {{assignment to readonly property}}
}
// rdar://8747333
Modified: cfe/trunk/test/SemaObjC/property-user-setter.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-user-setter.m?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/property-user-setter.m (original)
+++ cfe/trunk/test/SemaObjC/property-user-setter.m Tue Oct 25 02:27:56 2011
@@ -20,7 +20,7 @@
-(void) im0 {
self.x = 0;
self.y = 2;
- self.z = 2; // expected-error {{assigning to property with 'readonly' attribute not allowed}}
+ self.z = 2; // expected-error {{assignment to readonly property}}
}
@end
@@ -85,7 +85,7 @@
- (void)setFoo:(int)value;
@end
-void g(int);
+void g(int); // expected-note {{passing argument to parameter here}}
void f(C *c) {
c.Foo = 17; // OK
Modified: cfe/trunk/test/SemaObjCXX/propert-dot-error.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/propert-dot-error.mm?rev=142914&r1=142913&r2=142914&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/propert-dot-error.mm (original)
+++ cfe/trunk/test/SemaObjCXX/propert-dot-error.mm Tue Oct 25 02:27:56 2011
@@ -20,7 +20,7 @@
@end
void f(A* a) {
- a.x = X(); // expected-error {{setter method is needed to assign to object using property assignment syntax}}
+ a.x = X(); // expected-error {{no setter method 'setX:' for assignment to property}}
}
struct Y : X { };
More information about the cfe-commits
mailing list