From: Sebastian Redl Date: Mon, 16 Mar 2009 23:22:08 +0000 (+0000) Subject: Almost complete implementation of rvalue references. One bug, and a few unclear areas... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7c80bd64032e610c0dbd74fc0ef6ea334447f2fd;p=clang 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/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 8a8be1e775..124f7db449 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -59,7 +59,8 @@ class ASTContext { llvm::FoldingSet ComplexTypes; llvm::FoldingSet PointerTypes; llvm::FoldingSet BlockPointerTypes; - llvm::FoldingSet ReferenceTypes; + llvm::FoldingSet LValueReferenceTypes; + llvm::FoldingSet RValueReferenceTypes; llvm::FoldingSet MemberPointerTypes; llvm::FoldingSet ConstantArrayTypes; llvm::FoldingSet 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 diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 13668569ca..4e1672d435 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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(CanonicalType.getUnqualifiedType()); } +inline bool Type::isLValueReferenceType() const { + return isa(CanonicalType.getUnqualifiedType()); +} +inline bool Type::isRValueReferenceType() const { + return isa(CanonicalType.getUnqualifiedType()); +} inline bool Type::isFunctionPointerType() const { if (const PointerType* T = getAsPointerType()) return T->getPointeeType()->isFunctionType(); diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index e071f640ba..4c5c02d2a5 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -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) diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 4d721bc331..d415ee5392 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -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") diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index dd2a17e791..a2ba0e9708 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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 " diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 80e17746bb..c318107dab 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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(T)) ++NumBlockPointer; - else if (isa(T)) - ++NumReference; + else if (isa(T)) + ++NumLValueReference; + else if (isa(T)) + ++NumRValueReference; else if (isa(T)) ++NumMemberPointer; else if (isa(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(); diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index 4655cf392d..7eab2679e8 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -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; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index fd900834ca..a3c7997c6d 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -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; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 669f5c8225..2f7e3630fd 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -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(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(this)->getTypeAsWritten()->isReferenceType()) + if (cast(this)->getTypeAsWritten()-> + isLValueReferenceType()) return LV_Valid; break; case CXXTypeidExprClass: diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 6fb2abe7cd..a0ef7460c5 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -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, diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index fc71097c12..1714e84129 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -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(this)) return RTy; - + // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { + if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(this)) + return RTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(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(this)) + return RTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(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(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(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(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(getPointeeType())) S = '(' + S + ')'; diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp index 1b9fed4866..8498e0123e 100644 --- a/lib/AST/TypeSerialization.cpp +++ b/lib/AST/TypeSerialization.cpp @@ -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(); } //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 9b56b8449f..0dac6ba920 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -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: diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 8cd353408f..1a64e3c905 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -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(); } diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 2d4c27c2ac..85d7384c6c 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -266,7 +266,8 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { ConvertTypeRecursive(cast(Ty).getElementType()); return llvm::StructType::get(EltTy, EltTy, NULL); } - case Type::Reference: { + case Type::LValueReference: + case Type::RValueReference: { const ReferenceType &RTy = cast(Ty); QualType ETy = RTy.getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(); diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 92eeb5db14..d54849bd78 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -365,12 +365,17 @@ void CXXNameMangler::mangleType(QualType T) { mangleType(PT->getPointeeType()); } // ::= R # reference-to - // ::= O # rvalue reference-to (C++0x) - else if (const ReferenceType *RT = dyn_cast(T.getTypePtr())) { - // FIXME: rvalue references + else if (const LValueReferenceType *RT = + dyn_cast(T.getTypePtr())) { Out << 'R'; mangleType(RT->getPointeeType()); } + // ::= O # rvalue reference-to (C++0x) + else if (const RValueReferenceType *RT = + dyn_cast(T.getTypePtr())) { + Out << 'O'; + mangleType(RT->getPointeeType()); + } // ::= C # complex pair (C 2000) else if (const ComplexType *CT = dyn_cast(T.getTypePtr())) { Out << 'C'; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 29d0796dcb..13c3e87bfe 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index fa84c7d2de..acf8224542 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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(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. diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 5450d1949f..b3d94c372d 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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: diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 02df9b32fa..e0d3b7e545 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -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()) diff --git a/lib/Sema/SemaNamedCast.cpp b/lib/Sema/SemaNamedCast.cpp index a8ad10d382..9f5c5e5870 100644 --- a/lib/Sema/SemaNamedCast.cpp +++ b/lib/Sema/SemaNamedCast.cpp @@ -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(&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(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 8943aa602e..5321935cfc 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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(); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index dbdc5a8a71..fd541f3680 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -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 diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index bfbc6c3708..ac0e1e1f73 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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: { diff --git a/test/Parser/cxx-reference.cpp b/test/Parser/cxx-reference.cpp index 1fd2fd652c..8d65defe7d 100644 --- a/test/Parser/cxx-reference.cpp +++ b/test/Parser/cxx-reference.cpp @@ -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 index 0000000000..3643233272 --- /dev/null +++ b/test/Parser/cxx0x-rvalue-reference.cpp @@ -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); diff --git a/test/SemaCXX/convert-to-bool.cpp b/test/SemaCXX/convert-to-bool.cpp index 100267c17f..74d925a3d5 100644 --- a/test/SemaCXX/convert-to-bool.cpp +++ b/test/SemaCXX/convert-to-bool.cpp @@ -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 } diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp index 7a5e06e5fa..d51354e169 100644 --- a/test/SemaCXX/overloaded-operator.cpp +++ b/test/SemaCXX/overloaded-operator.cpp @@ -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'}} } diff --git a/test/SemaCXX/references.cpp b/test/SemaCXX/references.cpp index 61e30b584d..8ee7745b92 100644 --- a/test/SemaCXX/references.cpp +++ b/test/SemaCXX/references.cpp @@ -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 index 0000000000..ae2644919a --- /dev/null +++ b/test/SemaCXX/rval-references.cpp @@ -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; +} diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp index 9bbcdf670b..bf7561d1d8 100644 --- a/test/SemaCXX/static-cast.cpp +++ b/test/SemaCXX/static-cast.cpp @@ -54,7 +54,7 @@ void t_529_2() //(void)static_cast((H*)0); // {{static_cast from 'struct H *' to 'struct A *' is not allowed}} (void)static_cast((int*)0); // expected-error {{static_cast from 'int *' to 'int' is not allowed}} (void)static_cast((B**)0); // expected-error {{static_cast from 'struct B **' to 'struct A **' is not allowed}} - (void)static_cast(i); // expected-error {{non-const reference to type 'char' cannot be initialized with a value of type 'int'}} + (void)static_cast(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((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(*((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((B*)0); // expected-error {{static_cast from 'struct B *' to 'struct E *' is not allowed}} - (void)static_cast(*((B*)0)); // expected-error {{non-const reference to type 'struct E' cannot be initialized with a value of type 'struct B'}} + (void)static_cast(*((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.