Almost complete implementation of rvalue references. One bug, and a few unclear areas. Maybe Doug can shed some light on some of the fixmes.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67059 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 80e1774..c318107 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -85,9 +85,9 @@
   fprintf(stderr, "  %d types total.\n", (int)Types.size());
   unsigned NumBuiltin = 0, NumPointer = 0, NumArray = 0, NumFunctionP = 0;
   unsigned NumVector = 0, NumComplex = 0, NumBlockPointer = 0;
-  unsigned NumFunctionNP = 0, NumTypeName = 0, NumTagged = 0, NumReference = 0;
-  unsigned NumMemberPointer = 0;
-  
+  unsigned NumFunctionNP = 0, NumTypeName = 0, NumTagged = 0;
+  unsigned NumLValueReference = 0, NumRValueReference = 0, NumMemberPointer = 0;
+
   unsigned NumTagStruct = 0, NumTagUnion = 0, NumTagEnum = 0, NumTagClass = 0;
   unsigned NumObjCInterfaces = 0, NumObjCQualifiedInterfaces = 0;
   unsigned NumObjCQualifiedIds = 0;
@@ -101,8 +101,10 @@
       ++NumPointer;
     else if (isa<BlockPointerType>(T))
       ++NumBlockPointer;
-    else if (isa<ReferenceType>(T))
-      ++NumReference;
+    else if (isa<LValueReferenceType>(T))
+      ++NumLValueReference;
+    else if (isa<RValueReferenceType>(T))
+      ++NumRValueReference;
     else if (isa<MemberPointerType>(T))
       ++NumMemberPointer;
     else if (isa<ComplexType>(T))
@@ -145,7 +147,8 @@
   fprintf(stderr, "    %d builtin types\n", NumBuiltin);
   fprintf(stderr, "    %d pointer types\n", NumPointer);
   fprintf(stderr, "    %d block pointer types\n", NumBlockPointer);
-  fprintf(stderr, "    %d reference types\n", NumReference);
+  fprintf(stderr, "    %d lvalue reference types\n", NumLValueReference);
+  fprintf(stderr, "    %d rvalue reference types\n", NumRValueReference);
   fprintf(stderr, "    %d member pointer types\n", NumMemberPointer);
   fprintf(stderr, "    %d complex types\n", NumComplex);
   fprintf(stderr, "    %d array types\n", NumArray);
@@ -165,10 +168,12 @@
           NumObjCQualifiedIds);
   fprintf(stderr, "    %d typeof types\n", NumTypeOfTypes);
   fprintf(stderr, "    %d typeof exprs\n", NumTypeOfExprTypes);
-  
+
   fprintf(stderr, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+
     NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+
     NumComplex*sizeof(ComplexType)+NumVector*sizeof(VectorType)+
+    NumLValueReference*sizeof(LValueReferenceType)+
+    NumRValueReference*sizeof(RValueReferenceType)+
     NumMemberPointer*sizeof(MemberPointerType)+
     NumFunctionP*sizeof(FunctionProtoType)+
     NumFunctionNP*sizeof(FunctionNoProtoType)+
@@ -411,7 +416,8 @@
     Align = Target.getPointerAlign(AS);
     break;
   }
-  case Type::Reference:
+  case Type::LValueReference:
+  case Type::RValueReference:
     // "When applied to a reference or a reference type, the result is the size
     // of the referenced type." C++98 5.3.3p2: expr.sizeof.
     // FIXME: This is wrong for struct layout: a reference in a struct has
@@ -910,32 +916,65 @@
   return QualType(New, 0);
 }
 
-/// getReferenceType - Return the uniqued reference to the type for a reference
-/// to the specified type.
-QualType ASTContext::getReferenceType(QualType T) {
+/// getLValueReferenceType - Return the uniqued reference to the type for an
+/// lvalue reference to the specified type.
+QualType ASTContext::getLValueReferenceType(QualType T) {
   // Unique pointers, to guarantee there is only one pointer of a particular
   // structure.
   llvm::FoldingSetNodeID ID;
   ReferenceType::Profile(ID, T);
 
   void *InsertPos = 0;
-  if (ReferenceType *RT = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos))
+  if (LValueReferenceType *RT =
+        LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos))
     return QualType(RT, 0);
-  
+
   // If the referencee type isn't canonical, this won't be a canonical type
   // either, so fill in the canonical type field.
   QualType Canonical;
   if (!T->isCanonical()) {
-    Canonical = getReferenceType(getCanonicalType(T));
-   
+    Canonical = getLValueReferenceType(getCanonicalType(T));
+
     // Get the new insert position for the node we care about.
-    ReferenceType *NewIP = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
+    LValueReferenceType *NewIP =
+      LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
     assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
   }
 
-  ReferenceType *New = new (*this,8) ReferenceType(T, Canonical);
+  LValueReferenceType *New = new (*this,8) LValueReferenceType(T, Canonical);
   Types.push_back(New);
-  ReferenceTypes.InsertNode(New, InsertPos);
+  LValueReferenceTypes.InsertNode(New, InsertPos);
+  return QualType(New, 0);
+}
+
+/// getRValueReferenceType - Return the uniqued reference to the type for an
+/// rvalue reference to the specified type.
+QualType ASTContext::getRValueReferenceType(QualType T) {
+  // Unique pointers, to guarantee there is only one pointer of a particular
+  // structure.
+  llvm::FoldingSetNodeID ID;
+  ReferenceType::Profile(ID, T);
+
+  void *InsertPos = 0;
+  if (RValueReferenceType *RT =
+        RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos))
+    return QualType(RT, 0);
+
+  // If the referencee type isn't canonical, this won't be a canonical type
+  // either, so fill in the canonical type field.
+  QualType Canonical;
+  if (!T->isCanonical()) {
+    Canonical = getRValueReferenceType(getCanonicalType(T));
+
+    // Get the new insert position for the node we care about.
+    RValueReferenceType *NewIP =
+      RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
+    assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+  }
+
+  RValueReferenceType *New = new (*this,8) RValueReferenceType(T, Canonical);
+  Types.push_back(New);
+  RValueReferenceTypes.InsertNode(New, InsertPos);
   return QualType(New, 0);
 }
 
@@ -2641,9 +2680,12 @@
   // C++ [expr]: If an expression initially has the type "reference to T", the
   // type is adjusted to "T" prior to any further analysis, the expression
   // designates the object or function denoted by the reference, and the
-  // expression is an lvalue.
+  // expression is an lvalue unless the reference is an rvalue reference and
+  // the expression is a function call (possibly inside parentheses).
   // FIXME: C++ shouldn't be going through here!  The rules are different
   // enough that they should be handled separately.
+  // FIXME: Merging of lvalue and rvalue references is incorrect. C++ *really*
+  // shouldn't be going through here!
   if (const ReferenceType *RT = LHS->getAsReferenceType())
     LHS = RT->getPointeeType();
   if (const ReferenceType *RT = RHS->getAsReferenceType())
@@ -2746,7 +2788,8 @@
     assert(false && "Non-canonical and dependent types shouldn't get here");
     return QualType();
 
-  case Type::Reference:
+  case Type::LValueReference:
+  case Type::RValueReference:
   case Type::MemberPointer:
     assert(false && "C++ should never be in mergeTypes");
     return QualType();
diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp
index 4655cf3..7eab267 100644
--- a/lib/AST/Builtins.cpp
+++ b/lib/AST/Builtins.cpp
@@ -183,7 +183,7 @@
     if (Type->isArrayType()) {
       Type = Context.getArrayDecayedType(Type);
     } else {
-      Type = Context.getReferenceType(Type);
+      Type = Context.getLValueReferenceType(Type);
     }
     break;
   case 'V': {
@@ -224,8 +224,9 @@
         Type = Context.getPointerType(Type);
         break;
       case '&':
-        Type = Context.getReferenceType(Type);
+        Type = Context.getLValueReferenceType(Type);
         break;
+      // FIXME: There's no way to have a built-in with an rvalue ref arg.
       case 'C':
         Type = Type.getQualifiedType(QualType::Const);
         break;
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index fd90083..a3c7997 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -102,7 +102,7 @@
       continue;
     bool AcceptsConst = true;
     QualType ArgType = FnType->getArgType(0);
-    if (const ReferenceType *Ref = ArgType->getAsReferenceType()) {
+    if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) {
       ArgType = Ref->getPointeeType();
       // Is it a non-const reference?
       if (!ArgType.isConstQualified())
@@ -152,7 +152,7 @@
   assert(FnType && "Overloaded operator has no proto function type.");
   assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
   QualType ArgType = FnType->getArgType(0);
-  if (const ReferenceType *Ref = ArgType->getAsReferenceType())
+  if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType())
     ArgType = Ref->getPointeeType();
 
   ArgType = ArgType.getUnqualifiedType();
@@ -263,8 +263,9 @@
 
   const ParmVarDecl *Param = getParamDecl(0);
 
-  // Do we have a reference type?
-  const ReferenceType *ParamRefType = Param->getType()->getAsReferenceType();
+  // Do we have a reference type? Rvalue references don't count.
+  const LValueReferenceType *ParamRefType =
+    Param->getType()->getAsLValueReferenceType();
   if (!ParamRefType)
     return false;
 
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 669f5c8..2f7e363 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -575,10 +575,7 @@
   if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers())
     return LV_IncompleteVoidType;
 
-  /// FIXME: Expressions can't have reference type, so the following
-  /// isn't needed.
-  if (TR->isReferenceType()) // C++ [expr]
-    return LV_Valid;
+  assert(!TR->isReferenceType() && "Expressions can't have reference type.");
 
   // the type looks fine, now check the expression
   switch (getStmtClass()) {
@@ -691,16 +688,16 @@
   case CallExprClass: 
   case CXXOperatorCallExprClass:
   case CXXMemberCallExprClass: {
-    // C++ [expr.call]p10:
+    // C++0x [expr.call]p10
     //   A function call is an lvalue if and only if the result type
-    //   is a reference.
+    //   is an lvalue reference.
     QualType CalleeType = cast<CallExpr>(this)->getCallee()->getType();
     if (const PointerType *FnTypePtr = CalleeType->getAsPointerType())
       CalleeType = FnTypePtr->getPointeeType();
     if (const FunctionType *FnType = CalleeType->getAsFunctionType())
-      if (FnType->getResultType()->isReferenceType())
+      if (FnType->getResultType()->isLValueReferenceType())
         return LV_Valid;
-    
+
     break;
   }
   case CompoundLiteralExprClass: // C99 6.5.2.5p5
@@ -733,10 +730,11 @@
   case CXXReinterpretCastExprClass:
   case CXXConstCastExprClass:
     // The result of an explicit cast is an lvalue if the type we are
-    // casting to is a reference type. See C++ [expr.cast]p1, 
+    // casting to is an lvalue reference type. See C++ [expr.cast]p1,
     // C++ [expr.static.cast]p2, C++ [expr.dynamic.cast]p2,
     // C++ [expr.reinterpret.cast]p1, C++ [expr.const.cast]p1.
-    if (cast<ExplicitCastExpr>(this)->getTypeAsWritten()->isReferenceType())
+    if (cast<ExplicitCastExpr>(this)->getTypeAsWritten()->
+          isLValueReferenceType())
       return LV_Valid;
     break;
   case CXXTypeidExprClass:
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 6fb2abe..a0ef746 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -696,6 +696,7 @@
 /// as GCC.
 static int EvaluateBuiltinClassifyType(const CallExpr *E) {
   // The following enum mimics the values returned by GCC.
+  // FIXME: Does GCC differ between lvalue and rvalue references here?
   enum gcc_type_class {
     no_type_class = -1,
     void_type_class, integer_type_class, char_type_class,
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index fc71097..1714e84 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -117,7 +117,8 @@
   case IncompleteArray:
   case FunctionProto:
   case FunctionNoProto:
-  case Reference:
+  case LValueReference:
+  case RValueReference:
   case Record:
     return true;
   default:
@@ -264,9 +265,9 @@
   // If this is directly a reference type, return it.
   if (const ReferenceType *RTy = dyn_cast<ReferenceType>(this))
     return RTy;
-  
+
   // If the canonical form of this type isn't the right kind, reject it.
-  if (!isa<ReferenceType>(CanonicalType)) {    
+  if (!isa<ReferenceType>(CanonicalType)) {
     // Look through type qualifiers
     if (isa<ReferenceType>(CanonicalType.getUnqualifiedType()))
       return CanonicalType.getUnqualifiedType()->getAsReferenceType();
@@ -278,6 +279,42 @@
   return getDesugaredType()->getAsReferenceType();
 }
 
+const LValueReferenceType *Type::getAsLValueReferenceType() const {
+  // If this is directly an lvalue reference type, return it.
+  if (const LValueReferenceType *RTy = dyn_cast<LValueReferenceType>(this))
+    return RTy;
+
+  // If the canonical form of this type isn't the right kind, reject it.
+  if (!isa<LValueReferenceType>(CanonicalType)) {
+    // Look through type qualifiers
+    if (isa<LValueReferenceType>(CanonicalType.getUnqualifiedType()))
+      return CanonicalType.getUnqualifiedType()->getAsLValueReferenceType();
+    return 0;
+  }
+
+  // If this is a typedef for an lvalue reference type, strip the typedef off
+  // without losing all typedef information.
+  return getDesugaredType()->getAsLValueReferenceType();
+}
+
+const RValueReferenceType *Type::getAsRValueReferenceType() const {
+  // If this is directly an rvalue reference type, return it.
+  if (const RValueReferenceType *RTy = dyn_cast<RValueReferenceType>(this))
+    return RTy;
+
+  // If the canonical form of this type isn't the right kind, reject it.
+  if (!isa<RValueReferenceType>(CanonicalType)) {
+    // Look through type qualifiers
+    if (isa<RValueReferenceType>(CanonicalType.getUnqualifiedType()))
+      return CanonicalType.getUnqualifiedType()->getAsRValueReferenceType();
+    return 0;
+  }
+
+  // If this is a typedef for an rvalue reference type, strip the typedef off
+  // without losing all typedef information.
+  return getDesugaredType()->getAsRValueReferenceType();
+}
+
 const MemberPointerType *Type::getAsMemberPointerType() const {
   // If this is directly a member pointer type, return it.
   if (const MemberPointerType *MTy = dyn_cast<MemberPointerType>(this))
@@ -1116,14 +1153,25 @@
   PointeeType.getAsStringInternal(S);
 }
 
-void ReferenceType::getAsStringInternal(std::string &S) const {
+void LValueReferenceType::getAsStringInternal(std::string &S) const {
   S = '&' + S;
-  
+
   // Handle things like 'int (&A)[4];' correctly.
   // FIXME: this should include vectors, but vectors use attributes I guess.
   if (isa<ArrayType>(getPointeeType()))
     S = '(' + S + ')';
-  
+
+  getPointeeType().getAsStringInternal(S);
+}
+
+void RValueReferenceType::getAsStringInternal(std::string &S) const {
+  S = "&&" + S;
+
+  // Handle things like 'int (&&A)[4];' correctly.
+  // FIXME: this should include vectors, but vectors use attributes I guess.
+  if (isa<ArrayType>(getPointeeType()))
+    S = '(' + S + ')';
+
   getPointeeType().getAsStringInternal(S);
 }
 
@@ -1133,7 +1181,7 @@
   C += "::*";
   S = C + S;
 
-  // Handle things like 'int (&A)[4];' correctly.
+  // Handle things like 'int (Cls::*A)[4];' correctly.
   // FIXME: this should include vectors, but vectors use attributes I guess.
   if (isa<ArrayType>(getPointeeType()))
     S = '(' + S + ')';
diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp
index 1b9fed4..8498e01 100644
--- a/lib/AST/TypeSerialization.cpp
+++ b/lib/AST/TypeSerialization.cpp
@@ -107,8 +107,12 @@
       D.RegisterPtr(PtrID, BlockPointerType::CreateImpl(Context, D));
       break;
 
-    case Type::Reference:
-      D.RegisterPtr(PtrID, ReferenceType::CreateImpl(Context, D));
+    case Type::LValueReference:
+      D.RegisterPtr(PtrID, LValueReferenceType::CreateImpl(Context, D));
+      break;
+
+    case Type::RValueReference:
+      D.RegisterPtr(PtrID, RValueReferenceType::CreateImpl(Context, D));
       break;
 
     case Type::Record:
@@ -261,8 +265,12 @@
   S.Emit(getPointeeType());
 }
 
-Type* ReferenceType::CreateImpl(ASTContext& Context, Deserializer& D) {
-  return Context.getReferenceType(QualType::ReadVal(D)).getTypePtr();
+Type* LValueReferenceType::CreateImpl(ASTContext& Context, Deserializer& D) {
+  return Context.getLValueReferenceType(QualType::ReadVal(D)).getTypePtr();
+}
+
+Type* RValueReferenceType::CreateImpl(ASTContext& Context, Deserializer& D) {
+  return Context.getRValueReferenceType(QualType::ReadVal(D)).getTypePtr();
 }
 
 //===----------------------------------------------------------------------===//