Implement static_cast from lvalue to rvalue reference.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Sun, 22 Mar 2009 22:30:06 +0000 (22:30 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Sun, 22 Mar 2009 22:30:06 +0000 (22:30 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67487 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaNamedCast.cpp
test/SemaCXX/rval-references.cpp

index 390554ff9e14f51cdc5120fa245fa1ba931aed27..f4a8470ecbe4cb0be818efce0b2f95a88e7ca07a 100644 (file)
@@ -1010,6 +1010,9 @@ def err_ambiguous_base_to_derived_cast : Error<
   "ambiguous static_cast from base %0 to derived %1:%2">;
 def err_static_downcast_via_virtual : Error<
   "cannot cast %0 to %1 via virtual base %2">;
+def err_bad_lvalue_to_rvalue_cast : Error<
+  "cannot cast from lvalue of type %0 to rvalue reference to %1; types are "
+  "not compatible">;
 
 // Other C++ expressions
 def err_need_header_before_typeid : Error<
index 9f5c5e58708f63fb6e05953e42d2d9496f7f3a0c..96de1bbad0b1c7d332d6e0865d7d332d09692ef5 100644 (file)
@@ -39,6 +39,8 @@ static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
                              const SourceRange &DestRange);
 
 static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType);
+static TryStaticCastResult TryLValueToRValueCast(
+  Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange);
 static TryStaticCastResult TryStaticReferenceDowncast(
   Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange);
 static TryStaticCastResult TryStaticPointerDowncast(
@@ -452,6 +454,13 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
     return;
   }
 
+  // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue
+  //   reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
+  if (TryLValueToRValueCast(Self, SrcExpr, DestType, OpRange) >
+      TSC_NotApplicable) {
+    return;
+  }
+
   // C++ 5.2.9p2: An expression e can be explicitly converted to a type T
   //   [...] if the declaration "T t(e);" is well-formed, [...].
   if (TryStaticImplicitCast(Self, SrcExpr, DestType, OpRange) >
@@ -533,6 +542,36 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
     << OpRange;
 }
 
+/// Tests whether a conversion according to N2844 is valid.
+TryStaticCastResult
+TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
+                      const SourceRange &OpRange)
+{
+  // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue
+  //   reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
+  const RValueReferenceType *R = DestType->getAsRValueReferenceType();
+  if (!R)
+    return TSC_NotApplicable;
+
+  if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid)
+    return TSC_NotApplicable;
+
+  // Because we try the reference downcast before this function, from now on
+  // this is the only cast possibility, so we issue an error if we fail now.
+  bool DerivedToBase;
+  if (Self.CompareReferenceRelationship(SrcExpr->getType(), R->getPointeeType(),
+                                        DerivedToBase) <
+        Sema::Ref_Compatible_With_Added_Qualification) {
+    Self.Diag(OpRange.getBegin(), diag::err_bad_lvalue_to_rvalue_cast)
+      << SrcExpr->getType() << R->getPointeeType() << OpRange;
+    return TSC_Failed;
+  }
+
+  // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation
+  // than nothing.
+  return TSC_Success;
+}
+
 /// Tests whether a conversion according to C++ 5.2.9p5 is valid.
 TryStaticCastResult
 TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType,
index aafb334b849e90e2a80f7010689f3eb8d565ee72..59be9f50f6182bb9249307aeaad7234a0c7376a2 100644 (file)
@@ -28,6 +28,8 @@ void f() {
   int i1 = 0;
   int &&virr4 = i1; // expected-error {{rvalue reference cannot bind to lvalue}}
   int &&virr5 = ret_irr();
+  int &&virr6 = static_cast<int&&>(i1);
+  (void)static_cast<not_int&&>(i1); // expected-error {{types are not compatible}}
 
   int i2 = over(i1);
   not_int ni1 = over(0);