aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/Expr.cpp26
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2
-rw-r--r--lib/Sema/SemaExprCXX.cpp35
3 files changed, 59 insertions, 4 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 083bf3b808..83efc75bae 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -772,6 +772,32 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
case CXXTypeidExprClass:
// C++ 5.2.8p1: The result of a typeid expression is an lvalue of ...
return LV_Valid;
+ case ConditionalOperatorClass: {
+ // Complicated handling is only for C++.
+ if (!Ctx.getLangOptions().CPlusPlus)
+ return LV_InvalidExpression;
+
+ // Sema should have taken care to ensure that a CXXTemporaryObjectExpr is
+ // everywhere there's an object converted to an rvalue. Also, any other
+ // casts should be wrapped by ImplicitCastExprs. There's just the special
+ // case involving throws to work out.
+ const ConditionalOperator *Cond = cast<ConditionalOperator>(this);
+ Expr *LHS = Cond->getLHS();
+ Expr *RHS = Cond->getRHS();
+ // C++0x 5.16p2
+ // If either the second or the third operand has type (cv) void, [...]
+ // the result [...] is an rvalue.
+ if (LHS->getType()->isVoidType() || RHS->getType()->isVoidType())
+ return LV_InvalidExpression;
+
+ // Both sides must be lvalues for the result to be an lvalue.
+ if (LHS->isLvalue(Ctx) != LV_Valid || RHS->isLvalue(Ctx) != LV_Valid)
+ return LV_InvalidExpression;
+
+ // That's it.
+ return LV_Valid;
+ }
+
default:
break;
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 9fd62269f2..734b6ce3a0 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2120,6 +2120,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
ICS->Standard.ReferenceBinding = true;
ICS->Standard.DirectBinding = true;
ICS->Standard.RRefBinding = false;
+ ICS->Standard.CopyConstructor = 0;
// Nothing more to do: the inaccessibility/ambiguity check for
// derived-to-base conversions is suppressed when we're
@@ -2273,6 +2274,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
ICS->Standard.ReferenceBinding = true;
ICS->Standard.DirectBinding = false;
ICS->Standard.RRefBinding = isRValRef;
+ ICS->Standard.CopyConstructor = 0;
} else {
// FIXME: Binding to a subobject of the rvalue is going to require
// more AST annotation than this.
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 8f41c003f9..0539caa712 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1137,6 +1137,35 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
return true;
}
+/// \brief Perform an "extended" implicit conversion as returned by
+/// TryClassUnification.
+///
+/// TryClassUnification generates ICSs that include reference bindings.
+/// PerformImplicitConversion is not suitable for this; it chokes if the
+/// second part of a standard conversion is ICK_DerivedToBase. This function
+/// handles the reference binding specially.
+static bool ConvertForConditional(Sema &Self, Expr *&E,
+ const ImplicitConversionSequence &ICS)
+{
+ if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion &&
+ ICS.Standard.ReferenceBinding) {
+ assert(ICS.Standard.DirectBinding &&
+ "TryClassUnification should never generate indirect ref bindings");
+ Self.ImpCastExprToType(E, TargetType(ICS), true);
+ return false;
+ }
+ if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion &&
+ ICS.UserDefined.After.ReferenceBinding) {
+ assert(ICS.UserDefined.After.DirectBinding &&
+ "TryClassUnification should never generate indirect ref bindings");
+ Self.ImpCastExprToType(E, TargetType(ICS), true);
+ return false;
+ }
+ if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, "converting"))
+ return true;
+ return false;
+}
+
/// \brief Check the operands of ?: under C++ semantics.
///
/// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y
@@ -1223,13 +1252,11 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// the chosen operand and the converted operands are used in place of the
// original operands for the remainder of this section.
if (HaveL2R) {
- if (PerformImplicitConversion(LHS, TargetType(ICSLeftToRight),
- ICSLeftToRight, "converting"))
+ if (ConvertForConditional(*this, LHS, ICSLeftToRight))
return QualType();
LTy = LHS->getType();
} else if (HaveR2L) {
- if (PerformImplicitConversion(RHS, TargetType(ICSRightToLeft),
- ICSRightToLeft, "converting"))
+ if (ConvertForConditional(*this, RHS, ICSRightToLeft))
return QualType();
RTy = RHS->getType();
}