summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorNAKAMURA Takumi <geek4civic@gmail.com>2011-10-25 14:32:25 +0000
committerNAKAMURA Takumi <geek4civic@gmail.com>2011-10-25 14:32:25 +0000
commit9a8f13961cc6fc9471ff9c916c7576c0bc13de39 (patch)
tree05e45eb81660bf306a4b068e96d69c5dff21de5c /clang/lib/Sema
parent6ca458e49a3addfa7436a0c02e2a84c4a174f13a (diff)
downloadbcm5719-llvm-9a8f13961cc6fc9471ff9c916c7576c0bc13de39.tar.gz
bcm5719-llvm-9a8f13961cc6fc9471ff9c916c7576c0bc13de39.zip
Revert r142914 and r142915, due to possibly missing file.
r142914: "Introduce a placeholder type for "pseudo object"" r142915: "Pull the pseudo-object stuff into its own file." llvm-svn: 142921
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/CMakeLists.txt1
-rw-r--r--clang/lib/Sema/SemaChecking.cpp3
-rw-r--r--clang/lib/Sema/SemaExpr.cpp410
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp28
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp48
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp96
-rw-r--r--clang/lib/Sema/SemaInit.cpp18
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp8
-rw-r--r--clang/lib/Sema/SemaOverload.cpp56
-rw-r--r--clang/lib/Sema/SemaStmt.cpp4
-rw-r--r--clang/lib/Sema/TreeTransform.h6
11 files changed, 411 insertions, 267 deletions
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 06d02252d68..dbbb980de85 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -31,7 +31,6 @@ add_clang_library(clangSema
SemaLookup.cpp
SemaObjCProperty.cpp
SemaOverload.cpp
- SemaPseudoObject.cpp
SemaStmt.cpp
SemaTemplate.cpp
SemaTemplateDeduction.cpp
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 6e81c3c9661..daab1cd4877 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -4256,8 +4256,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
if (LT != Qualifiers::OCL_None)
return;
- if (ObjCPropertyRefExpr *PRE
- = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens())) {
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
if (PRE->isImplicitProperty())
return;
const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 885b9664d62..3b4a40b51ab 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -363,9 +363,19 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
assert(!T.isNull() && "r-value conversion on typeless expression?");
// We can't do lvalue-to-rvalue on atomics yet.
- if (T->isAtomicType())
+ if (T->getAs<AtomicType>())
return Owned(E);
+ // Create a load out of an ObjCProperty l-value, if necessary.
+ if (E->getObjectKind() == OK_ObjCProperty) {
+ ExprResult Res = ConvertPropertyForRValue(E);
+ if (Res.isInvalid())
+ return Owned(E);
+ E = Res.take();
+ if (!E->isGLValue())
+ return Owned(E);
+ }
+
// We don't want to throw lvalue-to-rvalue casts on top of
// expressions of certain types in C++.
if (getLangOptions().CPlusPlus &&
@@ -3959,23 +3969,6 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
unsigned NumInit = InitArgList.size();
Expr **InitList = InitArgList.release();
- // Immediately handle non-overload placeholders. Overloads can be
- // resolved contextually, but everything else here can't.
- for (unsigned I = 0; I != NumInit; ++I) {
- if (const BuiltinType *pty
- = InitList[I]->getType()->getAsPlaceholderType()) {
- if (pty->getKind() == BuiltinType::Overload) continue;
-
- ExprResult result = CheckPlaceholderExpr(InitList[I]);
-
- // Ignore failures; dropping the entire initializer list because
- // of one failure would be terrible for indexing/etc.
- if (result.isInvalid()) continue;
-
- InitList[I] = result.take();
- }
- }
-
// Semantic analysis for initializers is done by ActOnDeclarator() and
// CheckInitializer() - it requires knowledge of the object being intialized.
@@ -6960,41 +6953,51 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
/// depends on various declarations and thus must be treated specially.
///
static bool IsReadonlyProperty(Expr *E, Sema &S) {
- const ObjCPropertyRefExpr *PropExpr = dyn_cast<ObjCPropertyRefExpr>(E);
- if (!PropExpr) return false;
- if (PropExpr->isImplicitProperty()) return false;
+ if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) {
+ const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
+ if (PropExpr->isImplicitProperty()) return false;
- ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
- QualType BaseType = PropExpr->isSuperReceiver() ?
+ ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
+ QualType BaseType = PropExpr->isSuperReceiver() ?
PropExpr->getSuperReceiverType() :
PropExpr->getBase()->getType();
- if (const ObjCObjectPointerType *OPT =
- BaseType->getAsObjCInterfacePointerType())
- if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
- if (S.isPropertyReadonly(PDecl, IFace))
- return true;
+ if (const ObjCObjectPointerType *OPT =
+ BaseType->getAsObjCInterfacePointerType())
+ if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
+ if (S.isPropertyReadonly(PDecl, IFace))
+ return true;
+ }
return false;
}
static bool IsConstProperty(Expr *E, Sema &S) {
- const ObjCPropertyRefExpr *PropExpr = dyn_cast<ObjCPropertyRefExpr>(E);
- if (!PropExpr) return false;
- if (PropExpr->isImplicitProperty()) return false;
+ if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) {
+ const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E);
+ if (PropExpr->isImplicitProperty()) return false;
- ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
- QualType T = PDecl->getType().getNonReferenceType();
- return T.isConstQualified();
+ ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
+ QualType T = PDecl->getType();
+ if (T->isReferenceType())
+ T = T->getAs<ReferenceType>()->getPointeeType();
+ CanQualType CT = S.Context.getCanonicalType(T);
+ return CT.isConstQualified();
+ }
+ return false;
}
static bool IsReadonlyMessage(Expr *E, Sema &S) {
- const MemberExpr *ME = dyn_cast<MemberExpr>(E);
- if (!ME) return false;
- if (!isa<FieldDecl>(ME->getMemberDecl())) return false;
- ObjCMessageExpr *Base =
- dyn_cast<ObjCMessageExpr>(ME->getBase()->IgnoreParenImpCasts());
- if (!Base) return false;
- return Base->getMethodDecl() != 0;
+ if (E->getStmtClass() != Expr::MemberExprClass)
+ return false;
+ const MemberExpr *ME = cast<MemberExpr>(E);
+ NamedDecl *Member = ME->getMemberDecl();
+ if (isa<FieldDecl>(Member)) {
+ Expr *Base = ME->getBase()->IgnoreParenImpCasts();
+ if (Base->getStmtClass() != Expr::ObjCMessageExprClass)
+ return false;
+ return cast<ObjCMessageExpr>(Base)->getMethodDecl() != 0;
+ }
+ return false;
}
/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not,
@@ -7082,8 +7085,10 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
Diag = diag::err_block_decl_ref_not_modifiable_lvalue;
break;
case Expr::MLV_ReadonlyProperty:
+ Diag = diag::error_readonly_property_assignment;
+ break;
case Expr::MLV_NoSetterProperty:
- llvm_unreachable("readonly properties should be processed differently");
+ Diag = diag::error_nosetter_property_assignment;
break;
case Expr::MLV_InvalidMessageExpression:
Diag = diag::error_readonly_message_assignment;
@@ -7109,8 +7114,6 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
SourceLocation Loc,
QualType CompoundType) {
- assert(!LHSExpr->hasPlaceholderType(BuiltinType::PseudoObject));
-
// Verify that LHS is a modifiable lvalue, and emit error if not.
if (CheckForModifiableLvalue(LHSExpr, Loc, *this))
return QualType();
@@ -7121,6 +7124,14 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
AssignConvertType ConvTy;
if (CompoundType.isNull()) {
QualType LHSTy(LHSType);
+ // Simple assignment "x = y".
+ if (LHSExpr->getObjectKind() == OK_ObjCProperty) {
+ ExprResult LHSResult = Owned(LHSExpr);
+ ConvertPropertyForLValue(LHSResult, RHS, LHSTy);
+ if (LHSResult.isInvalid())
+ return QualType();
+ LHSExpr = LHSResult.take();
+ }
ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
if (RHS.isInvalid())
return QualType();
@@ -7281,6 +7292,104 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
return ResType.getUnqualifiedType();
}
}
+
+ExprResult Sema::ConvertPropertyForRValue(Expr *E) {
+ assert(E->getValueKind() == VK_LValue &&
+ E->getObjectKind() == OK_ObjCProperty);
+ const ObjCPropertyRefExpr *PRE = E->getObjCProperty();
+
+ QualType T = E->getType();
+ QualType ReceiverType;
+ if (PRE->isObjectReceiver())
+ ReceiverType = PRE->getBase()->getType();
+ else if (PRE->isSuperReceiver())
+ ReceiverType = PRE->getSuperReceiverType();
+ else
+ ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver());
+
+ ExprValueKind VK = VK_RValue;
+ if (PRE->isImplicitProperty()) {
+ if (ObjCMethodDecl *GetterMethod =
+ PRE->getImplicitPropertyGetter()) {
+ T = getMessageSendResultType(ReceiverType, GetterMethod,
+ PRE->isClassReceiver(),
+ PRE->isSuperReceiver());
+ VK = Expr::getValueKindForType(GetterMethod->getResultType());
+ }
+ else {
+ Diag(PRE->getLocation(), diag::err_getter_not_found)
+ << PRE->getBase()->getType();
+ }
+ }
+ else {
+ // lvalue-ness of an explicit property is determined by
+ // getter type.
+ QualType ResT = PRE->getGetterResultType();
+ VK = Expr::getValueKindForType(ResT);
+ }
+
+ E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty,
+ E, 0, VK);
+
+ ExprResult Result = MaybeBindToTemporary(E);
+ if (!Result.isInvalid())
+ E = Result.take();
+
+ return Owned(E);
+}
+
+void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS,
+ QualType &LHSTy) {
+ assert(LHS.get()->getValueKind() == VK_LValue &&
+ LHS.get()->getObjectKind() == OK_ObjCProperty);
+ const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty();
+
+ bool Consumed = false;
+
+ if (PropRef->isImplicitProperty()) {
+ // If using property-dot syntax notation for assignment, and there is a
+ // setter, RHS expression is being passed to the setter argument. So,
+ // type conversion (and comparison) is RHS to setter's argument type.
+ if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) {
+ ObjCMethodDecl::param_const_iterator P = SetterMD->param_begin();
+ LHSTy = (*P)->getType();
+ Consumed = (getLangOptions().ObjCAutoRefCount &&
+ (*P)->hasAttr<NSConsumedAttr>());
+
+ // Otherwise, if the getter returns an l-value, just call that.
+ } else {
+ QualType Result = PropRef->getImplicitPropertyGetter()->getResultType();
+ ExprValueKind VK = Expr::getValueKindForType(Result);
+ if (VK == VK_LValue) {
+ LHS = ImplicitCastExpr::Create(Context, LHS.get()->getType(),
+ CK_GetObjCProperty, LHS.take(), 0, VK);
+ return;
+ }
+ }
+ } else {
+ const ObjCMethodDecl *setter
+ = PropRef->getExplicitProperty()->getSetterMethodDecl();
+ if (setter) {
+ ObjCMethodDecl::param_const_iterator P = setter->param_begin();
+ LHSTy = (*P)->getType();
+ if (getLangOptions().ObjCAutoRefCount)
+ Consumed = (*P)->hasAttr<NSConsumedAttr>();
+ }
+ }
+
+ if ((getLangOptions().CPlusPlus && LHSTy->isRecordType()) ||
+ getLangOptions().ObjCAutoRefCount) {
+ InitializedEntity Entity =
+ InitializedEntity::InitializeParameter(Context, LHSTy, Consumed);
+ ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), RHS);
+ if (!ArgE.isInvalid()) {
+ RHS = ArgE;
+ if (getLangOptions().ObjCAutoRefCount && !PropRef->isSuperReceiver())
+ checkRetainCycles(const_cast<Expr*>(PropRef->getBase()), RHS.get());
+ }
+ }
+ LHSTy = LHSTy.getNonReferenceType();
+}
/// getPrimaryDecl - Helper function for CheckAddressOfOperand().
@@ -7364,39 +7473,31 @@ static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc,
/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
/// In C++, the operand might be an overloaded function name, in which case
/// we allow the '&' but retain the overloaded-function type.
-static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
+static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp,
SourceLocation OpLoc) {
- if (const BuiltinType *PTy = OrigOp.get()->getType()->getAsPlaceholderType()){
- if (PTy->getKind() == BuiltinType::Overload) {
- if (!isa<OverloadExpr>(OrigOp.get()->IgnoreParens())) {
- S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
- << OrigOp.get()->getSourceRange();
- return QualType();
- }
-
- return S.Context.OverloadTy;
- }
-
- if (PTy->getKind() == BuiltinType::UnknownAny)
- return S.Context.UnknownAnyTy;
-
- if (PTy->getKind() == BuiltinType::BoundMember) {
- S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
- << OrigOp.get()->getSourceRange();
+ if (OrigOp->isTypeDependent())
+ return S.Context.DependentTy;
+ if (OrigOp->getType() == S.Context.OverloadTy) {
+ if (!isa<OverloadExpr>(OrigOp->IgnoreParens())) {
+ S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
+ << OrigOp->getSourceRange();
return QualType();
}
-
- OrigOp = S.CheckPlaceholderExpr(OrigOp.take());
- if (OrigOp.isInvalid()) 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();
}
- if (OrigOp.get()->isTypeDependent())
- return S.Context.DependentTy;
-
- assert(!OrigOp.get()->getType()->isPlaceholderType());
+ assert(!OrigOp->getType()->isPlaceholderType());
// Make sure to ignore parentheses in subsequent checks
- Expr *op = OrigOp.get()->IgnoreParens();
+ Expr *op = OrigOp->IgnoreParens();
if (S.getLangOptions().C99) {
// Implement C99-only parts of addressof rules.
@@ -7429,16 +7530,16 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
// 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.get()->getSourceRange();
+ << OrigOp->getSourceRange();
return QualType();
}
DeclRefExpr *DRE = cast<DeclRefExpr>(op);
CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());
// The id-expression was parenthesized.
- if (OrigOp.get() != DRE) {
+ if (OrigOp != DRE) {
S.Diag(OpLoc, diag::err_parens_pointer_member_function)
- << OrigOp.get()->getSourceRange();
+ << OrigOp->getSourceRange();
// The method was named without a qualifier.
} else if (!DRE->getQualifier()) {
@@ -7452,15 +7553,10 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
// C99 6.5.3.2p1
// The operand must be either an l-value or a function designator
if (!op->getType()->isFunctionType()) {
- // 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();
- }
+ // 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
@@ -7685,6 +7781,23 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
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());
@@ -7980,83 +8093,38 @@ ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
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)
- return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
+ 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);
+ }
}
// Build a built-in binary operation.
@@ -8082,9 +8150,12 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
Opc == UO_PreDec);
break;
case UO_AddrOf:
- resultType = CheckAddressOfOperand(*this, Input, OpLoc);
+ resultType = CheckAddressOfOperand(*this, Input.get(), 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;
@@ -8106,6 +8177,11 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
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());
@@ -8123,7 +8199,11 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
<< resultType << Input.get()->getSourceRange();
else if (resultType->hasIntegerRepresentation())
break;
- else {
+ 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());
}
@@ -8151,6 +8231,10 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
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());
@@ -8191,32 +8275,6 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
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
@@ -10093,10 +10151,6 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
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:
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index c96ab42b880..9267860d157 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2260,7 +2260,15 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
break;
case ICK_Lvalue_To_Rvalue:
- assert(From->getObjectKind() != OK_ObjCProperty);
+ // 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;
+ }
+
FromType = FromType.getUnqualifiedType();
From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue,
From, 0, VK_RValue);
@@ -4186,10 +4194,6 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,
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()) {
@@ -4588,12 +4592,6 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
/// 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
@@ -4609,6 +4607,14 @@ ExprResult Sema::IgnoredValueConversions(Expr *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.
if (getLangOptions().CPlusPlus) return Owned(E);
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 25d3c2a4254..16c17fb8909 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -777,7 +777,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
QualType BaseType = BaseExprType;
if (IsArrow) {
assert(BaseType->isPointerType());
- BaseType = BaseType->castAs<PointerType>()->getPointeeType();
+ BaseType = BaseType->getAs<PointerType>()->getPointeeType();
}
R.setBaseObjectType(BaseType);
@@ -814,6 +814,15 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
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()) {
@@ -1200,8 +1209,11 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
- return Owned(new (Context) ObjCPropertyRefExpr(PD,
- Context.PseudoObjectTy,
+ QualType T = PD->getType();
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ T = getMessageSendResultType(BaseType, Getter, false, false);
+
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
@@ -1219,10 +1231,16 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
SetterSel, Context))
SMD = dyn_cast<ObjCMethodDecl>(SDecl);
+ QualType PType = getMessageSendResultType(BaseType, OMD, false,
+ false);
- return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD,
- Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
+ 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,
MemberLoc, BaseExpr.take()));
}
}
@@ -1277,9 +1295,23 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
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,
- Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
+ PType, VK, OK,
MemberLoc, BaseExpr.take()));
}
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index ceff1de3d49..527983805c9 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -527,35 +527,6 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
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,
@@ -604,14 +575,23 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
// 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, Context.PseudoObjectTy,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
VK_LValue, OK_ObjCProperty,
MemberLoc,
SuperLoc, SuperType));
else
- return Owned(new (Context) ObjCPropertyRefExpr(PD, Context.PseudoObjectTy,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
VK_LValue, OK_ObjCProperty,
MemberLoc, BaseExpr));
}
@@ -623,16 +603,17 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
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,
- Context.PseudoObjectTy,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
SuperLoc, SuperType));
else
- return Owned(new (Context) ObjCPropertyRefExpr(PD,
- Context.PseudoObjectTy,
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
@@ -687,16 +668,28 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
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,
- Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
+ PType, VK, OK,
MemberLoc,
SuperLoc, SuperType));
else
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
+ PType, VK, OK,
MemberLoc, BaseExpr));
}
@@ -832,17 +825,34 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
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,
- Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
+ PType, VK, OK,
propertyNameLoc,
receiverNameLoc,
Context.getObjCInterfaceType(IFace)));
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
- Context.PseudoObjectTy,
- VK_LValue, OK_ObjCProperty,
+ PType, VK, OK,
propertyNameLoc,
receiverNameLoc, IFace));
}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 77cfe6c2de5..59901cb11b0 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -3795,8 +3795,15 @@ InitializationSequence::InitializationSequence(Sema &S,
setSequenceKind(NormalSequence);
for (unsigned I = 0; I != NumArgs; ++I)
- if (const BuiltinType *PlaceholderTy
- = Args[I]->getType()->getAsPlaceholderType()) {
+ 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()) {
// FIXME: should we be doing this here?
if (PlaceholderTy->getKind() != BuiltinType::Overload) {
ExprResult result = S.CheckPlaceholderExpr(Args[I]);
@@ -4486,6 +4493,13 @@ InitializationSequence::Perform(Sema &S,
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;
}
diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp
index 617dbefadaf..7e9bb46cd60 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -800,7 +800,9 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
SelfExpr, true, true);
ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
ParmVarDecl *Param = (*P);
- QualType T = Param->getType().getNonReferenceType();
+ QualType T = Param->getType();
+ if (T->isReferenceType())
+ T = T->getAs<ReferenceType>()->getPointeeType();
Expr *rhs = new (Context) DeclRefExpr(Param, T,
VK_LValue, SourceLocation());
ExprResult Res = BuildBinOp(S, lhs->getLocEnd(),
@@ -952,8 +954,8 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
ObjCMethodDecl *GetterMethod,
SourceLocation Loc) {
if (GetterMethod &&
- !Context.hasSameType(GetterMethod->getResultType().getNonReferenceType(),
- property->getType().getNonReferenceType())) {
+ GetterMethod->getResultType().getNonReferenceType()
+ != property->getType().getNonReferenceType()) {
AssignConvertType result = Incompatible;
if (property->getType()->isObjCObjectPointerType())
result = CheckAssignmentConstraints(Loc, GetterMethod->getResultType(),
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index f5494dee173..44395c59df1 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -575,6 +575,17 @@ namespace {
/// 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.
@@ -992,9 +1003,6 @@ ExprResult
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 &&
@@ -4078,9 +4086,6 @@ TryContextuallyConvertToBool(Sema &S, Expr *From) {
/// 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);
@@ -4140,9 +4145,6 @@ TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) {
/// 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);
@@ -9007,9 +9009,39 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (checkPlaceholderForOverload(*this, Args[1]))
return ExprError();
- // Do placeholder-like conversion on the LHS; note that we should
- // not get here with a PseudoObject LHS.
- assert(Args[0]->getObjectKind() != OK_ObjCProperty);
+ // 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.
if (checkPlaceholderForOverload(*this, Args[0]))
return ExprError();
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 887dd398940..3297c0641fe 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -492,10 +492,6 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
if (!Cond)
return StmtError();
- CondResult = CheckPlaceholderExpr(Cond);
- if (CondResult.isInvalid())
- return StmtError();
-
CondResult
= ConvertToIntegralOrEnumerationType(SwitchLoc, Cond,
PDiag(diag::err_typecheck_statement_requires_integer),
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 59c132caccd..3c118cb423d 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2249,8 +2249,8 @@ public:
/// 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 @@ TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
E->getLocation());
return getDerived().RebuildObjCPropertyRefExpr(Base.get(),
- SemaRef.Context.PseudoObjectTy,
+ E->getType(),
E->getImplicitPropertyGetter(),
E->getImplicitPropertySetter(),
E->getLocation());
OpenPOWER on IntegriCloud