[cfe-commits] r69354 - in /cfe/trunk: include/clang/AST/Expr.h lib/AST/Expr.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/conditional-expr.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Fri Apr 17 09:30:54 PDT 2009


Author: cornedbee
Date: Fri Apr 17 11:30:52 2009
New Revision: 69354

URL: http://llvm.org/viewvc/llvm-project?rev=69354&view=rev
Log:
Implement lvalue test for conditional expressions.
Add a few commented lines to the test case that point out things that don't work yet.

Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/test/SemaCXX/conditional-expr.cpp

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=69354&r1=69353&r2=69354&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Fri Apr 17 11:30:52 2009
@@ -136,6 +136,7 @@
   ///  - *e, the type of e cannot be a function type
   ///  - string-constant
   ///  - reference type [C++ [expr]]
+  ///  - b ? x : y, where x and y are lvalues of suitable types [C++]
   ///
   enum isLvalueResult {
     LV_Valid,

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=69354&r1=69353&r2=69354&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri Apr 17 11:30:52 2009
@@ -772,6 +772,32 @@
   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;
   }

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=69354&r1=69353&r2=69354&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Apr 17 11:30:52 2009
@@ -2120,6 +2120,7 @@
       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 @@
       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.

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=69354&r1=69353&r2=69354&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Apr 17 11:30:52 2009
@@ -1137,6 +1137,35 @@
   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 @@
     //   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();
     }

Modified: cfe/trunk/test/SemaCXX/conditional-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conditional-expr.cpp?rev=69354&r1=69353&r2=69354&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/conditional-expr.cpp (original)
+++ cfe/trunk/test/SemaCXX/conditional-expr.cpp Fri Apr 17 11:30:52 2009
@@ -19,12 +19,17 @@
 struct Base {
   int trick();
   A trick() const;
+  void fn1();
+};
+struct Derived : Base {
+  void fn2();
 };
-struct Derived : Base {};
 struct Convertible { operator Base&(); };
 struct Priv : private Base {};
 struct Mid : Base {};
 struct Fin : Mid, Derived {};
+typedef void (Derived::*DFnPtr)();
+struct ToMemPtr { operator DFnPtr(); };
 
 struct BadDerived;
 struct BadBase { operator BadDerived&(); };
@@ -65,11 +70,10 @@
   Base base;
   Derived derived;
   Convertible conv;
-  // FIXME: lvalueness
-  /*Base &bar1 =*/(void)( i1 ? base : derived);
-  /*Base &bar2 =*/(void)( i1 ? derived : base);
-  /*Base &bar3 =*/(void)( i1 ? base : conv);
-  /*Base &bar4 =*/(void)( i1 ? conv : base);
+  Base &bar1 = i1 ? base : derived;
+  Base &bar2 = i1 ? derived : base;
+  Base &bar3 = i1 ? base : conv;
+  Base &bar4 = i1 ? conv : base;
   // these are ambiguous
   BadBase bb;
   BadDerived bd;
@@ -96,7 +100,7 @@
   // should fail: const lost
   (void)(i1 ? Base() : constder()); // expected-error {{incompatible operand types ('struct Base' and 'struct Derived const')}}
   (void)(i1 ? constder() : Base()); // expected-error {{incompatible operand types ('struct Derived const' and 'struct Base')}}
-  // should fail: private or ambiguous base
+  // FIXME: should fail: private or ambiguous base
   (void)(i1 ? Base() : Priv()); // xpected-error private base
   (void)(i1 ? Priv() : Base()); // xpected-error private base
   (void)(i1 ? Base() : Fin()); // xpected-error ambiguous base
@@ -115,19 +119,24 @@
   (void)(i1 ? B() : A()); // expected-error {{incompatible operand types}}
   (void)(i1 ? 1 : Ambig()); // expected-error {{incompatible operand types}}
   (void)(i1 ? Ambig() : 1); // expected-error {{incompatible operand types}}
+  // By the way, this isn't an lvalue:
+  &(i1 ? i1 : i2); // expected-error {{address expression must be an lvalue or a function designator}}
 
   // p4 (lvalue, same type)
-  //Fields flds;
-  int &ir1 = i1;
-  //int &ir1 = i1 ? flds.i1 : flds.i2;
-  //(i1 ? flds.b1 : flds.i2) = 0;
-  //(i1 ? flds.i1 : flds.b2) = 0;
-  //(i1 ? flds.b1 : flds.b2) = 0;
+  Fields flds;
+  int &ir1 = i1 ? flds.i1 : flds.i2;
+  (i1 ? flds.b1 : flds.i2) = 0;
+  (i1 ? flds.i1 : flds.b2) = 0;
+  (i1 ? flds.b1 : flds.b2) = 0;
 
   // p5 (conversion to built-in types)
   // GCC 4.3 fails these
   double d1 = i1 ? I() : K();
   pfn = i1 ? F() : G();
+  DFnPtr pfm;
+  // FIXME: Overload resolution won't choose the member pointer yet.
+  //pfm = i1 ? DFnPtr() : &Base::fn1;
+  //pfm = i1 ? &Base::fn1 : DFnPtr();
 
   // p6 (final conversions)
   i1 = i1 ? i1 : ir1;
@@ -137,6 +146,16 @@
   i1 = i1 ? EVal : i1;
   d1 = i1 ? 'c' : 4.0;
   d1 = i1 ? 4.0 : 'c';
+  pfm = i1 ? &Derived::fn2 : 0;
+  pfm = i1 ? 0 : &Derived::fn2;
+  // FIXME: pointer conversions don't work yet.
+  //Base *pb = i1 ? (Base*)0 : (Derived*)0;
+  //Base *pb = i1 ? (Derived*)0 : (Base*)0;
+  //pfm = i1 ? &Base::fn1 : &Derived::fn2;
+  //pfm = i1 ? &Derived::fn2 : &Base::fn1;
+  // Conversion of primitives does not result in an lvalue.
+  &(i1 ? i1 : d1); // expected-error {{address expression must be an lvalue or a function designator}}
+
 
   // Note the thing that this does not test: since DR446, various situations
   // *must* create a separate temporary copy of class objects. This can only





More information about the cfe-commits mailing list