Restore r142914 and r142915, now with missing file and apparent

GCC compiler workaround.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142931 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2011-10-25 17:37:35 +00:00
parent edae1a2fc8
commit 3c3b7f90a8
33 changed files with 702 additions and 441 deletions

View File

@ -496,7 +496,7 @@ public:
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
CanQualType VoidPtrTy, NullPtrTy; CanQualType VoidPtrTy, NullPtrTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy; CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
CanQualType ARCUnbridgedCastTy; CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand. // Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.

View File

@ -179,6 +179,24 @@ PLACEHOLDER_TYPE(Overload, OverloadTy)
// x->foo # if only contains non-static members // x->foo # if only contains non-static members
PLACEHOLDER_TYPE(BoundMember, BoundMemberTy) 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 // __builtin_any_type. A placeholder type. Useful for clients
// like debuggers that don't know what type to give something. // like debuggers that don't know what type to give something.
// Only a small number of operations are valid on expressions of // Only a small number of operations are valid on expressions of

View File

@ -1456,12 +1456,26 @@ public:
bool isPrefix() const { return isPrefix(getOpcode()); } bool isPrefix() const { return isPrefix(getOpcode()); }
bool isPostfix() const { return isPostfix(getOpcode()); } bool isPostfix() const { return isPostfix(getOpcode()); }
static bool isIncrementOp(Opcode Op) {
return Op == UO_PreInc || Op == UO_PostInc;
}
bool isIncrementOp() const { 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 { bool isIncrementDecrementOp() const {
return Opc <= UO_PreDec; return isIncrementDecrementOp(getOpcode());
} }
static bool isArithmeticOp(Opcode Op) { static bool isArithmeticOp(Opcode Op) {
return Op >= UO_Plus && Op <= UO_LNot; return Op >= UO_Plus && Op <= UO_LNot;
} }

View File

@ -227,7 +227,6 @@ public:
/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC /// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC
/// property. /// property.
///
class ObjCPropertyRefExpr : public Expr { class ObjCPropertyRefExpr : public Expr {
private: private:
/// If the bool is true, this is an implicit property reference; the /// If the bool is true, this is an implicit property reference; the
@ -237,6 +236,11 @@ private:
llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter; llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter;
ObjCMethodDecl *Setter; 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; SourceLocation IdLoc;
/// \brief When the receiver in property access is 'super', this is /// \brief When the receiver in property access is 'super', this is
@ -255,6 +259,7 @@ public:
base->containsUnexpandedParameterPack()), base->containsUnexpandedParameterPack()),
PropertyOrGetter(PD, false), Setter(0), PropertyOrGetter(PD, false), Setter(0),
IdLoc(l), ReceiverLoc(), Receiver(base) { IdLoc(l), ReceiverLoc(), Receiver(base) {
assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
} }
ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t,
@ -265,6 +270,7 @@ public:
st->containsUnexpandedParameterPack()), st->containsUnexpandedParameterPack()),
PropertyOrGetter(PD, false), Setter(0), PropertyOrGetter(PD, false), Setter(0),
IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) { IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) {
assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject));
} }
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@ -275,6 +281,7 @@ public:
Base->containsUnexpandedParameterPack()), Base->containsUnexpandedParameterPack()),
PropertyOrGetter(Getter, true), Setter(Setter), PropertyOrGetter(Getter, true), Setter(Setter),
IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) { IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) {
assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
} }
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@ -284,6 +291,7 @@ public:
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false),
PropertyOrGetter(Getter, true), Setter(Setter), PropertyOrGetter(Getter, true), Setter(Setter),
IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) { IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) {
assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
} }
ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter,
@ -293,6 +301,7 @@ public:
: Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false),
PropertyOrGetter(Getter, true), Setter(Setter), PropertyOrGetter(Getter, true), Setter(Setter),
IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) { IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) {
assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject));
} }
explicit ObjCPropertyRefExpr(EmptyShell Empty) explicit ObjCPropertyRefExpr(EmptyShell Empty)
@ -348,14 +357,15 @@ public:
if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl()) if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl())
ResultType = Getter->getResultType(); ResultType = Getter->getResultType();
else else
ResultType = getType(); ResultType = PDecl->getType();
} else { } else {
const ObjCMethodDecl *Getter = getImplicitPropertyGetter(); const ObjCMethodDecl *Getter = getImplicitPropertyGetter();
ResultType = Getter->getResultType(); // with reference! if (Getter)
ResultType = Getter->getResultType(); // with reference!
} }
return ResultType; return ResultType;
} }
QualType getSetterArgType() const { QualType getSetterArgType() const {
QualType ArgType; QualType ArgType;
if (isImplicitProperty()) { if (isImplicitProperty()) {

View File

@ -3612,16 +3612,22 @@ def ext_gnu_ptr_func_arith : Extension<
"arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 function " "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">, "type%select{|s}2 %1%select{| and %3}2 is a GNU extension">,
InGroup<PointerArith>; InGroup<PointerArith>;
def error_readonly_property_assignment : Error<
"assigning to property with 'readonly' attribute not allowed">;
def error_readonly_message_assignment : Error< def error_readonly_message_assignment : Error<
"assigning to 'readonly' return result of an objective-c message not allowed">; "assigning to 'readonly' return result of an objective-c message not allowed">;
def ext_integer_increment_complex : Extension< def ext_integer_increment_complex : Extension<
"ISO C does not support '++'/'--' on complex integer type %0">; "ISO C does not support '++'/'--' on complex integer type %0">;
def ext_integer_complement_complex : Extension< def ext_integer_complement_complex : Extension<
"ISO C does not support '~' for complex conjugation of %0">; "ISO C does not support '~' for complex conjugation of %0">;
def error_nosetter_property_assignment : Error< def err_nosetter_property_assignment : Error<
"setter method is needed to assign to object using property" " assignment syntax">; "%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< def error_no_subobject_property_setting : Error<
"expression is not assignable">; "expression is not assignable">;
def err_qualified_objc_access : Error< def err_qualified_objc_access : Error<

View File

@ -5319,6 +5319,8 @@ public:
ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel, ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel,
const ObjCObjectPointerType *OPT, const ObjCObjectPointerType *OPT,
bool IsInstance); bool IsInstance);
ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty,
bool IsInstance);
bool inferObjCARCLifetime(ValueDecl *decl); bool inferObjCARCLifetime(ValueDecl *decl);
@ -5777,10 +5779,13 @@ public:
// For compound assignment, pass both expressions and the converted type. // For compound assignment, pass both expressions and the converted type.
QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] QualType CheckAssignmentOperands( // C99 6.5.16.[1,2]
Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType); Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType);
void ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc,
QualType& LHSTy); UnaryOperatorKind Opcode, Expr *Op);
ExprResult ConvertPropertyForRValue(Expr *E); ExprResult checkPseudoObjectAssignment(Scope *S, SourceLocation OpLoc,
BinaryOperatorKind Opcode,
Expr *LHS, Expr *RHS);
ExprResult checkPseudoObjectRValue(Expr *E);
QualType CheckConditionalOperands( // C99 6.5.15 QualType CheckConditionalOperands( // C99 6.5.15
ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprResult &Cond, ExprResult &LHS, ExprResult &RHS,

View File

@ -556,7 +556,9 @@ namespace clang {
/// \brief The OpenCL 'half' / ARM NEON __fp16 type. /// \brief The OpenCL 'half' / ARM NEON __fp16 type.
PREDEF_TYPE_HALF_ID = 33, PREDEF_TYPE_HALF_ID = 33,
/// \brief ARC's unbridged-cast placeholder type. /// \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 /// \brief The number of predefined type IDs that are reserved for

View File

@ -461,6 +461,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
// Placeholder type for bound members. // Placeholder type for bound members.
InitBuiltinType(BoundMemberTy, BuiltinType::BoundMember); InitBuiltinType(BoundMemberTy, BuiltinType::BoundMember);
// Placeholder type for pseudo-objects.
InitBuiltinType(PseudoObjectTy, BuiltinType::PseudoObject);
// "any" type; useful for debugger-like clients. // "any" type; useful for debugger-like clients.
InitBuiltinType(UnknownAnyTy, BuiltinType::UnknownAny); InitBuiltinType(UnknownAnyTy, BuiltinType::UnknownAny);

View File

@ -1493,6 +1493,7 @@ const char *BuiltinType::getName(const PrintingPolicy &Policy) const {
case NullPtr: return "nullptr_t"; case NullPtr: return "nullptr_t";
case Overload: return "<overloaded function type>"; case Overload: return "<overloaded function type>";
case BoundMember: return "<bound member function type>"; case BoundMember: return "<bound member function type>";
case PseudoObject: return "<pseudo-object type>";
case Dependent: return "<dependent type>"; case Dependent: return "<dependent type>";
case UnknownAny: return "<unknown type>"; case UnknownAny: return "<unknown type>";
case ARCUnbridgedCast: return "<ARC unbridged cast type>"; case ARCUnbridgedCast: return "<ARC unbridged cast type>";

View File

@ -238,6 +238,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::BoundMember: case BuiltinType::BoundMember:
case BuiltinType::UnknownAny: case BuiltinType::UnknownAny:
case BuiltinType::ARCUnbridgedCast: case BuiltinType::ARCUnbridgedCast:
case BuiltinType::PseudoObject:
case BuiltinType::ObjCId: case BuiltinType::ObjCId:
case BuiltinType::ObjCClass: case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel: case BuiltinType::ObjCSel:

View File

@ -326,7 +326,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
} }
case CK_GetObjCProperty: { case CK_GetObjCProperty: {
LValue LV = CGF.EmitLValue(E->getSubExpr()); LValue LV =
CGF.EmitObjCPropertyRefLValue(E->getSubExpr()->getObjCProperty());
assert(LV.isPropertyRef()); assert(LV.isPropertyRef());
RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV, getReturnValueSlot()); RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV, getReturnValueSlot());
EmitMoveFromReturnSlot(E, RV); EmitMoveFromReturnSlot(E, RV);

View File

@ -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_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
case CK_GetObjCProperty: { case CK_GetObjCProperty: {
LValue LV = CGF.EmitLValue(Op); LValue LV = CGF.EmitObjCPropertyRefLValue(Op->getObjCProperty());
assert(LV.isPropertyRef() && "Unknown LValue type!"); assert(LV.isPropertyRef() && "Unknown LValue type!");
return CGF.EmitLoadOfPropertyRefLValue(LV).getComplexVal(); return CGF.EmitLoadOfPropertyRefLValue(LV).getComplexVal();
} }

View File

@ -1167,10 +1167,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
break; break;
case CK_GetObjCProperty: { case CK_GetObjCProperty: {
assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy));
assert(E->isGLValue() && E->getObjectKind() == OK_ObjCProperty && assert(E->isGLValue() && E->getObjectKind() == OK_ObjCProperty &&
"CK_GetObjCProperty for non-lvalue or non-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(); return RV.getScalarVal();
} }

View File

@ -1304,7 +1304,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitSetter(BinaryOperator *BinOp, Expr *
} else { } else {
OMD = PropRefExpr->getImplicitPropertySetter(); OMD = PropRefExpr->getImplicitPropertySetter();
Sel = OMD->getSelector(); Sel = OMD->getSelector();
Ty = PropRefExpr->getType(); Ty = (*OMD->param_begin())->getType();
} }
Super = PropRefExpr->isSuperReceiver(); Super = PropRefExpr->isSuperReceiver();
if (!Super) { if (!Super) {
@ -1380,7 +1380,7 @@ Stmt *RewriteObjC::RewritePropertyOrImplicitGetter(Expr *PropOrGetterRefExpr) {
} else { } else {
OMD = PropRefExpr->getImplicitPropertyGetter(); OMD = PropRefExpr->getImplicitPropertyGetter();
Sel = OMD->getSelector(); Sel = OMD->getSelector();
Ty = PropRefExpr->getType(); Ty = OMD->getResultType();
} }
Super = PropRefExpr->isSuperReceiver(); Super = PropRefExpr->isSuperReceiver();
if (!Super) if (!Super)

View File

@ -31,6 +31,7 @@ add_clang_library(clangSema
SemaLookup.cpp SemaLookup.cpp
SemaObjCProperty.cpp SemaObjCProperty.cpp
SemaOverload.cpp SemaOverload.cpp
SemaPseudoObject.cpp
SemaStmt.cpp SemaStmt.cpp
SemaTemplate.cpp SemaTemplate.cpp
SemaTemplateDeduction.cpp SemaTemplateDeduction.cpp

View File

@ -4256,7 +4256,8 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
if (LT != Qualifiers::OCL_None) if (LT != Qualifiers::OCL_None)
return; return;
if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) { if (ObjCPropertyRefExpr *PRE
= dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens())) {
if (PRE->isImplicitProperty()) if (PRE->isImplicitProperty())
return; return;
const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); const ObjCPropertyDecl *PD = PRE->getExplicitProperty();

View File

@ -363,19 +363,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
assert(!T.isNull() && "r-value conversion on typeless expression?"); assert(!T.isNull() && "r-value conversion on typeless expression?");
// We can't do lvalue-to-rvalue on atomics yet. // We can't do lvalue-to-rvalue on atomics yet.
if (T->getAs<AtomicType>()) if (T->isAtomicType())
return Owned(E); 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 // We don't want to throw lvalue-to-rvalue casts on top of
// expressions of certain types in C++. // expressions of certain types in C++.
if (getLangOptions().CPlusPlus && if (getLangOptions().CPlusPlus &&
@ -3969,6 +3959,23 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
unsigned NumInit = InitArgList.size(); unsigned NumInit = InitArgList.size();
Expr **InitList = InitArgList.release(); 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 // Semantic analysis for initializers is done by ActOnDeclarator() and
// CheckInitializer() - it requires knowledge of the object being intialized. // CheckInitializer() - it requires knowledge of the object being intialized.
@ -6953,51 +6960,41 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
/// depends on various declarations and thus must be treated specially. /// depends on various declarations and thus must be treated specially.
/// ///
static bool IsReadonlyProperty(Expr *E, Sema &S) { static bool IsReadonlyProperty(Expr *E, Sema &S) {
if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) { const ObjCPropertyRefExpr *PropExpr = dyn_cast<ObjCPropertyRefExpr>(E);
const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E); if (!PropExpr) return false;
if (PropExpr->isImplicitProperty()) return false; if (PropExpr->isImplicitProperty()) return false;
ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty(); ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
QualType BaseType = PropExpr->isSuperReceiver() ? QualType BaseType = PropExpr->isSuperReceiver() ?
PropExpr->getSuperReceiverType() : PropExpr->getSuperReceiverType() :
PropExpr->getBase()->getType(); PropExpr->getBase()->getType();
if (const ObjCObjectPointerType *OPT = if (const ObjCObjectPointerType *OPT =
BaseType->getAsObjCInterfacePointerType()) BaseType->getAsObjCInterfacePointerType())
if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl()) if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
if (S.isPropertyReadonly(PDecl, IFace)) if (S.isPropertyReadonly(PDecl, IFace))
return true; return true;
}
return false; return false;
} }
static bool IsConstProperty(Expr *E, Sema &S) { static bool IsConstProperty(Expr *E, Sema &S) {
if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) { const ObjCPropertyRefExpr *PropExpr = dyn_cast<ObjCPropertyRefExpr>(E);
const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E); if (!PropExpr) return false;
if (PropExpr->isImplicitProperty()) return false; if (PropExpr->isImplicitProperty()) return false;
ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty(); ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
QualType T = PDecl->getType(); QualType T = PDecl->getType().getNonReferenceType();
if (T->isReferenceType()) return T.isConstQualified();
T = T->getAs<ReferenceType>()->getPointeeType();
CanQualType CT = S.Context.getCanonicalType(T);
return CT.isConstQualified();
}
return false;
} }
static bool IsReadonlyMessage(Expr *E, Sema &S) { static bool IsReadonlyMessage(Expr *E, Sema &S) {
if (E->getStmtClass() != Expr::MemberExprClass) const MemberExpr *ME = dyn_cast<MemberExpr>(E);
return false; if (!ME) return false;
const MemberExpr *ME = cast<MemberExpr>(E); if (!isa<FieldDecl>(ME->getMemberDecl())) return false;
NamedDecl *Member = ME->getMemberDecl(); ObjCMessageExpr *Base =
if (isa<FieldDecl>(Member)) { dyn_cast<ObjCMessageExpr>(ME->getBase()->IgnoreParenImpCasts());
Expr *Base = ME->getBase()->IgnoreParenImpCasts(); if (!Base) return false;
if (Base->getStmtClass() != Expr::ObjCMessageExprClass) return Base->getMethodDecl() != 0;
return false;
return cast<ObjCMessageExpr>(Base)->getMethodDecl() != 0;
}
return false;
} }
/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not, /// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not,
@ -7085,10 +7082,8 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
Diag = diag::err_block_decl_ref_not_modifiable_lvalue; Diag = diag::err_block_decl_ref_not_modifiable_lvalue;
break; break;
case Expr::MLV_ReadonlyProperty: case Expr::MLV_ReadonlyProperty:
Diag = diag::error_readonly_property_assignment;
break;
case Expr::MLV_NoSetterProperty: case Expr::MLV_NoSetterProperty:
Diag = diag::error_nosetter_property_assignment; llvm_unreachable("readonly properties should be processed differently");
break; break;
case Expr::MLV_InvalidMessageExpression: case Expr::MLV_InvalidMessageExpression:
Diag = diag::error_readonly_message_assignment; Diag = diag::error_readonly_message_assignment;
@ -7114,6 +7109,8 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
SourceLocation Loc, SourceLocation Loc,
QualType CompoundType) { QualType CompoundType) {
assert(!LHSExpr->hasPlaceholderType(BuiltinType::PseudoObject));
// Verify that LHS is a modifiable lvalue, and emit error if not. // Verify that LHS is a modifiable lvalue, and emit error if not.
if (CheckForModifiableLvalue(LHSExpr, Loc, *this)) if (CheckForModifiableLvalue(LHSExpr, Loc, *this))
return QualType(); return QualType();
@ -7124,14 +7121,6 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
AssignConvertType ConvTy; AssignConvertType ConvTy;
if (CompoundType.isNull()) { if (CompoundType.isNull()) {
QualType LHSTy(LHSType); 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); ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
if (RHS.isInvalid()) if (RHS.isInvalid())
return QualType(); return QualType();
@ -7292,104 +7281,6 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
return ResType.getUnqualifiedType(); 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(). /// getPrimaryDecl - Helper function for CheckAddressOfOperand().
@ -7473,31 +7364,39 @@ static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc,
/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue. /// 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 /// In C++, the operand might be an overloaded function name, in which case
/// we allow the '&' but retain the overloaded-function type. /// 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) { SourceLocation OpLoc) {
if (OrigOp->isTypeDependent()) if (const BuiltinType *PTy = OrigOp.get()->getType()->getAsPlaceholderType()){
return S.Context.DependentTy; if (PTy->getKind() == BuiltinType::Overload) {
if (OrigOp->getType() == S.Context.OverloadTy) { if (!isa<OverloadExpr>(OrigOp.get()->IgnoreParens())) {
if (!isa<OverloadExpr>(OrigOp->IgnoreParens())) { S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) << OrigOp.get()->getSourceRange();
<< OrigOp->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 QualType();
} }
return S.Context.OverloadTy; OrigOp = S.CheckPlaceholderExpr(OrigOp.take());
} if (OrigOp.isInvalid()) return QualType();
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();
} }
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 // Make sure to ignore parentheses in subsequent checks
Expr *op = OrigOp->IgnoreParens(); Expr *op = OrigOp.get()->IgnoreParens();
if (S.getLangOptions().C99) { if (S.getLangOptions().C99) {
// Implement C99-only parts of addressof rules. // Implement C99-only parts of addressof rules.
@ -7530,16 +7429,16 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
// If the underlying expression isn't a decl ref, give up. // If the underlying expression isn't a decl ref, give up.
if (!isa<DeclRefExpr>(op)) { if (!isa<DeclRefExpr>(op)) {
S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function) S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
<< OrigOp->getSourceRange(); << OrigOp.get()->getSourceRange();
return QualType(); return QualType();
} }
DeclRefExpr *DRE = cast<DeclRefExpr>(op); DeclRefExpr *DRE = cast<DeclRefExpr>(op);
CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl()); CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());
// The id-expression was parenthesized. // The id-expression was parenthesized.
if (OrigOp != DRE) { if (OrigOp.get() != DRE) {
S.Diag(OpLoc, diag::err_parens_pointer_member_function) S.Diag(OpLoc, diag::err_parens_pointer_member_function)
<< OrigOp->getSourceRange(); << OrigOp.get()->getSourceRange();
// The method was named without a qualifier. // The method was named without a qualifier.
} else if (!DRE->getQualifier()) { } else if (!DRE->getQualifier()) {
@ -7553,10 +7452,15 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
// C99 6.5.3.2p1 // C99 6.5.3.2p1
// The operand must be either an l-value or a function designator // The operand must be either an l-value or a function designator
if (!op->getType()->isFunctionType()) { if (!op->getType()->isFunctionType()) {
// FIXME: emit more specific diag... // Use a special diagnostic for loads from property references.
S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) if (isa<ObjCPropertyRefExpr>(op->IgnoreImplicit()->IgnoreParens())) {
<< op->getSourceRange(); AddressOfError = AO_Property_Expansion;
return QualType(); } 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 } else if (op->getObjectKind() == OK_BitField) { // C99 6.5.3.2p1
// The operand cannot be a bit-field // The operand cannot be a bit-field
@ -7781,23 +7685,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ExprValueKind VK = VK_RValue; ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary; 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) { switch (Opc) {
case BO_Assign: case BO_Assign:
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType()); ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
@ -8093,38 +7980,83 @@ ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
return BuildBinOp(S, TokLoc, Opc, LHSExpr, RHSExpr); 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, ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
BinaryOperatorKind Opc, BinaryOperatorKind Opc,
Expr *LHSExpr, Expr *RHSExpr) { 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) { if (getLangOptions().CPlusPlus) {
bool UseBuiltinOperator; bool UseBuiltinOperator;
if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) { if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) {
UseBuiltinOperator = false; UseBuiltinOperator = false;
} else if (Opc == BO_Assign &&
LHSExpr->getObjectKind() == OK_ObjCProperty) {
UseBuiltinOperator = true;
} else { } else {
UseBuiltinOperator = !LHSExpr->getType()->isOverloadableType() && UseBuiltinOperator = !LHSExpr->getType()->isOverloadableType() &&
!RHSExpr->getType()->isOverloadableType(); !RHSExpr->getType()->isOverloadableType();
} }
if (!UseBuiltinOperator) { if (!UseBuiltinOperator)
// Find all of the overloaded operators visible from this return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
// 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);
}
} }
// Build a built-in binary operation. // Build a built-in binary operation.
@ -8150,12 +8082,9 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
Opc == UO_PreDec); Opc == UO_PreDec);
break; break;
case UO_AddrOf: case UO_AddrOf:
resultType = CheckAddressOfOperand(*this, Input.get(), OpLoc); resultType = CheckAddressOfOperand(*this, Input, OpLoc);
break; break;
case UO_Deref: { case UO_Deref: {
ExprResult resolved = CheckPlaceholderExpr(Input.get());
if (!resolved.isUsable()) return ExprError();
Input = move(resolved);
Input = DefaultFunctionArrayLvalueConversion(Input.take()); Input = DefaultFunctionArrayLvalueConversion(Input.take());
resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc); resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
break; break;
@ -8177,11 +8106,6 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
Opc == UO_Plus && Opc == UO_Plus &&
resultType->isPointerType()) resultType->isPointerType())
break; 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) return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange()); << resultType << Input.get()->getSourceRange());
@ -8199,11 +8123,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
<< resultType << Input.get()->getSourceRange(); << resultType << Input.get()->getSourceRange();
else if (resultType->hasIntegerRepresentation()) else if (resultType->hasIntegerRepresentation())
break; break;
else if (resultType->isPlaceholderType()) { else {
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) return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange()); << resultType << Input.get()->getSourceRange());
} }
@ -8231,10 +8151,6 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
Input = ImpCastExprToType(Input.take(), Context.BoolTy, Input = ImpCastExprToType(Input.take(), Context.BoolTy,
ScalarTypeToBooleanCastKind(resultType)); ScalarTypeToBooleanCastKind(resultType));
} }
} 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) return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange()); << resultType << Input.get()->getSourceRange());
@ -8275,6 +8191,32 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
UnaryOperatorKind Opc, Expr *Input) { 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() && if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType() &&
UnaryOperator::getOverloadedOperator(Opc) != OO_None) { UnaryOperator::getOverloadedOperator(Opc) != OO_None) {
// Find all of the overloaded operators visible from this // Find all of the overloaded operators visible from this
@ -10151,6 +10093,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
case BuiltinType::UnknownAny: case BuiltinType::UnknownAny:
return diagnoseUnknownAnyExpr(*this, E); return diagnoseUnknownAnyExpr(*this, E);
// Pseudo-objects.
case BuiltinType::PseudoObject:
return checkPseudoObjectRValue(E);
// Everything else should be impossible. // Everything else should be impossible.
#define BUILTIN_TYPE(Id, SingletonId) \ #define BUILTIN_TYPE(Id, SingletonId) \
case BuiltinType::Id: case BuiltinType::Id:

View File

@ -2260,15 +2260,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
break; break;
case ICK_Lvalue_To_Rvalue: case ICK_Lvalue_To_Rvalue:
// Should this get its own ICK? assert(From->getObjectKind() != OK_ObjCProperty);
if (From->getObjectKind() == OK_ObjCProperty) {
ExprResult FromRes = ConvertPropertyForRValue(From);
if (FromRes.isInvalid())
return ExprError();
From = FromRes.take();
if (!From->isGLValue()) break;
}
FromType = FromType.getUnqualifiedType(); FromType = FromType.getUnqualifiedType();
From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue, From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue,
From, 0, VK_RValue); From, 0, VK_RValue);
@ -4194,6 +4186,10 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
if (Result.isInvalid()) return ExprError(); if (Result.isInvalid()) return ExprError();
Base = Result.get(); Base = Result.get();
Result = CheckPlaceholderExpr(Base);
if (Result.isInvalid()) return ExprError();
Base = Result.take();
QualType BaseType = Base->getType(); QualType BaseType = Base->getType();
MayBePseudoDestructor = false; MayBePseudoDestructor = false;
if (BaseType->isDependentType()) { if (BaseType->isDependentType()) {
@ -4592,6 +4588,12 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
/// Perform the conversions required for an expression used in a /// Perform the conversions required for an expression used in a
/// context that ignores the result. /// context that ignores the result.
ExprResult Sema::IgnoredValueConversions(Expr *E) { 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: // C99 6.3.2.1:
// [Except in specific positions,] an lvalue that does not have // [Except in specific positions,] an lvalue that does not have
// array type is converted to the value stored in the // array type is converted to the value stored in the
@ -4607,14 +4609,6 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
return Owned(E); 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. // Otherwise, this rule does not apply in C++, at least not for the moment.
if (getLangOptions().CPlusPlus) return Owned(E); if (getLangOptions().CPlusPlus) return Owned(E);

View File

@ -777,7 +777,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
QualType BaseType = BaseExprType; QualType BaseType = BaseExprType;
if (IsArrow) { if (IsArrow) {
assert(BaseType->isPointerType()); assert(BaseType->isPointerType());
BaseType = BaseType->getAs<PointerType>()->getPointeeType(); BaseType = BaseType->castAs<PointerType>()->getPointeeType();
} }
R.setBaseObjectType(BaseType); R.setBaseObjectType(BaseType);
@ -814,15 +814,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R)) CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R))
return ExprError(); 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 // Construct an unresolved result if we in fact got an unresolved
// result. // result.
if (R.isOverloadedResult() || R.isUnresolvableResult()) { if (R.isOverloadedResult() || R.isUnresolvableResult()) {
@ -1209,11 +1200,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (DiagnoseUseOfDecl(PD, MemberLoc)) if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError(); return ExprError();
QualType T = PD->getType(); return Owned(new (Context) ObjCPropertyRefExpr(PD,
if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) Context.PseudoObjectTy,
T = getMessageSendResultType(BaseType, Getter, false, false);
return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
VK_LValue, VK_LValue,
OK_ObjCProperty, OK_ObjCProperty,
MemberLoc, MemberLoc,
@ -1231,16 +1219,10 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0, if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
SetterSel, Context)) SetterSel, Context))
SMD = dyn_cast<ObjCMethodDecl>(SDecl); SMD = dyn_cast<ObjCMethodDecl>(SDecl);
QualType PType = getMessageSendResultType(BaseType, OMD, false,
false);
ExprValueKind VK = VK_LValue; return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD,
if (!getLangOptions().CPlusPlus && PType.isCForbiddenLValueType()) Context.PseudoObjectTy,
VK = VK_RValue; VK_LValue, OK_ObjCProperty,
ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType,
VK, OK,
MemberLoc, BaseExpr.take())); MemberLoc, BaseExpr.take()));
} }
} }
@ -1295,23 +1277,9 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
return ExprError(); return ExprError();
if (Getter || Setter) { 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, return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
PType, VK, OK, Context.PseudoObjectTy,
VK_LValue, OK_ObjCProperty,
MemberLoc, BaseExpr.take())); MemberLoc, BaseExpr.take()));
} }

View File

@ -527,6 +527,35 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
return Method; 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 /// LookupMethodInQualifiedType - Lookups up a method in protocol qualifier
/// list of a qualified objective pointer type. /// list of a qualified objective pointer type.
ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel, ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel,
@ -575,23 +604,14 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
// Check whether we can reference this property. // Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc)) if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError(); 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) if (Super)
return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy,
VK_LValue, OK_ObjCProperty, VK_LValue, OK_ObjCProperty,
MemberLoc, MemberLoc,
SuperLoc, SuperType)); SuperLoc, SuperType));
else else
return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy,
VK_LValue, OK_ObjCProperty, VK_LValue, OK_ObjCProperty,
MemberLoc, BaseExpr)); MemberLoc, BaseExpr));
} }
@ -603,17 +623,16 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
if (DiagnoseUseOfDecl(PD, MemberLoc)) if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError(); return ExprError();
QualType T = PD->getType();
if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
T = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
if (Super) if (Super)
return Owned(new (Context) ObjCPropertyRefExpr(PD, T, return Owned(new (Context) ObjCPropertyRefExpr(PD,
Context.PseudoObjectTy,
VK_LValue, VK_LValue,
OK_ObjCProperty, OK_ObjCProperty,
MemberLoc, MemberLoc,
SuperLoc, SuperType)); SuperLoc, SuperType));
else else
return Owned(new (Context) ObjCPropertyRefExpr(PD, T, return Owned(new (Context) ObjCPropertyRefExpr(PD,
Context.PseudoObjectTy,
VK_LValue, VK_LValue,
OK_ObjCProperty, OK_ObjCProperty,
MemberLoc, MemberLoc,
@ -668,28 +687,16 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
return ExprError(); return ExprError();
if (Getter || Setter) { 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) if (Super)
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
PType, VK, OK, Context.PseudoObjectTy,
VK_LValue, OK_ObjCProperty,
MemberLoc, MemberLoc,
SuperLoc, SuperType)); SuperLoc, SuperType));
else else
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
PType, VK, OK, Context.PseudoObjectTy,
VK_LValue, OK_ObjCProperty,
MemberLoc, BaseExpr)); MemberLoc, BaseExpr));
} }
@ -825,34 +832,17 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
return ExprError(); return ExprError();
if (Getter || Setter) { 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) if (IsSuper)
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
PType, VK, OK, Context.PseudoObjectTy,
VK_LValue, OK_ObjCProperty,
propertyNameLoc, propertyNameLoc,
receiverNameLoc, receiverNameLoc,
Context.getObjCInterfaceType(IFace))); Context.getObjCInterfaceType(IFace)));
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
PType, VK, OK, Context.PseudoObjectTy,
VK_LValue, OK_ObjCProperty,
propertyNameLoc, propertyNameLoc,
receiverNameLoc, IFace)); receiverNameLoc, IFace));
} }

View File

@ -3795,15 +3795,8 @@ InitializationSequence::InitializationSequence(Sema &S,
setSequenceKind(NormalSequence); setSequenceKind(NormalSequence);
for (unsigned I = 0; I != NumArgs; ++I) for (unsigned I = 0; I != NumArgs; ++I)
if (Args[I]->getObjectKind() == OK_ObjCProperty) { if (const BuiltinType *PlaceholderTy
ExprResult Result = S.ConvertPropertyForRValue(Args[I]); = Args[I]->getType()->getAsPlaceholderType()) {
if (Result.isInvalid()) {
SetFailed(FK_ConversionFromPropertyFailed);
return;
}
Args[I] = Result.take();
} else if (const BuiltinType *PlaceholderTy
= Args[I]->getType()->getAsPlaceholderType()) {
// FIXME: should we be doing this here? // FIXME: should we be doing this here?
if (PlaceholderTy->getKind() != BuiltinType::Overload) { if (PlaceholderTy->getKind() != BuiltinType::Overload) {
ExprResult result = S.CheckPlaceholderExpr(Args[I]); ExprResult result = S.CheckPlaceholderExpr(Args[I]);
@ -4493,13 +4486,6 @@ InitializationSequence::Perform(Sema &S,
assert(Args.size() == 1); assert(Args.size() == 1);
CurInit = Args.get()[0]; CurInit = Args.get()[0];
if (!CurInit.get()) return ExprError(); 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; break;
} }

View File

@ -800,9 +800,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
SelfExpr, true, true); SelfExpr, true, true);
ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
ParmVarDecl *Param = (*P); ParmVarDecl *Param = (*P);
QualType T = Param->getType(); QualType T = Param->getType().getNonReferenceType();
if (T->isReferenceType())
T = T->getAs<ReferenceType>()->getPointeeType();
Expr *rhs = new (Context) DeclRefExpr(Param, T, Expr *rhs = new (Context) DeclRefExpr(Param, T,
VK_LValue, SourceLocation()); VK_LValue, SourceLocation());
ExprResult Res = BuildBinOp(S, lhs->getLocEnd(), ExprResult Res = BuildBinOp(S, lhs->getLocEnd(),
@ -954,8 +952,8 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
ObjCMethodDecl *GetterMethod, ObjCMethodDecl *GetterMethod,
SourceLocation Loc) { SourceLocation Loc) {
if (GetterMethod && if (GetterMethod &&
GetterMethod->getResultType().getNonReferenceType() !Context.hasSameType(GetterMethod->getResultType().getNonReferenceType(),
!= property->getType().getNonReferenceType()) { property->getType().getNonReferenceType())) {
AssignConvertType result = Incompatible; AssignConvertType result = Incompatible;
if (property->getType()->isObjCObjectPointerType()) if (property->getType()->isObjCObjectPointerType())
result = CheckAssignmentConstraints(Loc, GetterMethod->getResultType(), result = CheckAssignmentConstraints(Loc, GetterMethod->getResultType(),

View File

@ -575,17 +575,6 @@ namespace {
/// Return true on unrecoverable error. /// Return true on unrecoverable error.
static bool checkPlaceholderForOverload(Sema &S, Expr *&E, static bool checkPlaceholderForOverload(Sema &S, Expr *&E,
UnbridgedCastsSet *unbridgedCasts = 0) { 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()) { if (const BuiltinType *placeholder = E->getType()->getAsPlaceholderType()) {
// We can't handle overloaded expressions here because overload // We can't handle overloaded expressions here because overload
// resolution might reasonably tweak them. // resolution might reasonably tweak them.
@ -1003,6 +992,9 @@ ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType, Sema::PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action, bool AllowExplicit, AssignmentAction Action, bool AllowExplicit,
ImplicitConversionSequence& ICS) { ImplicitConversionSequence& ICS) {
if (checkPlaceholderForOverload(*this, From))
return ExprError();
// Objective-C ARC: Determine whether we will allow the writeback conversion. // Objective-C ARC: Determine whether we will allow the writeback conversion.
bool AllowObjCWritebackConversion bool AllowObjCWritebackConversion
= getLangOptions().ObjCAutoRefCount && = getLangOptions().ObjCAutoRefCount &&
@ -4086,6 +4078,9 @@ TryContextuallyConvertToBool(Sema &S, Expr *From) {
/// PerformContextuallyConvertToBool - Perform a contextual conversion /// PerformContextuallyConvertToBool - Perform a contextual conversion
/// of the expression From to bool (C++0x [conv]p3). /// of the expression From to bool (C++0x [conv]p3).
ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) { ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) {
if (checkPlaceholderForOverload(*this, From))
return ExprError();
ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From); ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From);
if (!ICS.isBad()) if (!ICS.isBad())
return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting); return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting);
@ -4145,6 +4140,9 @@ TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) {
/// PerformContextuallyConvertToObjCPointer - Perform a contextual /// PerformContextuallyConvertToObjCPointer - Perform a contextual
/// conversion of the expression From to an Objective-C pointer type. /// conversion of the expression From to an Objective-C pointer type.
ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) { ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) {
if (checkPlaceholderForOverload(*this, From))
return ExprError();
QualType Ty = Context.getObjCIdType(); QualType Ty = Context.getObjCIdType();
ImplicitConversionSequence ICS = ImplicitConversionSequence ICS =
TryContextuallyConvertToObjCPointer(*this, From); TryContextuallyConvertToObjCPointer(*this, From);
@ -9009,39 +9007,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (checkPlaceholderForOverload(*this, Args[1])) if (checkPlaceholderForOverload(*this, Args[1]))
return ExprError(); return ExprError();
// The LHS is more complicated. // Do placeholder-like conversion on the LHS; note that we should
if (Args[0]->getObjectKind() == OK_ObjCProperty) { // not get here with a PseudoObject LHS.
assert(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.
if (checkPlaceholderForOverload(*this, Args[0])) if (checkPlaceholderForOverload(*this, Args[0]))
return ExprError(); return ExprError();

View File

@ -0,0 +1,342 @@
//===--- SemaPseudoObject.cpp - Semantic Analysis for Pseudo-Objects ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis for expressions involving
// pseudo-object references. Pseudo-objects are conceptual objects
// whose storage is entirely abstract and all accesses to which are
// translated through some sort of abstraction barrier.
//
// For example, Objective-C objects can have "properties", either
// declared or undeclared. A property may be accessed by writing
// expr.prop
// where 'expr' is an r-value of Objective-C pointer type and 'prop'
// is the name of the property. If this expression is used in a context
// needing an r-value, it is treated as if it were a message-send
// of the associated 'getter' selector, typically:
// [expr prop]
// If it is used as the LHS of a simple assignment, it is treated
// as a message-send of the associated 'setter' selector, typically:
// [expr setProp: RHS]
// If it is used as the LHS of a compound assignment, or the operand
// of a unary increment or decrement, both are required; for example,
// 'expr.prop *= 100' would be translated to:
// [expr setProp: [expr prop] * 100]
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Initialization.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/Preprocessor.h"
using namespace clang;
using namespace sema;
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 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;
QualType T;
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();
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);
}
}
E->setType(T);
E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty, E, 0, VK);
ExprResult Result = MaybeBindToTemporary(E);
if (!Result.isInvalid())
E = Result.take();
return Owned(E);
}
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)) {
setSetter(setter);
return;
}
// If that failed, trust the type on the @property declaration.
if (!prop->isReadOnly()) {
HasSetter = true;
SetterParamType = prop->getType().getUnqualifiedType();
}
}
};
}
/// 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)
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 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();
}
// 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;
}

View File

@ -492,6 +492,10 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
if (!Cond) if (!Cond)
return StmtError(); return StmtError();
CondResult = CheckPlaceholderExpr(Cond);
if (CondResult.isInvalid())
return StmtError();
CondResult CondResult
= ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond,
PDiag(diag::err_typecheck_statement_requires_integer), PDiag(diag::err_typecheck_statement_requires_integer),

View File

@ -2249,8 +2249,8 @@ public:
/// By default, performs semantic analysis to build the new expression. /// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior. /// Subclasses may override this routine to provide different behavior.
ExprResult RebuildObjCPropertyRefExpr(Expr *BaseArg, ExprResult RebuildObjCPropertyRefExpr(Expr *BaseArg,
ObjCPropertyDecl *Property, ObjCPropertyDecl *Property,
SourceLocation PropertyLoc) { SourceLocation PropertyLoc) {
CXXScopeSpec SS; CXXScopeSpec SS;
ExprResult Base = getSema().Owned(BaseArg); ExprResult Base = getSema().Owned(BaseArg);
LookupResult R(getSema(), Property->getDeclName(), PropertyLoc, LookupResult R(getSema(), Property->getDeclName(), PropertyLoc,
@ -8049,7 +8049,7 @@ TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
E->getLocation()); E->getLocation());
return getDerived().RebuildObjCPropertyRefExpr(Base.get(), return getDerived().RebuildObjCPropertyRefExpr(Base.get(),
E->getType(), SemaRef.Context.PseudoObjectTy,
E->getImplicitPropertyGetter(), E->getImplicitPropertyGetter(),
E->getImplicitPropertySetter(), E->getImplicitPropertySetter(),
E->getLocation()); E->getLocation());

View File

@ -52,6 +52,7 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break; case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break;
case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break; case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break;
case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER; 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::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break;
case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break; case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break;
case BuiltinType::ARCUnbridgedCast: case BuiltinType::ARCUnbridgedCast:

View File

@ -3857,6 +3857,7 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break;
case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break; case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break;
case PREDEF_TYPE_BOUND_MEMBER: T = Context.BoundMemberTy; 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_DEPENDENT_ID: T = Context.DependentTy; break;
case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break; case PREDEF_TYPE_UNKNOWN_ANY: T = Context.UnknownAnyTy; break;
case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break; case PREDEF_TYPE_NULLPTR_ID: T = Context.NullPtrTy; break;

View File

@ -48,6 +48,6 @@ int main(int argc, char **argv) {
@implementation I0 // expected-warning {{property 'p0' requires method 'p0' to be define}} @implementation I0 // expected-warning {{property 'p0' requires method 'p0' to be define}}
- (void) foo { - (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 @end

View File

@ -13,9 +13,9 @@
@end @end
void f0(A *a, B* b) { 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; 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; b.ok = 20;
} }
@ -39,6 +39,6 @@ NSRect NSMakeRect();
@implementation NSWindow (Category) @implementation NSWindow (Category)
-(void)methodToMakeClangCrash -(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 @end

View File

@ -9,7 +9,7 @@
void FUNC () { void FUNC () {
Foo *foo; 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 // rdar://8747333

View File

@ -20,7 +20,7 @@
-(void) im0 { -(void) im0 {
self.x = 0; self.x = 0;
self.y = 2; 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 @end
@ -85,7 +85,7 @@ static int g_val;
- (void)setFoo:(int)value; - (void)setFoo:(int)value;
@end @end
void g(int); void g(int); // expected-note {{passing argument to parameter here}}
void f(C *c) { void f(C *c) {
c.Foo = 17; // OK c.Foo = 17; // OK

View File

@ -20,7 +20,7 @@ struct X {
@end @end
void f(A* a) { 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 { }; struct Y : X { };