]> granicus.if.org Git - clang/commitdiff
Almost complete implementation of rvalue references. One bug, and a few unclear areas...
authorSebastian Redl <sebastian.redl@getdesigned.at>
Mon, 16 Mar 2009 23:22:08 +0000 (23:22 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Mon, 16 Mar 2009 23:22:08 +0000 (23:22 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67059 91177308-0d34-0410-b5e6-96231b3b80d8

31 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/Type.h
include/clang/AST/TypeNodes.def
include/clang/Basic/DiagnosticSemaKinds.def
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/ASTContext.cpp
lib/AST/Builtins.cpp
lib/AST/DeclCXX.cpp
lib/AST/Expr.cpp
lib/AST/ExprConstant.cpp
lib/AST/Type.cpp
lib/AST/TypeSerialization.cpp
lib/CodeGen/CGDebugInfo.cpp
lib/CodeGen/CGExprScalar.cpp
lib/CodeGen/CodeGenTypes.cpp
lib/CodeGen/Mangle.cpp
lib/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaNamedCast.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaType.cpp
test/Parser/cxx-reference.cpp
test/Parser/cxx0x-rvalue-reference.cpp [new file with mode: 0644]
test/SemaCXX/convert-to-bool.cpp
test/SemaCXX/overloaded-operator.cpp
test/SemaCXX/references.cpp
test/SemaCXX/rval-references.cpp [new file with mode: 0644]
test/SemaCXX/static-cast.cpp

index 8a8be1e775d01537e0af8c719db661c862361960..124f7db449c3dcbec02a78ee7d507c358fa81888 100644 (file)
@@ -59,7 +59,8 @@ class ASTContext {
   llvm::FoldingSet<ComplexType> ComplexTypes;
   llvm::FoldingSet<PointerType> PointerTypes;
   llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
-  llvm::FoldingSet<ReferenceType> ReferenceTypes;
+  llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes;
+  llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes;
   llvm::FoldingSet<MemberPointerType> MemberPointerTypes;
   llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes;
   llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes;
@@ -207,9 +208,13 @@ public:
   /// of the specified type.
   QualType getBlockPointerType(QualType T);
 
-  /// getReferenceType - Return the uniqued reference to the type for a
-  /// reference to the specified type.
-  QualType getReferenceType(QualType T);
+  /// getLValueReferenceType - Return the uniqued reference to the type for an
+  /// lvalue reference to the specified type.
+  QualType getLValueReferenceType(QualType T);
+
+  /// getRValueReferenceType - Return the uniqued reference to the type for an
+  /// rvalue reference to the specified type.
+  QualType getRValueReferenceType(QualType T);
 
   /// getMemberPointerType - Return the uniqued reference to the type for a
   /// member pointer to the specified type in the specified class. The class
index 13668569ca73cd7780981cc4fe1930d59c9b9c00..4e1672d4356d755c2484c6ecefd9fe40e0b6a328 100644 (file)
@@ -337,6 +337,8 @@ public:
   bool isPointerType() const;
   bool isBlockPointerType() const;
   bool isReferenceType() const;
+  bool isLValueReferenceType() const;
+  bool isRValueReferenceType() const;
   bool isFunctionPointerType() const;
   bool isMemberPointerType() const;
   bool isMemberFunctionPointerType() const;
@@ -383,6 +385,8 @@ public:
   const PointerType *getAsPointerType() const;
   const BlockPointerType *getAsBlockPointerType() const;
   const ReferenceType *getAsReferenceType() const;
+  const LValueReferenceType *getAsLValueReferenceType() const;
+  const RValueReferenceType *getAsRValueReferenceType() const;
   const MemberPointerType *getAsMemberPointerType() const;
   const TagType *getAsTagType() const;
   const RecordType *getAsRecordType() const;
@@ -674,19 +678,17 @@ public:
     friend class Type;
 };
 
-/// ReferenceType - C++ 8.3.2 - Reference Declarators.
+/// ReferenceType - Base for LValueReferenceType and RValueReferenceType
 ///
 class ReferenceType : public Type, public llvm::FoldingSetNode {
   QualType PointeeType;
 
-  ReferenceType(QualType Referencee, QualType CanonicalRef) :
-    Type(Reference, CanonicalRef, Referencee->isDependentType()), 
+protected:
+  ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef) :
+    Type(tc, CanonicalRef, Referencee->isDependentType()),
     PointeeType(Referencee) {
   }
-  friend class ASTContext;  // ASTContext creates these.
 public:
-  virtual void getAsStringInternal(std::string &InnerString) const;
-
   QualType getPointeeType() const { return PointeeType; }
 
   void Profile(llvm::FoldingSetNodeID &ID) {
@@ -696,11 +698,52 @@ public:
     ID.AddPointer(Referencee.getAsOpaquePtr());
   }
 
-  static bool classof(const Type *T) { return T->getTypeClass() == Reference; }
+  static bool classof(const Type *T) {
+    return T->getTypeClass() == LValueReference ||
+           T->getTypeClass() == RValueReference;
+  }
   static bool classof(const ReferenceType *) { return true; }
 
 protected:
   virtual void EmitImpl(llvm::Serializer& S) const;
+};
+
+/// LValueReferenceType - C++ [dcl.ref] - Lvalue reference
+///
+class LValueReferenceType : public ReferenceType {
+  LValueReferenceType(QualType Referencee, QualType CanonicalRef) :
+    ReferenceType(LValueReference, Referencee, CanonicalRef) {
+  }
+  friend class ASTContext; // ASTContext creates these
+public:
+  virtual void getAsStringInternal(std::string &InnerString) const;
+
+  static bool classof(const Type *T) {
+    return T->getTypeClass() == LValueReference;
+  }
+  static bool classof(const LValueReferenceType *) { return true; }
+
+protected:
+  static Type* CreateImpl(ASTContext& Context, llvm::Deserializer& D);
+  friend class Type;
+};
+
+/// RValueReferenceType - C++0x [dcl.ref] - Rvalue reference
+///
+class RValueReferenceType : public ReferenceType {
+  RValueReferenceType(QualType Referencee, QualType CanonicalRef) :
+    ReferenceType(RValueReference, Referencee, CanonicalRef) {
+  }
+  friend class ASTContext; // ASTContext creates these
+public:
+  virtual void getAsStringInternal(std::string &InnerString) const;
+
+  static bool classof(const Type *T) {
+    return T->getTypeClass() == RValueReference;
+  }
+  static bool classof(const RValueReferenceType *) { return true; }
+
+protected:
   static Type* CreateImpl(ASTContext& Context, llvm::Deserializer& D);
   friend class Type;
 };
@@ -1798,6 +1841,12 @@ inline bool Type::isBlockPointerType() const {
 inline bool Type::isReferenceType() const {
   return isa<ReferenceType>(CanonicalType.getUnqualifiedType());
 }
+inline bool Type::isLValueReferenceType() const {
+  return isa<LValueReferenceType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isRValueReferenceType() const {
+  return isa<RValueReferenceType>(CanonicalType.getUnqualifiedType());
+}
 inline bool Type::isFunctionPointerType() const {
   if (const PointerType* T = getAsPointerType())
     return T->getPointeeType()->isFunctionType();
index e071f640ba0e52359adc6827efb5ff70e303ba87..4c5c02d2a550bc52f5ee186bb6f91e6162c9dc9b 100644 (file)
@@ -51,7 +51,9 @@ TYPE(FixedWidthInt, Type)
 TYPE(Complex, Type)
 TYPE(Pointer, Type)
 TYPE(BlockPointer, Type)
-TYPE(Reference, Type)
+ABSTRACT_TYPE(Reference, Type)
+TYPE(LValueReference, Reference)
+TYPE(RValueReference, Reference)
 TYPE(MemberPointer, Type)
 ABSTRACT_TYPE(Array, Type)
 TYPE(ConstantArray, ArrayType)
index 4d721bc33166ce698235fd52e9bcf22d6d509201..d415ee53926af373d8d50c96fcc7fa296aa00617 100644 (file)
@@ -304,9 +304,12 @@ DIAG(err_destructor_typedef_name, ERROR,
      "destructor cannot be declared using a typedef %0 of the class name")
 
 // C++ initialization
+DIAG(err_lvalue_to_rvalue_ref, ERROR,
+     "rvalue reference cannot bind to lvalue")
 // FIXME: passing in an English string as %1!
 DIAG(err_not_reference_to_const_init, ERROR,
-     "non-const reference to type %0 cannot be initialized with a %1 of type %2")
+     "non-const lvalue reference to type %0 cannot be initialized "
+     "with a %1 of type %2")
 // FIXME: passing in an English string as %1!
 DIAG(err_reference_init_drops_quals, ERROR,
      "initialization of reference to type %0 with a %1 of type %2 drops qualifiers")
index dd2a17e791b45173bbfe808233c689ea0183709f..a2ba0e97080dfe241b36c8837ae78848f0f4a32d 100644 (file)
@@ -271,9 +271,11 @@ def err_destructor_typedef_name : Error<
   "destructor cannot be declared using a typedef %0 of the class name">;
 
 // C++ initialization
+def err_lvalue_to_rvalue_ref : Error<"rvalue reference cannot bind to lvalue">;
 // FIXME: passing in an English string as %1!
 def err_not_reference_to_const_init : Error<
-  "non-const reference to type %0 cannot be initialized with a %1 of type %2">;
+  "non-const lvalue reference to type %0 cannot be initialized "
+  "with a %1 of type %2">;
 // FIXME: passing in an English string as %1!
 def err_reference_init_drops_quals : Error<
   "initialization of reference to type %0 with a %1 of type %2 drops "
index 80e17746bbe6673d52d99b8ac32e948e8dcdbe5d..c318107dab324479d2954ca23a195794c4f8282f 100644 (file)
@@ -85,9 +85,9 @@ void ASTContext::PrintStats() const {
   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 @@ void ASTContext::PrintStats() const {
       ++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 @@ void ASTContext::PrintStats() const {
   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 @@ void ASTContext::PrintStats() const {
           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 @@ ASTContext::getTypeInfo(const Type *T) {
     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 @@ QualType ASTContext::getBlockPointerType(QualType T) {
   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.
+    LValueReferenceType *NewIP =
+      LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
+    assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+  }
+
+  LValueReferenceType *New = new (*this,8) LValueReferenceType(T, Canonical);
+  Types.push_back(New);
+  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.
-    ReferenceType *NewIP = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
+    RValueReferenceType *NewIP =
+      RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
     assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
   }
 
-  ReferenceType *New = new (*this,8) ReferenceType(T, Canonical);
+  RValueReferenceType *New = new (*this,8) RValueReferenceType(T, Canonical);
   Types.push_back(New);
-  ReferenceTypes.InsertNode(New, InsertPos);
+  RValueReferenceTypes.InsertNode(New, InsertPos);
   return QualType(New, 0);
 }
 
@@ -2641,9 +2680,12 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
   // 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 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
     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();
index 4655cf392d7384b20ef1add20ce632c26084d64a..7eab2679e800e92aa7d6091d0090e59dea0161e1 100644 (file)
@@ -183,7 +183,7 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
     if (Type->isArrayType()) {
       Type = Context.getArrayDecayedType(Type);
     } else {
-      Type = Context.getReferenceType(Type);
+      Type = Context.getLValueReferenceType(Type);
     }
     break;
   case 'V': {
@@ -224,8 +224,9 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
         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;
index fd900834caf468d2f57d3a2d01ce7c9cb5e799fc..a3c7997c6ddfab9bfb23c72e9c65dc8db7c77d1a 100644 (file)
@@ -102,7 +102,7 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const {
       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 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
   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 @@ CXXConstructorDecl::isCopyConstructor(ASTContext &Context,
 
   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;
 
index 669f5c8225a262343b8ec024f0a85a8140455060..2f7e3630fdc876c0ad7be79f446b5eb7c8571caf 100644 (file)
@@ -575,10 +575,7 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
   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 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
   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 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
   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:
index 6fb2abe7cd7f02f553eea33aeea38c06739fc804..a0ef7460c5f96a3b70f4a16b0e241446a9185939 100644 (file)
@@ -696,6 +696,7 @@ bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
 /// 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,
index fc71097c123757b3eaf1b5f992f14cb896caa6cf..1714e841299d2770a342978674bf29f4f1afe7a7 100644 (file)
@@ -117,7 +117,8 @@ bool Type::isDerivedType() const {
   case IncompleteArray:
   case FunctionProto:
   case FunctionNoProto:
-  case Reference:
+  case LValueReference:
+  case RValueReference:
   case Record:
     return true;
   default:
@@ -264,9 +265,9 @@ const ReferenceType *Type::getAsReferenceType() const {
   // 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 @@ const ReferenceType *Type::getAsReferenceType() const {
   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 @@ void BlockPointerType::getAsStringInternal(std::string &S) const {
   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 @@ void MemberPointerType::getAsStringInternal(std::string &S) const {
   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 + ')';
index 1b9fed4866aef7e7e3186e173b9763e09bc4b75c..8498e0123e66c12ce6c2836aeec9662195d7a984 100644 (file)
@@ -107,8 +107,12 @@ void Type::Create(ASTContext& Context, unsigned i, Deserializer& D) {
       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 @@ void ReferenceType::EmitImpl(Serializer& S) const {
   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();
 }
 
 //===----------------------------------------------------------------------===//
index 9b56b8449fad0c4bc535e1b4643205d0b45e31b0..0dac6ba920eb06d8e05b8b390069ded4e63e1ab2 100644 (file)
@@ -502,7 +502,8 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
     assert(false && "Dependent types cannot show up in debug information");
     
   case Type::Complex:
-  case Type::Reference:
+  case Type::LValueReference:
+  case Type::RValueReference:
   case Type::Vector:
   case Type::ExtVector:
   case Type::ExtQual:
index 8cd353408fdc897a045200c3e9f7af23a640c0d8..1a64e3c905a4adc9608ff0514cf3fb76535c2a15 100644 (file)
@@ -571,6 +571,7 @@ Value *ScalarExprEmitter::VisitImplicitCastExpr(const ImplicitCastExpr *E) {
     return V;
     
   } else if (E->getType()->isReferenceType()) {
+    // FIXME: An expression cannot have reference type.
     return EmitLValue(Op).getAddress();
   }
   
index 2d4c27c2aca0c44fdeb1e1fa700c64656fd45588..85d7384c6c7046a0d1ca251840b2b3c814389cb6 100644 (file)
@@ -266,7 +266,8 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
       ConvertTypeRecursive(cast<ComplexType>(Ty).getElementType());
     return llvm::StructType::get(EltTy, EltTy, NULL);
   }
-  case Type::Reference: {
+  case Type::LValueReference:
+  case Type::RValueReference: {
     const ReferenceType &RTy = cast<ReferenceType>(Ty);
     QualType ETy = RTy.getPointeeType();
     llvm::OpaqueType *PointeeType = llvm::OpaqueType::get();
index 92eeb5db144bb36492d22910e4d5356f730ba69b..d54849bd780d507cd1a68927de4c98a116cb1904 100644 (file)
@@ -365,12 +365,17 @@ void CXXNameMangler::mangleType(QualType T) {
     mangleType(PT->getPointeeType());
   }
   //         ::= R <type>   # reference-to
-  //         ::= O <type>   # rvalue reference-to (C++0x)
-  else if (const ReferenceType *RT = dyn_cast<ReferenceType>(T.getTypePtr())) {
-    // FIXME: rvalue references
+  else if (const LValueReferenceType *RT =
+           dyn_cast<LValueReferenceType>(T.getTypePtr())) {
     Out << 'R';
     mangleType(RT->getPointeeType());
   }
+  //         ::= O <type>   # rvalue reference-to (C++0x)
+  else if (const RValueReferenceType *RT =
+           dyn_cast<RValueReferenceType>(T.getTypePtr())) {
+    Out << 'O';
+    mangleType(RT->getPointeeType());
+  }
   //         ::= C <type>   # complex pair (C 2000)
   else if (const ComplexType *CT = dyn_cast<ComplexType>(T.getTypePtr())) {
     Out << 'C';
index 29d0796dcb0c75f3eb80d4e90bacffcec22ac85c..13c3e87bfe19a8db1d93b5e09af57148c9a194d7 100644 (file)
@@ -272,7 +272,7 @@ public:
   void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
   QualType BuildPointerType(QualType T, unsigned Quals, 
                             SourceLocation Loc, DeclarationName Entity);
-  QualType BuildReferenceType(QualType T, unsigned Quals, 
+  QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
                               SourceLocation Loc, DeclarationName Entity);
   QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
                           Expr *ArraySize, unsigned Quals,
index fa84c7d2de225921f2309feb1b85dc4f70769a0a..acf82245424fcb4552cb4cf2e6023812955dffa7 100644 (file)
@@ -802,7 +802,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
     QualType ArgType = ClassType;
     if (HasConstCopyConstructor)
       ArgType = ArgType.withConst();
-    ArgType = Context.getReferenceType(ArgType);
+    ArgType = Context.getLValueReferenceType(ArgType);
 
     //   An implicitly-declared copy constructor is an inline public
     //   member of its class.
@@ -880,10 +880,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
     //
     //       X& X::operator=(X&)
     QualType ArgType = ClassType;
-    QualType RetType = Context.getReferenceType(ArgType);
+    QualType RetType = Context.getLValueReferenceType(ArgType);
     if (HasConstCopyAssignment)
       ArgType = ArgType.withConst();
-    ArgType = Context.getReferenceType(ArgType);
+    ArgType = Context.getLValueReferenceType(ArgType);
 
     //   An implicitly-declared copy assignment operator is an inline public
     //   member of its class.
@@ -1630,7 +1630,8 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
 Sema::ReferenceCompareResult 
 Sema::CompareReferenceRelationship(QualType T1, QualType T2, 
                                    bool& DerivedToBase) {
-  assert(!T1->isReferenceType() && "T1 must be the pointee type of the reference type");
+  assert(!T1->isReferenceType() &&
+    "T1 must be the pointee type of the reference type");
   assert(!T2->isReferenceType() && "T2 cannot be a reference type");
 
   T1 = Context.getCanonicalType(T1);
@@ -1713,6 +1714,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
   }
 
   // Compute some basic properties of the types and the initializer.
+  bool isRValRef = DeclType->isRValueReferenceType();
   bool DerivedToBase = false;
   Expr::isLvalueResult InitLvalue = Init->isLvalue(Context);
   ReferenceCompareResult RefRelationship 
@@ -1738,6 +1740,15 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
       RefRelationship >= Ref_Compatible_With_Added_Qualification) {
     BindsDirectly = true;
 
+    // Rvalue references cannot bind to lvalues (N2812).
+    // FIXME: This part of rvalue references is still in flux. Revisit later.
+    if (isRValRef) {
+      if (!ICS)
+        Diag(Init->getSourceRange().getBegin(), diag::err_lvalue_to_rvalue_ref)
+          << Init->getSourceRange();
+      return true;
+    }
+
     if (ICS) {
       // C++ [over.ics.ref]p1:
       //   When a parameter of reference type binds directly (8.5.3)
@@ -1774,7 +1785,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
   //          92) (this conversion is selected by enumerating the
   //          applicable conversion functions (13.3.1.6) and choosing
   //          the best one through overload resolution (13.3)),
-  if (!SuppressUserConversions && T2->isRecordType()) {
+  // FIXME: Without standard language for N2812, the rvalue reference treatment
+  // here is pretty much a guess.
+  if (!isRValRef && !SuppressUserConversions && T2->isRecordType()) {
     // FIXME: Look for conversions in base classes!
     CXXRecordDecl *T2RecordDecl 
       = dyn_cast<CXXRecordDecl>(T2->getAsRecordType()->getDecl());
@@ -1790,7 +1803,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
       // If the conversion function doesn't return a reference type,
       // it can't be considered for this conversion.
       // FIXME: This will change when we support rvalue references.
-      if (Conv->getConversionType()->isReferenceType() &&
+      if (Conv->getConversionType()->isLValueReferenceType() &&
           (AllowExplicit || !Conv->isExplicit()))
         AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
     }
@@ -1862,8 +1875,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
   }
 
   //     -- Otherwise, the reference shall be to a non-volatile const
-  //        type (i.e., cv1 shall be const).
-  if (T1.getCVRQualifiers() != QualType::Const) {
+  //        type (i.e., cv1 shall be const), or shall be an rvalue reference.
+  if (!isRValRef && T1.getCVRQualifiers() != QualType::Const) {
     if (!ICS)
       Diag(Init->getSourceRange().getBegin(),
            diag::err_not_reference_to_const_init)
@@ -2200,6 +2213,8 @@ Sema::DeclTy *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D)
       RequireCompleteType(Begin, BaseType, DK))
     Invalid = true;
 
+  // FIXME: C++0x [except.handle] names the handler as cv T or cv T&, i.e.
+  // rvalue references aren't there. Oversight or intentional?
   // FIXME: Need to test for ability to copy-construct and destroy the
   // exception variable.
   // FIXME: Need to check for abstract classes.
index 5450d1949f0f62dd2762467ca22535321bfbfef7..b3d94c372dc77ff9b3e41b06b3354fadd25c5010 100644 (file)
@@ -764,7 +764,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
     // the constructor or conversion operator, and then cope with the
     // standard conversions.
     ImpCastExprToType(From, ToType.getNonReferenceType(), 
-                      ToType->isReferenceType());
+                      ToType->isLValueReferenceType());
     return false;
 
   case ImplicitConversionSequence::EllipsisConversion:
@@ -800,7 +800,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
     // FIXME: Create a temporary object by calling the copy
     // constructor.
     ImpCastExprToType(From, ToType.getNonReferenceType(), 
-                      ToType->isReferenceType());
+                      ToType->isLValueReferenceType());
     return false;
   }
 
@@ -893,8 +893,10 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
     break;
 
   case ICK_Qualification:
+    // FIXME: Not sure about lvalue vs rvalue here in the presence of
+    // rvalue references.
     ImpCastExprToType(From, ToType.getNonReferenceType(), 
-                      ToType->isReferenceType());
+                      ToType->isLValueReferenceType());
     break;
 
   default:
index 02df9b32fa36cb9c35b36b0251035b4c9df9cbbe..e0d3b7e545d03eb687ef0ae5cf284219aafaf40b 100644 (file)
@@ -121,7 +121,7 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
     return false;
   
   // C++ [dcl.init.ref]p1:
-  //   A variable declared to be a T&, that is "reference to type T"
+  //   A variable declared to be a T& or T&&, that is "reference to type T"
   //   (8.3.2), shall be initialized by an object, or function, of
   //   type T or by an object that can be converted into a T.
   if (DeclType->isReferenceType())
index a8ad10d38266e68b83cbc747385e55833254a243..9f5c5e58708f63fb6e05953e42d2d9496f7f3a0c 100644 (file)
@@ -115,9 +115,10 @@ CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
 
   DestType = Self.Context.getCanonicalType(DestType);
   QualType SrcType = SrcExpr->getType();
-  if (const ReferenceType *DestTypeTmp = DestType->getAsReferenceType()) {
+  if (const LValueReferenceType *DestTypeTmp =
+        DestType->getAsLValueReferenceType()) {
     if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
-      // Cannot cast non-lvalue to reference type.
+      // Cannot cast non-lvalue to lvalue reference type.
       Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
         << "const_cast" << OrigDestType << SrcExpr->getSourceRange();
       return;
@@ -141,6 +142,8 @@ CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
   if (!DestType->isPointerType() && !DestType->isMemberPointerType()) {
     // Cannot cast to non-pointer, non-reference type. Note that, if DestType
     // was a reference type, we converted it to a pointer above.
+    // The status of rvalue references isn't entirely clear, but it looks like
+    // conversion to them is simply invalid.
     // C++ 5.2.11p3: For two pointer types [...]
     Self.Diag(OpRange.getBegin(), diag::err_bad_const_cast_dest)
       << OrigDestType << DestRange;
@@ -214,7 +217,8 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
 
   DestType = Self.Context.getCanonicalType(DestType);
   QualType SrcType = SrcExpr->getType();
-  if (const ReferenceType *DestTypeTmp = DestType->getAsReferenceType()) {
+  if (const LValueReferenceType *DestTypeTmp =
+        DestType->getAsLValueReferenceType()) {
     if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
       // Cannot cast non-lvalue to reference type.
       Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
@@ -226,6 +230,14 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
     //   same effect as the conversion *reinterpret_cast<T*>(&x) with the
     //   built-in & and * operators.
     // This code does this transformation for the checked types.
+    DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
+    SrcType = Self.Context.getPointerType(SrcType);
+  } else if (const RValueReferenceType *DestTypeTmp =
+               DestType->getAsRValueReferenceType()) {
+    // Both the reference conversion and the rvalue rules apply.
+    Self.DefaultFunctionArrayConversion(SrcExpr);
+    SrcType = SrcExpr->getType();
+
     DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
     SrcType = Self.Context.getPointerType(SrcType);
   } else {
@@ -425,6 +437,8 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
   // conversion using B's conversion constructor.
   // DR 427 specifies that the downcast is to be applied here.
 
+  // FIXME: With N2812, casts to rvalue refs will change.
+
   // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void".
   if (DestType->isVoidType()) {
     return;
@@ -787,9 +801,11 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
     return;
   }
 
-  // C++ 5.2.7p2: If T is a pointer type, v shall be an rvalue of a pointer to
-  //   complete class type, [...]. If T is a reference type, v shall be an
-  //   lvalue of a complete class type, [...].
+  // C++0x 5.2.7p2: If T is a pointer type, v shall be an rvalue of a pointer to
+  //   complete class type, [...]. If T is an lvalue reference type, v shall be
+  //   an lvalue of a complete class type, [...]. If T is an rvalue reference
+  //   type, v shall be an expression having a complete effective class type,
+  //   [...]
 
   QualType SrcType = Self.Context.getCanonicalType(OrigSrcType);
   QualType SrcPointee;
@@ -801,12 +817,14 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
         << OrigSrcType << SrcExpr->getSourceRange();
       return;
     }
-  } else {
+  } else if (DestReference->isLValueReferenceType()) {
     if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
       Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue)
         << "dynamic_cast" << OrigDestType << OpRange;
     }
     SrcPointee = SrcType;
+  } else {
+    SrcPointee = SrcType;
   }
 
   const RecordType *SrcRecord = SrcPointee->getAsRecordType();
index 8943aa602eb1a60cb074ab540ec8319ba8db5740..5321935cfc7bfd88f3c72e4f0e1912d2743b814c 100644 (file)
@@ -519,8 +519,10 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
     // We were able to resolve the address of the overloaded function,
     // so we can convert to the type of that function.
     FromType = Fn->getType();
-    if (ToType->isReferenceType())
-      FromType = Context.getReferenceType(FromType);
+    if (ToType->isLValueReferenceType())
+      FromType = Context.getLValueReferenceType(FromType);
+    else if (ToType->isRValueReferenceType())
+      FromType = Context.getRValueReferenceType(FromType);
     else if (ToType->isMemberPointerType()) {
       // Resolve address only succeeds if both sides are member pointers,
       // but it doesn't have to be the same class. See DR 247.
@@ -2734,7 +2736,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
          Arith < NumArithmeticTypes; ++Arith) {
       QualType ArithTy = ArithmeticTypes[Arith];
       QualType ParamTypes[2] 
-        = { Context.getReferenceType(ArithTy), Context.IntTy };
+        = { Context.getLValueReferenceType(ArithTy), Context.IntTy };
 
       // Non-volatile version.
       if (NumArgs == 1)
@@ -2743,7 +2745,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
         AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet);
 
       // Volatile version
-      ParamTypes[0] = Context.getReferenceType(ArithTy.withVolatile());
+      ParamTypes[0] = Context.getLValueReferenceType(ArithTy.withVolatile());
       if (NumArgs == 1)
         AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
       else
@@ -2767,7 +2769,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
         continue;
 
       QualType ParamTypes[2] = { 
-        Context.getReferenceType(*Ptr), Context.IntTy 
+        Context.getLValueReferenceType(*Ptr), Context.IntTy 
       };
       
       // Without volatile
@@ -2778,7 +2780,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
 
       if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) {
         // With volatile
-        ParamTypes[0] = Context.getReferenceType((*Ptr).withVolatile());
+        ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile());
         if (NumArgs == 1)
           AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet);
         else
@@ -2802,7 +2804,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
          Ptr != CandidateTypes.pointer_end(); ++Ptr) {
       QualType ParamTy = *Ptr;
       QualType PointeeTy = ParamTy->getAsPointerType()->getPointeeType();
-      AddBuiltinCandidate(Context.getReferenceType(PointeeTy), 
+      AddBuiltinCandidate(Context.getLValueReferenceType(PointeeTy), 
                           &ParamTy, Args, 1, CandidateSet);
     }
     break;
@@ -3021,14 +3023,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
       QualType ParamTypes[2];
 
       // T& operator=(T&, T)
-      ParamTypes[0] = Context.getReferenceType(*Enum);
+      ParamTypes[0] = Context.getLValueReferenceType(*Enum);
       ParamTypes[1] = *Enum;
       AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
                           /*IsAssignmentOperator=*/false);
 
       if (!Context.getCanonicalType(*Enum).isVolatileQualified()) {
         // volatile T& operator=(volatile T&, T)
-        ParamTypes[0] = Context.getReferenceType((*Enum).withVolatile());
+        ParamTypes[0] = Context.getLValueReferenceType((*Enum).withVolatile());
         ParamTypes[1] = *Enum;
         AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
                             /*IsAssignmentOperator=*/false);
@@ -3060,13 +3062,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
       ParamTypes[1] = (Op == OO_Equal)? *Ptr : Context.getPointerDiffType();
 
       // non-volatile version
-      ParamTypes[0] = Context.getReferenceType(*Ptr);
+      ParamTypes[0] = Context.getLValueReferenceType(*Ptr);
       AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
                           /*IsAssigmentOperator=*/Op == OO_Equal);
 
       if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) {
         // volatile version
-        ParamTypes[0] = Context.getReferenceType((*Ptr).withVolatile());
+        ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile());
         AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
                             /*IsAssigmentOperator=*/Op == OO_Equal);
       }
@@ -3094,13 +3096,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
         ParamTypes[1] = ArithmeticTypes[Right];
 
         // Add this built-in operator as a candidate (VQ is empty).
-        ParamTypes[0] = Context.getReferenceType(ArithmeticTypes[Left]);
+        ParamTypes[0] = Context.getLValueReferenceType(ArithmeticTypes[Left]);
         AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
                             /*IsAssigmentOperator=*/Op == OO_Equal);
 
         // Add this built-in operator as a candidate (VQ is 'volatile').
         ParamTypes[0] = ArithmeticTypes[Left].withVolatile();
-        ParamTypes[0] = Context.getReferenceType(ParamTypes[0]);
+        ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
         AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
                             /*IsAssigmentOperator=*/Op == OO_Equal);
       }
@@ -3132,13 +3134,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
         ParamTypes[1] = ArithmeticTypes[Right];
 
         // Add this built-in operator as a candidate (VQ is empty).
-        ParamTypes[0] = Context.getReferenceType(ArithmeticTypes[Left]);
+        ParamTypes[0] = Context.getLValueReferenceType(ArithmeticTypes[Left]);
         AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
 
         // Add this built-in operator as a candidate (VQ is 'volatile').
         ParamTypes[0] = ArithmeticTypes[Left];
         ParamTypes[0].addVolatile();
-        ParamTypes[0] = Context.getReferenceType(ParamTypes[0]);
+        ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]);
         AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
       }
     }
@@ -3190,7 +3192,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
          Ptr != CandidateTypes.pointer_end(); ++Ptr) {
       QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() };
       QualType PointeeType = (*Ptr)->getAsPointerType()->getPointeeType();
-      QualType ResultTy = Context.getReferenceType(PointeeType);
+      QualType ResultTy = Context.getLValueReferenceType(PointeeType);
 
       // T& operator[](T*, ptrdiff_t)
       AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet);
@@ -3407,11 +3409,17 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
         // retaining as many typedefs as possible while still showing
         // the function type (and, therefore, its parameter types).
         QualType FnType = Cand->Surrogate->getConversionType();
-        bool isReference = false;
+        bool isLValueReference = false;
+        bool isRValueReference = false;
         bool isPointer = false;
-        if (const ReferenceType *FnTypeRef = FnType->getAsReferenceType()) {
+        if (const LValueReferenceType *FnTypeRef =
+              FnType->getAsLValueReferenceType()) {
           FnType = FnTypeRef->getPointeeType();
-          isReference = true;
+          isLValueReference = true;
+        } else if (const RValueReferenceType *FnTypeRef =
+                     FnType->getAsRValueReferenceType()) {
+          FnType = FnTypeRef->getPointeeType();
+          isRValueReference = true;
         }
         if (const PointerType *FnTypePtr = FnType->getAsPointerType()) {
           FnType = FnTypePtr->getPointeeType();
@@ -3421,7 +3429,8 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
         FnType = QualType(FnType->getAsFunctionType(), 0);
         // Reconstruct the pointer/reference as appropriate.
         if (isPointer) FnType = Context.getPointerType(FnType);
-        if (isReference) FnType = Context.getReferenceType(FnType);
+        if (isRValueReference) FnType = Context.getRValueReferenceType(FnType);
+        if (isLValueReference) FnType = Context.getLValueReferenceType(FnType);
 
         Diag(Cand->Surrogate->getLocation(), diag::err_ovl_surrogate_cand)
           << FnType;
@@ -4144,7 +4153,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
     // FIXME: Represent the user-defined conversion in the AST!
     ImpCastExprToType(Object,
                       Conv->getConversionType().getNonReferenceType(),
-                      Conv->getConversionType()->isReferenceType());
+                      Conv->getConversionType()->isLValueReferenceType());
     return ActOnCallExpr(S, ExprArg(*this, Object), LParenLoc,
                          MultiExprArg(*this, (ExprTy**)Args, NumArgs),
                          CommaLocs, RParenLoc).release();
index dbdc5a8a7169fc9d06e959b82534e87b4a5072bd..fd541f3680cf053173bc234575ec469f5738d98c 100644 (file)
@@ -218,14 +218,24 @@ TemplateTypeInstantiator::InstantiateBlockPointerType(const BlockPointerType *T,
   return QualType();
 }
 
-QualType 
-TemplateTypeInstantiator::InstantiateReferenceType(const ReferenceType *T, 
-                                                   unsigned Quals) const {
+QualType
+TemplateTypeInstantiator::InstantiateLValueReferenceType(
+    const LValueReferenceType *T, unsigned Quals) const {
+  QualType ReferentType = Instantiate(T->getPointeeType());
+  if (ReferentType.isNull())
+    return QualType();
+
+  return SemaRef.BuildReferenceType(ReferentType, true, Quals, Loc, Entity);
+}
+
+QualType
+TemplateTypeInstantiator::InstantiateRValueReferenceType(
+    const RValueReferenceType *T, unsigned Quals) const {
   QualType ReferentType = Instantiate(T->getPointeeType());
   if (ReferentType.isNull())
     return QualType();
 
-  return SemaRef.BuildReferenceType(ReferentType, Quals, Loc, Entity);
+  return SemaRef.BuildReferenceType(ReferentType, false, Quals, Loc, Entity);
 }
 
 QualType 
index bfbc6c370809bf2ae269954bf0963d2628cb30c3..ac0e1e1f73c53fe04ba43e67b23e8d4d038159d9 100644 (file)
@@ -319,8 +319,16 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals,
 ///
 /// \returns A suitable reference type, if there are no
 /// errors. Otherwise, returns a NULL type.
-QualType Sema::BuildReferenceType(QualType T, unsigned Quals, 
+QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,
                                   SourceLocation Loc, DeclarationName Entity) {
+  if (LValueRef) {
+    if (const RValueReferenceType *R = T->getAsRValueReferenceType()) {
+      // FIXME: Find the C++0x reference for reference collapsing.
+      // In reference collapsing, lvalue refs win over rvalue refs.
+      return Context.getLValueReferenceType(R->getPointeeType()).
+               getQualifiedType(Quals);
+    }
+  }
   if (T->isReferenceType()) {
     // C++ [dcl.ref]p4: There shall be no references to references.
     // 
@@ -367,7 +375,9 @@ QualType Sema::BuildReferenceType(QualType T, unsigned Quals,
   Quals &= ~QualType::Volatile;
 
   // Handle restrict on references.
-  return Context.getReferenceType(T).getQualifiedType(Quals);
+  if (LValueRef)
+    return Context.getLValueReferenceType(T).getQualifiedType(Quals);
+  return Context.getRValueReferenceType(T).getQualifiedType(Quals);
 }
 
 /// \brief Build an array type.
@@ -603,8 +613,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
       T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name);
       break;
     case DeclaratorChunk::Reference:
-      T = BuildReferenceType(T, 
-                             DeclType.Ref.HasRestrict? QualType::Restrict : 0,
+      T = BuildReferenceType(T, DeclType.Ref.LValueRef,
+                             DeclType.Ref.HasRestrict ? QualType::Restrict : 0,
                              DeclType.Loc, Name);
       break;
     case DeclaratorChunk::Array: {
index 1fd2fd652c911e01574a6abca1ee61231c875a74..8d65defe7df69751575cdc7989b858c0d2760ca3 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: clang -fsyntax-only -verify -std=c++0x %s
+// RUN: clang -fsyntax-only -verify %s
 
 extern char *bork;
 char *& bar = bork;
@@ -17,8 +17,3 @@ int & const X = val; // expected-error {{'const' qualifier may not be applied to
 int & volatile Y = val; // expected-error {{'volatile' qualifier may not be applied to a reference}}
 int & const volatile Z = val; /* expected-error {{'const' qualifier may not be applied}} \
                            expected-error {{'volatile' qualifier may not be applied}} */
-
-int && r1(int &&a);
-
-typedef int && R;
-void r2(const R a);
diff --git a/test/Parser/cxx0x-rvalue-reference.cpp b/test/Parser/cxx0x-rvalue-reference.cpp
new file mode 100644 (file)
index 0000000..3643233
--- /dev/null
@@ -0,0 +1,6 @@
+// RUN: clang -fsyntax-only -verify -std=c++0x %s
+
+int && r1(int &&a);
+
+typedef int && R;
+void r2(const R a);
index 100267c17f7fcc9267c67ea56fe36f0cafe7fe4b..74d925a3d58eb6fecc8fcaf58564eb1fbddda16b 100644 (file)
@@ -49,7 +49,7 @@ void test_explicit_bool(ExplicitConvToBool ecb) {
 }
 
 void test_explicit_conv_to_ref(ExplicitConvToRef ecr) {
-  int& i1 = ecr; // expected-error{{non-const reference to type 'int' cannot be initialized with a value of type 'struct ExplicitConvToRef'}}
+  int& i1 = ecr; // expected-error{{non-const lvalue reference to type 'int' cannot be initialized with a value of type 'struct ExplicitConvToRef'}}
   int& i2(ecr); // okay
 }
 
@@ -61,7 +61,7 @@ struct C {
 };
 
 void test_copy_init_conversions(C c) {
-  A &a = c; // expected-error{{non-const reference to type 'struct A' cannot be initialized with a value of type 'struct C'}}
+  A &a = c; // expected-error{{non-const lvalue reference to type 'struct A' cannot be initialized with a value of type 'struct C'}}
   B &b = b; // okay
 }
 
index 7a5e06e5fad888663bf79946fae00a82937afe44..d51354e16993012824b602b86715400615be3f67 100644 (file)
@@ -67,7 +67,7 @@ void enum_test(Enum1 enum1, Enum2 enum2, E1 e1, E2 e2) {
   float &f1 = (e1 == e2);
   float &f2 = (enum1 == e2); 
   float &f3 = (e1 == enum2); 
-  float &f4 = (enum1 == enum2);  // expected-error{{non-const reference to type 'float' cannot be initialized with a temporary of type '_Bool'}}
+  float &f4 = (enum1 == enum2);  // expected-error{{non-const lvalue reference to type 'float' cannot be initialized with a temporary of type '_Bool'}}
 }
 
 
index 61e30b584dfcc082ddc99a20289a5f85fe80869b..8ee7745b925629d23be9a86bd498a1c90b78a1e1 100644 (file)
@@ -44,9 +44,9 @@ B fB();
 
 // C++ [dcl.init.ref]p5b2
 void test4() {
-  double& rd2 = 2.0; // expected-error{{non-const reference to type 'double' cannot be initialized with a temporary of type 'double'}}
+  double& rd2 = 2.0; // expected-error{{non-const lvalue reference to type 'double' cannot be initialized with a temporary of type 'double'}}
   int i = 2;
-  double& rd3 = i; // expected-error{{non-const reference to type 'double' cannot be initialized with a value of type 'int'}}
+  double& rd3 = i; // expected-error{{non-const lvalue reference to type 'double' cannot be initialized with a value of type 'int'}}
 
   const A& rca = fB();
 }
diff --git a/test/SemaCXX/rval-references.cpp b/test/SemaCXX/rval-references.cpp
new file mode 100644 (file)
index 0000000..ae26449
--- /dev/null
@@ -0,0 +1,33 @@
+// RUN: clang -fsyntax-only -verify -std=c++0x %s
+
+typedef int&& irr;
+typedef irr& ilr_c1; // Collapses to int&
+typedef int& ilr;
+typedef ilr&& ilr_c2; // Collapses to int&
+
+irr ret_irr() {
+  return 0;
+}
+
+struct not_int {};
+
+int over(int&);
+not_int over(int&&);
+
+void f() {
+  int &&virr1; // expected-error {{declaration of reference variable 'virr1' requires an initializer}}
+  int &&virr2 = 0;
+  // FIXME: named rvalue references are lvalues!
+  //int &&virr3 = virr1; // xpected-error {{rvalue reference cannot bind to lvalue}}
+  int i1 = 0;
+  int &&virr4 = i1; // expected-error {{rvalue reference cannot bind to lvalue}}
+  int &&virr5 = ret_irr();
+
+  int i2 = over(i1);
+  not_int ni1 = over(0);
+  int i3 = over(virr2);
+  not_int ni2 = over(ret_irr());
+
+  ilr_c1 vilr1 = i1;
+  ilr_c2 vilr2 = i1;
+}
index 9bbcdf670be9dd689825d9cd9428e948905b0ba3..bf7561d1d8e8fc6e842dee6ba9dc382968def264 100644 (file)
@@ -54,7 +54,7 @@ void t_529_2()
   //(void)static_cast<A*>((H*)0); // {{static_cast from 'struct H *' to 'struct A *' is not allowed}}
   (void)static_cast<int>((int*)0); // expected-error {{static_cast from 'int *' to 'int' is not allowed}}
   (void)static_cast<A**>((B**)0); // expected-error {{static_cast from 'struct B **' to 'struct A **' is not allowed}}
-  (void)static_cast<char&>(i); // expected-error {{non-const reference to type 'char' cannot be initialized with a value of type 'int'}}
+  (void)static_cast<char&>(i); // expected-error {{non-const lvalue reference to type 'char' cannot be initialized with a value of type 'int'}}
 }
 
 // Anything to void
@@ -86,7 +86,7 @@ void t_529_5_8()
   (void)static_cast<H*>((A*)0); // expected-error {{ambiguous static_cast from base 'struct A' to derived 'struct H':\n    struct A -> struct B -> struct G1 -> struct H\n    struct A -> struct B -> struct G2 -> struct H}}
   (void)static_cast<H&>(*((A*)0)); // expected-error {{ambiguous static_cast from base 'struct A' to derived 'struct H':\n    struct A -> struct B -> struct G1 -> struct H\n    struct A -> struct B -> struct G2 -> struct H}}
   (void)static_cast<E*>((B*)0); // expected-error {{static_cast from 'struct B *' to 'struct E *' is not allowed}}
-  (void)static_cast<E&>(*((B*)0)); // expected-error {{non-const reference to type 'struct E' cannot be initialized with a value of type 'struct B'}}
+  (void)static_cast<E&>(*((B*)0)); // expected-error {{non-const lvalue reference to type 'struct E' cannot be initialized with a value of type 'struct B'}}
 
   // TODO: Test inaccessible base in context where it's accessible, i.e.
   // member function and friend.